Tensorflow學習筆記No.8

使用VGG16網絡進行遷移學習

使用在ImageNet數據上預訓練的VGG16網絡模型對貓狗數據集進行分類識別。html

1.預訓練網絡

預訓練網絡是一個保存好的,已經在大型數據集上訓練好的卷積神經網絡。網絡

若是這個數據集足夠大且通用,那麼預訓練網絡學習到的模型參數能夠有效的對圖片進行特徵提取。即便新問題與本來的數據徹底不一樣,但學習到的特徵提取方法依然能夠在不一樣的問題之間進行移植,進而能夠在全新的數據集上提取到有效的特徵。對這些有效的高級特徵進行分類能夠大大提升模型分類的準確率app

遷移學習主要適用於已有數據相對較少的狀況,若是擁有的數據量足夠大,即便不須要遷移學習也可以獲得很是高的準確率。dom

2.如何使用與訓練網絡

2.1載入圖像並建立數據集

首先,讀入貓狗數據集中的圖片。(實現過程的詳細說明在Tensorflow學習筆記No.5中,這裏再也不贅述)學習

 

 1 import tensorflow as tf
 2 import numpy as np
 3 import pandas as pd
 4 import matplotlib.pyplot as plt
 5 %matplotlib inline
 6 import pathlib
 7 import random
 8 
 9 data_root = pathlib.Path('../input/cat-and-dog/training_set/training_set')
10 
11 all_image_path = list(data_root.glob('*/*.jpg'))
12 random.shuffle(all_image_path)
13 image_count = len(all_image_path)
14 
15 label_name = sorted([item.name for item in data_root.glob('*')])
16 name_to_indx = dict((name, indx) for indx, name in enumerate(label_name))
17 
18 all_image_path = [str(path) for path in all_image_path]
19 all_image_label = [name_to_indx[pathlib.Path(p).parent.name] for p in all_image_path]
20 
21 def load_pregrosess_image(path, label):
22     image = tf.io.read_file(path)
23     image = tf.image.decode_jpeg(image, channels = 3)
24     image = tf.image.resize(image, [256, 256])
25     image = tf.cast(image, tf.float32)
26     image = image / 255
27     return image, label
28 
29 train_image_ds = tf.data.Dataset.from_tensor_slices((all_image_path, all_image_label))
30 
31 AUTOTUNE = tf.data.experimental.AUTOTUNE
32 dataset = train_image_ds.map(load_pregrosess_image, num_parallel_calls = AUTOTUNE)
33 
34 BATCHSIZE = 16
35 train_count = int(image_count * 0.8)
36 test_count = image_count - train_count
37 
38 train_dataset = dataset.take(train_count)
39 test_dataset = dataset.skip(train_count)
40 
41 train_dataset = train_dataset.shuffle(train_count).repeat().batch(BATCHSIZE)
42 test_dataset = test_dataset.repeat().batch(BATCHSIZE)

 

2.2加載與訓練網絡並構建網絡模型

與訓練的網絡由兩個部分構成,訓練好的卷積基和訓練好的分類器。咱們須要使用訓練好的卷積基來提取特徵,並使用自定義的分類器對本身的數據集進行分類識別。測試

以下圖所示:spa

 

 

訓練過程當中,咱們僅僅對自定義的分類器進行訓練,而不訓練預訓練好的卷積基部分。code

 

預訓練的卷積基能夠很是好的提取圖像的某些特徵,在訓練過程當中,因爲分類器是一個全新的沒有訓練過的分類器,在訓練初期會產生很大的loss值,因爲數據量較少,若是不對預訓練的卷積基進行凍結(不更新參數)處理,產生的loss值經梯度傳遞會對預訓練的卷積基形成很是大的影響,且因爲可訓練數據較少兒難以恢復,因此只對自定義的分類器進行訓練,而不訓練卷積基。htm

 

 首先從tf.keras.applications中建立一個預訓練VGG16的卷積基。blog

1 cov_base = tf.keras.applications.VGG16(weights = 'imagenet', include_top = False)

weight是咱們要使用的模型權重,咱們使用經imagenet訓練過的模型的權重信息進行遷移學習。

include_top是指,是否使用預訓練的分類器。在遷移學習過程當中咱們使用自定義的分類器,因此參數爲False。

而後咱們對建立好的卷積基進行凍結處理,凍結全部的可訓練參數。

1 cov_base.trainable = False

使用keras.Sequential()建立網絡模型。

1 model = tf.keras.Sequential()
2 model.add(cov_base)
3 model.add(tf.keras.layers.GlobalAveragePooling2D())
4 model.add(tf.keras.layers.Dense(512, activation = 'relu'))
5 model.add(tf.keras.layers.Dense(1, activation = 'sigmoid'))

在模型中加入卷積基和自定義的分類器。

模型結構以下圖所示:

咱們獲得了一個可訓練參數僅爲263,169的預訓練VGG16網絡模型。

2.3使用自定義數據訓練分類器

此時模型已經搭建完畢,咱們使用以前處理好的數據對它進行訓練。

 1 model.compile(optimizer = 'adam',
 2               loss = 'binary_crossentropy',
 3               metrics = ['acc']
 4              )
 5 
 6 history = model.fit(train_dataset,
 7                     steps_per_epoch = train_count // BATCHSIZE,
 8                     epochs = 10,
 9                     validation_data = test_dataset,
10                     validation_steps = test_count // BATCHSIZE
11                    )
12 
13 plt.plot(history.epoch, history.history.get('acc'), label = 'acc')
14 plt.plot(history.epoch, history.history.get('val_acc'), label = 'acc')

訓練結果以下圖所示:

模型在訓練集和測試機上的正確率均達到了94%左右,並且僅僅通過了10個epoch就達到了這樣的效果,足以看出遷移學習在小規模數據上的優點。

3.微調

雖然使用預訓練網絡能夠輕易的達到94%左右的正確率,可是,若是咱們還想繼續提升這個正確率該怎樣進行調整呢?

所謂微調,是凍結卷積基底部的卷積層,共同訓練新添加的分類器和卷積基頂部的部分卷積層。

根據卷積神經網絡提取特徵的原理咱們不難發現,越底層的卷積層提取到的圖像特徵越抽象越細小,而頂層的卷積層提取到的特徵更大,更加的接近咱們能直接觀察到的數據特徵,因爲咱們須要訓練的數據和預訓練時使用的數據不盡相同,因此越頂層的卷積層提取到的特徵與咱們所須要的特徵差異越大因此,咱們只凍結底部的卷積層,將頂部的卷積層與訓練好的分類器共同訓練,會獲得更好的擬合效果。

只有分類器以及訓練好了,才能微調卷積基的頂部卷積層,不然因爲訓練初期的偏差很大,會將卷積層以前學習到的參數破壞掉。

因此咱們對卷積基進行解凍,並只對底部的卷積進行凍結。

1 cov_base.trainable = True
2 for layers in cov_base.layers[:-3]:
3     layers.trainable = False

而後將模型繼續進行訓練。

 1 model.compile(optimizer = tf.keras.optimizers.Adam(lr = 0.0001),
 2               loss = 'binary_crossentropy',
 3               metrics = ['acc']
 4              )
 5 
 6 history = model.fit(train_dataset,
 7                     steps_per_epoch = train_count // BATCHSIZE,
 8                     epochs = 20,
 9                     initial_epoch = 10,
10                     validation_data = test_dataset,
11                     validation_steps = test_count // BATCHSIZE
12                    )
13 
14 plt.plot(history.epoch, history.history.get('acc'), label = 'acc')
15 plt.plot(history.epoch, history.history.get('val_acc'), label = 'acc')

注意將學習率調小,以便儘量的達到loss的極小值點。

獲得的結果以下圖所示:

模型再訓練集上達到了近乎100%的準確率,在測試集上也達到了96%左右準確率,微調的效果仍是較爲明顯的。

 

那麼關於遷移學習的介紹到這裏就結束了o(* ̄▽ ̄*)o,後續會更新更多內容。

相關文章
相關標籤/搜索