GoogLeNet—tensorflow2.0实战(Fashion mnist数据集)
目录
GoogLeNet—tensorflow2.0实战(Fashion mnist数据集)
1、GoogLeNet —V1简单介绍
这是GoogLeNet的最早版本,出现在2014年的《Going deeper with convolutions》。之所以名为“GoogLeNet”而非“GoogleNet”,文章说是为了向早期的LeNet致敬。深度学习以及神经网络快速发展,人们不再只关注硬件、数据集、模型,而是更在意新的创意、新的算法以及模型的改进。一般来说,提升网络性能最直接的办法就是增加网络深度和宽度,这也就意味着需要训练大量的参数。过多的参数可能会导致结果过拟合,并且计算量增大。
最终解决过拟合以及计算量大这两个问题的根本方法是从全连接层的结构过渡到稀疏的连接结构,甚至在卷积内部也是如此。
2、Inception结构介绍
Inception结构最初是作为第一作者的案例研究来评估复杂网络拓扑构造算法的假设提出的,该算法试图逼近暗示的视觉网络的稀疏结构,并通过密集,易于获得的方法覆盖了假设的结果。 在进一步调整学习率,超参数和改进的训练方法之后,我们确定了所得的Inception体系结构在定位和目标检测中特别有用。 有趣的是,尽管大多数原始结构选择都受到了质疑和测试,但事实证明它们至少是局部最优的。尽管提出的体系结构已经可以用于计算机视觉,但是其质量是否可以归功于导致其构建的指导原则仍然值得怀疑。 确保将需要进行更彻底的分析和验证:例如,如果基于下述原理的自动化工具能够为视觉网络找到相似但更好的拓扑结构。 最有说服力的证明是,如果一个自动化系统创建的网络拓扑结构能够使用相同的算法,但在全局架构上却大不相同,从而在其他域中获得相似的收益。 至少,Inception结构的最初成功为在此方向上未来的激动人心的工作产生了坚定的动力。
3、Inception作用
显著增加了每一步的单元数目,计算复杂度不会不受限制,尺度较大的块卷积之前先降维。 视觉信息在不同尺度上进行处理聚合,这样下一步可以从不同尺度提取特征。文章指出Inception的作用:代替人工确定卷积层中的过滤器类型或者确定是否需要创建卷积层和池化层,即:不需要人为的决定使用哪个过滤器,是否需要池化层等,由网络自行决定这些参数,可以给网络添加所有可能值,将输出连接起来,网络自己学习它需要什么样的参数。
4、结构细节
对上图做以下说明:
1、采用不同大小的卷积核意味着不同大小的感受野,最后拼接意味着不同尺度特征的融合;
2、之所以卷积核大小采用1、3和5,主要是为了方便对齐。设定卷积步长stride=1之后,只要分别设定padding=0、1、2,3、之后便可以得到相同维度的特征,然后这些特征就可以直接拼接在一起了;
4、Inception里面也嵌入了pooling,结果挺有效;
5、网络越到后面,特征越抽象,而且每个特征所涉及的感受野也更大了,因此随着层数的增加,3x3和5x5卷积的比例也要增加。
5、GooLeNet网络结构
1、平均池化层采用5×5的卷积核大小,步长为3,导致(4a)的输出为4×4×512,(4d)的输出为4×4×528。
2、具有128个1×1大小的卷积核,用于减小尺寸和校正线性激活。
3、具有1024个节点的全连接层,并具有线性校正激活功能。
4、尽管移除了全连接,但是网络中依然使用了Dropout ,避免过拟合。
5、一个具有softmax损失的线性层作为分类器(预测与主分类器相同的1000个分类,但在推理时将其删除)。
6、实验代码
Inception设计
import tensorflow as tf
import numpy as np
from tensorflow import keras
import os
class ConvBNRelu(keras.Model):
def __init__(self, ch, kernelsz=3, strides=1, padding='same'):
super(ConvBNRelu, self).__init__()
self.model = keras.models.Sequential([
keras.layers.Conv2D(ch, kernelsz, strides=strides, padding=padding),
keras.layers.BatchNormalization(),
keras.layers.ReLU()
])
def call(self, x, training=None):
x = self.model(x, training=training)
return x
# Inception Block 模块。
class InceptionBlk(keras.Model):
def __init__(self, ch, strides=1):
super(InceptionBlk, self).__init__()
self.ch = ch
self.strides = strides
self.conv1 = ConvBNRelu(ch, strides=strides)
self.conv2 = ConvBNRelu(ch, kernelsz=3, strides=strides)
self.conv3_1 = ConvBNRelu(ch, kernelsz=3, strides=strides)
self.conv3_2 = ConvBNRelu(ch, kernelsz=3, strides=1)
self.pool = keras.layers.MaxPooling2D(3, strides=1, padding='same')
self.pool_conv = ConvBNRelu(ch, strides=strides)
def call(self, x, training=None):
x1 = self.conv1(x, training=training)
x2 = self.conv2(x, training=training)
x3_1 = self.conv3_1(x, training=training)
x3_2 = self.conv3_2(x3_1, training=training)
x4 = self.pool(x)
x4 = self.pool_conv(x4, training=training)
# concat along axis=channel 通道数
x = tf.concat([x1, x2, x3_2, x4], axis=3)
return x
# Res Block 模块。继承keras.Model或者keras.Layer都可以
class Inception(keras.Model):
def __init__(self, num_layers, num_classes, init_ch=16, **kwargs):
super(Inception, self).__init__(**kwargs)
self.in_channels = init_ch
self.out_channels = init_ch
self.num_layers = num_layers
self.init_ch = init_ch
self.conv1 = ConvBNRelu(init_ch)
self.blocks = keras.models.Sequential(name='dynamic-blocks')
for block_id in range(num_layers):
for layer_id in range(2):
if layer_id == 0:
block = InceptionBlk(self.out_channels, strides=2)
else:
block = InceptionBlk(self.out_channels, strides=1)
self.blocks.add(block)
# enlarger out_channels per block
self.out_channels *= 2
self.avg_pool = keras.layers.GlobalAveragePooling2D()
self.fc = keras.layers.Dense(num_classes)
def call(self, x, training=None):
out = self.conv1(x, training=training)
out = self.blocks(out, training=training)
out = self.avg_pool(out)
out = self.fc(out)
return out
数据集预处理
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
tf.random.set_seed(22)
batchsize = 512
def preprocess(x, y): #数据预处理
x = tf.cast(x, dtype=tf.float32)/ 255. - 0.5
y = tf.cast(y, dtype=tf.int32)
return x,y
(x_train, y_train),(x_test, y_test) = keras.datasets.fashion_mnist.load_data()
print(x_train.shape, y_train.shape)
# [b, 28, 28] => [b, 28, 28, 1]
x_train, x_test = np.expand_dims(x_train, axis=3), np.expand_dims(x_test, axis=3)
#训练集预处理
db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train)) #构造数据集,这里可以自动的转换为tensor类型了
db_train = db_train.map(preprocess).shuffle(10000).batch(batchsize)
#测试集预处理
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test)) #构造数据集
db_test = db_test.map(preprocess).shuffle(10000).batch(batchsize)
db_iter = iter(db_train)
sample = next(db_iter)
print("batch: ", sample[0].shape, sample[1].shape)
调用Inception
model = Inception(2, 10) # 第一参数为残差块数,第二个参数为类别数;
# derive input shape for every layers.
model.build(input_shape=(None, 28, 28, 1))
model.summary()
optimizer =keras.optimizers.Adam(learning_rate=1e-3)
criteon = keras.losses.CategoricalCrossentropy(from_logits=True) # 分类器
acc_meter = keras.metrics.Accuracy()
for epoch in range(100):
for step, (x, y) in enumerate(db_train):
with tf.GradientTape() as tape:
# print(x.shape, y.shape)
# [b, 10]
logits = model(x)
# [b] vs [b, 10]
loss = criteon(tf.one_hot(y, depth=10), logits)
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
if step % 20 == 0:
print(epoch, step, 'loss:', loss.numpy())
# 测试集测试
acc_meter.reset_states()
for x, y in db_test:
# [b, 10]
logits = model(x, training=False)
# [b, 10] => [b]
pred = tf.argmax(logits, axis=1)
# [b] vs [b, 10]
acc_meter.update_state(y, pred)
print(epoch, 'evaluation acc:', acc_meter.result().numpy())
Model: "inception_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv_bn_relu_42 (ConvBNRelu) multiple 224 _________________________________________________________________ dynamic-blocks (Sequential) multiple 292704 _________________________________________________________________ global_average_pooling2d_2 ( multiple 0 _________________________________________________________________ dense_2 (Dense) multiple 1290 ================================================================= Total params: 294,218 Trainable params: 293,226 Non-trainable params: 992 _________________________________________________________________ 0 0 loss: 2.3045938 0 20 loss: 1.329363 0 40 loss: 0.9938534 0 60 loss: 0.69767785 0 80 loss: 0.7414908 0 100 loss: 0.6246513 1 0 loss: 0.57690525 1 20 loss: 0.7181334 1 40 loss: 0.6372799 1 60 loss: 0.56322277 1 80 loss: 0.519943 1 100 loss: 0.53726363 2 0 loss: 0.60184646 2 20 loss: 0.53243566 2 40 loss: 0.5325299 2 60 loss: 0.4348207 2 80 loss: 0.4384783 2 100 loss: 0.44925293 3 0 loss: 0.67428815 3 20 loss: 0.5142151 3 40 loss: 0.44201934 3 60 loss: 0.41263458 3 80 loss: 0.4190077 3 100 loss: 0.36581862 4 0 loss: 0.4223614 4 20 loss: 0.42564046 4 40 loss: 0.38395065 4 60 loss: 0.39734188 4 80 loss: 0.3508845 4 100 loss: 0.37631914 5 0 loss: 0.36114857 5 20 loss: 0.3901283 5 40 loss: 0.32644668 5 60 loss: 0.41383916 5 80 loss: 0.3583411 5 100 loss: 0.34498602 6 0 loss: 0.45242745 6 20 loss: 0.3334728 6 40 loss: 0.3804313 6 60 loss: 0.34394422 6 80 loss: 0.3270644 6 100 loss: 0.32063553 7 0 loss: 0.31886974 7 20 loss: 0.3142283 7 40 loss: 0.2726599 7 60 loss: 0.29281652 7 80 loss: 0.2711956 7 100 loss: 0.3366116 8 0 loss: 0.44309464 8 20 loss: 0.318788 8 40 loss: 0.3126357 8 60 loss: 0.28127334 8 80 loss: 0.2736734 8 100 loss: 0.27562279 9 0 loss: 0.2749536 9 20 loss: 0.31452334 9 40 loss: 0.24373831 9 60 loss: 0.3058698 9 80 loss: 0.29490903 9 100 loss: 0.2548433 10 0 loss: 0.22642994 10 20 loss: 0.25524795 10 40 loss: 0.25892287 10 60 loss: 0.3305801 10 80 loss: 0.2680674 10 100 loss: 0.24107268 11 0 loss: 0.2675702 11 20 loss: 0.28717366 11 40 loss: 0.30391273 11 60 loss: 0.25676006 11 80 loss: 0.24093005 11 100 loss: 0.25176764 12 0 loss: 0.24184336 12 20 loss: 0.2655635 12 40 loss: 0.24473307 12 60 loss: 0.18223602 12 80 loss: 0.2300067 12 100 loss: 0.24467997 13 0 loss: 0.2915982 13 20 loss: 0.21357125 13 40 loss: 0.21650207 13 60 loss: 0.29005748 13 80 loss: 0.23573406 13 100 loss: 0.23202647 14 0 loss: 0.24281901 14 20 loss: 0.21868399 14 40 loss: 0.19210878 14 60 loss: 0.22449979 14 80 loss: 0.25175282 14 100 loss: 0.20557953 15 0 loss: 0.23304522 15 20 loss: 0.19441521 15 40 loss: 0.22906345 15 60 loss: 0.18750042 15 80 loss: 0.22950414 15 100 loss: 0.25577813 16 0 loss: 0.21919861 16 20 loss: 0.16465753 16 40 loss: 0.21372154 16 60 loss: 0.26617402 16 80 loss: 0.18787542 16 100 loss: 0.22275339 17 0 loss: 0.2142167 17 20 loss: 0.21959808 17 40 loss: 0.21935801 17 60 loss: 0.23098597 17 80 loss: 0.19962177 17 100 loss: 0.1983304 18 0 loss: 0.20799458 18 20 loss: 0.20041838 18 40 loss: 0.1563338 18 60 loss: 0.20617214 18 80 loss: 0.23493534 18 100 loss: 0.14152527 19 0 loss: 0.20739853 19 20 loss: 0.2525779 19 40 loss: 0.2526775 19 60 loss: 0.20153278 19 80 loss: 0.1991007 19 100 loss: 0.22249362 20 0 loss: 0.1700981 20 20 loss: 0.2237401 20 40 loss: 0.19593716 20 60 loss: 0.16197991 20 80 loss: 0.18780659 20 100 loss: 0.18872637 21 0 loss: 0.14666645 21 20 loss: 0.16460156 21 40 loss: 0.1799635 21 60 loss: 0.13943696 21 80 loss: 0.19984484 21 100 loss: 0.1610533 22 0 loss: 0.16185123
......
7、结论
在2014年 ILSVRC 挑战赛 ImageNet 分类任务
上获得冠军
,如下表所示:
与较浅和较不宽泛的网络相比,此方法的主要优点是在计算需求适度增加的情况下可显着提高质量。 还要注意,尽管我们既未利用上下文也未执行边界框回归,但检测工作具有竞争优势,这一事实进一步证明了Inception体系结构的实力。 尽管可以预期,通过深度和宽度相近的昂贵得多的网络可以达到类似的结果质量,但是我们的方法得出的确凿证据表明,转向稀疏结构通常是可行且有用的想法。 这表明在[2]的基础上,未来的工作有希望以自动方式创建稀疏和更精细的结构。
8、参考
GoogLeNet论文翻译:《Going deeper with convolutions》
TF2.0深度学习实战(六):搭建GoogLeNet卷积神经网络
感谢以上博主的分享。