CNN 入門講解:圖片在卷積神經網路中是怎麼變化的
微信公眾號:follow_bobo
首發於知乎:蔣竺波
這一期我們主要一邊寫代碼
一邊看圖片經過卷積層發生了什麼變化
經過採樣層發生了什麼變化
經過激活層發生了什麼變化
相當於實踐了前向傳播
走著
----------我又來當分割線了---------------------
看到代碼不要慌,很容易看懂的。
第一步:把需要的functions 全部先導進去,我們這裡主要是使用keras
import cv2
from keras import backend as K
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization,Activation, Dropout, Dense,UpSampling2D,Input,add
from keras.models import Model, Sequential, load_model
import numpy as np
------------------------------------------------------------------------------------------
我們今天的網路結構如下,沒有經過訓練的:
model = Sequential()
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_1"))#加入一個卷積層,filter數量為3,卷積核size為(3,3)
model.add(MaxPooling2D(pool_size=(3,3)))#加入一個pooling 層,size為(3,3)
model.add(Activation("relu"))# 加入激活函數"ReLu", 只保留大於0 的值
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Activation("relu"))
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_3"))
model.add(Activation("relu"))
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_4"))
model.add(Activation("relu"))
model.add(Flatten())#把上層輸出平鋪
model.add(Dense(8, activation="relu",name="dens_1"))#加入全連接層,分為8類
-----------------------------------------------------------------------------------------------
因為conv2d這個function 對於權值是隨機初始化的
每運行一次程序權值就變了,權值變了就沒有比較意義了,而我們不用pretrained model,所以我們要保存第一次初始化的權值
-----------------------------------------------------------------------------------------------
model.save_weights("girl.h5")
第二步:我們先來看看我們的輸入數據:
girl = cv2.imread(『girl.jpg』)
girl.jpg shape= (575,607)
第三步:搭建一個卷積層
girl = cv2.imread("girl.jpg")
model = Sequential()
model.add(Conv2D(3,3,3,input_shape= girl.shape ,name="conv_1")) # filter =3, kernel_size =(3,3)
model.load_weights("girl.h5", by_name=True) # 『by_name』表示只給和保存模型相同卷積層名字的卷積層導入權值,這裡就是把上一步『conv_1』的權值導入這一步『conv_1』,當然結構得相同
第四步:數據增維
由於keras 只能按批處理數據,因此需要把單個數據提高一個維度
girl_batch = np.expand_dims(girl,axis=0)
#數據維度由(575,607,3)變為(1,575,607,3)
第五步:查看卷積層輸出---特徵圖
conv_girl = model.predict(girl_batch)
girl_img = np.squeeze(conv_girl,axis=0)
#把圖像的像素值大小rescale 到0-255之間
max_img = np.max(img)
min_img = np.min(img)
img = img-(min_img)
img=img/(max_img - min_img)
img = img*255
cv2.imwrite("conv1_output.jpg",girl_img)
conv_1,filter=3,kernel =3x3 ,shape = (573,605)
可以看到圖像的一些紋理,邊緣,或者顏色信息被一定程度上提取出來了,shape也發生了變化
第七步:加入pooling 層
model = Sequential()
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_1"))
model.add(MaxPooling2D(pool_size=(2,2)))
conv_1, filter=3,kernel =3x3,pool=(3,3) shape=(191,201)
從上圖可以明顯的看到特徵更加明顯,並且shape減為三分之一了
第八步 加入激活函數"ReLu"
model = Sequential()
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_1"))
model.add(MaxPooling2D(pool_size=(3,3)))
model.add(Activation("relu"))# 只保留大於0 的值
ReLu
conv_1, filter=3, kernel =3x3, pool=(2,2), activation ="ReLu", shape=(191,201)
可以看到只有一些邊緣的特徵被保留下來了
第九步 在原來的基礎上加入新的卷積層
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
conv_2, filter=3,kernel =3x3,shape=(189,199)
紋理的信息更明顯了
第九步 在原來的基礎上加入新的採樣層
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
model.add(MaxPooling2D(pool_size=(2,2)))
conv_2, filter=3,kernel =3x3,pool=(2,2),shape=(94,99)
第十步:在原來的基礎上加入新的激活函數"ReLu』
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Activation("relu")
conv_2, filter=3, kernel =3x3, pool=(2,2), activation =『relu", shape=(94,99)
番外步:把原來激活函數"relu", 全部改為『sigmoid』
model = Sequential()
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_1"))
model.add(MaxPooling2D(pool_size=(3,3)))
model.add(Activation("sigmoid"))
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Activation("sigmoid"))
Sigmoid
conv_2, filter=3, kernel =3x3, pool=(2,2), activation =『sigmoid", shape=(94,99)
番外步:把原來激活函數"Relu",全部改為"tanh』
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_2"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Activation("tanh"))
tanh
conv_2, filter=3, kernel =3x3, pool=(2,2), activation = "tanh", shape=(94,99)
第十一步 增加兩個卷積層和激活函數『relu』
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_3"))
model.add(Activation("relu"))
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_4"))
model.add(Activation("relu"))
conv_4, filter=3, kernel =3x3, activation = "relu", shape=(90,95)
第十一步 全連接層輸出
model.add(Conv2D(3,3,3,input_shape= girl.shape,name="conv_4"))
model.add(Activation("relu"))
model.add(Flatten())
model.add(Dense(8, activation="relu",name="dens_1"))#分為8類
dens_1, classes = 8 ,shape = (1,8)
番外篇:不同kernel size 之間的對比
這裡只用一個卷積層做測試,為了方便比較,所有的weights 值都設為0.12
model = Sequential()
model.add(Conv2D(filter1,ke_width,ke_height,kernel_initializer = keras.initializers.Constant(value=0.12),input_shape= girl.shape,name="conv_1"))
conv_1, filter=3, kernel =3x3, shape=(573,605)
conv_1, filter=3, kernel =12x12, shape=(564,596)
conv_1, filter=3, kernel =24x24, shape=(552,584)
擺代碼什麼的最輕鬆了,嘿嘿嘿
喜歡的朋友點個贊再走啊
你的贊是我寫下去的動力!!!
Come on!!!!!
全部代碼如下:https://github.com/jiangzhubo/cnn_forward_propagation-
TAG:隨波竺流 |