1. 程式人生 > >CS20SI-tensorflow for research筆記: Lecture3

CS20SI-tensorflow for research筆記: Lecture3

cas spa total times input HERE 全部 nis 發現

本文整理自知乎專欄深度煉丹,轉載請征求原作者同意。
CS20SI是Stanford大學開設的基於Tensorflow的深度學習研究課程。

TensorFlow中的Linear Regression

我們用tensorflow實現一個線性回歸的例子。
問題:希望找到城市中縱火案和盜竊案之間的關系,縱火案的數量是\(X\),盜竊案的數量是\(Y\),我們假設存在如下線性關系:\(Y=wX+b\)

TensorFlow實現

  1. 首先定義輸入\(X\)和目標\(Y\)的占位符(placeholder)

    X = tf.placeholder(tf.float32, shape=[], name=‘input‘
    ) Y = tf.placeholder(tf.float32, shape=[], name=‘label‘)

    裏面shape=[]表示標量(scalar)

  2. 定義需要更新和學習的參數\(w\)\(b\)

    w = tf.get_variable(‘weight‘, shape=[], initializer=tf.truncated_normal_initializer())
    b = tf.get_variable(‘bias‘, shape=[], initializer=tf.zeros_initializer())
  3. 定義模型的輸出和誤差函數,這裏使用均方誤差\((Y-Y\_predicted)^2\)

    Y_predicted = w * X + b
    loss = tf.squre(Y - Y_predicted, name=‘loss‘)
  4. 定義優化函數,這裏使用簡單梯度下降,這裏的學習率可以是常量和tensor

    optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-3).minimizer(loss)

    tensorflow如何判斷哪些參數更新,哪些不更新呢?tf.Variable(trainable=False)表示不對該參數更新,默認為True

  5. session中做運算

    init = tf.global_variables_initializer()
    with
    tf.Session() as sess: writer = tf.summary.FileWriter(‘./linear_log‘, graph=sess.graph) sess.run(init) for i in range(100): total_loss=0 for x, y in data: _, l = sess.run([optimizer, loss], feed_dict={X:x, Y:y}) total_loss+=1 print(‘Epoch {0}: {1}.format(i, total_loss/n_samples))

可視化

打開tensorboard查看我們的結構圖
技術分享圖片
最後將數據點和預測直線畫出來:
技術分享圖片

如何改善模型

  1. 增加維度,原始模型是\(Y=wX+b\),我們可以提升一維,使其變成\(Y=w_1X^2+w_2X+b\)
  2. 換一種計算loss的方法,比如huber loss,當誤差小的時候用均方誤差,誤差大的時候使用絕對值誤差
    \[L_\delta(y,f(x))=\left\{\begin{array}{ll}\frac{1}{2}(y-f(x))^2&\textrm{for}|y-f(x)|\leq\delta \\ \delta|y-f(x)|-\frac{1}{2}\delta^2&\textrm{otherwise}\end{array} \right. \]
    在實現huber loss的時候,因為tf是以圖的形式來定義,所以不能使用邏輯語句,比如if等,我們可以使用TensorFlow中的條件判斷語句,比如tf.wheretf.case等等,huber loss的實現方法如下:

    def huber_loss(labels, predictions, delta=1.0):
        residual = tf.abs(prediction - labels)
        condition = tf.less(residual, delta)
        small_res = 0.5 * residual**2;
        large_res = delta * residual - 0.5 * delta**2
    return tf.where(condition, small_res, large_res)

關於Optimizer

TensorFlow會自動求導,然後更新參數,使用一行代碼:

tf.train.GradientDescentOptimizer(learning_rate=1e-3).minimize(loss)

這裏的過程我們分開來細講。

自動梯度

  1. 首先是我們定義好優化函數:

    opt = tf.train.GradientDescentOptimizer(learning_rate)
  2. 定義好優化函數後,可以通過如下步驟計算梯度:

    grads_and_vars=opt.compute_gradients(loss, <list of variables>)

    第二個參數是一個list,該函數會計算loss對於變量列表裏的每一個變量的梯度。得到的grads_and_vars是一個list of tuple,list中的每個tuple都是由(gradient, variable)對構成,我們可以通過使用如下代碼提取出來:

    get_grads_and_vars=[(gv[0],gv[1]) for gv in grads_and_vars]
  3. 更新參數

    opt.apply_gradients(get_grads_and_vars)

舉個例子:

import tensorflow as tf

x = tf.Variable(5, dtype=tf.float32)
y = tf.Variable(3, dtype=tf.float32)

z = x**2 + x * y + 3

sess = tf.Session()
# 初始化變量
sess.run(tf.global_variable_initialize())

# 定義優化函數
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1)

# 計算z關於x,y的梯度
grads_and_vars = optimizer.compute_gradients(z, [x, y])

# 獲取變量
get_grads_vars = [(gv[0], gv[1]) for gv in grads_and_vars]

# dz/dx = 2*x + y = 13
# dz/dy = x = 5
print(‘grads and variables‘)
print(‘x: grad {}, value {}‘.format(sess.run(get_grads_vars[0][0]), sess.run(get_grads_and_vars[0][1])))

print(‘y: grad {}, value {}‘.format(sess.run(get_grads_vars[1][0]), sess.run(get_grads_and_vars[1][1])))

print(‘Before optimization‘)
print(‘x: {}, y:{}‘.format(sess.run(x), sess.run(y)))

# 優化參數
opt.optimizer.apply_gradients(get_grads_and_vars)
# x = x-0.1*dz/dx = 5-0.1*13=3.7
# y = y-0.1*dz/dy = 3-0.1*5 = 2.5
print(‘After optimization using learning rate 0.1‘)
sess.run(opt)
print(‘x: {:.3f}, y: {:.3f}‘.format(sess.run(x), sess.run(y)))
sess.close()

可得到結果:
技術分享圖片
在實際操作中,不需要手動更新參數,optimizer類可以幫我們自動更新。另外還有一個函數也能夠計算梯度。

tf.gradients(ys, xs, grad_ys=None, name=‘gradients‘, colocate_gradients_with_ops=False,gate_gradients=False, aggregation_method=None)

該函數返回一個list,list的長度就是xs的長度,list中每個元素都是\(sum_{ys}(d(ys)/dx)\)
實際運用: 這個方法對於只訓練部分網絡非常有用,我們能夠使用上面的函數只對網絡中一部分參數求梯度,然後對他們進行梯度的更新。

優化函數類型

SGD只是TF的一個小的更新方法,目前支持的更新方法如下:

tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer

TensorFlow中的Logistic Regression

我們使用簡單的logistic regression來解決分類問題,使用MNIST手寫字體,模型公式如下:
\[\begin{array}{rl}logits &= X*w+b \\Y_{predicted} &={\bf softmax}(logits)\loss &= {\bf CrossEntropy}(Y, Y_{predicted})\end{array}\]

TensorFlow實現

  1. 讀取MNIST數據集

    from tensorflow.examples.tutorials.mnist import input_data
    mnist = input_data.read_data_sets(‘./data/mnist‘, one_hot = True)
  2. 定義占位符和權重參數

    x = tf.placeholder(tf.float32, shape=[None, 784], name=‘image‘)
    y = tf.placeholder(tf.int32, shape=[None, 10], name=‘label‘)
    
    w = tf.get_variable(‘weight‘, shape=[784,10], initializer=tf.truncated_normal_initializer())
    b = tf.get_variable(‘bias‘, shape=[10], initializer=tf.zeros_initializer())

    輸入數據的shape=[None, 784]表示第一維接受任何長度的輸入,第二維等於784因為\(28\times 28=784\)。權重w使用均值為0,方差為1的正太分布,偏置b初始化為0.

  3. 定義預測結果、loss和優化函數

    logits = tf.matmul(x, w)+b
    entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=logits)
    loss = tf.reduce_mean(entropy, axis=0)
    optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)

    使用tf.matmul做矩陣乘法,然後使用分類問題的loss函數交叉熵,最後將一個batch中的loss求均值,對其使用隨機梯度下降法。

  4. 數據集中有測試集,可以在測試集上驗證準確率

    preds = tf.nn.softmax(logits)
    correct_preds = tf.equal(tf.argmax(preds, 1), tf.argmax(y, 1))
    accuracy = tf.reduce_sum(tf.cast(correct_preds, tf.float32), axis=0)

    首先對輸出結果進行softmax得到概率分布,然後使用tf.argmax得到預測的label,使用tf.equal得到label和實際的label相同的個數,這是一個長為batch的0-1向量,然後使用tf.reduce_sum得到正確的總數。

  5. 在session中運算

結果可視化

最後可以得到訓練集的loss的驗證集準確率如下
技術分享圖片
可以發現經過10 epochs,驗證集能夠實現74%的準確率。同時,我們還能夠得到tensorboard可視化如下。
技術分享圖片
本文的全部代碼都在原作者GitHub倉庫github

CS20SI-tensorflow for research筆記: Lecture3