目錄鏈接:吳恩達(dá)Deep Learning學(xué)習(xí)筆記目錄
??1.Tensorflow2.0 tf.keras 入門
??2.殘差網(wǎng)絡(luò)
1. Tensorflow2.0 tf.keras 入門
??通過Tensorflow2.0 tf.keras框架搭建模型來識(shí)別圖片是否是笑臉(笑臉標(biāo)簽1,非笑臉標(biāo)簽0)绵疲。搭建模型一共三種方法:
??①通過tf.keras.models.Sequenctial()來搭建
??②通過tf.keras中的function API來搭建
??③通過tf.keras.Model的子類來搭建
?(1)包引入及數(shù)據(jù)描述
import os
# os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
import sklearn
import sys
import time
import tensorflow as tf
from tensorflow import keras
import pprint
print(tf.__version__)
print(sys.version_info)
for module in mpl,np,pd,sklearn,tf,keras:
print(module.__name__,module.__version__)
#設(shè)置邏輯GPU锦秒,及限制GPU內(nèi)存(筆記本GTX1060犀被,一個(gè)顯卡琢唾,不限制內(nèi)存楞件,內(nèi)存占滿會(huì)非承苏簦卡,而且會(huì)崩)
tf.debugging.set_log_device_placement(True)
gpus = tf.config.experimental.list_physical_devices('GPU')
tf.config.experimental.set_virtual_device_configuration(
gpus[0],
[tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024),
tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])
print(len(gpus))
logical_gpu = tf.config.experimental.list_logical_devices('GPU')
print(len(logical_gpu))
數(shù)據(jù)描述:
import kt_utils
X_train,Y_train,X_test,Y_test,classes = kt_utils.load_dataset()
Y_train = Y_train.T
Y_test = Y_test.T
print("num of training samples:" ,X_train.shape[0])
print("num of test samples:" ,X_test.shape[0])
print("X_train shape:",X_train.shape)
print("Y_train shape:",Y_train.shape)
print("X_test shape:",X_test.shape)
print("Y_test shape:",Y_test.shape)
"""
輸出:
num of training samples: 600
num of test samples: 150
X_train shape: (600, 64, 64, 3)
Y_train shape: (600, 1)
X_test shape: (150, 64, 64, 3)
Y_test shape: (150, 1)
"""
數(shù)據(jù)繪圖:
def show_imgs(n_rows,n_cols,x_data,y_data):
assert len(x_data) == len(y_data)
assert n_rows * n_cols < len(x_data)
plt.figure(figsize = (n_cols*1.4,n_rows*1.6))
for row in range(n_rows):
for col in range(n_cols):
index = n_cols * row + col
plt.subplot(n_rows,n_cols,index+1)
plt.imshow(x_data[index],cmap = 'binary',interpolation='nearest')
plt.axis('off')
plt.title(y_data[index])
plt.show()
show_imgs(3,5,X_train,Y_train)
歸一化
X_train = X_train / 255
X_test = X_test / 255
?(2)通過tf.keras.models.Sequenctial()來搭建
??由于版本的更新细办,tf.keras.models.Sequenctial()有很多Aliases:
??Class tf.compat.v1.keras.Sequential
??Class tf.compat.v1.keras.models.Sequential
??Class tf.compat.v2.keras.Sequential
??Class tf.compat.v2.keras.models.Sequential
??Class tf.keras.models.Sequential
??tf.keras.models.Sequenctial()用于構(gòu)建神經(jīng)網(wǎng)絡(luò)模型橙凳,其參數(shù)是一個(gè)含有各個(gè)計(jì)算layer的列表。tf.keras.layers中有很多l(xiāng)ayer類笑撞,如卷積岛啸、池化、全連接茴肥、歸一化等函數(shù)坚踩,通過這些類來構(gòu)建每一層計(jì)算:
model = keras.models.Sequential([
#卷積層:卷積→BN→激活
keras.layers.Conv2D(filters = 32,kernel_size = 7,padding = "same",input_shape = (64,64,3)),
keras.layers.BatchNormalization(),
keras.layers.Activation("relu"),
#池化
keras.layers.MaxPool2D(pool_size = 2),
#全連接層
keras.layers.Flatten(),
keras.layers.Dense(1,activation = "sigmoid"),
])
model.summary()#用于描述搭建的模型
解釋:
??第一步:卷積,前兩個(gè)參數(shù)分別為卷積核數(shù)量瓤狐,卷積核大小
??第二步:批歸一化
??第三步:relu激活
??第四步:池化瞬铸,池化核大小為2。以上構(gòu)成網(wǎng)絡(luò)的第一層(由于數(shù)據(jù)太小及配置問題础锐,不再添加卷積層)
??第五步:將數(shù)據(jù)展平(全連接層)
??第六步:輸出層(二分類嗓节,輸出單元為1,激活函數(shù)為sigmoid)
模型結(jié)構(gòu):
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_9 (Conv2D) (None, 64, 64, 32) 4736
_________________________________________________________________
batch_normalization_9 (Batch (None, 64, 64, 32) 128
_________________________________________________________________
activation_9 (Activation) (None, 64, 64, 32) 0
_________________________________________________________________
max_pooling2d_9 (MaxPooling2 (None, 32, 32, 32) 0
_________________________________________________________________
flatten_6 (Flatten) (None, 32768) 0
_________________________________________________________________
dense_12 (Dense) (None, 1) 32769
=================================================================
Total params: 37,633
Trainable params: 37,569
Non-trainable params: 64
編譯及訓(xùn)練:
model.compile(loss="binary_crossentropy",
optimizer = "sgd",
metrics = ["acc"])
his = model.fit(X_train,Y_train,epochs=40,validation_data=(X_test,Y_test),batch_size=50)
訓(xùn)練結(jié)果:
def plot_learning_curves(history):
pd.DataFrame(history.history).plot(figsize=(8,5))
plt.grid(True)
plt.gca().set_ylim(0,5)
plt.show()
plot_learning_curves(his)
??(3)通過tf.keras中的function API來搭建
??tf.keras中不僅含有各種類皆警,還含有一些函數(shù)如Input()用于初始化keras tensor拦宣,concatenate()用于連接層。同時(shí)信姓,tf.keras中各種類在這里將被當(dāng)作函數(shù)API來使用:
def my_model_1(start_shape):
input_start = keras.Input(start_shape)
conv = keras.layers.Conv2D(filters = 32,kernel_size = 7,padding = "same")(input_start)
bn = keras.layers.BatchNormalization(axis=3)(conv)
acti = keras.layers.Activation("relu")(bn)
pool_max_1 = keras.layers.MaxPool2D(pool_size=2)(acti)
fla = keras.layers.Flatten()(pool_max_1)
output_end = keras.layers.Dense(1,activation="sigmoid")(fla)
model = keras.Model(inputs=input_start,outputs=output_end)
return model
model_1 = my_model_1(X_train.shape[1:])
model_1.compile(loss="binary_crossentropy",
optimizer = "sgd",
metrics = ["acc"])
his1 = model_1.fit(X_train,Y_train,epochs=40,validation_data=(X_test,Y_test),batch_size=50)
解釋:
??第一步:采用此方法來構(gòu)建模型鸵隧,需要第一步用Input()來初始化keras tensor
??后續(xù):結(jié)構(gòu)與(2)相同,但在此意推,每一步的輸出將作為下一步函數(shù)的參數(shù)豆瘫。
??(4)通過tf.keras.Model的子類來搭建
??通過創(chuàng)建一個(gè)類(繼承于tf.keras.Model類)來構(gòu)建模型,init函數(shù)用于定義layer左痢,call函數(shù)用于模型的前向計(jì)算過程:
class My_model(tf.keras.Model):
def __init__(self):
super(My_model,self).__init__()
self.hidden_conv = tf.keras.layers.Conv2D(filters = 32,kernel_size = 7,padding = "same")
self.hidden_bn = tf.keras.layers.BatchNormalization()
self.hidden_ac = tf.keras.layers.Activation("relu")
self.max_pool_1 = tf.keras.layers.MaxPool2D(pool_size = 2)
self.fla = tf.keras.layers.Flatten()
self.out_put = tf.keras.layers.Dense(1,activation="sigmoid")
def call(self,input_start):
h_conv = self.hidden_conv(input_start)
h_bn = self.hidden_bn(h_conv)
h_ac = self.hidden_ac(h_bn)
m_p_1 = self.max_pool_1(h_ac)
f_la = self.fla(m_p_1)
return self.out_put(f_la)
# model2 = keras.models.Sequential([My_model()])#等同下行
model2 = My_model()
model2.build(input_shape = (None,64,64,3))
model2.compile(loss="binary_crossentropy",
optimizer = "sgd",
metrics = ["acc"])
his2 = model2.fit(X_train,Y_train,epochs=40,validation_data=(X_test,Y_test),batch_size=50)
解釋:由于子類實(shí)現(xiàn)的模型不知道數(shù)據(jù)輸入的shape靡羡,通過model2.build()接收到的輸入來構(gòu)建模型系洛。
注:
tf.keras文檔見Module: tf.keras
??(4)測(cè)試模型
??從網(wǎng)上隨便找張人臉圖片用于測(cè)試,下載下來的圖片需要經(jīng)過如下處理:
img = keras.preprocessing.image.load_img('./datasets/smile.jpg',target_size=(64,64))
plt.imshow(img)
x = keras.preprocessing.image.img_to_array(img)
x = np.expand_dims(x,axis=0)
print(x.shape)
"""
輸出:(1, 64, 64, 3)
"""
print(model2.predict(x))
"""
輸出:[[1]]
"""
2. 殘差網(wǎng)絡(luò)
?2.1手動(dòng)搭建殘差網(wǎng)絡(luò)
??神經(jīng)網(wǎng)絡(luò)用于大規(guī)模數(shù)據(jù)進(jìn)行訓(xùn)練時(shí)略步,效果良好描扯,理論上,隨著網(wǎng)絡(luò)結(jié)構(gòu)的深入趟薄,所訓(xùn)練出的模型的性能應(yīng)該是越來越好的绽诚,但實(shí)際上并不是,在達(dá)到一定layer后杭煎,模型性能開始變差恩够。其中一個(gè)原因是隨著網(wǎng)絡(luò)越深入,梯度消失問題變得嚴(yán)重(激活函數(shù)改善羡铲、批歸一化僅僅是削弱了梯度消失的問題蜂桶,并沒有完全解決神經(jīng)網(wǎng)絡(luò)梯度消失和梯度爆炸的問題)。
??殘差網(wǎng)絡(luò)允許原始輸入直接輸入到后面的層也切,這相當(dāng)于直接用后面的層來學(xué)習(xí)所期望輸出和輸入的差值扑媚,理論上它至少不會(huì)比輸入更差。參見深度學(xué)習(xí)——?dú)埐钌窠?jīng)網(wǎng)絡(luò)ResNet在分別在Keras和tensorflow框架下的應(yīng)用案例雷恃。
??論文中疆股,在每?jī)蓪?x3的卷積采用”遠(yuǎn)跳連接“,但也提到了三層模型倒槐,先采用1x1卷積降維旬痹,通過中間3x3卷積后,再通過1x1卷積升維讨越。①在維度相同的卷積層之間采用”恒等連接“两残,直接將X加和到后面層的Z即可;②對(duì)于不同維度層之間把跨,需要采用卷積核來對(duì)原始輸入進(jìn)行調(diào)整磕昼。
??(1)恒等連接
??恒等連接在原始輸入數(shù)據(jù)高、寬與后面連接層輸出的高节猿、寬相同時(shí)使用票从,如下圖:
def identity_block(X,f,kernels):
f1,f2,f3 = kernels
#保存原始輸入
X_short_cut = X
#1x1卷積通道降維
conv1 = keras.layers.Conv2D(filters=f1,kernel_size=(1,1),strides=(1,1),
padding="valid",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(X)
bn1 = keras.layers.BatchNormalization(axis=3)(conv1)
relu1 = keras.layers.Activation("relu")(bn1)
#3x3卷積峰鄙,保持高寬不變
conv2 = keras.layers.Conv2D(filters=f2,kernel_size=(f,f),strides=(1,1),
padding="same",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(relu1)
bn2 = keras.layers.BatchNormalization(axis=3)(conv2)
relu2 = keras.layers.Activation("relu")(bn2)
#1x1卷積,通道升維
conv3 = keras.layers.Conv2D(filters=f3,kernel_size=(1,1),strides=(1,1),
padding="valid",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(relu2)
bn3 = keras.layers.BatchNormalization(axis=3)(conv3)
Z = keras.layers.Add()([bn3,X_short_cut])
relu3 = keras.layers.Activation("relu")(Z)
return relu3
注:在第三層升維度時(shí)太雨,原始輸入要并入到第三層的歸一化數(shù)據(jù)里吟榴,當(dāng)作Z輸入激活函數(shù)來激活。
??(2)卷積連接
??當(dāng)原始輸入和輸出的高寬不一致時(shí)囊扳,遠(yuǎn)跳連接不能直接加和到輸出層吩翻,需要通過卷積來調(diào)整維度兜看,使得維度和輸出層相同:
def conv_block(X,f,kernels,s=2):
f1,f2,f3 = kernels
X_short_cut = X
conv1 = keras.layers.Conv2D(filters=f1,kernel_size=(1,1),strides=(s,s),
padding="valid",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(X)
bn1 = keras.layers.BatchNormalization(axis=3)(conv1)
relu1 = keras.layers.Activation("relu")(bn1)
conv2 = keras.layers.Conv2D(filters=f2,kernel_size=(f,f),strides=(1,1),
padding="same",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(relu1)
bn2 = keras.layers.BatchNormalization(axis=3)(conv2)
relu2 = keras.layers.Activation("relu")(bn2)
conv3 = keras.layers.Conv2D(filters=f3,kernel_size=(1,1),strides=(1,1),
padding="valid",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(relu2)
bn3 = keras.layers.BatchNormalization(axis=3)(conv3)
X_short_cut_conv = keras.layers.Conv2D(filters=f3,kernel_size=(1,1),strides=(s,s),
padding="valid",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(X_short_cut)
X_short_cut_bn = keras.layers.BatchNormalization(axis=3)(X_short_cut_conv)
Z = keras.layers.Add()([bn3,X_short_cut_bn])
relu3 = keras.layers.Activation("relu")(Z)
return relu3
??(2)模型構(gòu)建
??ResNet50模型結(jié)構(gòu)如下:
def my_resnet(input_shape,classes):
start_input = keras.Input(input_shape)
start_input_zero_padding = keras.layers.ZeroPadding2D((3,3))(start_input)
stage_1_conv = keras.layers.Conv2D(64,kernel_size=(7,7),strides=(2,2),
kernel_initializer=keras.initializers.glorot_uniform(seed=0))(start_input_zero_padding)
stage_1_bn = keras.layers.BatchNormalization(axis=3)(stage_1_conv)
stage_1_relu = keras.layers.Activation("relu")(stage_1_bn)
stage_1_pooling = keras.layers.MaxPool2D(pool_size=(3,3),strides=(2,2))(stage_1_relu)
stage_2_conv = conv_block(stage_1_pooling,f=3,kernels=[64,64,256],s=1)
stage_2_idblock_1 = identity_block(stage_2_conv,f=3,kernels=[64,64,256])
stage_2_idblock_2 = identity_block(stage_2_idblock_1,f=3,kernels=[64,64,256])
stage_3_conv = conv_block(stage_2_idblock_2,f=3,kernels=[128,128,512],s=2)
stage_3_idblock_1 = identity_block(stage_3_conv,f=3,kernels=[128,128,512])
stage_3_idblock_2 = identity_block(stage_3_idblock_1,f=3,kernels=[128,128,512])
stage_3_idblock_3 = identity_block(stage_3_idblock_2,f=3,kernels=[128,128,512])
stage_4_conv = conv_block(stage_3_idblock_3,f=3,kernels=[256,256,1024],s=2)
stage_4_idblock_1 = identity_block(stage_4_conv,f=3,kernels=[256,256,1024])
stage_4_idblock_2 = identity_block(stage_4_idblock_1,f=3,kernels=[256,256,1024])
stage_4_idblock_3 = identity_block(stage_4_idblock_2,f=3,kernels=[256,256,1024])
stage_4_idblock_4 = identity_block(stage_4_idblock_3,f=3,kernels=[256,256,1024])
stage_4_idblock_5 = identity_block(stage_4_idblock_4,f=3,kernels=[256,256,1024])
stage_5_conv = conv_block(stage_4_idblock_5,f=3,kernels=[512,512,2048],s=2)
stage_5_idblock_1 = identity_block(stage_5_conv,f=3,kernels=[256,256,2048])
stage_5_idblock_2 = identity_block(stage_5_idblock_1,f=3,kernels=[256,256,2048])
average_pooling = keras.layers.AveragePooling2D(pool_size=(2,2))(stage_5_idblock_2)
fla = keras.layers.Flatten()(average_pooling)
output_end = keras.layers.Dense(classes,activation="softmax",kernel_initializer=keras.initializers.glorot_uniform(seed=0))(fla)
model = keras.Model(inputs = start_input,outputs = output_end)
return model
??在ResNet50中,默認(rèn)的輸入大小是(224狭瞎,224细移,3),本文采用的是GPU來訓(xùn)練熊锭,奈何GTX1060顯存不夠用弧轧,如果直接用(224,224,3)的圖片來訓(xùn)練(batch_size=24),會(huì)導(dǎo)致顯存不夠報(bào)錯(cuò):
ResourceExhaustedError: OOM when allocating tensor with shape[24,256,55,55]
??減少batch_size至12還是報(bào)錯(cuò)碗殷,所以在訓(xùn)練時(shí)使用的圖片大小為(64,64,3),batch_size=12精绎。此處采用的數(shù)據(jù)是10 Monkey Species,下載下來的數(shù)據(jù)按類別分別保存在不同的文件夾锌妻,這里采用keras.preprocessing.image.ImageDataGenetor()來作為數(shù)據(jù)輸入管道代乃,官方API文檔見tf.keras.preprocessing.image.ImageDataGenerator,各參數(shù)的作用在Keras ImageDataGenerator參數(shù)中進(jìn)行了說明仿粹,對(duì)各個(gè)參數(shù)進(jìn)行了單獨(dú)測(cè)試襟己。
??數(shù)據(jù)文件路徑:
train_dir = "./input/training/training"
valid_dir = "./input/validation/validation"
labels_file = "./input/monkey_labels.txt"
labels = pd.read_csv(labels_file)
print(labels)
"""
輸出:
Label Latin Name Common Name \
0 n0 alouatta_palliata\t mantled_howler
1 n1 erythrocebus_patas\t patas_monkey
2 n2 cacajao_calvus\t bald_uakari
3 n3 macaca_fuscata\t japanese_macaque
4 n4 cebuella_pygmea\t pygmy_marmoset
5 n5 cebus_capucinus\t white_headed_capuchin
6 n6 mico_argentatus\t silvery_marmoset
7 n7 saimiri_sciureus\t common_squirrel_monkey
8 n8 aotus_nigriceps\t black_headed_night_monkey
9 n9 trachypithecus_johnii nilgiri_langur
Train Images Validation Images
0 131 26
1 139 28
2 137 27
3 152 30
4 131 26
5 141 28
6 132 26
7 142 28
8 133 27
9 132 26
"""
??數(shù)據(jù)處理并生成generator:
height = 64
width = 64
channels = 3
batch_size = 12
num_classes = 10
#設(shè)置ImageDataGenerator(),即該函數(shù)如何對(duì)數(shù)據(jù)進(jìn)行處理
train_data_generator = keras.preprocessing.image.ImageDataGenerator(
rescale = 1. / 255,
rotation_range = 40,#隨機(jī)旋轉(zhuǎn)
width_shift_range = 0.2,#水平位移的比例
height_shift_range = 0.2,#垂直位移的比例
shear_range = 0.2,#隨機(jī)剪切扭曲的比例
zoom_range = 0.2,#隨機(jī)縮放的比例
horizontal_flip = True,#設(shè)置水平翻轉(zhuǎn)
fill_mode = "nearest")#數(shù)據(jù)變換后牍陌,如果與數(shù)據(jù)設(shè)置邊界大小不符時(shí)的灰度值填充方法
#通過已設(shè)置好的ImageDataGenerator()來讀取并處理圖片數(shù)據(jù)
train_generator = train_data_generator.flow_from_directory(
train_dir,#各類圖片的根文件路徑
target_size = (height,width),#生成圖片的大小
batch_size = batch_size,
seed = 42,
shuffle = True,
class_mode = "categorical")
valid_data_generator = keras.preprocessing.image.ImageDataGenerator(rescale = 1. / 255)#用于驗(yàn)證,不用進(jìn)行數(shù)據(jù)增強(qiáng)
valid_generator = valid_data_generator.flow_from_directory(
valid_dir,
target_size = (height,width),
batch_size = batch_size,
seed = 42,
shuffle = True,
class_mode = "categorical")
num_train = train_generator.samples
num_valid = valid_generator.samples
"""
輸出:
Found 1098 images belonging to 10 classes.
Found 272 images belonging to 10 classes.
"""
??生成generator返回的是一個(gè)DataFrameIterator员咽,通過一個(gè)元組(x,y)來接收毒涧,x是以一個(gè)numpy array,包含了一個(gè)batch的數(shù)據(jù)贝室,y是一個(gè)numpy array契讲,對(duì)應(yīng)于x的標(biāo)簽數(shù)據(jù):
for i in range(1):
x,y = train_generator.next()
print(x.shape,y.shape)
print(y)
"""
輸出:
(12, 64, 64, 3) (12, 10)
[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]]
"""
編譯
model_1 = my_resnet(input_shape=(64,64,3),classes=10)
model_1.compile(loss = "categorical_crossentropy",
optimizer = "adam",
metrics = ['accuracy'])
model_1.summary()
訓(xùn)練:
logdir = os.path.join("my_resnet")
if not os.path.exists(logdir):
os.mkdir(logdir)
callback = [
keras.callbacks.TensorBoard(logdir),
]
his_1 = model_1.fit_generator(train_generator,
steps_per_epoch = num_train // batch_size,
epochs = 300,
validation_data = valid_generator,
validation_steps = num_valid // batch_size)
??emm,結(jié)果不太好滑频,由于太費(fèi)時(shí)間捡偏,不再繼續(xù)訓(xùn)練。下面采用已經(jīng)訓(xùn)練好的ResNet50的參數(shù)進(jìn)行訓(xùn)練峡迷。
?2.2 遷移學(xué)習(xí)
??即將已經(jīng)訓(xùn)練好的ResNet網(wǎng)絡(luò)及其參數(shù)用于這個(gè)數(shù)據(jù)集的分類银伟,在這個(gè)基礎(chǔ)上進(jìn)行微調(diào),一般有兩種做法绘搞,①保留卷積層所有參數(shù)彤避,修改頂層的全連接層,只訓(xùn)練全連接層的參數(shù)夯辖;②另一個(gè)是訓(xùn)練卷積層后幾層琉预。
??(1)僅修改全連接層
??generator:采用ImageDataGenerator,數(shù)據(jù)處理采用resnet50.preprocess_input來進(jìn)行預(yù)處理
height = 224
width = 224
channels = 3
batch_size = 24
num_classes = 10
#設(shè)置ImageDataGenerator()蒿褂,即該函數(shù)如何對(duì)數(shù)據(jù)進(jìn)行處理
train_data_generator = keras.preprocessing.image.ImageDataGenerator(
preprocessing_function = keras.applications.resnet50.preprocess_input,
rotation_range = 40,#隨機(jī)旋轉(zhuǎn)
width_shift_range = 0.2,#水平位移的比例
height_shift_range = 0.2,#垂直位移的比例
shear_range = 0.2,#隨機(jī)剪切扭曲的比例
zoom_range = 0.2,#隨機(jī)縮放的比例
horizontal_flip = True,#設(shè)置水平翻轉(zhuǎn)
fill_mode = "nearest")#數(shù)據(jù)變換后圆米,如果與數(shù)據(jù)設(shè)置邊界大小不符時(shí)的灰度值填充方法
train_generator = train_data_generator.flow_from_directory(
train_dir,#各類圖片的根文件路徑
target_size = (height,width),#生成圖片的大小
batch_size = batch_size,
seed = 42,
shuffle = True,
class_mode = "categorical")
valid_data_generator = keras.preprocessing.image.ImageDataGenerator(preprocessing_function = keras.applications.resnet50.preprocess_input)
valid_generator = valid_data_generator.flow_from_directory(
valid_dir,
target_size = (height,width),
batch_size = batch_size,
seed = 42,
shuffle = True,
class_mode = "categorical")
num_train = train_generator.samples
num_valid = valid_generator.samples
??模型修改:①添加ResNet時(shí)卒暂,將其作為一個(gè)層來輸入,參數(shù)控制其不保留頂層全連接層娄帖;②編譯前也祠,設(shè)定這一整個(gè)層的參數(shù)不可訓(xùn)練。
resnet50_fine_tune = keras.models.Sequential([
keras.applications.ResNet50(include_top = False,#是否保留頂層的全連接網(wǎng)絡(luò)
pooling = 'avg',#池化方式
weights = 'imagenet'),#若設(shè)置為None則不采用原resnet50的參數(shù)
keras.layers.Dense(num_classes,activation="softmax")#在原網(wǎng)絡(luò)卷積層的基礎(chǔ)上添加一個(gè)全連接層來作為輸出
])
resnet50_fine_tune.layers[0].trainable = False #設(shè)置原網(wǎng)絡(luò)中所有參數(shù)不參與訓(xùn)練块茁,直接使用”imagenet“中參數(shù)
resnet50_fine_tune.compile(loss = "categorical_crossentropy",
optimizer = "sgd",
metrics = ['accuracy'])
resnet50_fine_tune.summary()
his_2 = resnet50_fine_tune.fit_generator(train_generator,
steps_per_epoch = num_train // batch_size,
validation_data = valid_generator,
validation_steps = num_valid // batch_size,
epochs = 10)
??采用已訓(xùn)練好的網(wǎng)絡(luò)齿坷,僅迭代10次,就可以獲得不錯(cuò)的結(jié)果:
??(2)ResNet50卷積層后幾層參數(shù)重新訓(xùn)練
resnet50_conv = keras.applications.ResNet50(include_top = False,pooling = "avg",weights = "imagenet")
#將resnet50卷積層倒數(shù)第5層以前的參數(shù)都不可訓(xùn)練数焊,即后5層可訓(xùn)練
for layer in resnet50_conv.layers[0:-5]:
layer.trainable = False
resnet50_fine_tune_2 = keras.models.Sequential([
resnet50_conv,
keras.layers.Dense(num_classes,activation = "softmax"),
])
resnet50_fine_tune_2.compile(loss = "categorical_crossentropy",
optimizer = "sgd",
metrics = ['accuracy'])
resnet50_fine_tune_2.summary()
??emm,又又又報(bào)錯(cuò)了永淌,顯存不夠,但用CPU可以佩耳,但太慢了遂蛀,不訓(xùn)練了,over干厚。