神經網路從庫到架構(二)
來自專欄機器不學習1 人贊了文章
對於機器學習研究而言,這是最好的時代,也是最糟的時代。隨處可見那些胡亂地將文檔、論文和開源項目拼湊在一起就出版的圖書,也隨處可見那些只會clone gayhub的讀者。《烏合之眾》里有這樣一句話:群體中的個人是沙中之沙,風可以隨意攪動他們。作為一粒沙子,聚沙成塔才是我們的力量。希望本系列文章,能對真正願意入門神經網路的人有所幫助。
目錄
神經網路從庫到架構(一)從循環到矢量化
神經網路從庫到架構(二)計算圖和層
神經網路從庫到架構(三)模型的封裝
計算圖
計算圖通過圖的形式描述了計算的結構(即計算步驟),如同瀏覽器中的HTML代碼描述了頁面的DOM結構。定義好計算圖後,Tensorflow會調用 C++ 和 CUDA根據計算圖進行計算,如同瀏覽器中的JS代碼,將DOM結構Render在頁面上。將定義和計算分離,使得求導和反向傳播更為方便,也為GPU加速、分散式計算提供了可能。
變數
init_data = tf.random_normal([32, 32]) # 初始值var = tf.Variable(init_data) # 聲明變數節點init = tf.global_variables_initializer() # 初始化器節點with tf.Session() as sess: sess.run(init) # 運行初始化器,手動初始化
值得注意的是,變數作為數據流的起點,在訓練前必須手動初始化
常量
const = tf.constant([1, 2, 3, 4])
session
session是節點的運行器,下面的代碼運行了變數初始化器、優化求解器
with tf.Session() as sess: sess.run(init) sess.run(optimizer, feed_dict={x: x_vals})
session還是獲取節點結果的指針,下面的代碼運行了變數初始化器,獲得了變數節點的指針
init_data = tf.random_normal([4])var = tf.Variable(init_data)init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) sess.run(var)# array([ 1.6322708 , 0.8162201 , -0.95614713, 0.26919913], dtype=float32)
層
層在計算圖中的地位和函數在程序中的地位很像,它是對數學計算的一種封裝。Tensorflow封裝了用C++實現的卷積、歸一化、池化等操作。如果我們需要某種運算,而Tensorflow並未提供該種功能的層,那就只能自己用Tensorflow中的變數和常量加減乘除,封裝一下了。
例如,自定義實現softmax_cross_entropy_with_logits
:
output = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=expected)# 其實就是下面的封裝softmax = tf.nn.softmax(logits)output = -tf.reduce_sum(expected * tf.log(softmax))
全連接層
input = tf.random_normal([2, 20]) # 2個樣本,長度為20# array([[ 0.37190542, -0.08906209, 0.79456073, -1.524693 , 1.9822656 , 0.5696286 , -1.0686922 , -0.26792818, 1.7241213 , 0.02738742, 0.3193202 , 0.05315805, 1.3907676 , 0.37621617, -0.13928153, 0.06548243, 0.46920976, 0.6956967 , -1.2024548 , -0.8060812 ], [-1.5818218 , 0.03099131, 0.2808555 , -0.8627778 , -0.74100137, -1.208587 , -0.98276514, 0.633931 , -0.4962376 , 0.26105964, -0.10297604, 0.600884 , 0.20762599, 0.23266725, -0.891421 , 1.1547216 , 0.02443211, 0.20738238, 0.8341983 , -0.31083474]], dtype=float32)layer = tf.layers.dense(input, 20, activation=tf.nn.relu)sess.run(tf.global_variables_initializer())sess.run(layer)# array([[4.82327640e-02, 0.00000000e+00, 0.00000000e+00, 6.59807086e-01, 4.08874154e-01, 0.00000000e+00, 5.50900280e-01, 0.00000000e+00, 0.00000000e+00, 1.80825591e-05, 1.36644578e+00, 6.28557742e-01, 6.21535659e-01, 0.00000000e+00, 1.03333330e+00, 0.00000000e+00, 0.00000000e+00, 1.13170683e+00, 1.47637725e-02, 5.09270787e-01], [0.00000000e+00, 2.15164989e-01, 3.05164754e-01, 4.94074017e-01, 1.65222490e+00, 0.00000000e+00, 5.63413501e-01, 7.11654425e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 3.02060342e+00, 1.02120042e+00, 0.00000000e+00, 1.45242047e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.76542997e+00]], dtype=float32)
在Tensorflow中,全連接層是C++實現的,可以根據去全連接層的定義,練習全連接層的python實現:
def dense_layer(inputs, units, activation=None): Weights = tf.get_variable("weights",shape=[tf.rank(inputs), units], initializer=tf.truncated_normal_initializer(stddev=0.1)) biases = tf.get_variable("biases", shape=[1, units], initializer=tf.truncated_normal_initializer(stddev=0.1)) Wx_plus_b = tf.matmul(inputs, Weights) + biases if activation is None: outputs = Wx_plus_b else: outputs = activation(Wx_plus_b) return outputs
卷積層
sess = tf.InteractiveSession()image = tf.constant([ [1, 1, 1, 0, 0], [0, 1, 1, 1, 0], [0, 0, 1, 1, 1], [0, 0, 1, 1, 0], [0, 1, 1, 0, 0]], dtype=tf.float32)image = tf.reshape(image, [1, 5, 5, 1]) # 1個樣本,寬為5,高為5,通道數為1kernal = tf.constant([ [1, 0, 1], [0, 1, 0], [1, 0, 1]], dtype=tf.float32)kernal = tf.reshape(kernal, [3, 3, 1, 1]) # 寬為3, 高為3,通道數為1,卷積核個數為1layer = tf.nn.conv2d(image, kernal, [1, 1, 1, 1], "VALID") #調用 步長為1sess.run(layer)# array([[[[4.], [3.], [4.]], [[2.], [4.], [3.]], [[2.], [3.], [4.]]]], dtype=float32)
池化層
sess = tf.InteractiveSession()input = tf.constant([ [1, 2, 3], [4, 5, 6]])input = tf.reshape(input, [2, 3, 1]) # 2個樣本,長度為3,通道數為1max_pool = tf.layers.max_pooling1d(input, 3, 1) # 調用 步長為1sess.run(max_pool)# array([[[3]], [[6]]])
損失層
layer_result = tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])loss = tf.reduce_sum(layer_result )sess.run(loss)
優化求解器
Tensorflow中的優化求解器會根據計算圖,求得loss關於輸入數據的導數,在梯度更大的方向調整變數,以降低loss
import tensorflow as tfx = tf.Variable(tf.random_normal(shape=[1,1], mean=5, stddev=2)) # 變數y = x**2optimizer = tf.train.RMSPropOptimizer(0.001).minimize(y) # 優化求解器init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) for step in range(3000): _, val = sess.run([optimizer, y]) if step % 5 == 0: print("step: {}, value: {}".format(step, val[0][0]))
全連接層中的權值變數也這樣調整
import tensorflow as tfimport numpy as npx = tf.placeholder(shape=[None, 3], dtype=tf.float32)nn = tf.layers.dense(x, 3, activation=tf.nn.sigmoid)cost = tf.reduce_mean(nn - x)optimizer = tf.train.RMSPropOptimizer(0.01).minimize(cost)init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) x_vals = np.random.normal(0, 1, (10000, 3)) for step in range(10000): _, val = sess.run([optimizer, cost], feed_dict={x: x_vals}) if step % 5 == 0: print("step: {}, value: {}".format(step, val))
但是,要解決一個實際問題,我們還會在上面加很多很多層。當然可以就這樣直接面向過程編程,一路寫下去,但是代碼就會變成這樣
import tensorflow as tfimport numpy as npx = ...```這裡有1000行400行複製粘貼的400行稍微改了點參數200行完全不同```cost = ...optimizer = tf.train.RMSPropOptimizer(0.01).minimize(cost)init = tf.global_variables_initializer()with tf.Session() as sess: sess.run(init) x_vals = np.random.normal(0, 1, (10000, 3)) for step in range(10000): _, val = sess.run([optimizer, cost], feed_dict={x: x_vals}) if step % 5 == 0: print("step: {}, value: {}".format(step, val))
為了提高可讀性、便於修改,我們可以按照工廠模式,可以寫出Factory,根據參數生成各種各樣的複合層。下一部分我們將具體講解如何組織模型中的層結構。
TO BE CONTINUE
推薦閱讀:
※【翻譯】《利用Python進行數據分析·第2版》第5章(上)pandas入門
※[code]批量視頻/圖片 切圖做樣本
※基於C++的open cv 和 基於 Python 的open cv 分別能實現什麼功能?有什麼區別?
※0基礎自學Python學習路線圖(內含大綱+視頻+工具+教材+面試)
※獲取本機的上網IP