tensorflow從零開始實現分類任務

實驗環境:tensorflow-1.14, python3.7。

可根據莫煩教程學習相關基礎知識。

所有代碼和數據集詳見:https://gitee.com/lakuite/tensorflow_classfication

 

Windows下tensorflow-1.14,cpu版的安裝

官方教程:https://tensorflow.google.cn/install/pip#windows

這個網站是tensorflow官網給的pip安裝的方法,它的系統需求是python3.5-3.7,pip19.0版本及以上,windows7版本及以上。

1. python3.7

下載地址:https://www.python.org/downloads/release/python-377/

下載對應的安裝包,然後直接雙擊安裝就可以了。

需要注意在安裝時勾選“添加環境變量”,不然裝完後要手動添加一下。

安裝完成後在命令行輸入python,出現圖中所示信息說明安裝成功:

該方法安裝的python已經自動安裝了pip。

2. 新建虛擬環境(推薦)

官網教程推薦virtualenv,這個不裝也可以,但是爲了以後發生版本對應問題,最好還是裝一個。

安裝virtualenv只要在命令行輸入下面2條語句就可以了:

python -m pip install --upgrade pip
pip install virtualenv

裝完後可以輸出它的版本以檢查是否安裝成功:

 然後在保存python項目的路徑下進入cmd,用下面的命令創建虛擬環境venv,然後激活該環境:

# 創建虛擬環境venv
virtualenv --system-site-packages -p python3 ./venv
# 激活環境
.\venv\Scripts\activate
# 退出環境
deactivate

在環境激活狀態下升級pip,查看在該環境中安裝過的包:

pip install --upgrade pip
pip list

3. 安裝tensoeflow-1.14-cpu

在虛擬環境中執行:

pip install tensorflow==1.14

1.14是指定版本,不指定則安裝最新版本。

如果下載速度慢的話可以用國內源進行安裝。

在C:\Users\<電腦用戶名>\pip下新建文檔 pip.ini:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host=mirrors.aliyun.com

再使用pip安裝。

測試是否安裝成功,在cmd中:

python
import tensorflow as tf
print(tf.__version__)

如果出現報錯:

FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecate 

可降級numpy爲1.16來解決:

pip install numpy==1.16.0

 

一、全連接網絡實現手寫數字識別[1]

1. MNIST數據集簡介

共60000張圖片作爲訓練集(其中包含5000張驗證集),10000張圖片爲測試集。

每張圖片大小均爲28x28的灰度圖(即通道數爲1)。

每張圖片對應一個標籤,標籤爲one-hot格式,即對於圖片  ,其標籤爲:

[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]

可使用下述代碼下載mnist數據集:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

下載完後會在當前路徑下生成 MNIST_data 的文件夾,裏面有相關數據文件:

數據集使用:

2. 網絡結構

mnist數據集的每一張圖片都表示一個數字,從0到9, 可以構造一個模型得到給定圖片代表每個數字的概率。

爲了得到一張給定圖片屬於某個特定數字類的證據(evidence),需要對圖片像素值進行加權求和。

同時因爲輸入往往會帶有一些無關的干擾量,也需要加入一個額外的偏置量(bias)。 其中,Wi代表權重,bi代表數字 i 類的偏置量,j代表給定圖片x的像素索引用於像素求和。

Softmax會正則化這些權重值,使它們的總和等於1,以此構造一個有效的概率分佈。

3. 模型訓練過程

xs表示輸入的圖片數據,ys表示每張圖片代表的標籤。

Weights和biases是訓練過程中要學習的權重和偏置。

4. 模型評估

5. 實驗結果

  

 

二、CNN實現手寫數字識別[2]

1. 網絡結構

由2層卷積池化層和2層全連接層組成:

輸入圖片大小爲28x28x1,經過第一層卷積池化[3]後大小變爲14x14x32,經過第二層卷積池化後大小變爲7x7x64,提取了圖片的高維度特徵,相當於把圖片長寬變小高度變厚了。然後經過2個全連接層,最後使用softmax激活獲得一個大小爲10的圖片預測數字的概率分佈。

2. 卷積

卷積即爲內積,就是根據多個一定的權重(即卷積核kernel),對一個塊的像素進行內積運算,其輸出就是提取的特徵之一。

卷積包含kernel,stride,padding 3個屬性。

  (卷積核)

上圖中輸入圖片爲綠色部分,大小爲5x5;kernel爲黃色部分,大小爲3x3。stride=1, padding=VALID。

卷積後的圖片大小爲3x3(即(5+1)/2),4=1x1+1x0+1x1+0x0+1x1+1x0+0x1+0x0+1x1。

# 定義卷積
def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

卷積中 strides 表示每次卷積移動的步長,strides=[1,1,1,1] 中,兩邊的1不可變,中間紅色的1表示該卷積的步長爲1,。若步長爲2,則 strides=[1,2,2,1]。

padding表示卷積方式,VALID爲不填充邊緣,卷積後圖片變小。SAME爲填充邊緣,卷積後圖像大小不變。

 

如上圖,同樣輸入圖片大小爲4x4,卷積核大小3x3,步長爲1。VALID方式卷積後圖像大小變爲2x2,SAME方式卷積後圖片大小還是4x4。

3. 池化

池化pooling是指將一個矩形區域的像素變成一個像素,下圖即將20x20大小的圖片經過10x10的池化,變成2x2大小的圖片:

常用的 pooling 方法有 max pooling 和 average pooling。max pooling 是將矩形區域最大的值作爲結果,average pooling 是將矩形區域的均值作爲結果。

上圖爲最大池化,5=max{5,2,4,1};若爲平均池化,則有(5+2+4+1)/4=3。

# 定義池化
def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

ksize=[1,2,2,1]表示池化的矩形大小爲2x2,strides和卷積一樣,表示步長爲2。padding定義也和卷積一樣。

4. 網絡搭建

搭建卷積池化層一:

搭建卷積池化層二:

搭建全連接層一:

搭建輸出層(全連接層二):

5. 實驗任務

6. 實驗結果

lr=0.0001, step=2000, Adam:

對比結果:

(1)在一定範圍內,lr越大,每次迭代權重更新的越快,最終acc越高,loss越小;

(2)在一定範圍內,step越大,學習次數越多,最終acc越高,loss越小;

(3)在學習率同爲0.0001的情況下,SGD和Adam最後的準確率沒有明顯區別,loss收斂有些微區別;

(4)學習率0.001,step=2000時,Adam下的loss已經降到了一個比較低的數值,測試集上也獲得了99%的好結果;

(5)學習率0.001時,SGD會出現loss爲nan的現象,可能發生了梯度爆炸,因此把lr調成了0.0005。而Adam在0.001下並不會發生該現象,因此,SGD比Adam每次更新的程度更大。

 

三、CNN實現人臉識別(用自己的數據集實現分類任務)

1. orl數據集

該數據集共400張圖片,共40類,每類圖片10張,圖片大小爲56x46的灰度圖。

選擇每類圖片的前9張作爲訓練集(共360張),最後一張作爲測試集(共40張)。並構建one-hot編碼的數據集標籤。

2. 數據集預處理與label構建

下載下來的orl數據集,圖片數據全部在orl文件夾下,運行下述代碼進行圖片位置劃分:

import os
import shutil

# 數據集路徑,需修改
orl_dir = 'C:/Users/lakuite/Desktop/orl'
orl_list = os.listdir(orl_dir)

os.mkdir(orl_dir + '/train')
os.mkdir(orl_dir + '/test')

# 把圖片分爲train和test
for i, img in enumerate(orl_list):
    img_path = orl_dir + '/' + img
    if (i+1)%10==0:
        shutil.copy(img_path, os.path.join(orl_dir, 'test', img))
    else:
        shutil.copy(img_path, os.path.join(orl_dir, 'train', img))
    os.remove(img_path)

更多文件處理相關方法可見[4]

運行後結果,360張圖片在train下作爲訓練集,40張圖片在test下作爲測試集:

可用下述代碼將數組轉換爲one-hot標籤格式:

train_label = tf.one_hot(train_label,40)

效果如下:

3. 網絡構成

cnn網絡和第二個任務一樣,爲2層卷積池化+2層全連接。

4. 實驗任務

5. 實驗結果

參數設置:lr=0.001,epoch=30,batch_size=40

訓練結果:

 

測試結果:

pic後的數表示圖片的真實類別,label後的數表示識別錯誤的圖片誤識別成的類別。

訓練次數可能多了點,有過擬合現象,測試集準確率不夠高,82.5%。

訓練和測試圖片原本就是灰度圖,但是沒有/255和轉爲float,應該沒有影響。

6. 注意事項

(1)損失函數

上次任務中最後的輸出層爲:

y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

損失函數爲:

cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv))

而這次任務中,損失函數爲:

cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y_conv))

已經包含了softmax,故輸出層的softmax應去掉,否則會出現y_conv爲nan,loss爲nan的問題。

(2)學習速率

學習速率設置爲0.01時,loss一直在3.7左右波動,即ln(40),沒有學習。

原因可能是學習速率過大,導致一開始梯度就到了錯誤的位置。改爲0.001後結果正確。

 

四、在人臉識別中使用數據增強

1. 數據增強

數據增強(Data Augmentation)是一種通過讓有限的數據產生更多的等價數據來人工擴展訓練數據集的技術。它是克服訓練數據不足的有效手段,目前在深度學習的各個領域中應用廣泛。

使用數據增強的原因:

(1)增加訓練樣本的數量以及多樣性(噪聲數據),提升模型魯棒性;

(2)深度神經網絡需要大量數據來避免過擬合。

2. tf自帶相關函數

# 調整大小
resized = tf.image.resize_images(img_data, [300, 300], method=0)
# 裁剪填充
croped = tf.image.resize_image_with_crop_or_pad(img_data, 300, 300)
# 上下翻轉
flipped1 = tf.image.flip_up_down(img_data)
# 左右翻轉
flipped2 = tf.image.flip_left_right(img_data)
# 對角翻轉
transposed = tf.image.transpose_image(img_data)
# 調整亮度
adjusted = tf.image.adjust_brightness(img_data, 0.5)
# 調對比度
adjusted = tf.image.adjust_contrast(img_data, -5)
# 調飽和度
adjusted = tf.image.adjust_saturation(img_data, 5)
# 圖像標準化
adjusted = tf.image.per_image_standardization(img_data)

3. GT數據集

訓練集70張,測試10張,rgb圖,每張圖大小不同:

上傳的數據集已將圖片resize爲83x57大小的灰度圖:

4. 數據集預處理

對訓練集進行數據增強處理,這裏採用旋轉和上採樣2種方式。處理完後訓練集擴增爲210張。

 (上採樣)

(旋轉)

5. 實驗任務

6. 實驗結果

數據增強前(lr=0.01, epoch=15, batch_size=10):

數據增強後(lr=0.001, epoch=22, batch_size=30):

訓練結果:

測試結果:

原則上來說,數據增強會使準確率有些微或明顯提升。

在數據增強前,雖然訓練集圖片很少,但已取得不錯的結果,在測試集上有0.9的準確率。

數據增強後,加大了訓練難度,且訓練收斂程度具有隨機性,雖然數據集增加了,但依然不是很多,在準確率方面並沒有明顯的提升。因爲測試集僅有10張圖片,每類一張,數量太少,測試準確率也不能表達一般性。

 

參考文檔

[1] MNIST機器學習入門

[2] 深入MNIST

[3] CNN Explaniner

[4] python文件處理常用代碼

[5] tf.one_hot()函數簡介

[6] Tensorflow將自己的數據分割成batch訓練

[7] 數據增強的方法總結及代碼實現

[8] Python中讀取,顯示,保存圖片的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章