這次來做一個小項目,算是tensorflow入門級別的實踐。手頭有一份北京全年氣溫的數據,現在通過訓練模型擬合出一條全年氣溫的曲線,可用於對北京某個日期下氣溫的預測。

數據獲取與加工

從kaggle下載了北京PM2.5的全年數據,數據表中包含了全年氣溫,數據文件是CSV格式,可以點擊這裡下載,下面是數據文件的格式與內容:

表格中每一行表示北京一年中某一天凌晨0點的數據,一共365條數據,每天一條,本篇中只會用到溫度數據。

下面是數據獲取的代碼部分:

# 引入tensorflow、numpy和matplotlib庫import tensorflow as tfimport numpy as npimport matplotlib.pyplot as plt# 獲取數據data = np.genfromtxt(/Users/Bruce/Desktop/PM25.csv, dtype=float, delimiter=,, skip_header=1)x_data = np.array([x[0] for x in data])[:, np.newaxis]y_data = np.array([y[13] for y in data])[:, np.newaxis]# 繪圖,繪出訓練數據fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.scatter(x_data, y_data)# plt.ion()plt.show()print(x_data)print("----------------------")print(y_data)

為簡單起見,x_data只獲取序號,y_data則表示每天的數據,需要注意的是,獲取數據後需要轉格式成np.array,並且轉換成 [n, 1] 矩陣。

通過matplotlib.pyplot庫將數據繪製出來,如下圖所示:

橫坐標是日期,縱坐標是溫度,在開始建模之前,還需要對數據做一些處理,因為x_data的範圍是1-365,這個範圍太大了,在機器學習過程中可能會遇到梯度爆炸,即無法擬合的情況,所以需要將x_data映射到0至1的範圍內,這一過程稱為歸一化,公式是這樣的:

下面將代碼做了修改:

# 引入tensorflow、numpy和matplotlib庫import tensorflow as tfimport numpy as npimport matplotlib.pyplot as plt# 獲取數據data = np.genfromtxt(/Users/Bruce/Desktop/PM25.csv, dtype=float, delimiter=,, skip_header=1)x_ = np.array([x[0] for x in data])[:, np.newaxis]# 數據歸一化amin, amax = x_.min(), x_.max() # 求最大最小值x_data = (x_ - amin)/(amax - amin)y_data = np.array([y[13] for y in data])[:, np.newaxis]# 繪圖,繪出訓練數據fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.scatter(x_data, y_data)# plt.ion()plt.show()print(x_data)print("----------------------")print(y_data)

模型結構

模型分為輸入層、隱藏層和輸出層。

輸入層就是現有的訓練數據,日期與氣溫,這是 [n, 1] 的矩陣結構。輸出層即通過機器學習或的預測值。在輸入層和輸出層之前還設計了1層隱藏層,隱藏層一共包含200個節點,大概的樣子是這樣的。

下面是代碼實現:

#輸入層xs = tf.placeholder(tf.float32, [None, 1]) #佔位符,None表示n*1維矩陣ys = tf.placeholder(tf.float32, [None, 1]) #佔位符,None表示n*1維矩陣#隱層(200個神經元)W1 = tf.Variable(tf.random_normal([1,200])) #權重,1*200的矩陣,並用符合正態分佈的隨機數填充b1 = tf.Variable(tf.zeros([1,200]) + 0.1) #偏置,1*200的矩陣,使用0.1填充Wx_plus_b1 = tf.matmul(xs,W1) + b1 #矩陣xs和W1相乘,然後加上偏置output1 = tf.nn.sigmoid(Wx_plus_b1) #激活函數使用tf.nn.sigmoid#輸出層W2 = tf.Variable(tf.random_normal([200,1])) #權重,200*1的矩陣,並用符合正態分佈的隨機數填充b2 = tf.Variable(tf.zeros([1])+0.1) # 偏置,使用0.1填充Wx_plus_b2 = tf.matmul(output1,W2) + b2output2 = Wx_plus_b2 # 輸出層不使用激活函數

輸入層使用了placeholder;

隱藏層定義了 [1, 200] 矩陣格式的權重和偏置,其中權重W1初始值是平均值0的正態分佈的隨機數,偏置b1初始化為0.1,隱藏層會計算 tf.matmul(xs,W1) + b1 的值,因為我們需要擬合的曲線不是線性曲線(即通過y=wx+b的函數無法表達出曲線樣式),所以需要在這裡加上激活函數以去線性。這裡使用了tf.nn.sigmoid激活函數(tensorflow還提供了其他激活函數),通過激活函數處理的值可能是任意形式的曲線,這樣有助於去擬合複雜的數據。

輸出層和隱藏層很類似,但是沒有加激活函數,另外輸出層的節點數量是1,實際會輸出一個一維矩陣。

損失函數與訓練演算法

通過隱藏層和輸出層的計算,會得到一個一維矩陣,矩陣中的元素是通過計算得出的每天對應的氣溫,這個計算值與訓練樣本中的氣溫值的差距就是損失,在計算損失時,使用了偏差平方求和,再取平均值的方式,如下:

#損失loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-output2),reduction_indices=[1])) #在第一維上,偏差平方後求和,再求平均值,來計算損失

機器學習的目的就是使損失降低,這裡使用了梯度下降的方式來降低損失,關於梯度下降演算法這裡不做說明,基本邏輯是通過計算損失,去修改模型中的權重和偏置的值(反向傳播),並計算新的損失,直至損失降低到可接受的範圍內,這樣就得到了模型的全部權重和偏置,即本篇中擬合曲線的實現公式。

train_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss) # 使用梯度下降法,設置步長0.005,來最小化損失

在設置梯度下降演算法時,需要人工設置學習率(步長),一般數值都比較小,如果發現無法擬合,可以調小學習率,如果擬合速度過慢,可以調大學習率。

完整代碼

下面是完整的實現代碼

# 引入tensorflow、numpy和matplotlib庫import tensorflow as tfimport numpy as npimport matplotlib.pyplot as plt# 獲取數據data = np.genfromtxt(/Users/Bruce/Desktop/PM25.csv, dtype=float, delimiter=,, skip_header=1)x_ = np.array([x[0] for x in data])[:, np.newaxis]# 數據歸一化amin, amax = x_.min(), x_.max() # 求最大最小值x_data = (x_ - amin)/(amax - amin)y_data = np.array([y[13] for y in data])[:, np.newaxis]# 繪圖,繪出訓練數據fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.scatter(x_data, y_data)plt.ion()plt.show()#輸入層xs = tf.placeholder(tf.float32, [None, 1]) #佔位符,None表示n*1維矩陣ys = tf.placeholder(tf.float32, [None, 1]) #佔位符,None表示n*1維矩陣#隱層(200個神經元)W1 = tf.Variable(tf.random_normal([1,200])) #權重,1*200的矩陣,並用符合正態分佈的隨機數填充b1 = tf.Variable(tf.zeros([1,200]) + 0.1) #偏置,1*200的矩陣,使用0.1填充Wx_plus_b1 = tf.matmul(xs,W1) + b1 #矩陣xs和W1相乘,然後加上偏置output1 = tf.nn.sigmoid(Wx_plus_b1) #激活函數使用tf.nn.sigmoid#輸出層W2 = tf.Variable(tf.random_normal([200,1])) #權重,200*1的矩陣,並用符合正態分佈的隨機數填充b2 = tf.Variable(tf.zeros([1])+0.1) # 偏置,使用0.1填充Wx_plus_b2 = tf.matmul(output1,W2) + b2output2 = Wx_plus_b2 # 輸出層不使用激活函數#損失loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-output2),reduction_indices=[1])) #在第一維上,偏差平方後求和,再求平均值,來計算損失train_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss) # 使用梯度下降法,設置步長0.005,來最小化損失#初始化init = tf.global_variables_initializer() #初始化所有變數sess = tf.Session()sess.run(init) #變數初始化#訓練for i in range(5001): #訓練10000次 _,loss_value = sess.run([train_step,loss],feed_dict={xs:x_data,ys:y_data}) #進行梯度下降運算,並計算每一步的損失 if(i%20==0): print("第%d步,loss_value = %f" % (i,loss_value)) # 每50步輸出一次損失 try: ax.lines.remove(lines[0]) # 在每一次繪圖之前先講上一次繪圖刪除 except Exception: pass lines = ax.plot(x_data, sess.run(output2, feed_dict={xs:x_data}), r-) plt.pause(0.1)sess.close()

訓練循環總共設置了5001步,每20步列印出當前的損失數值,並且繪製出擬合的曲線樣式,運行起來會看到動畫的擬合過程,比較直觀。

數字極客-學知識,做最酷的事!?

www.digeek.tech
圖標

推薦閱讀:
相关文章