慕課:《深度學習應用開發-TensorFlow實踐》
章節:第六講 多元線性回歸:波士頓房價預測問題TesnsorFlow實戰
TensorFlow版本為2.3
問題介紹
波士頓房價數據集包括506個樣本,每個樣本包括12個特征變量和該地區的平均房價房價(單價),顯然和多個特征變量相關,不是單變量線性回歸(一元線性回歸)問題。選擇多個特征變量來建立線性方程,這就是多變量線性回歸(多元線性回歸)問題
數據集介紹
數據集放在下面鏈接了,也可以去慕課上下
鏈接:https://pan.baidu.com/s/1CYTQSYUNi4U04i26wLYR9w
提取碼:ymfa
簡單看一下數據集
各個參數的含義
- CRIM: 城鎮人均犯罪率
- ZN:住宅用地超過 25000 sq.ft. 的比例
- INDUS: 城鎮非零售商用土地的比例
- CHAS: 邊界是河流為1,否則0
- NOX: 一氧化氮濃度
- RM: 住宅平均房間數
- AGE: 1940年之前建成的自用房屋比例
- DIS:到波士頓5個中心區域的加權距離
- RAD: 輻射性公路的靠近指數
- TAX: 每10000美元的全值財產稅率
- PTRATIO: 城鎮師生比例
- LSTAT: 人口中地位低下者的比例
- MEDV: 自住房的平均房價,單位:千美元
接下來,代碼走起來!!
數據處理
數據讀取
首先,下載數據集,然后把csv文件和你的python文件放在同一個目錄下,下面的代碼里,一些顯而易見的注釋就不寫了哈
第一步還是常規的導入包
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import pandas as pd
from sklearn.utils import shuffle
from sklearn.preprocessing import scale#導入sklearn的相關包
print(tf.__version__)
這里用到了兩個新的庫:pandas
和sklearn
,所以呢,如果出現了下面這些報錯
不要慌,pandas
沒裝,打開終端,進入環境,下面代碼跑一跑
pip install pandas
10.2MB,可能還有一丟丟的慢,怎么辦?換個源,走起
pip install pandas -i https://pypi.doubanio.com/simple/
接着幾秒之后就好了。
順帶的,動動手指把sklearn
也裝了,自己看網絡,下面倆選一個
pip install sklearn
或者
pip install sklearn -i https://pypi.doubanio.com/simple/
裝完回來,就發現它好了
接下來,數據集保存在CSV文件中,所以我們這里用pandas
庫去讀取相應的數據,至於pandas
,這里就不介紹了,自行百度教程吧,用到的也不多,其實就一兩個方法
df = pd.read_csv("boston.csv",header=0)
它讀入的是pandas.core.frame.DataFrame
類型,但是我們后面要處理他,所以要把它轉換成我們所需要的np.array
類型才可以,我們可以獲取它對應的values
值來實現我們要的效果,順帶看一下規格
df=df.values#返回np.array
df.shape
輸出
(506, 13)
分離特征和標簽
在數據集里面,前十二列是特征值,最后一列是標簽,我們需要把它們分隔開來
x_data=df[:,:12]
y_data=df[:,12]
print(f"x_data shape:{x_data.shape},y_data shape:{y_data.shape}")
輸出
x_data shape:(506, 12),y_data shape:(506,)
歸一化操作,在上面那一段代碼后面加一個
for
循環,如果不做這一步,后果會在后面的訓練部分講到
for i in range(12):
x_data[:,i]=(x_data[:,i]-x_data[:,i].min())/(x_data[:,i].max()-x_data[:,i].min())
划分訓練集、驗證集和測試集
為啥要划分數據集呢?
構建和訓練機器學習模型是希望對新的數據做出良好預測。那么,如果我們將所有的數據都去用於訓練,這就好像我們考試前給你一份題庫,並且告訴你所有考試題目都從上面出,一個字都不帶改的,那么只要好好看過了,這不人均90+?
機器也是這樣,你將所有數據都給它訓練,那么他在這個數據集上的效果就會非常的好,但如果給它一份新的數據,那么效果就不得而知了。
既然如此,我們就把數據集划分一下,只給它一部分用來訓練,測試的時候就可以給他新的數據了
一般而言,我們會將一個數據集划分成訓練集和測試集
- 訓練集 - 用於訓練模型的子集
- 測試集 - 用於測試模型的子集
在測試集上表現是否良好是衡量能否在新數據上表現良好的有用指標,前提是:測試集足夠大、不會反復使用相同的測試集來作假
此外,要確保測試集滿足以下兩個條件:
- 規模足夠大,可產生具有統計意義的結果
- 能代表整個數據集,測試集的特征應該與訓練集的特征相同
差不多流程就是這個樣子的
不過這里有個問題,在每次迭代時,都會對訓練數據進行訓練並評估測試數據,並以基於測試數據的評估結果為指導來選擇和更改各種模型超參數,那么.......多次重復執行該流程可能導致模型不知不覺地擬合了特定測試集的特性
怎么辦呢?
簡單,再划分一個驗證集出來,讓驗證集來進行上面流程中測試集的任務,而測試集只在最后測試一次,確保測試集機器只看到一次,然后工作流程就變成了這樣
ok,原理講完,代碼走起
train_num=300# 訓練集數量
valid_num=100# 驗證集數量
test_num=len(x_data)-train_num-valid_num# 測試集數量
# 訓練集划分
x_train=x_data[:train_num]
y_train=y_data[:train_num]
# 驗證集划分
x_valid=x_data[train_num:train_num+valid_num]
y_valid=y_data[train_num:train_num+valid_num]
# 測試集划分
x_test=x_data[train_num+valid_num:train_num+valid_num+test_num]
y_test=y_data[train_num+valid_num:train_num+valid_num+test_num]
由於我們之后要將數據放入模型中訓練、計算損失啥的,所以我們這里把它轉換成tf.float32
x_train=tf.cast(x_train,dtype=tf.float32)
x_valid=tf.cast(x_valid,dtype=tf.float32)
x_test=tf.cast(x_test,dtype=tf.float32)
構建模型
定義模型
模型其實和我們上次一次做的單變量線性回歸是一毛一樣的,只不過這里的w和b不再是一個標量,而是一個矩陣罷了
def model(x,w,b):
return tf.matmul(x,w)+b
創建變量
w=tf.Variable(tf.random.normal([12,1],mean=0.0,stddev=1.0,dtype=tf.float32))
b=tf.Variable(tf.zeros(1),dtype=tf.float32)
print(w,b)
訓練模型
設置超參數
training_epochs=50
lr=0.001
batch_size=10
定義均方差損失函數
def loss(x,y,w,b):
err=model(x,w,b)-y#計算預測值和真實值之間的差異
squarred_err=tf.square(err)#求平方,得出方差
return tf.reduce_mean(squarred_err)#求均值,得出均方差
定義梯度計算函數
def grad(x,y,w,b):
with tf.GradientTape() as tape:
loss_=loss(x,y,w,b)
return tape.gradient(loss_,[w,b])# 返回梯度向量
選擇優化器
這里我們選擇了預制的一個SGD
優化器
optimizer=tf.keras.optimizers.SGD(lr)
迭代訓練
接下來就是訓練的過程了
loss_list_train=[]#train loss
loss_list_valid=[]#val loss
total_step=int(train_num/batch_size)
for epoch in range(training_epochs):
for step in range(total_step):
xs=x_train[step*batch_size:(step+1)*batch_size,:]
ys=y_train[step*batch_size:(step+1)*batch_size]
grads=grad(xs,ys,w,b)#計算梯度
optimizer.apply_gradients(zip(grads,[w,b]))#優化器調參
loss_train=loss(x_train,y_train,w,b).numpy()
loss_valid=loss(x_valid,y_valid,w,b).numpy()
loss_list_train.append(loss_train)
loss_list_valid.append(loss_valid)
print(f"epoch={epoch+1},train_loss={loss_train},valid_loss={loss_valid}")
但是,你如果將數據直接就開始這樣訓練,那么就會出現下面這樣的輸出
epoch=1,train_loss=nan,valid_loss=nan
epoch=2,train_loss=nan,valid_loss=nan
epoch=3,train_loss=nan,valid_loss=nan
epoch=4,train_loss=nan,valid_loss=nan
epoch=5,train_loss=nan,valid_loss=nan
epoch=6,train_loss=nan,valid_loss=nan
epoch=7,train_loss=nan,valid_loss=nan
epoch=8,train_loss=nan,valid_loss=nan
epoch=9,train_loss=nan,valid_loss=nan
epoch=10,train_loss=nan,valid_loss=nan
epoch=11,train_loss=nan,valid_loss=nan
epoch=12,train_loss=nan,valid_loss=nan
epoch=13,train_loss=nan,valid_loss=nan
epoch=14,train_loss=nan,valid_loss=nan
epoch=15,train_loss=nan,valid_loss=nan
epoch=16,train_loss=nan,valid_loss=nan
epoch=17,train_loss=nan,valid_loss=nan
epoch=18,train_loss=nan,valid_loss=nan
epoch=19,train_loss=nan,valid_loss=nan
epoch=20,train_loss=nan,valid_loss=nan
epoch=21,train_loss=nan,valid_loss=nan
epoch=22,train_loss=nan,valid_loss=nan
epoch=23,train_loss=nan,valid_loss=nan
epoch=24,train_loss=nan,valid_loss=nan
epoch=25,train_loss=nan,valid_loss=nan
epoch=26,train_loss=nan,valid_loss=nan
epoch=27,train_loss=nan,valid_loss=nan
epoch=28,train_loss=nan,valid_loss=nan
epoch=29,train_loss=nan,valid_loss=nan
epoch=30,train_loss=nan,valid_loss=nan
epoch=31,train_loss=nan,valid_loss=nan
epoch=32,train_loss=nan,valid_loss=nan
epoch=33,train_loss=nan,valid_loss=nan
epoch=34,train_loss=nan,valid_loss=nan
epoch=35,train_loss=nan,valid_loss=nan
epoch=36,train_loss=nan,valid_loss=nan
epoch=37,train_loss=nan,valid_loss=nan
epoch=38,train_loss=nan,valid_loss=nan
epoch=39,train_loss=nan,valid_loss=nan
epoch=40,train_loss=nan,valid_loss=nan
epoch=41,train_loss=nan,valid_loss=nan
epoch=42,train_loss=nan,valid_loss=nan
epoch=43,train_loss=nan,valid_loss=nan
epoch=44,train_loss=nan,valid_loss=nan
epoch=45,train_loss=nan,valid_loss=nan
epoch=46,train_loss=nan,valid_loss=nan
epoch=47,train_loss=nan,valid_loss=nan
epoch=48,train_loss=nan,valid_loss=nan
epoch=49,train_loss=nan,valid_loss=nan
epoch=50,train_loss=nan,valid_loss=nan
可以看到,loss
輸出都是nan
,他的原因就是輸出太大了,那么我們要避免這個問題就需要對數據進行一定的標准化,因此,在這里我們要對數據做一個歸一化操作,歸一化測操作我在分離特征和標簽
這個步驟里已經寫了,歸一化之后,再重新運行,就好了
epoch=1,train_loss=611.9638061523438,valid_loss=410.65576171875
epoch=2,train_loss=480.1791076660156,valid_loss=300.2012634277344
epoch=3,train_loss=381.4595642089844,valid_loss=223.76609802246094
epoch=4,train_loss=307.4804992675781,valid_loss=171.88424682617188
epoch=5,train_loss=252.01597595214844,valid_loss=137.6017303466797
epoch=6,train_loss=210.4091796875,valid_loss=115.82573699951172
epoch=7,train_loss=179.17657470703125,valid_loss=102.8398666381836
epoch=8,train_loss=155.71231079101562,valid_loss=95.94418334960938
epoch=9,train_loss=138.06668090820312,valid_loss=93.18765258789062
epoch=10,train_loss=124.78082275390625,valid_loss=93.16976165771484
epoch=11,train_loss=114.76297760009766,valid_loss=94.89347839355469
epoch=12,train_loss=107.19605255126953,valid_loss=97.6563949584961
epoch=13,train_loss=101.46824645996094,valid_loss=100.97039031982422
epoch=14,train_loss=97.12144470214844,valid_loss=104.50247192382812
epoch=15,train_loss=93.81257629394531,valid_loss=108.03101348876953
epoch=16,train_loss=91.28462982177734,valid_loss=111.41390991210938
epoch=17,train_loss=89.34487915039062,valid_loss=114.56527709960938
epoch=18,train_loss=87.84889221191406,valid_loss=117.43827819824219
epoch=19,train_loss=86.68826293945312,valid_loss=120.01301574707031
epoch=20,train_loss=85.78163146972656,valid_loss=122.2874755859375
epoch=21,train_loss=85.06792449951172,valid_loss=124.2712631225586
epoch=22,train_loss=84.50117492675781,valid_loss=125.98110961914062
epoch=23,train_loss=84.04681396484375,valid_loss=127.43778991699219
epoch=24,train_loss=83.67878723144531,valid_loss=128.66384887695312
epoch=25,train_loss=83.3774642944336,valid_loss=129.68228149414062
epoch=26,train_loss=83.12799072265625,valid_loss=130.5154571533203
epoch=27,train_loss=82.91910552978516,valid_loss=131.18463134765625
epoch=28,train_loss=82.74230194091797,valid_loss=131.70956420898438
epoch=29,train_loss=82.59107971191406,valid_loss=132.10824584960938
epoch=30,train_loss=82.46050262451172,valid_loss=132.39715576171875
epoch=31,train_loss=82.34676361083984,valid_loss=132.59092712402344
epoch=32,train_loss=82.24696350097656,valid_loss=132.70252990722656
epoch=33,train_loss=82.1588363647461,valid_loss=132.74366760253906
epoch=34,train_loss=82.08061981201172,valid_loss=132.72451782226562
epoch=35,train_loss=82.01095581054688,valid_loss=132.6539764404297
epoch=36,train_loss=81.94876861572266,valid_loss=132.53993225097656
epoch=37,train_loss=81.89318084716797,valid_loss=132.38919067382812
epoch=38,train_loss=81.84352111816406,valid_loss=132.2075958251953
epoch=39,train_loss=81.79922485351562,valid_loss=132.00039672851562
epoch=40,train_loss=81.75981140136719,valid_loss=131.7720489501953
epoch=41,train_loss=81.72492980957031,valid_loss=131.52635192871094
epoch=42,train_loss=81.69425201416016,valid_loss=131.26663208007812
epoch=43,train_loss=81.66749572753906,valid_loss=130.99574279785156
epoch=44,train_loss=81.64443969726562,valid_loss=130.71609497070312
epoch=45,train_loss=81.6248779296875,valid_loss=130.42990112304688
epoch=46,train_loss=81.6086196899414,valid_loss=130.1387939453125
epoch=47,train_loss=81.59551239013672,valid_loss=129.84445190429688
epoch=48,train_loss=81.58541107177734,valid_loss=129.5481414794922
epoch=49,train_loss=81.57818603515625,valid_loss=129.2509307861328
epoch=50,train_loss=81.5737075805664,valid_loss=128.953857421875
接下來我們可以可視化一下loss
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.plot(loss_list_train,'blue',label="Train loss")
plt.plot(loss_list_valid,'red',label='Valid loss')
plt.legend(loc=1)
測試模型
查看測試集損失
print(f"Test_loss:{loss(x_test,y_test,w,b).numpy()}")
輸出:
Test_loss:115.94937133789062
應用模型
測試集里隨機選一條
# use model
test_house_id=np.random.randint(0,test_num)
y=y_test[test_house_id]
y_pred=model(x_test,w,b)[test_house_id]
y_predit=tf.reshape(y_pred,()).numpy()
print(f"House id {test_house_id} actual value {y} predicted value {y_predit}")
輸出
House id 34 actual value 11.7 predicted value 23.49941062927246
到這里就算結束了,建議去看看慕課。
學習筆記,僅供參考,如有錯誤,敬請指正!