吳恩達(dá)Deep Learning第四課作業(yè)(第二周 Tensorflow2.0)

目錄鏈接:吳恩達(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í)使用票从,如下圖:
??為了減小計(jì)算量,這里采用的是三層遠(yuǎn)跳連接模型滨嘱。代碼如下:

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干厚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末李滴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛮瞄,更是在濱河造成了極大的恐慌所坯,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挂捅,死亡現(xiàn)場(chǎng)離奇詭異芹助,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闲先,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門状土,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伺糠,你說我怎么就攤上這事蒙谓。” “怎么了训桶?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵累驮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我舵揭,道長(zhǎng)慰照,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任琉朽,我火速辦了婚禮区赵,結(jié)果婚禮上峭梳,老公的妹妹穿的比我還像新娘瞧剖。我一直安慰自己,他們只是感情好惕医,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著算色,像睡著了一般抬伺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灾梦,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天峡钓,我揣著相機(jī)與錄音,去河邊找鬼若河。 笑死能岩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萧福。 我是一名探鬼主播拉鹃,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鲫忍!你這毒婦竟也來了膏燕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤悟民,失蹤者是張志新(化名)和其女友劉穎坝辫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體射亏,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡近忙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸦泳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡永品,死狀恐怖做鹰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鼎姐,我是刑警寧澤钾麸,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炕桨,受9級(jí)特大地震影響饭尝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜献宫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一钥平、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姊途,春花似錦涉瘾、人聲如沸知态。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽负敏。三九已至,卻和暖如春秘蛇,著一層夾襖步出監(jiān)牢的瞬間其做,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工赁还, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妖泄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓秽浇,卻偏偏與公主長(zhǎng)得像浮庐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柬焕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容