Tensorflow 搭建自己的神經網路(一)
神經網路的輸入只能是數值型:BP神經網路反向的誤差傳播過程中有求導運算的,必須是連續可導的函式才能進行此運算,所以輸入也必須是數值型的資料(向量或者矩陣)。
優化問題:梯度下降法;牛頓法;最小二乘法
Tensorflow中的資料型別基本都是float32
一.Tensorflow的簡單使用
一個簡單的例子:
import tensorflow as tf import numpy as np # 建立資料 x_data = np.random.rand(100).astype(np.float32) y_data = x_data*0.1 + 0.3 # 搭建模型 Weights = tf.Variable(tf.random_uniform([1], -1.0, 1.0)) biases = tf.Variable(tf.zeros([1])) y = Weights*x_data + biases # 計算誤差 loss = tf.reduce_mean(tf.square(y-y_data)) # 優化 學習率為0.5 optimizer = tf.train.GradientDescentOptimizer(0.5) train = optimizer.minimize(loss) # 初始化所有之前定義的Variable init = tf.global_variables_initializer() # 建立會話 Session sess = tf.Session() sess.run(init) for step in range(201): sess.run(train) if step % 20 == 0: print(step, sess.run(Weights), sess.run(biases)) sess.close()
Session的兩種開啟模式:
import tensorflow as tf # create two matrixes matrix1 = tf.constant([[3,3]]) matrix2 = tf.constant([[2], [2]]) product = tf.matmul(matrix1,matrix2) # 矩陣乘法,相當於numpy中的np.dot() # method 1 sess = tf.Session() result = sess.run(product) print(result) sess.close() # [[12]] # method 2 with tf.Session() as sess: result2 = sess.run(product) print(result2) # [[12]]
Variable 變數:
import tensorflow as tf # 定義變數 state = tf.Variable(0, name='counter') # 定義常量 one = tf.constant(1) # 定義加法步驟 (注: 此步並沒有直接計算) new_value = tf.add(state, one) # 將 state 更新成 new_value update = tf.assign(state, new_value) # 如果定義 Variable, 就一定要 initialize init = tf.global_variables_initializer() # 使用 Session with tf.Session() as sess: sess.run(init) for _ in range(3): sess.run(update) print(sess.run(state)) # 直接 print(state) 不起作用,一定要把 sess 的指標指向 state 再進行 print 才能得到想要的結果
如果在 Tensorflow 中設定了變數(Variable),那麼初始化變數是最重要的!!所以定義了變數以後, 一定要定義 init = tf.global_variables_initializer()
placeholder 傳入值:
placeholder
是 Tensorflow 中的佔位符,暫時儲存變數.Tensorflow 如果想要從外部傳入data, 那就需要用到 tf.placeholder()
, 然後以這種形式傳輸資料: sess.run(***, feed_dict={input: **})
.
import tensorflow as tf
#在 Tensorflow 中需要定義 placeholder 的 type ,一般為 float32 形式
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
# 將input1和input2 做乘法運算,並輸出為 output
ouput = tf.multiply(input1, input2)
# 傳值的工作交給了 sess.run() , placeholder 與 feed_dict={} 是繫結在一起出現的。
with tf.Session() as sess:
print(sess.run(ouput, feed_dict={input1: [7.], input2: [2.]}))
# [ 14.]
啟用函式(激勵函式):
層數較少時,選擇哪個啟用函式都可以;層數較多時,為避免梯度消失和梯度爆炸,需要慎重選擇啟用函式
在卷積神經網路的卷積層中,推薦使用relu;在迴圈神經網路中,推薦使用relu或tanh
激勵函式執行時啟用神經網路中某一部分神經元,將啟用資訊向後傳入下一層的神經系統。激勵函式的實質是非線性方程。 Tensorflow 的神經網路裡面處理較為複雜的問題時都需要運用激勵函式 activation function
二.搭建一個神經網路
新增層 def add_layer():
在 Tensorflow 裡定義一個新增層的函式可以很容易的新增神經層,為之後的新增省下不少時間.神經層裡常見的引數通常有weights
、biases
和激勵函式。
import tensorflow as tf
def add_layer(inputs, in_size, out_size, activation_function=None):
Weights = tf.Variable(tf.random_normal([in_size, out_size]))
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
# 在機器學習中,biases的推薦值不為0,所以這裡是在0向量的基礎上又加了0.1
Wx_plus_b = tf.matmul(inputs, Weights) + biases
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
搭建神經網路:
import numpy as np
# 構建所需的資料。這裡的x_data和y_data並不是嚴格的一元二次函式的關係,因為我們多加了一個noise,這樣看起來會更像真實情況。
x_data = np.linspace(-1,1,300, dtype=np.float32)[:, np.newaxis]
noise = np.random.normal(0, 0.05, x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise
# 利用佔位符定義我們所需的神經網路的輸入。tf.placeholder()就是代表佔位符,這裡的None代表無論輸入有多少都可以,因為輸入只有一個特徵,所以這裡是1。
xs = tf.placeholder(tf.float32, [None, 1])
ys = tf.placeholder(tf.float32, [None, 1])
# 開始定義神經層。通常神經層都包括輸入層、隱藏層和輸出層。這裡的輸入層只有一個屬性,所以我們就只有一個輸入;隱藏層我們可以自己假設,這裡我們假設隱藏層有10個神經元;輸出層和輸入層的結構是一樣的,所以我們的輸出層也是隻有一層。所以,我們構建的是——輸入層1個、隱藏層10個、輸出層1個的神經網路。
# 開始定義隱藏層,利用之前的add_layer()函式,這裡使用 Tensorflow 自帶的激勵函式tf.nn.relu。
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)
# 接著,定義輸出層。此時的輸入就是隱藏層的輸出——l1,輸入有10層(隱藏層的輸出層),輸出有1層。
prediction = add_layer(l1, 10, 1, activation_function=None)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
reduction_indices=[1])) # reduction_indices=[1]即axis=1
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
# 定義Session,並用 Session 來執行 init 初始化步驟(注意:在tensorflow中,只有session.run()才會執行我們定義的運算)
sess = tf.Session()
sess.run(init)
# 訓練
for i in range(1000):
sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
if i % 50 == 0:
print(sess.run(loss, feed_dict={xs: x_data, ys: y_data}))
# 如果誤差是在逐漸減小,則說明機器學習是有積極的效果的。
sess.close()
視覺化:
import matplotlib.pyplot as plt
# plot the real data
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.ion()# 用於連續顯示,否則只顯示初始的狀態
plt.show()
for i in range(1000):
# training
sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
if i % 50 == 0:
# to visualize the result and improvement
try:
ax.lines.remove(lines[0])
except Exception:
pass
prediction_value = sess.run(prediction, feed_dict={xs: x_data})
# plot the prediction
lines = ax.plot(x_data, prediction_value, 'r-', lw=5)
plt.pause(0.1)
# 每隔50次訓練重新整理一次圖形,用紅色、寬度為5的線來顯示我們的預測資料和輸入之間的關係,每次顯示暫停0.1s。
加速神經網路訓練:
- Stochastic Gradient Descent (SGD) 隨機梯度下降
- Momentum 動量法
- AdaGrad
- RMSProp
- Adam 最常用 比較好用
優化器:
Tensorflow
提供了7種優化器:
視覺化工具:Tensorboard
三.高階內容
分類問題(mnist手寫體數字識別):
相當於一個多分類問題,二分類使用邏輯迴歸(sigmoid函式作啟用函式),多分類使用邏輯迴歸的變種(softmax函式作啟用函式)
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
# 定義add_layer函式
def compute_accuracy(v_xs,v_ys):
global prediction
y_pre = sess.run(prediction,feed_dict={xs:v_xs})
correct_prediction = tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# tf.cast(x,dtype,name=None):將x的資料格式轉化為dtype
result = sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys})
return result
xs = tf.placeholder(tf.float32,[None,784]) # 28*28
ys = tf.placeholder(tf.float32,[None,10])
prediction = add_layer(xs,784,10,activation_function=tf.nn.softmax)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(
ys * tf.log(prediction),reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(1000):
# 開始train,每次只取100張圖片,免得資料太多訓練太慢
batch_xs,batch_ys = mnist.train.next_batch(100)
sess.run(train_step,feed_dict={xs:batch_xs,ys:batch_ys})
if i % 50 == 0:
print(compute_accuracy(mnist.test.images,mnist.test.labels))
sess.close()
dropout正則化:
有一種專門用在神經網路的正規化的方法, 叫作 dropout. 在訓練的時候, 我們隨機忽略掉一些神經元和神經聯結 , 使這個神經網路變得”不完整”. 用一個不完整的神經網路訓練一次.
到第二次再隨機忽略另一些, 變成另一個不完整的神經網路. 有了這些隨機 drop 掉的規則, 我們可以想象其實每次訓練的時候, 我們都讓每一次預測結果都不會依賴於其中某部分特定的神經元. 像l1, l2正規化一樣, 過度依賴的 W , 也就是訓練引數W的數值會很大, l1, l2會懲罰這些大的引數. Dropout 的做法是從根本上讓神經網路沒機會過度依賴.
keep_prob = tf.placeholder(tf.float32)
Wx_plus_b = tf.nn.dropout(Wx_plus_b, keep_prob)
...
...
sess.run(train_step, feed_dict={xs: X_train, ys: y_train, keep_prob: 0.5})
keep_prob
是保留概率,即我們要保留的結果所佔比例,它作為一個placeholder
,在run
時傳入, 當keep_prob=1
的時候,相當於100%保留,也就是dropout沒有起作用。