深度學習-圖片識別(上)
本文主要針對優達學城深度學習課程中的練習題,整理練習內容,有興趣者可結合本文內容然後按練習題實踐,幫助理解。
任務一:下載並整理數據
任務主要完成圖片下載、圖片內容數字化、選取三個數據集、打亂順序、持久化數據等,步驟如下:
- 下載包含10個字母的兩份圖片數據,large與small
large與small不止數量大小區別,還在於large中的圖片有沒經過人工篩選,有噪點以及損壞圖片,從中選取數據作爲訓練集與驗證集,small中的圖片經過人工篩選,數據相對乾淨,從中選取數據作爲測試集
- 處理每個字母文件夾
每張圖片可以用一個
28 x 28
的二維數組表示,一個目錄下的n張圖片放到一個n x 28 x 28
的三維數組中,然後通過pickle序列化到文件中
- 選取訓練集、驗證集、測試集
從處理好的數據中選取訓練集、驗證集、測試集,選取過程中每個類別打亂順序併合並不同類別,同時使用數組記錄每個數據項對應的類別(label)
- 再次打亂順序,並序列化到文件
針對每個數據集與label,再次打亂順序,然後把所有數據集以及相應label包裝成dict序列化到磁盤
任務作業
使用sklearn.linear_model中的LogisticRegression模型訓練一個模型,主要代碼:
import numpy as np
import pickle
from sklearn.linear_model import LogisticRegression
image_size = 28
train_size = 1000
data = pickle.load(open('notMNIST.pickle','rb'))
train_features = data['train_dataset'][:train_size]
train_labels = data['train_labels'][:train_size]
test_features = data['test_dataset']
test_labels = data['test_labels']
train_features = train_features.reshape(len(train_features), image_size * image_size)
test_features = test_features.reshape(len(test_features), image_size * image_size)
print 'start train!'
classifier = LogisticRegression()
classifier.fit(train_features, train_labels)
print 'start predict!'
score = classifier.score(test_features,test_labels)
print 'The accuray score is %.3f' % score
結果:
start train!
start predict!
The accuray score is 0.828
任務二:TF邏輯迴歸訓練模型
任務主要構造TF計算圖、訓練模型,最後驗證隨機梯度下降算法帶來的速度優化,這部分內容比上一個任務難度增加,開始涉及TF編程,分爲以下幾步:
- 重新格式化特徵與標籤
將特徵數組由
n x 28 x 28
的變形爲n x 784
,label的值使用One-Hot編碼
- 構造計算圖
選取了部分訓練數據作爲輸入,使用tf.truncated_normal生成權重矩陣,計算輸入矩陣與權重矩陣的乘積再加上偏差,然後計算softmax和交叉熵,並使用所有樣本的交叉熵平均值作爲模型針對樣本的損失值,最後使用梯度下降算法優化器優化模型
- 訓練
訓練801步,每訓練100步,輸出模型針對訓練集與驗證集的損失值、準確度
- 使用隨機梯度下降算法訓練模型
重新構造計算圖,然後使用隨機梯度下降算法訓練3001步,訓練速度比普通梯度下降算法更快
任務作業
任務二下面有留下一個需要解答的問題:“添加一層通過ReLU函數激活的隱藏層”,主要代碼如下:
batch_size = 128
hidden_layer_node_num = 1024
graph = tf.Graph()
with graph.as_default():
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
hidden_weights = tf.Variable(tf.truncated_normal([image_size * image_size, hidden_layer_node_num]))
hidden_biases = tf.Variable(tf.zeros([hidden_layer_node_num]))
weights = tf.Variable(tf.truncated_normal([hidden_layer_node_num, num_labels]))
biases = tf.Variable(tf.zeros([num_labels]))
logits = tf.matmul(tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases), weights) + biases
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits))
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
train_prediction = tf.nn.softmax(logits)
valid_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_valid_dataset, hidden_weights) + hidden_biases), weights) + biases)
test_prediction = tf.nn.softmax(tf.matmul(tf.nn.relu(tf.matmul(tf_test_dataset, hidden_weights) + hidden_biases), weights) + biases)
任務三:優化模型
任務三本身沒有多少現成代碼,主要靠自己動手。
L2正則化
接任務二ReLU的代碼,只要爲損失函數loss添加L2正則化的結果即可,選0.001438作爲超參λ的值,課程沒有講如何選擇超參的值,這個值是從他人文章中借用的。
在之前的損失函數賦值後面添加:
loss = loss + 0.001438 * (tf.nn.l2_loss(hidden_weights) + tf.nn.l2_loss(hidden_biases) + tf.nn.l2_loss(weights) + tf.nn.l2_loss(biases))
過度擬合
將訓練數據減少爲幾個批次的量,演示過度擬合。
從訓練數據中取出一個較小的子集作爲訓練集:
batch_size = 128
train_dataset = train_dataset[:batch_size * 5, :]
train_labels = train_labels[:batch_size * 5, :]
過度擬合,會導致模型在訓練集上的表現很好,但針對驗證集或測試集,表現大打折扣。
丟棄法
dropout會隨機將輸入值丟棄或縮放,可達到訓練模型冗餘性,防止過度擬合。
核心代碼:
tmp = tf.nn.relu(tf.matmul(tf_train_dataset, hidden_weights) + hidden_biases)
tmp = tf.nn.dropout(tmp, 0.5)
logits = tf.matmul(tmp, weights) + biases
dropout第二個參數0.5,說明dropout的行爲是隨機將部分值置爲0,另外一部分x2,這樣,整體樣本的平均值不會變化。
多層神經網絡
該習題的目的是使用多層神經網絡,使最終測試集的準確率達到97.1%。
核心代碼:
hlnn1 = 4096
hlnn2 = 2048
hlnn3 = 128
hw1 = tf.Variable(tf.truncated_normal([image_size * image_size, hlnn1], stddev=np.sqrt(2.0 / (image_size * image_size))))
hb1 = tf.Variable(tf.zeros([hlnn1]))
hw2 = tf.Variable(tf.truncated_normal([hlnn1, hlnn2], stddev=np.sqrt(2.0 / hlnn1)))
hb2 = tf.Variable(tf.zeros([hlnn2]))
hw3 = tf.Variable(tf.truncated_normal([hlnn2, hlnn3], stddev=np.sqrt(2.0 / hlnn2)))
hb3 = tf.Variable(tf.zeros([hlnn3]))
weights = tf.Variable(tf.truncated_normal([hlnn3, num_labels], stddev=np.sqrt(2.0 / hlnn3)))
biases = tf.Variable(tf.zeros([num_labels]))
tmp = tf.nn.relu(tf.matmul(tf_train_dataset, hw1) + hb1)
tmp = tf.nn.relu(tf.matmul(tmp, hw2) + hb2)
tmp = tf.nn.relu(tf.matmul(tmp, hw3) + hb3)
logits = tf.matmul(tmp, weights) + biases
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits))
loss = loss + tf_beta * (tf.nn.l2_loss(hw1) + tf.nn.l2_loss(hb1) + tf.nn.l2_loss(hw2) + tf.nn.l2_loss(hb2) +
tf.nn.l2_loss(hw3) + tf.nn.l2_loss(hb3) + tf.nn.l2_loss(weights) + tf.nn.l2_loss(biases))
learning_rate = tf.train.exponential_decay(0.5, global_step, 1000, 0.7, staircase=True)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
添加多個隱藏層,然後使用學習速率衰減方式,讓損失降低,準確率進一步提升,到這一步我的Mac電腦已經開始喫不消,訓練5000步,模型在測試集上的準確率95.1%,繼續訓練,模型的表現應該會更好。