參考博客:https://zhuanlan.zhihu.com/p/27853521
該代碼默認是梯度下降法,可自行從注釋中選擇其他訓練方法
在異或問題上,由於訓練的樣本數較少,神經網絡簡單,訓練結果最好的是GD梯度下降法。
1 # -*- coding:utf-8 -*- 2 3 # 將tensorflow 引入並命名tf 4 import tensorflow as tf 5 # 矩陣操作庫numpy,命名為np 6 import numpy as np 7 8 ''' 9 生成數據 10 用python使用tensorflow時,輸入到網絡中的訓練數據需要以np.array的類型 11 存在。並且要限制dtype為32bit以下。變量后跟着“.astype('float32')”總可以滿足要求 12 ''' 13 # X和Y是4個數據的矩陣,X[i]和Y[i]的值始終對應 14 X = [[0, 0], [0, 1], [1, 0], [1, 1]] 15 Y = [[0], [1], [1], [0]] 16 X = np.array(X).astype('int16') 17 Y = np.array(Y).astype('int16') 18 19 ''' 20 定義變量 21 ''' 22 # 網絡結構:2維輸入--> 2維隱含層 -->1維輸出 23 # 學習速率(learing rate):0.0001 24 25 D_input = 2 26 D_hidden = 2 27 D_label = 1 28 lr = 0.0001 29 ''' 30 容器 31 ''' 32 # x為列向量 可變樣本數*D_input; y為列向量 1*D_label 用GPU訓練需要float32以下精度 33 x = tf.placeholder(tf.float32, [None, D_input], name=None) 34 t = tf.placeholder(tf.float32, [None, D_label], name=None) 35 36 ''' 37 隱含層 38 ''' 39 # 初始化權重W [D_input ,D_hidden ] 40 # truncated_normal 正對數函數,返回隨機截短的正態分布,默認均值為0,區間為[-2.0,2.0] 41 W_h1 = tf.Variable(tf.truncated_normal([D_input, D_hidden], stddev=1.0), name="W_h") 42 # 初始化b D_hidden 一維 43 b_h1 = tf.Variable(tf.constant(0.1, shape=[D_hidden]), name="b_h") 44 # 計算Wx+b 可變樣本數*D_hidden 45 pre_act_h1 = tf.matmul(x, W_h1) + b_h1 46 # 計算a(Wx+b) a代表激活函數,有tf.nn.relu()、tf.nn.tanh()、tf.nn.sigmoid() 47 act_h1 = tf.nn.relu(pre_act_h1, name=None) 48 49 ''' 50 輸出層 51 ''' 52 W_o = tf.Variable(tf.truncated_normal([D_hidden, D_label], stddev=1.0), name="W_o") 53 b_o = tf.Variable(tf.constant(0.1, shape=[D_label]), name="b_o") 54 pre_act_o = tf.matmul(act_h1, W_o) + b_o 55 y = tf.nn.relu(pre_act_o, name=None) 56 57 ''' 58 損失函數和更新方法 59 ''' 60 loss = tf.reduce_mean((y - t)**2) 61 train_step = tf.train.AdamOptimizer(lr).minimize(loss) 62 ''' 63 訓練 64 sess = tf.InteractiveSession()是比較方便的創建方法。也有sess = 65 tf.Session()方式,但該方式無法使用tensor.eval()快速取值等功能 66 ''' 67 sess = tf.InteractiveSession() 68 # 初始化權重 69 # tf.tables_initializer(name="init_all_tables").run()調試時報錯,可能是版本問題
70 # Add the variable initializer Op. 71 init = tf.global_variables_initializer() 72 sess.run(init) 73 # 訓練網絡 74 ''' 75 GD(Gradient Descent):X和Y是4組不同的訓練數據。上面將所有數據輸入到網絡, 76 算出平均梯度來更新一次網絡的方法叫做GD。效率很低,也容易卡在局部極小值,但更新方向穩定 77 ''' 78 79 T = 100000 # 訓練次數 80 for i in range(T): 81 sess.run(train_step, feed_dict={x: X, t: Y}) 82 83 84 ''' 85 SGD(Gradient Descent):一次只輸入一個訓練數據到網絡,算出梯度來更新一次網絡的方法叫做SGD。 86 效率高,適合大規模學習任務,容易掙脫局部極小值(或鞍點),但更新方向不穩定。代碼如下 87 ''' 88 ''' 89 T = 100000 # 訓練幾epoch 90 for i in range(T): 91 for j in range(X.shape[0]): # X.shape[0]表示樣本個數 X.shape[0] 報錯 'Placeholder:0', which has shape '(?, 2) 92 sess.run(train_step, feed_dict={x: [X[j]], t: [Y[j]]}) 93 ''' 94 ''' 95 batch-GD:這是上面兩個方法的折中方式。每次計算部分數據的平均梯度來更新權重。 96 部分數據的數量大小叫做batch_size,對訓練效果有影響。一般10個以下的也叫mini-batch-GD。代碼如下: 97 ''' 98 ''' 99 T = 10000 # 訓練幾epoch 100 b_idx = 0 # batch計數 101 b_size = 2 # batch大小 102 for i in range(T): 103 while b_idx <= X.shape[0]: 104 sess.run(train_step, feed_dict={x: X[b_idx:b_idx+b_size], t: Y[b_idx:b_idx+b_size]}) 105 b_idx += b_size # 更新batch計數 106 ''' 107 108 109 ''' 110 shuffle:SGD和batch-GD由於只用到了部分數據。若數據都以相同順序進入網絡會使得隨后的epoch影響很小。 111 shuffle是用於打亂數據在矩陣中的排列順序,提高后續epoch的訓練效果。代碼如下: 112 ''' 113 ''' 114 # shuffle 115 def shufflelists(lists): # 多個序列以相同順序打亂 116 ri = np.random.permutation(len(lists[1])) 117 out = [] 118 for l in lists: 119 out.append(l[ri]) 120 return out 121 122 # 訓練網絡 123 T = 100000 # 訓練幾epoch 124 b_idx = 0 # batch計數 125 b_size = 2 # batch大小 126 for i in range(T): # 每次epoch都打亂順 127 X, Y = shufflelists([X, Y]) 128 while b_idx <= X.shape[0]: 129 sess.run(train_step, feed_dict={x: X[b_idx:b_idx + b_size], t: Y[b_idx:b_idx + b_size]}) 130 b_idx += b_size # 更新batch計數 131 ''' 132 # 預測數據 133 print(sess.run(y, feed_dict={x: X})) 134 print(sess.run(act_h1, feed_dict={x: X}))