cs224n_Lecture7_TensorFlow框架及線性迴歸實現

Introduction to TensorFlow

深度學習框架簡介

爲什麼要用成熟的框架,而不是從頭寫一個:

  • 這些深度學習框架有助於擴展機器學習代碼
  • 可以自動計算梯度(Gradients)!(使得我們可以把重點放在高層次的數學上)
  • 標準化機器學習應用,方便共享交流
  • 多種算法、理念、抽象、編程語言等的融合
  • 提供GPU並行運算的接口

TF是什麼?

Tenorflow是谷歌開發的一個使用流式圖進行數值計算的開源軟件庫。

It’s just a deep learning framework, an open source software library for numerical computation using flow graphs from Google.

TF的工作原理和基本範例

  • 最核心的思想

    將數值計算表示爲圖的形式(express a numeric computation as a graph)

    • 圖的節點是某種運算,支持任意數量的輸入和輸出
    • 圖的邊是tensor(張量,n維數組),在節點之間流動
  • 擁有一個隱藏層的神經網絡的例子

    其在TensorFlow中的計算圖如下:

h=ReLU(Wx+b)h=ReLU(Wx+b)

  • 其中ReLU是一個表示修正線性單元的激活函數,我們在線性輸入上加入一些非線性函數,能夠賦予神經網絡一定的表達能力。ReLU表示在你的輸入和0之間取最大值,即max(input,0)。
  • xx只是一個placeholder(佔位符),只在執行的時候填充輸入,編程的時候指定大小即可。

構建運算圖

要描述這樣的graph flow,只需要編寫代碼:

import tensorflow as tf

# 定義一個變量b初始化爲0 大小爲100維; w是一個服從[-1,1]的均勻分佈
b = tf.Varable(tf.Zeros((100,))) 
w = tf.Varable(tf.random_uniform((784,100),-1,1))

# x是一個佔位符,並沒有被初始化爲任何值,編程時只需要指定它:僅接收32位浮點數的數據類型,接收一個(100,784)的shape
x = tf.placeholder(tf.float32,(100,784))

# actually build our flow graph
h = tf.nn.relu(tf.matmul(x,w) +b)

這段代碼只是構建了運算圖,連輸入都沒有,自然無法馬上獲取h的值。上述代碼並沒有顯式地聲明節點和邊,TensorFlow根據數學表達式自動構造了運算圖。

如何得到輸出(Getting output)

到目前爲止,我們只定義了一張圖,如何執行它呢?我們可以通過session將這張圖部署到某個執行環境(CPU、GPU、Google的TensorProcessingUnit……)上去。session就是支持圖中所有操作的執行的硬件環境。

sess.run(fetches,feeds)

  • 建立一個會話對象(session object)

  • 調用兩個參數fetches和feeds

    • fetches:圖結點列表,返回這些結點的輸出結果
    • feeds:將圖結點映射至具體值的字典(Dictionary)
    # 創建一個會話對象
    sess = tf.Session()
    # sess.run 初始化所有變量
    sess.run(tf.initialize_all_variables())
    sess.run(h,{x: np.random.random(100,784)})
    

如何訓練模型

  1. 對於優化過程而言,如何定義損失?

    # prediction是在網絡結束時的預測值,是對神經網絡頂層進行softmax函數計算,輸出一個概率向量,這是一個迴歸過程
    prediction = tf.nn.softmax(...)
    # label是我們真實標記的佔位符,我們的模型根據它來訓練
    label = tf.placeholder(tf.float32,[100,10])
    
    # 創建交叉熵結點
    cross_entropy = -tf.reduce_sum(label * tf.log(prediction), axis=1)
    
  2. 如何計算梯度

    # 創建一個優化器
    train_step = tf.teain.GradientDescentOptimizer(0.5).minimize(cross_entropy)
    

    Tensorflow中有一個通用的抽象類叫優化器(optimizer),在這個類中的每一個子類都是針對特定學習算法的優化器。

    train_step這一步驟實際上在模型上對所有的變量進行梯度的計算,因爲.minimize函數在這裏做了兩件事:

    • 第一件是計算參數的梯度,本案例中參數爲交叉熵,它和我們圖中定義的所有變量相關。然後它會對這些變量根據梯度進行更新。
      • Q:我們是如何計算梯度的呢?
      • A:TensorFlow的工作方式是:每一個圖節點都有一個附加的梯度操作,都有相對於輸入預先構建的輸出梯度。因此,當我們在計算交叉熵相對於所有參數的梯度時,通過圖使用鏈式法則利用反向傳播計算是非常簡單的。

創建一個迭代的學習計劃(Building training schedule)

# 建立一個字典,將值傳給我們之前定義好的兩個佔位符,x和label是圖中的結點,即字典中的關鍵字是圖中的結點,對應的項是Numpy數據
for i in range(1000):
    batch_x, batch_label = data.next_batch()
    sess.run(train_step,feed_dict={x: batch_x,
                                label: batch_label })

變量共享

Q:有時候我們想要生成一張圖的多個實例,或者在多機多個GPU上訓練同一個模型,就會帶來同一個變量在不同位置出現。如何在不同位置共享同一個變量呢?

A:

  • 一種樸素的想法是:

    在代碼頂端創建這個變量的字典。把一些字符串的字典放到它們所代表的變量中。

variable_dict = {
    "weights":tf.Variable(tf.random_normal([782,100])),
    "biases":tf.Variable(tf.zeros([100]),name="biases")
}

這種做法的缺點在於:破壞了封裝性!(No good for encapsulation!)

  • 更成熟一些的做法:

    • Variable_scope()提供了一個簡單的命名空間方案來避免衝突

    • Get_variable() 如果一個具備特定名字的向量不存在的話,該函數會爲你創建一個變量

      ​ 否則,如果發現它存在,將訪問該變量

總結

TF的用法總結如下:

  1. 創建圖
    a 前向傳播/預測
    b 優化操作
  2. 初始化session
  3. 在session中執行

從線性迴歸來熟悉TensorFlow

現場vim敲代碼環節[撒花🎉]

首先初始程序框架如下,我們需要完成linear_regression()函數來擬合我們的數據分佈

# linear regression
# Author: Nishith Khandwala ([email protected])
# Adapted from https://github.com/hans/ipython-notebooks/

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('TKAgg')
from matplotlib import pyplot as plt

'''
Good ole linear regression: find the best linear fit to our data
'''

def generate_dataset():
    # data is generated by y = 2x + e
    # where 'e' is sampled from a normal distribution
    x_batch = np.linspace(-1, 1, 101)
    y_batch = 2 * x_batch + np.random.randn(*x_batch.shape) * 0.3
    return x_batch, y_batch
    
def linear_regression():
    return NotImplementedError

def run():
    pass
    x_batch, y_batch = generate_dataset()

    plt.figure(1)
    plt.scatter(x_batch, y_batch)
    plt.plot(x_batch, y_pred_batch)
    plt.savefig('plot.png')
        
if __name__ == '__main__':
    run()

小哥幾乎是敲一句解釋一句,把之前對tensorflow編程流程的講解很好地融入了進來,代碼的完成版如下:

# linear regression
# Author: Nishith Khandwala ([email protected])
# Adapted from https://github.com/hans/ipython-notebooks/

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('TKAgg')
from matplotlib import pyplot as plt

'''
Good ole linear regression: find the best linear fit to our data
'''

def generate_dataset():
    # data is generated by y = 2x + e
    # where epsilon 'e' is sampled from a normal distribution :e是從正態分佈採樣得到的
    x_batch = np.linspace(-1, 1, 101)
    y_batch = 2 * x_batch + np.random.randn(*x_batch.shape) * 0.3
    return x_batch, y_batch

# 我們將用圖來實現線性迴歸    
def linear_regression():
    # 首先定義流式圖 flow graph -> 第一步創建佔位符
    # 我們創建x類型爲浮點數,希望形狀更通用,設置shape爲(None),意味着你可以動態改變每一批次數據的數量,然後把它們送進網絡中
    
    x = tf.placeholder(tf.float32, shape=(None,), name="x")
    y = tf.placeholder(tf.float32, shape=(None,), name="y")

    # 定義變量作用域
    with tf.variable_scope("lreg") as scope:
        w = tf.Variable(np.random.normal(),name="w")
        y_pred = tf.multiply(w,x)

        loss = tf.reduce_mean(tf.square(y_pred - y))    
    return x, y, y_pred, loss

def run():
    x_batch, y_batch = generate_dataset()

    x,y,y_pred, loss=linear_regression()
    #優化器 定義學習率爲0.1,最小化模型的損失
    optimizer = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

    init = tf.global_variables_initializer()
    with tf.Session() as session:
        session.run(init)

        feed_dict = {x: x_batch,y: y_batch}
        for _ in range(30):
            loss_val, _= session.run([loss,optimizer], feed_dict)
            print('loss_val:',loss_val.mean())

        y_pred_batch = session.run(y_pred,{x: x_batch})

    plt.figure(1)
    plt.scatter(x_batch, y_batch)
    plt.plot(x_batch, y_pred_batch)
    plt.savefig('plot.png')
    plt.show()
    
if __name__ == '__main__':
    run()

實驗運行結果:

在terminal打印loss值:

loss_val: 0.6620599
loss_val: 0.587803
loss_val: 0.5233017

loss_val: 0.10778806
loss_val: 0.10634918

繪製出圖形如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章