GoogLeNet—tensorflow2.0實戰(Fashion mnist資料集)
目錄
GoogLeNet—tensorflow2.0實戰(Fashion mnist資料集)
1、GoogLeNet —V1簡單介紹
2、Inception結構介紹
3、Inception作用
4、結構細節
5、GooLeNet網絡結構
6、實驗代碼
7、結論
8、參考
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卷積神經網絡
GoogLeNetV1,V2系列講解
感謝以上部落客的分享。