卷积神经网络keras实作
- 数据 oxflower17 ,使用keras实作AlexNet,VggNet,InceptionNet
AlexNet
- 如果说 LeNet是卷积神经网络的开山鼻祖,那么在2012年ImageNet竞赛中以超过第二名10.9个百分点的AlexNet就是激起深度学习和卷积神经网络千层浪的巨石。
- 主要闪光点:
- 数据增广:ImageNet1000类,输入图片规定是256×256彩色图片,AlexNet在256x256图中随机裁剪多张224*224图作为训练数据。
- 第一次采用Relu激活函数替代Sigmoid。
- 采用dropout层,避免过拟合。
- 网络结构:
在AlexNet时代由于硬件设备的现在,所以将网络拆分成了两部分,在不同GPU上训练最后整合,对于现在我们可以直接将整个网络整合在一起训练。
type | kernel size / stride | output size |
---|---|---|
conv2d | 11x11/4 | 55x55x96 |
conv2d | 5x5/1 | 55x55x256 |
max pool | 2x2/2 | 27x27x256 |
conv2d | 3x3/1 | 27x27x384 |
max pool | 2x2/2 | 13x13x384 |
conv2d | 3x3/1 | 13x13x384 |
conv2d | 3x3/1 | 13x13x256 |
max pool | 2x2/2 | 6x6x256 |
dense | 4096 | |
dropout | 0.5 | |
dense | 4096 | |
dropout | 0.5 | |
dense | 1000 |
- keras 实作:使用的oxflower17 数据集太小,训练集accuracy基本达到99%,验证集accuracy接近50%,过拟合明显。
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import tflearn.datasets.oxflower17 as oxflower17
from sklearn.model_selection import train_test_split
x, y = oxflower17.load_data()
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2,shuffle = True)
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(filters=96,kernel_size=(11,11),strides=4,padding='same',activation='relu',input_shape=(224,224,3)))
model.add(keras.layers.Conv2D(filters=256,kernel_size=(5,5),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=384,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=384,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=256,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(4096,activation='relu'))
model.add(keras.layers.Dropout(0.5))
model.add(keras.layers.Dense(4096,activation='relu'))
model.add(keras.layers.Dropout(0.5))
model.add(keras.layers.Dense(17,activation='softmax'))
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.summary()
cb = [ keras.callbacks.EarlyStopping(patience=30,min_delta=1e-4),
keras.callbacks.ModelCheckpoint('./AlexNet.h5',save_best_only=True) ]
his = model.fit(x_train,y_train,batch_size=64,epochs=100,validation_data=(x_test,y_test),callbacks=cb)
pd.DataFrame(his.history).plot(figsize=(8,5))
plt.grid(True)
# plt.gca().set_ylim(0,1)
plt.show()
VGGNet
- VGG-Nets是由牛津大学VGG(Visual Geometry Group)提出,是2014年ImageNet竞赛定位任务第一名和分类任务第二名中的基础网络。
- 主要闪光点:
- 数据增广:采用更多种方式采集,例如先缩大成512x512,在截取224x224的样本图。
- 多使用更小的3x3卷积核。
- 层次更深。
- 网络结构:
每经过一个pooling层,通道数要翻倍。(因为pooling大小减小信息会丢失,所以使通道再翻倍。)
- keras 实作:同样使用oxflower17 小数据集,依旧过拟合明显,但模型效果确实更好,验证集accuracy接近60%。
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import tflearn.datasets.oxflower17 as oxflower17
from sklearn.model_selection import train_test_split
x, y = oxflower17.load_data()
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2,shuffle = True)
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(filters=64,kernel_size=(3,3),strides=1,padding='same',activation='relu',input_shape=(224,224,3)))
model.add(keras.layers.Conv2D(filters=64,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=128,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=128,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=256,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=256,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=256,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.Conv2D(filters=512,kernel_size=(3,3),strides=1,padding='same',activation='relu'))
model.add(keras.layers.MaxPool2D(pool_size=(2,2),strides=2))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(4096,activation='relu'))
model.add(keras.layers.Dropout(0.5))
model.add(keras.layers.Dense(4096,activation='relu'))
model.add(keras.layers.Dropout(0.5))
model.add(keras.layers.Dense(17,activation='softmax'))
model.compile(optimizer=keras.optimizers.Adam(lr=0.00001),loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.summary()
cb = [ keras.callbacks.EarlyStopping(patience=30,min_delta=1e-4),
keras.callbacks.ModelCheckpoint('./VggNet16.h5',save_best_only=True) ]
his = model.fit(x_train,y_train,batch_size=64,epochs=100,validation_data=(x_test,y_test),callbacks=cb)
InceptionNet
- GoogLeNet也称为InceptionNet因其特殊的Inception结构,在2014的ImageNet分类任务上击败了VGG-Nets夺得冠军。至目前从InceptionNet-V1 到 InceptionNet-V4共递进式的发展了4个版本。
- Inception-V1
主要闪光点:
- 引入Inception结构:替换中间单纯的卷积池化层,是一种分组卷积的思想。
对前一层的输出采用四种不同卷积策略进行卷积,4组不同卷积得到的feature map大小都是保持一致的,最后再将所有的feature map 一张张并排叠起来,作为输出。
1X1的卷积层做非线性变换,用于降维,减少大量参数。 - 中间加入了2个辅助LOSS单元,避免梯度消失的情況,让网络更好地被训练。这两个辅助LOSS单元的计算被乘以0.3,然后和最后的LOSS相加作为最终的损失函数来训练网络。
- 将最后的全连接层替换成Average Pooling,减少了大量的参数。
- Inception-V2
主要闪光点:
- 引入BatchNormalization层,在每一层卷积层后面。加速了网络训练,防止梯度消失,一定程度避免过拟合。
- 改进Inception结构:使用2个3x3卷积核替代5x5,且减少了28%的参数量。
- Inception-V3
主要闪光点:
- 继续改进Inception结构:nxn卷积核并非最小,可采用一组:1xn和nx1卷积核替换。3x3换成3x1和1x3,且参数量能再降低33%。
-
Inception-V4
主要闪光点:学习了ResNet,应入了残差连接块。 -
keras 实作Inception-V2:oxflower17 小数据集,同样过拟合明显,但验证集accuracy接近70%。
网络结构:
#3x3 reduce卷积 为连接 #3x3卷积 的 1x1卷积。
double #3x3 reduce卷积 为连接 double #3x3卷积 的 1x1卷积。
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import tflearn.datasets.oxflower17 as oxflower17
from sklearn.model_selection import train_test_split
x, y = oxflower17.load_data()
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2,shuffle = True)
def Conv2D_BN(inputs,filter,kernel,padding,stride):
outputs = keras.layers.Conv2D(filters=filter,kernel_size=kernel,padding=padding,strides=stride,activation='relu')(inputs)
outputs = keras.layers.BatchNormalization()(outputs)
return outputs
def InceptionBlock_1(inputs,channel_for_branch):
channel_branch1,channel_branch2,channel_branch3,channel_branch4 = channel_for_branch
branch_1_1 = Conv2D_BN(inputs,channel_branch1[0],(1,1),'same',1)
branch_3_3 = Conv2D_BN(inputs,channel_branch2[0],(1,1),'same',1)
branch_3_3 = Conv2D_BN(branch_3_3,channel_branch2[1],(3,3),'same',1)
branch_3_3_2 = Conv2D_BN(inputs,channel_branch3[0],(1,1),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch3[1],(3,3),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch3[1],(3,3),'same',1)
branch_pooling = keras.layers.AveragePooling2D(pool_size=(3,3),strides=1,padding='same')(inputs)
branch_pooling = Conv2D_BN(branch_pooling,channel_branch4[0],(1,1),'same',1)
outputs = keras.layers.concatenate([branch_1_1,branch_3_3,branch_3_3_2,branch_pooling])
return outputs
def InceptionBlock_2(inputs,channel_for_branch):
channel_branch1,channel_branch2 = channel_for_branch
branch_3_3 = Conv2D_BN(inputs,channel_branch1[0],(1,1),'same',1)
branch_3_3 = Conv2D_BN(branch_3_3,channel_branch1[1],(3,3),'same',2)
branch_3_3_2 = Conv2D_BN(inputs,channel_branch2[0],(1,1),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch2[1],(3,3),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch2[1],(3,3),'same',2)
branch_pooling = keras.layers.MaxPool2D(pool_size=(3,3),strides=2,padding='same')(inputs)
outputs = keras.layers.concatenate([branch_3_3,branch_3_3_2,branch_pooling])
return outputs
def InceptionBlock_3(inputs,channel_for_branch):
channel_branch1,channel_branch2,channel_branch3,channel_branch4 = channel_for_branch
branch_1_1 = Conv2D_BN(inputs,channel_branch1[0],(1,1),'same',1)
branch_3_3 = Conv2D_BN(inputs,channel_branch2[0],(1,1),'same',1)
branch_3_3 = Conv2D_BN(branch_3_3,channel_branch2[1],(3,3),'same',1)
branch_3_3_2 = Conv2D_BN(inputs,channel_branch3[0],(1,1),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch3[1],(3,3),'same',1)
branch_3_3_2 = Conv2D_BN(branch_3_3_2,channel_branch3[1],(3,3),'same',1)
branch_pooling = keras.layers.MaxPool2D(pool_size=(3,3),strides=1,padding='same')(inputs)
branch_pooling = Conv2D_BN(branch_pooling,channel_branch4[0],(1,1),'same',1)
outputs = keras.layers.concatenate([branch_1_1,branch_3_3,branch_3_3_2,branch_pooling])
return outputs
inputs = keras.Input(shape=(224,224,3))
x = Conv2D_BN(inputs,64,(7,7),'same',2)
x = keras.layers.MaxPool2D(pool_size=(3,3),strides=2,padding='same')(x)
x = Conv2D_BN(x,64,(1,1),'same',1)
x = Conv2D_BN(x,192,(3,3),'same',1)
x = keras.layers.MaxPool2D(pool_size=(3,3),strides=2,padding='same')(x)
x = InceptionBlock_1(x,[(64,),(64,64),(64,96),(32,)])
x = InceptionBlock_1(x,[(64,),(64,96),(64,96),(64,)])
x = InceptionBlock_2(x,[(128,160),(64,96)])
x = InceptionBlock_1(x,[(224,),(64,96),(96,128),(128,)])
x = InceptionBlock_1(x,[(192,),(96,128),(96,128),(128,)])
x = InceptionBlock_1(x,[(160,),(128,160),(128,160),(128,)])
x = InceptionBlock_1(x,[(96,),(128,192),(160,192),(128,)])
x = InceptionBlock_2(x,[(128,192),(192,256)])
x = InceptionBlock_1(x,[(352,),(192,320),(160,224),(128,)])
x = InceptionBlock_3(x,[(352,),(192,320),(192,224),(128,)])
x = keras.layers.AveragePooling2D(pool_size=(7,7),strides=1)(x)
x = keras.layers.Flatten()(x)
x = keras.layers.Dense(17,activation='softmax')(x)
model = keras.Model(inputs=inputs,outputs=x)
model.compile(optimizer=keras.optimizers.Adam(lr=0.00001),loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.summary()
cb = [ keras.callbacks.EarlyStopping(patience=30,min_delta=1e-4),
keras.callbacks.ModelCheckpoint('./InceptionNet.h5',save_best_only=True) ]
his = model.fit(x_train,y_train,batch_size=64,epochs=100,validation_data=(x_test,y_test),callbacks=cb)
pd.DataFrame(his.history).plot(figsize=(8,5))
plt.grid(True)
# plt.gca().set_ylim(0,1)
plt.show()