自己動手寫深度學習模型之全連接神經網路
本文作者王樂,首發於知乎專欄【每天都要機器學習哦】,AI 研習社獲得作者授權轉載
前半個多月總共寫了三篇深度學習相關的理論介紹文章,另外兩個月前,我們使用邏輯回歸演算法對sklearn裡面的moons數據集進行了分類實驗,最終準確率和召回率都達到了97.9%,詳情參看這篇文章:一文打盡:線性回歸和邏輯斯蒂線性回歸(https://zhuanlan.zhihu.com/p/31075733),今天我們嘗試使用神經網路來進行分類。全連接神經網路的搭建本身沒什麼難度,幾句代碼就夠了,但是本文的真正目的是:
讓大家了解Tensorflow 的基本使用方法;
使用 tensorboard 可視化你的神經網路結構和變數的更新情況;
斷點保存模型,可以在訓練意外中斷之後再次運行時接著中斷之前的狀態繼續訓練;
展示全連接神經網路是不是真的可以擬合任意函數,擬合效果怎樣。
了解以上前三點操作之後,你可以移植到任何網路之中,這樣有助於你更好的訓練模型,調參。
載入數據
defload_data(noise=0.1):
fromsklearn.datasetsimportmake_moons
m =2000
X_moons, y_moons = make_moons(m, noise=noise, random_state=42)
returnX_moons, y_moons
我們在moons 數據集中取2000 個點,其中參數 noise 表示在數據集中隨機增加雜訊;X_moons 是一個2維的數組,shape 為(2000,2);y_moons 為1維數組,shape為(2000,)。具體數據可以參考線性回歸那篇文章。
隨機 batch
訓練模型時,我們通常會將數據一批一批的丟給模型取訓練,而不是每次都把所有數據丟進取訓練,這麼做的理由和好處在文章深度學習中的優化問題以及常用優化演算法中已經做過說明。因此在每一步訓練中我們需要在訓練集中隨機取batch_size 個訓練數據出來,上述函數實現的就是這個功能。當然這個代碼這樣寫的話,有些訓練樣本可能一次都不會被取到,有的樣本會經常取到,但這是無關緊要的。
劃分訓練集和測試集
test_ratio =.2
test_size = int(len(data) * test_ratio)
X_train = data[:-test_size]
X_test = data[-test_size:]
y_train = label[:-test_size]
y_test = label[-test_size:]
上述代碼不需要解釋。
建立全連接神經網路層
# regularizer =tf.contrib.layers.l2_regularizer(lambd)def fc_layers(input_tensor,regularizer):
HINDENN1 =6
HINDENN2 =4
withtf.name_scope("full-connect-layer"):
fc1 =tf.layers.dense(input_tensor, HINDENN1, activation=tf.nn.elu,
kernel_regularizer=regularizer, name="fc1")
fc2 =tf.layers.dense(fc1, HINDENN2, activation=tf.nn.elu,
kernel_regularizer=regularizer, name="fc2")
returnfc2
在這個實驗中,我直搭建兩個隱藏層的全連接網路,第一個隱藏層 6 個神經元,第二層隱藏出 4個神經元。激活函數使用ELU,因為我之前介紹激活函數時說過,我們應該優先選擇ELU激活函數。在全連接中使用了L2正則化,lambd 表示正則係數,這裡數據量比較少,我取的正則係數也比較小,為0.01。
搭積木一樣搭建整個模型的結構
n_inputs = X_train.shape[1]
n_outputs =len(set(y_train))
withtf.name_scope("input"):
X=tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y=tf.placeholder(tf.int32, shape=(None), name="y")
regularizer =tf.contrib.layers.l2_regularizer(lambd)
fc2 = fc_layers(X,regularizer)
withtf.name_scope("output"):
logits =tf.layers.dense(fc2, n_outputs, kernel_regularizer=regularizer,name="output")
withtf.name_scope("loss"):
xentropy =tf.nn.sparse_softmax_cross_entropy_with_logits(labels =y, logits= logits)
loss =tf.reduce_mean(xentropy, name ="loss")
loss_summary =tf.summary.scalar("loss", loss)
global_step =tf.Variable(, trainable = False)
withtf.name_scope("train"):
optimizer =tf.train.AdamOptimizer(learning_rate)
grads_and_vars = optimizer.compute_gradients(loss)
train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)
withtf.name_scope("eval"):
predictions =tf.argmax(logits,1)
correct =tf.nn.in_top_k(logits,y,1)
accuracy =tf.reduce_mean(tf.cast(correct,tf.float32))
acc_summary =tf.summary.scalar("acc", accuracy)
summary_op =tf.summary.merge([loss_summary, acc_summary])
這裡建立了輸入層"input",輸出層"output",輸出層也是使用全連接網路,它將第二個隱藏層和輸出層(2個輸出神經元)連接起來;使用交叉熵計算損失,建立損失節點"loss",使用語句tf.summary.scalar("loss", loss) 將每一步的損失值寫入到文件中;在『train』節點中,使用了 Adam 優化演算法,之前我在在介紹優化演算法時葉說過,應該優先考慮使用 Adam 優化演算法;最後是 "eval" 節點,這裡有預測輸出結果 predictions,預測結果中正確的個數 correct ,根據預測正確與否計算準確率 accuracy ,語句 tf.summary.scalar("acc", accuracy) 將正確率數值實時寫入文件中;使用 tf.summary.merge([loss_summary, acc_summary]) 語句將上述兩個需要寫入文件的值 merge ,方便之後tensorflow 計算。
模型結構如下:
定義模型和變數的保存地址
checkpoint_path="./chickpoints/model.ckpt"
checkpoint_epoch_path= checkpoint_path +".epoch"
final_model_path="./chickpoints/model"
now= datetime.utcnow().strftime("%Y%m%d%H%M%S")
logdir="./logs/"+ now
file_writer= tf.summary.FileWriter(logdir, tf.get_default_graph())
saver= tf.train.Saver()
為了防止訓練的意外終止,我們需要定期保存模型,checkpoint_path 就是我們臨時保存模型的路徑;checkpoint_epoch_path 路徑保存我們每一次的 epoch數目,如果模型在epoch = 100時中斷,那麼我可以設置在下次繼續運行代碼時讓代碼接著在中斷的 100 epoch這裡繼續運行,而不需要從頭開始,這樣節省很多時間;final_model_path 為最終模型的保存路徑;logdir 為日誌文件路徑,就是我們保存 tensorboard 文件的地址。
訓練和驗證
n_epochs = n_epochsbatch_size = batch_sizen_batches =int(np.ceil(len(data) / batch_size))withtf.Session()assess:
init =tf.global_variables_initializer()
ifos.path.isfile(checkpoint_epoch_path):
#ifthe checkpointfileexists, restore the modelandload the epochnumber
withopen(checkpoint_epoch_path,"rb")asf:
start_epoch =int(f.read())
print("Training was interrupted. Continuing at epoch", start_epoch)
saver.restore(sess, checkpoint_path)
else:
start_epoch =
sess.run(init)
forepoch inrange(start_epoch, n_epochs):
forbatch_index inrange(n_batches):
X_batch, y_batch = random_batch(X_train, y_train, batch_size)
sess.run(train_op, feed_dict={X: X_batch,y: y_batch})
loss_val, summary_str,test_pred, test_acc = sess.run(
[loss, summary_op,predictions, accuracy],
feed_dict={X: X_test,y: y_test})
file_writer.add_summary(summary_str, epoch)
ifepoch %50==:
print("Epoch:", epoch," Loss:", loss_val," Acc:",test_acc)
saver.save(sess, checkpoint_path)
withopen(checkpoint_epoch_path,"wb")asf:
f.write(b"%d"% (epoch +1))
saver.save(sess, final_model_path)
y_pred = predictions.eval(feed_dict={X: X_test,y: y_test})
print("precision_score",precision_score(y_test, y_pred))
print("recall_score",recall_score(y_test, y_pred))
sess.close()
[loss, summary_op,predictions, accuracy],
feed_dict=),並且將要保存的日誌信息寫入文件 file_writer.add_summary(summary_str, epoch)。每 50 epoch 列印測試集上的損失和正確率 print("Epoch:", epoch, " Loss:", loss_val," Acc:",test_acc) ,並且保存臨時模型。在模型跑完之後,我們對測試集進行預測 y_pred = predictions.eval(feed_dict=),得到預測結果之後計算測試集的精確率和找回率,列印輸出。
整個過程到這裡結束。我們看看模型在測試集上的表現:
首先,我們將數據集的 noise 設置為0.1,並且不設置正則化,可以看到,效果非常好,精確率和召回率都達到100%;
在500 epoch 之前就達到100%,並一直保持
在1500epoch左右損失值降到最低,單從noise 設置為0.1看,訓練次數多了,可以適當降低epoch次數
但是如果將測試集的noise 設置為0.2和0.3時,模型的表現分別如下:
效果就變的比較差了,泛化能力較差,甚至低於邏輯回歸演算法。當然邏輯回歸使用的雜訊只有0.1,不能直接比,但是仍然可以看到當測試數據集雜訊大時,模型效果不是很好的。
接下來使用正則化,測試集的noise 分別設置為0.2和0.3,模型效果如下:
模型的準確率在0.970至0.973之間震蕩
模型在測試集上的損失雖然很震蕩,但是可以看出一直有下降的趨勢,我這裡設置的5000epoch應該不夠,可以加大epoch次數
加正則化之後,泛化效果還是提升不少。最後可以看到,全連接神經網路本身是一個很好的分類器,所以你會在很多網路結構中的最後幾層看到全連接神經網路,當然有些模型沒有全連接,也不需要見怪不怪,因為有許多演算法或者網路結構可以替代全連接分類器。
在接下來的三篇文章我回先介紹卷積神經網路,再像本文一樣使用tensorflow搭建一個卷積模型做圖像分類,然後接著會有一篇遷移模型的搭建文章。如果喜歡就給個讚唄……
完整代碼
https://github.com/wangle1218/Depp-learning-TensorFlow-tutorials/blob/master/fc_clf.pygithub.com
參考資料
Aure?lien Ge?ron,《 Hands-On Machine Learning with Scikit-Learn and TensoFlow》
鄭澤宇,顧思宇,《TensorFlow -- 實戰Google 深度學習框架》
NLP 工程師入門實踐班:基於深度學習的自然語言處理
三大模塊,五大應用,手把手快速入門 NLP
海外博士講師,豐富項目經驗
演算法 + 實踐,搭配典型行業應用
隨到隨學,專業社群,講師在線答疑
※從編程實現角度學習 Faster R-CNN
※拿到吳恩達 DeepLeaning 的課程證書能找到機器學習工作嗎?
TAG:AI研習社 |