TensorFlow中的Linear Regression
線性回歸是機(jī)器學(xué)習(xí)中非常簡(jiǎn)單的問題色建,我們用tensorflow實(shí)現(xiàn)一個(gè)小例子。
問題: 希望能夠找到一個(gè)城市中縱火案和盜竊案之間的關(guān)系蜘澜,縱火案的數(shù)量是X,盜竊案的數(shù)量是Y响疚,我們建設(shè)存在如下線性關(guān)系鄙信,Y = wX + b。
TensorFlow實(shí)現(xiàn)
首先定義輸入X和目標(biāo)Y的占位符(placeholder)
X = tf.placeholder(tf.float32, shape=[], name='input')
Y = tf.placeholder(tf.float32, shape=[], name='label')
里面shape=[]
表示標(biāo)量(scalar)
然后定義需要更新和學(xué)習(xí)的參數(shù)w和b
w = tf.get_variable(
'weight', shape=[], initializer=tf.truncated_normal_initializer())
b = tf.get_variable('bias', shape=[], initializer=tf.zeros_initializer())
接著定義好模型的輸出以及誤差函數(shù)忿晕,這里使用均方誤差(Y - Y_predicted)^2
Y_predicted = w * X + b
loss = tf.square(Y - Y_predicted, name='loss')
然后定義好優(yōu)化函數(shù)扮碧,這里使用最簡(jiǎn)單的梯度下降,這里的學(xué)習(xí)率不僅可以是常量杏糙,還可以是一個(gè)tensor
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-3).minimize(loss)
tensorflow是如何判斷哪些參數(shù)該更新,哪些參數(shù)不更新呢蚓土?tf.Variabel(trainable=False)
就表示不對(duì)該參數(shù)進(jìn)行更新宏侍,默認(rèn)下tf.Variable(trainable=True)
。
然后在session中做運(yùn)算
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, h_loss], feed_dict={X: x, Y: y})
total_loss += l
print("Epoch {0}: {1}".format(i, total_loss / n_samples))
可視化
我們可以打開tensorboard查看我們的結(jié)構(gòu)圖如下
最后我們將數(shù)據(jù)點(diǎn)和預(yù)測(cè)的直線畫出來
如何改善模型
我們可以增加維度蜀漆,原始模型是Y = Xw + b谅河,我們可以提升一維,使其變成Y = X^2 w1 + X w2 + b
可以換一種loss的計(jì)算方式确丢,比如huber loss绷耍,當(dāng)誤差比較小的時(shí)候使用均方誤差,誤差比較大的時(shí)候使用絕對(duì)值誤差
在實(shí)現(xiàn)huber loss的時(shí)候鲜侥,因?yàn)閠f是以圖的形式來定義褂始,所以不能使用邏輯語句,比如if等描函,我們可以使用TensorFlow中的條件判斷語句崎苗,比如tf.where
狐粱、tf.case
等等,huber loss的實(shí)現(xiàn)方法如下
def huber_loss(labels, predictions, delta=1.0):
residual = tf.abs(predictions - 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)
關(guān)于Optimizer
TensorFlow會(huì)自動(dòng)求導(dǎo)胆数,然后更新參數(shù)肌蜻,使用一行代碼tf.train.GradientDescentOptimizer(learning_rate=1e-3).minimize(loss)
,下面我們將其細(xì)分開來必尼,講一講每一步蒋搜。
自動(dòng)梯度
首先優(yōu)化函數(shù)的定義就是前面一部分opt = tf.train.GradientDescentOptimizer(learning_rate)
,定義好優(yōu)化函數(shù)之后判莉,可以通過grads_and_vars = opt.compute_gradients(loss, <list of variables>)
來計(jì)算loss對(duì)于一個(gè)變量列表里面每一個(gè)變量的梯度豆挽,得到的grads_and_vars
是一個(gè)list of tuples,list中的每個(gè)tuple都是由(gradient, variable)構(gòu)成的骂租,我們可以通過get_grads_and_vars = [(gv[0], gv[1]) for gv in grads_and_vars]
將其分別取出來祷杈,然后通過opt.apply_gradients(get_grads_and_vars)
來更新里面的參數(shù),下面我們舉一個(gè)小例子渗饮。
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()
# initialize variable
sess.run(tf.global_variables_initializer())
# define optimizer
optimizer = tf.train.GradientDescentOptimizer(0.1)
# compute gradient z w.r.t x and y
grads_and_vars = optimizer.compute_gradients(z, [x, y])
# fetch the variable
get_grads_and_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_and_vars[0][0]), sess.run(get_grads_and_vars[0][1])))
print('y: grad {}, value {}'.format(
sess.run(get_grads_and_vars[1][0]), sess.run(get_grads_and_vars[1][1])))
print('Before optimization')
print('x: {}, y: {}'.format(sess.run(x), sess.run(y)))
# optimize parameters
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()
上面程序的注釋已經(jīng)解釋了所有的內(nèi)容但汞,就不細(xì)講了,最后可以得到下面的結(jié)果互站。
在實(shí)際中私蕾,我們當(dāng)然不用手動(dòng)更新參數(shù),optimizer類可以幫我們自動(dòng)更新胡桃,另外還有一個(gè)函數(shù)也能夠計(jì)算梯度踩叭。
tf.gradients(ys, xs, grad_ys=None, name='gradients', colocate_gradients_with_ops=False, gate_gradients=False,
aggregation_method=None)
這個(gè)函數(shù)會(huì)返回list,list的長(zhǎng)度就是xs的長(zhǎng)度翠胰,list中每個(gè)元素都是$sum_{ys}(dys/dx)$容贝。
實(shí)際運(yùn)用: 這個(gè)方法對(duì)于只訓(xùn)練部分網(wǎng)絡(luò)非常有用,我們能夠使用上面的函數(shù)只對(duì)網(wǎng)絡(luò)中一部分參數(shù)求梯度之景,然后對(duì)他們進(jìn)行梯度的更新斤富。
優(yōu)化函數(shù)類型
隨機(jī)梯度下降(GradientDescentOptimizer)僅僅只是tensorflow中一個(gè)小的更新方法,下面是tensorflow目前支持的更新方法的總結(jié)
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
這個(gè)博客對(duì)上面的方法都做了介紹锻狗,感興趣的同學(xué)可以去看看满力,另外cs231n和coursera的神經(jīng)網(wǎng)絡(luò)課程也對(duì)各種優(yōu)化算法做了介紹。
TensorFlow 中的Logistic Regression
我們使用簡(jiǎn)單的logistic regression來解決分類問題轻纪,使用MNIST手寫字體油额,我們的模型公式如下
$$
logits = X * w + b
$$
$$
Y_{predicted} = softmax(logits)
$$
$$
loss = CrossEntropy(Y, Y_{predicted})
$$
TensorFlow實(shí)現(xiàn)
TF Learn中內(nèi)置了一個(gè)腳本可以讀取MNIST數(shù)據(jù)集
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('./data/mnist', one_hot=True)
接著定義占位符(placeholder)和權(quán)重參數(shù)
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())
輸入數(shù)據(jù)的shape=[None, 784]
表示第一維接受任何長(zhǎng)度的輸入,第二維等于784是因?yàn)?8x28=784刻帚。權(quán)重w使用均值為0,方差為1的正態(tài)分布潦嘶,偏置b初始化為0。
然后定義預(yù)測(cè)結(jié)果我擂、loss和優(yōu)化函數(shù)
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函數(shù)交叉熵缓艳,最后將一個(gè)batch中的loss求均值,對(duì)其使用隨機(jī)梯度下降法看峻。
因?yàn)閿?shù)據(jù)集中有測(cè)試集阶淘,所以可以在測(cè)試集上驗(yàn)證其準(zhǔn)確率
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)
首先對(duì)輸出結(jié)果進(jìn)行softmax得到概率分布,然后使用tf.argmax
得到預(yù)測(cè)的label互妓,使用tf.equal
得到預(yù)測(cè)的label和實(shí)際的label相同的個(gè)數(shù)溪窒,這是一個(gè)長(zhǎng)為batch的0-1向量,然后使用tf.reduce_sum
得到正確的總數(shù)冯勉。
最后在session中運(yùn)算澈蚌,這個(gè)過程就不再贅述。
結(jié)果與可視化
最后可以得到訓(xùn)練集的loss的驗(yàn)證集準(zhǔn)確率如下
可以發(fā)現(xiàn)經(jīng)過10 epochs灼狰,驗(yàn)證集能夠?qū)崿F(xiàn)74%的準(zhǔn)確率宛瞄。同時(shí),我們還能夠得到tensorboard可視化如下交胚。
這看著是有點(diǎn)混亂的份汗,所以下一次課會(huì)講一下如何結(jié)構(gòu)化我們的模型。
本文的全部代碼都在github
歡迎訪問我的博客
歡迎查看我的知乎專欄蝴簇,深度煉丹