tensorflow入門之訓練簡單的神經(jīng)網(wǎng)絡方法
這幾天開始學tensorflow,先來做一下學習記錄
一.神經(jīng)網(wǎng)絡解決問題步驟:
1.提取問題中實體的特征向量作為神經(jīng)網(wǎng)絡的輸入。也就是說要對數(shù)據(jù)集進行特征工程,然后知道每個樣本的特征維度,以此來定義輸入神經(jīng)元的個數(shù)。
2.定義神經(jīng)網(wǎng)絡的結(jié)構(gòu),并定義如何從神經(jīng)網(wǎng)絡的輸入得到輸出。也就是說定義輸入層,隱藏層以及輸出層。
3.通過訓練數(shù)據(jù)來調(diào)整神經(jīng)網(wǎng)絡中的參數(shù)取值,這是訓練神經(jīng)網(wǎng)絡的過程。一般來說要定義模型的損失函數(shù),以及參數(shù)優(yōu)化的方法,如交叉熵損失函數(shù)和梯度下降法調(diào)優(yōu)等。
4.利用訓練好的模型預測未知的數(shù)據(jù)。也就是評估模型的好壞。
二.訓練簡單的向前傳播神經(jīng)網(wǎng)絡
一下訓練的神經(jīng)模型是最簡單的一類,而且是線性的(也就是說沒有用激活函數(shù)去線性話),沒有反向傳播的過程,只是簡單的說明神經(jīng)網(wǎng)絡工作的流程。
import tensorflow as tf #定義隱藏層參數(shù),每個w變量是一個tensor(可以當成是n*m的數(shù)組,n表示上一層結(jié)點個數(shù),m表示本層結(jié)點個數(shù))表示上一層與本層的連接權(quán)重,這里先隨機定義權(quán)重 w1=tf.Variable(tf.random_normal([2,3],stddev=1)) w2=tf.Variable(tf.random_normal([3,1],stddev=1)) #定義存放輸入數(shù)據(jù)的地方,也就是x向量,這里shape為前一個傳入訓練的樣本個數(shù),后面出入每個樣本的維度大小 x=tf.placeholder(tf.float32,shape=(None,2),name="input") #矩陣乘法 a=tf.matmul(x,w1) y=tf.matmul(a,w2) with tf.Session() as sess: #新版本好像不能用這個函數(shù)初始化所有變量了 init_op=tf.initialize_all_variables() sess.run(init_op) #feed_dict用于向y中的x傳入?yún)?shù),這里傳入3個,則y輸出為一個3*1的tensor print(sess.run(y,feed_dict={x:[[0.7,0.9],[1.0,1.5],[2.1,2.3]]}))
至此,一個用x的每個維度乘以兩層權(quán)重之后輸出單個值得線性神經(jīng)網(wǎng)絡就定義好了。
三.定義損失函數(shù)以及反向傳播算法
有了上面的基礎,我們可以定義損失函數(shù)以及反向傳播算法去擬合數(shù)據(jù)了,非線性數(shù)據(jù)我們可以定義激活函數(shù)去線性化。還有一些細節(jié)就是學習率的問題,這次使用的是動態(tài)學習率,首先把學習率設定為比較大的值,加速收斂,然后隨著迭代次數(shù)的增加,學習率不斷下降,防止錯過局部最小值。還有一個問題,就是防止過擬合。一般神經(jīng)網(wǎng)絡防止過擬合的策略有兩種,一種是正則化,一種是dropout,我們暫且不作討論后者
損失函數(shù):交叉熵
反向傳播算法:梯度下降法
激活函數(shù):relu
# -*- coding: utf-8 -*- """ Created on Fri Aug 18 14:02:19 2017 @author: osT """ import tensorflow as tf import numpy as np #導入數(shù)據(jù),這里的數(shù)據(jù)是每一行代表一個樣本,每一行最后一列表示樣本標簽,0-32一共33個類 data=np.loadtxt('train_data.txt',dtype='float',delimiter=',') #將樣本標簽轉(zhuǎn)換成獨熱編碼 def label_change(before_label): label_num=len(before_label) change_arr=np.zeros((label_num,33)) for i in range(label_num): #該樣本標簽原本為0-32的,本人疏忽下32標記成33 if before_label[i]==33.0: change_arr[i,int(before_label[i]-1)]=1 else: change_arr[i,int(before_label[i])]=1 return change_arr #定義神經(jīng)網(wǎng)絡的輸入輸出結(jié)點,每個樣本為1*315維,以及輸出分類結(jié)果 INPUT_NODE=315 OUTPUT_NODE=33 #定義兩層隱含層的神經(jīng)網(wǎng)絡,一層300個結(jié)點,一層100個結(jié)點 LAYER1_NODE=300 LAYER2_NODE=100 #定義學習率,學習率衰減速度,正則系數(shù),訓練調(diào)整參數(shù)的次數(shù)以及平滑衰減率 LEARNING_RATE_BASE=0.5 LEARNING_RATE_DECAY=0.99 REGULARIZATION_RATE=0.0001 TRAINING_STEPS=2000 MOVING_AVERAGE_DECAY=0.99 #定義整個神經(jīng)網(wǎng)絡的結(jié)構(gòu),也就是向前傳播的過程,avg_class為平滑可訓練量的類,不傳入則不使用平滑 def inference(input_tensor,avg_class,w1,b1,w2,b2,w3,b3): if avg_class==None: #第一層隱含層,輸入與權(quán)重矩陣乘后加上常數(shù)傳入激活函數(shù)作為輸出 layer1=tf.nn.relu(tf.matmul(input_tensor,w1)+b1) #第二層隱含層,前一層的輸出與權(quán)重矩陣乘后加上常數(shù)作為輸出 layer2=tf.nn.relu(tf.matmul(layer1,w2)+b2) #返回 第二層隱含層與權(quán)重矩陣乘加上常數(shù)作為輸出 return tf.matmul(layer2,w3)+b3 else: #avg_class.average()平滑訓練變量,也就是每一層與上一層的權(quán)重 layer1=tf.nn.relu(tf.matmul(input_tensor,avg_class.average(w1))+avg_class.average(b1)) layer2=tf.nn.relu(tf.matmul(layer1,avg_class.average(w2))+avg_class.average(b2)) return tf.matmul(layer2,avg_class.average(w3))+avg_class.average(b3) def train(data): #混洗數(shù)據(jù) np.random.shuffle(data) #取錢850個樣本為訓練樣本,后面的全是測試樣本,約250個 data_train_x=data[:850,:315] data_train_y=label_change(data[:850,-1]) data_test_x=data[850:,:315] data_test_y=label_change(data[850:,-1]) #定義輸出數(shù)據(jù)的地方,None表示無規(guī)定一次輸入多少訓練樣本,y_是樣本標簽存放的地方 x=tf.placeholder(tf.float32,shape=[None,INPUT_NODE],name='x-input') y_=tf.placeholder(tf.float32,shape=[None,OUTPUT_NODE],name='y-input') #依次定義每一層與上一層的權(quán)重,這里用隨機數(shù)初始化,注意shape的對應關系 w1=tf.Variable(tf.truncated_normal(shape=[INPUT_NODE,LAYER1_NODE],stddev=0.1)) b1=tf.Variable(tf.constant(0.1,shape=[LAYER1_NODE])) w2=tf.Variable(tf.truncated_normal(shape=[LAYER1_NODE,LAYER2_NODE],stddev=0.1)) b2=tf.Variable(tf.constant(0.1,shape=[LAYER2_NODE])) w3=tf.Variable(tf.truncated_normal(shape=[LAYER2_NODE,OUTPUT_NODE],stddev=0.1)) b3=tf.Variable(tf.constant(0.1,shape=[OUTPUT_NODE])) #輸出向前傳播的結(jié)果 y=inference(x,None,w1,b1,w2,b2,w3,b3) #每訓練完一次就會增加的變量 global_step=tf.Variable(0,trainable=False) #定義平滑變量的類,輸入為平滑衰減率和global_stop使得每訓練完一次就會使用平滑過程 variable_averages=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step) #將平滑應用到所有可訓練的變量,即trainable=True的變量 variable_averages_op=variable_averages.apply(tf.trainable_variables()) #輸出平滑后的預測值 average_y=inference(x,variable_averages,w1,b1,w2,b2,w3,b3) #定義交叉熵和損失函數(shù),但為什么傳入的是label的arg_max(),就是對應分類的下標呢,我們遲點再說 cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.arg_max(y_,1)) #計算交叉熵的平均值,也就是本輪訓練對所有訓練樣本的平均值 cross_entrip_mean=tf.reduce_mean(cross_entropy) #定義正則化權(quán)重,并將其加上交叉熵作為損失函數(shù) regularizer=tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE) regularization=regularizer(w1)+regularizer(w2)+regularizer(w3) loss=cross_entrip_mean+regularization #定義動態(tài)學習率,隨著訓練的步驟增加不斷遞減 learning_rate=tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,900,LEARNING_RATE_DECAY) #定義向后傳播的算法,梯度下降發(fā),注意后面的minimize要傳入global_step train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step) #管理需要更新的變量,傳入的參數(shù)是包含需要訓練的變量的過程 train_op=tf.group(train_step,variable_averages_op) #正確率預測 correct_prediction=tf.equal(tf.arg_max(average_y,1),tf.arg_max(y_,1)) accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) with tf.Session() as sess: #初始所有變量 tf.global_variables_initializer().run() #訓練集輸入字典 validate_feed={x:data_train_x,y_:data_train_y} #測試集輸入字典 test_feed={x:data_test_x,y_:data_test_y} for i in range(TRAINING_STEPS): if i%1000==0: validate_acc=sess.run(accuracy,feed_dict=validate_feed) print("After %d training step(s),validation accuracy using average model is %g"%(i,validate_acc)) #每一輪通過同一訓練集訓練,由于樣本太少,沒辦法了 sess.run(train_op,feed_dict=validate_feed) #用測試集查看模型的準確率 test_acc=sess.run(accuracy,feed_dict=test_feed) print("After %d training step(s),test accuracy using average model is %g"%(TRAINING_STEPS,test_acc)) train(data)
然后我們來看一下為什么計算交叉熵時要傳入樣本的下標:
首先我們知道,輸出結(jié)點有33個,通過與前面的權(quán)重相乘后,則每個結(jié)點都會有一個輸出,每個輸出我們暫且認為是對應每個類的概率,該值越大,我們就越認為該樣本為對應的類。logits參數(shù)是神經(jīng)網(wǎng)絡的直接輸出,也就是未經(jīng)softmax函數(shù)處理的輸出,labels傳入的是單個值,也就是分類對應的下標,這是由于我們使用的計算交叉熵的函數(shù) tf.nn.sparse_softmax_cross_entropy_with_logits()有關。這個函數(shù)對于在只有一個正確分類的模型計算起到加速作用,而這個labels的輸入就是“這一個正確的分類”,對應到輸出的結(jié)點,就是其下標了。我們還有一個沒有加速的交叉熵函數(shù):tf.nn.softmax_cross_entropy_with_logis(logis=,labels=)這個時候我們就應該傳入本身的labels標簽了。
最后,我們來總結(jié)一下提高模型準確率的方法:
1.使用激活函數(shù)。也就是去線性化,這步幾乎是必須的。
2.增加隱含層。就本例而言,單隱含層300個結(jié)點,準確率在89%左右;單隱含層400個結(jié)點,準確率在93%左右;而雙隱含層300結(jié)點和100結(jié)點,準確率在94%左右。但增加隱含層意味著增加訓練時間。
3.使用動態(tài)學習率。這不但可以加快訓練的速度,還可以增加神經(jīng)網(wǎng)絡收斂到較低的極小值處的概率,從而增加準確率。
4.使用平滑模型。主要可以增加模型的健壯性,使其泛化能力更強。
5.加入正則化或者使用dropout防止過擬合。
附上訓練集
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Python 實現(xiàn)list,tuple,str和dict之間的相互轉(zhuǎn)換
這篇文章主要介紹了Python 實現(xiàn)list,tuple,str和dict之間的相互轉(zhuǎn)換,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03Nginx+Uwsgi+Django 項目部署到服務器的思路詳解
這篇文章主要介紹了Nginx+Uwsgi+Django 項目部署到服務器的思路,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05Python 日期區(qū)間處理 (本周本月上周上月...)
這篇文章主要介紹了Python 日期區(qū)間處理 (本周本月上周上月...),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08Python爬蟲數(shù)據(jù)的分類及json數(shù)據(jù)使用小結(jié)
這篇文章主要介紹了Python爬蟲數(shù)據(jù)的分類及json數(shù)據(jù)使用小結(jié),幫助大家更好的理解和學習使用python,感興趣的朋友可以了解下2021-03-03PyTorch之怎樣選擇合適的優(yōu)化器和損失函數(shù)
這篇文章主要介紹了PyTorch怎樣選擇合適的優(yōu)化器和損失函數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02