1. 程式人生 > >【TensorFlow】TensorFlow 的線性迴歸

【TensorFlow】TensorFlow 的線性迴歸

前面 有篇博文 講了講Ubuntu環境下安裝TensorFlow,今天來說一說在TensorFlow中如何進行線性迴歸。

訓練資料

本次使用的訓練資料是美國房價資料,做了一些預處理,完整資料可從這裡下載,原始資料共有1460行81列,其中我選用了LotArea(房屋面積)和SalePrice(售價)兩個變數來分別作為自變數和因變數,處理後樣本個數為1140個,也就是說全部訓練資料是一個1140*2的矩陣,部分資料如下所示:
訓練部分資料
訓練部分資料

模型

本次使用的是線性迴歸模型

y=Wx+b 其中W為權重,b為偏置。
具體地,x 即為LotArea,y 即為SalePrice。

開始訓練

使用TensorFlow訓練模型大致是這樣的步驟:

1. 設定各種超引數,例如學習率,迭代次數等;
2. 定義變數和模型;
3. 初始化變數;
4. 正式開始訓練.

廢話不多說上完整程式碼,程式碼裡有註釋:

from __future__ import print_function, division
import tensorflow as tf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn
# 我是在Jupyter Notebook裡執行的,所以需要這行
%matplotlib inline # 讀入資料 train = pd.read_csv("Dataset/train.csv") # 選取房屋面積小於12000的資料 train = train[train['LotArea'] < 12000] train_X = train['LotArea'].values.reshape(-1, 1) train_Y = train['SalePrice'].values.reshape(-1, 1) n_samples = train_X.shape[0] # 學習率 learning_rate = 2 # 迭代次數 training_epochs = 1000
# 每多少次輸出一次迭代結果 display_step = 50 # 這個X和Y和上面的train_X,train_Y是不一樣的,這裡只是個佔位符, # 訓練開始的時候需要“喂”(feed)資料給它 X = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) # 定義模型引數 W = tf.Variable(np.random.randn(), name="weight", dtype=tf.float32) b = tf.Variable(np.random.randn(), name="bias", dtype=tf.float32) # 定義模型 pred = tf.add(tf.mul(W, X), b) # 定義損失函式 cost = tf.reduce_sum(tf.pow(pred-Y, 2)) / (2 * n_samples) # 使用Adam演算法,至於為什麼不使用一般的梯度下降演算法,一會說 optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost) # 初始化所有變數 init = tf.initialize_all_variables() # 訓練開始 with tf.Session() as sess: sess.run(init) for epoch in range(training_epochs): for (x, y) in zip(train_X, train_Y): sess.run(optimizer, feed_dict={X: x, Y: y}) if (epoch + 1) % display_step == 0: c = sess.run(cost, feed_dict={X: train_X, Y: train_Y}) print("Epoch:", '%04d' % (epoch + 1), "cost=", "{:.3f}".format(c), "W=", sess.run(W), "b=", sess.run(b)) print("Optimization Finished!") training_cost = sess.run(cost, feed_dict={X: train_X, Y: train_Y}) print("Training cost=", training_cost, "W=", sess.run(W), "b=", sess.run(b), '\n') # 畫圖 plt.plot(train_X, train_Y, 'ro', label="Original data") plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label="Fitted line") plt.legend() plt.show()

結果如下,

Epoch: 0050 cost= 2283274240.000 W= 20.3469 b= 12945.2
Epoch: 0100 cost= 2196306176.000 W= 19.0349 b= 24402.2
Epoch: 0150 cost= 2128102656.000 W= 17.8766 b= 34479.1
Epoch: 0200 cost= 2074902912.000 W= 16.8604 b= 43292.1
Epoch: 0250 cost= 2033546240.000 W= 15.9735 b= 50965.1
Epoch: 0300 cost= 2001452160.000 W= 15.2026 b= 57622.0
Epoch: 0350 cost= 1976554496.000 W= 14.5348 b= 63380.2
Epoch: 0400 cost= 1957219584.000 W= 13.9577 b= 68350.4
Epoch: 0450 cost= 1942167424.000 W= 13.4598 b= 72634.2
Epoch: 0500 cost= 1930414208.000 W= 13.0309 b= 76322.2
Epoch: 0550 cost= 1921200000.000 W= 12.6619 b= 79494.2
Epoch: 0600 cost= 1913948928.000 W= 12.3445 b= 82220.2
Epoch: 0650 cost= 1908209664.000 W= 12.0717 b= 84562.8
Epoch: 0700 cost= 1903651840.000 W= 11.8377 b= 86572.4
Epoch: 0750 cost= 1900003456.000 W= 11.6364 b= 88299.7
Epoch: 0800 cost= 1897074944.000 W= 11.4638 b= 89781.0
Epoch: 0850 cost= 1894714880.000 W= 11.3161 b= 91048.3
Epoch: 0900 cost= 1892792320.000 W= 11.189 b= 92139.5
Epoch: 0950 cost= 1891217024.000 W= 11.0795 b= 93078.3
Epoch: 1000 cost= 1889932800.000 W= 10.9862 b= 93879.3
Optimization Finished!
Training cost= 1.88993e+09 W= 10.9862 b= 93879.3 

這裡寫圖片描述

幾個問題

  1. 在迭代次數相同的情況下,調節學習率能非常有效的改變損失的下降速度,剛開始學習率是0.001,結果非常的不好,損失比現在的大0.3e09左右,一步一步加大學習率效果顯著,即使現在的2也不算大(對於這個問題),但是對於其他問題,要具體情況具體分析,這個學習率或許太過激進;
  2. 至於優化演算法為什麼不選用更為常見的tf.train.GradientDescentOptimize,剛開始我也是用的這個演算法,結果發現 cost, W, b 都是nan,Not a Number,後來當我每一次迭代都輸出結果的時候,發現原來這幾個值異常迅速的增大,導致超出了表示範圍,如下,學習率為 0.001

    Epoch: 0001 W= 1541.27 b= -0.811313
    Epoch: 0001 W= -121530.0 b= -13.6312
    Epoch: 0001 W= 1.33729e+07 b= 1185.87
    Epoch: 0001 W= -1.05648e+09 b= -110841.0
    Epoch: 0001 W= 9.3181e+10 b= 9.23441e+06
    Epoch: 0001 W= -8.717e+12 b= -8.39367e+08
    Epoch: 0001 W= 2.77678e+14 b= 4.59572e+10
    Epoch: 0001 W= -1.31328e+16 b= -1.76138e+12
    Epoch: 0001 W= 1.43194e+18 b= 1.27263e+14
    Epoch: 0001 W= -1.7716e+20 b= -1.48503e+16
    Epoch: 0001 W= 1.74557e+22 b= 1.64051e+18
    Epoch: 0001 W= -1.80845e+24 b= -1.65567e+20
    Epoch: 0001 W= 5.76078e+25 b= 9.54297e+21
    Epoch: 0001 W= -6.32776e+27 b= -5.585e+23
    Epoch: 0001 W= 6.40024e+29 b= 5.93388e+25
    Epoch: 0001 W= -3.14474e+31 b= -4.18503e+27
    Epoch: 0001 W= 1.4992e+33 b= 2.01299e+29
    Epoch: 0001 W= -1.23312e+35 b= -1.26103e+31
    Epoch: 0001 W= inf b= inf
    Epoch: 0001 W= nan b= nan
    Epoch: 0001 W= nan b= nan

    其實就是正負跳的太厲害,而且貌似收斂不了。即使我減小學習率也是杯水車薪,後來試用了這個Adam(Adaptive Moment Estimation)演算法,結果沒有那個問題了,其實還有其他的演算法,我還沒有來得及一個一個試,如果想了解各種梯度下降演算法,可以參考這篇文章:An overview of gradient descent optimization algorithms

  3. 其實在這種簡單的模型上,我個人覺得使用 sklearn 效率更高點(當然 TensorFlow 的定製性比較強,更為底層),我用 sklearn 實現了一次,效果很好,基本就是傻瓜式操作,效果如圖,
    這裡寫圖片描述
    可以看到兩種方法得出的結果還是差不多的(當然TF更為繁瑣些)。另外在耗時上,sklearn 也要明顯快於 TF, sklearn 幾乎是秒出,TF 每次迭代大概需要 11 秒。

END

暫且就是這些,今天折騰了大半天,不容易啊,還是自己太嫩啦:)