微信公众号: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-
领取专属 10元无门槛券
私享最新 技术干货