教你使用百度深度学习框架PaddlePaddle完成波士顿房价预测(新手向)
?
? 首先,本文是一篇純新手向文章,我自己也只能算是入門,有說錯的地方歡迎大家批評討論
目錄
一、人工智能、機器學習、深度學習
二、PaddlePaddle(飛槳)
三、波士頓房價預測模型
數據處理
模型設計
訓練配置
訓練過程
模型保存
模型測試
四、小結
一、人工智能、機器學習、深度學習
? 近幾年人工智能可以說是火的不能再火,大家可能會覺得人工智能=機器學習=深度學習,其實不是這樣的,這三個概念是一種包含的層層深入的關系。
? 機器學習:專門研究計算機怎樣模擬或實現人類的學習行為,以獲取新的知識或技能,重新組織已有的知識結構使之不斷改善自身的性能。 它是人工智能的核心,是使計算機具有智能的根本途徑。
? 深度學習:深度學習是機器學習的分支,是一種以人工神經網絡為架構,對數據進行表征學習的算法。
其實這么說大家可能也沒聽懂,不過這并不是我們今天的主題,大致了解一下就好。
二、PaddlePaddle(飛槳)
? 大家平常接觸到的深度學習框架可能有PyTorch、TensorFlow等等,今天的飛槳是百度研制的一款開源的深度學習框架,個人認為可以滿足日常學習,另外,百度還配套有專門的線上實訓平臺aistudio,提供了豐富的課程以及免費的GPU(百度打錢,hahaha)十分良心。一下是PaddlePaddle的API以及GitHub地址,大家沒事可以多看看挺有意思的。
三、波士頓房價預測模型
? 波士頓房價預測項目是一個經典的入門級項目,我們認為波士頓地區(qū)的房價受多種因素影響(人均犯罪率,一氧化氮濃度等等),我們收集了房價隨各種因素變化而變化的數據,現在我們需要使用計算機根據這些數據來設計一個房價受各因素影響而變化的模型。對于預測問題,可以根據預測輸出的類型是連續(xù)的實數值,還是離散的標簽,區(qū)分為回歸任務和分類任務。因為房價是一個連續(xù)值,所以房價預測顯然是一個回歸任務。下面我們嘗試用最簡單的線性回歸模型解決這個問題,并用神經網絡來實現這個模型。
? 構建神經網絡的基本步驟如下圖所示,我們將會用飛槳框架來搭建這個項目,并對其中的基本概念進行解釋
數據處理
? 數據處理包含五個部分:數據導入、數據形狀變換、數據集劃分、數據歸一化處理和封裝load data函數。數據預處理后,才能被模型調用,可以說一個好的數據處理方式是優(yōu)秀網絡搭建的基石。
? 我們使用的數據的格式是一些506*14的數字
其中前13列代表影響因素,最后一列是房價(影響因素具體如下)
? ? ? ? ?
話不多說直接上代碼
數據導入
# 導入需要用到的package # 加載飛槳、Numpy和相關類庫 import paddle import paddle.fluid as fluid import paddle.fluid.dygraph as dygraph from paddle.fluid.dygraph import Linear import numpy as np import os import random # 讀入訓練數據 datafile = './work/housing.data' data = np.fromfile(datafile, sep=' ') print(data) # 在文件里的數據已經轉化為Python中的ndarry格式了 [6.320e-03 1.800e+01 2.310e+00 ... 3.969e+02 7.880e+00 1.190e+01]數據形狀變換
在原始文件中,我們的數據都是連在一起的是個一維的,我們不能區(qū)分出自變量(影響因素x)和因變量(房價y)之間的界限,因此我們需要對這些數據進行形狀變化,形成一個2維的矩陣,每行為一個數據樣本(14個值),每個數據樣本包含13個X(影響房價的特征)和一個Y(該類型房屋的均價)。
# 讀入之后的數據被轉化成1維array,其中array的第0-13項是第一條數據,第14-27項是第二條數據,以此類推.... # 這里對原始數據做reshape,變成N x 14的形式 feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE','DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ] feature_num = len(feature_names) data = data.reshape([data.shape[0] // feature_num, feature_num])# 查看數據 x = data[0] # 打印x的形狀 print(x.shape) print(x) 輸出: (14,) [6.320e-03 1.800e+01 2.310e+00 0.000e+00 5.380e-01 6.575e+00 6.520e+014.090e+00 1.000e+00 2.960e+02 1.530e+01 3.969e+02 4.980e+00 2.400e+01]數據集劃分
我們需要將數據集劃分成訓練集和測試集,其中訓練集用于確定模型的參數,驗證集用于調節(jié)模型超參數(如多個網絡結構、正則化權重的最優(yōu)選擇),測試集用于評判模型的效果。在本案例中,我們將80%的數據用作訓練集,20%用作測試集,由于數據不多,網絡簡單,所以沒有安排驗證集。
# 將0.8作為訓練集 ratio = 0.8 offset = int(data.shape[0] * ratio) # 從數據開始到0.8的位置都是訓練集部分 training_data = data[:offset] #查看訓練集大小 training_data.shape輸出: (404, 14)數據歸一化處理
對每個特征進行歸一化處理,使得每個特征的取值縮放到0~1之間。這樣做有兩個好處:一是模型訓練更高效;二是特征前的權重大小可以代表該變量對預測結果的貢獻度(因為每個特征值本身的范圍相同)
# 計算train數據集每個影響因素的最大值,最小值,平均值 maximums, minimums, avgs = \training_data.max(axis=0), \training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]# 對數據進行歸一化處理,并查看每一個影響因素中的最大值最小值和均值 for i in range(feature_num):print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - avgs[i]) / (maximums[i] - minimums[i]) 輸出十四列的最大值最小值均值: 0.9785367890017308 -0.021463210998269224 -1.2366345571319812e-18 0.8576732673267327 -0.14232673267326734 -2.6931152577540925e-17 0.6410350642051105 -0.35896493579488953 -1.09923071745065e-18 0.9133663366336635 -0.08663366336633646 9.364071674282725e-17 0.6980824471336023 -0.3019175528663977 -8.244230380879875e-19 0.4688428988520618 -0.5311571011479382 -4.1221151904399375e-19 0.366349379531156 -0.633650620468844 -3.0228844729892876e-18 0.7231389197081554 -0.27686108029184464 -3.0915863928299533e-18 0.7482780886784333 -0.2517219113215666 -3.022884472989288e-17 0.6536307075383947 -0.3463692924616053 2.1984614349013e-18 0.4227406783231515 -0.5772593216768486 -2.7480767936266252e-18 0.05191120077969154 -0.9480887992203084 1.5457931964149766e-18 0.7344108583043735 -0.2655891416956266 -3.29769215235195e-18 0.5738723872387239 -0.42612761276127614 4.259519030121269e-18封裝load data函數
就是將前幾步合起來方便使用
def load_data():# 從文件導入數據datafile = './work/housing.data'data = np.fromfile(datafile, sep=' ')# 每條數據包括14項,其中前面13項是影響因素,第14項是相應的房屋價格中位數feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', \'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]feature_num = len(feature_names)# 將原始數據進行Reshape,變成[N, 14]這樣的形狀data = data.reshape([data.shape[0] // feature_num, feature_num])# 將原數據集拆分成訓練集和測試集# 這里使用80%的數據做訓練,20%的數據做測試# 測試集和訓練集必須是沒有交集的ratio = 0.8offset = int(data.shape[0] * ratio)training_data = data[:offset]# 計算train數據集的最大值,最小值,平均值maximums, minimums, avgs = training_data.max(axis=0), training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]# 對數據進行歸一化處理for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - avgs[i]) / (maximums[i] - minimums[i])# 訓練集和測試集的劃分比例training_data = data[:offset]test_data = data[offset:]return training_data, test_data至此,我們數據處理已經告一段落了,接下來我們拿到數據看看處理結果
# 獲取數據 training_data, test_data = load_data() x = training_data[:, :-1] y = training_data[:, -1:]# 查看數據 print(x[0]) print(y[0])輸出結果: [-0.02146321 0.03767327 -0.28552309 -0.08663366 0.01289726 0.046348170.00795597 -0.00765794 -0.25172191 -0.11881188 -0.29002528 0.0519112-0.17590923] [-0.00390539]模型設計
模型設計帶有一定的經驗性,在這個項目里,我們采用線性的模型即,w,b就是我們需要求解的參數,我們不妨先給其一個隨機的初始值
w = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, -0.1, -0.2, -0.3, -0.4, 0.0] # 轉化為13*1的向量,方便進行乘法操作 w = np.array(w).reshape([13, 1])t=np.dot(x,w)b = -0.2 z = t + b這樣我們的模型就設計好了,為了方便調用,我們實現一個類,成員變量是w,b,其中有前向計算(輸入到輸出)的方法
# 純python class Network(object):def __init__(self, num_of_weights):# 隨機產生w的初始值# 為了保持程序每次運行結果的一致性,# 此處設置固定的隨機數種子np.random.seed(0)self.w = np.random.randn(num_of_weights, 1)self.b = 0.def forward(self, x):z = np.dot(x, self.w) + self.breturn z以上模型的配置是用純python來寫的,實際上飛槳中的全連接層就可以實現線性回歸這一模型
# 采用飛槳框架 class Regressor(fluid.dygraph.Layer):def __init__(self, name_scope):super(Regressor, self).__init__(name_scope)name_scope = self.full_name()# 定義一層全連接層,輸出維度是1,激活函數為None,即不使用激活函數self.fc = Linear(input_dim=13, output_dim=1, act=None)# 網絡的前向計算函數def forward(self, inputs):x = self.fc(inputs)return x?
訓練配置
# 定義飛槳動態(tài)圖的工作環(huán)境 with fluid.dygraph.guard():# 聲明定義好的線性回歸模型model = Regressor("Regressor")# 開啟模型訓練模式model.train()# 加載數據training_data, test_data = load_data()# 定義優(yōu)化算法,這里使用隨機梯度下降-SGD# 學習率設置為0.01opt = fluid.optimizer.SGD(learning_rate=0.01, parameter_list=model.parameters())在這里解釋幾個地方
- train()是父類的函數,表示訓練,除此之外還會有eval(),表示評估。在執(zhí)行時,train會進行前向傳播和后向傳播,而eval只會前向傳播
- 關于后向傳播,因為參數是我們隨機生成的,難免會出錯,在訓練的時候我們定義一個loss函數來表示當前預測值跟真實值的差別,我們的追求是loss盡可能小,為了找到最小的loss我們可以找梯度(可以理解為導數)最小的點,那么如何來找最小的點呢,就需要使用優(yōu)化器了
訓練過程
訓練的過程實際上就是不斷地將預測值與實際值進行比較,找到loss最小的點的一個循環(huán)過程,因此我們采用兩層循環(huán)來進行訓練,其中內層循環(huán)負責對每次獲得的數據進行計算反傳梯度等,外層循環(huán)負責遍歷數據集并用隨機的方式取得訓練的小批次
with dygraph.guard(fluid.CPUPlace()):EPOCH_NUM = 10 # 設置外層循環(huán)次數BATCH_SIZE = 10 # 設置batch大小# 定義外層循環(huán),我們會對數據集遍歷10次for epoch_id in range(EPOCH_NUM):# 在每輪迭代開始之前,將訓練數據的順序隨機的打亂np.random.shuffle(training_data)# 將訓練數據進行拆分,每個batch包含10條數據,一共就會有41個mini_batches,最后一個只有四個數據mini_batches = [training_data[k:k+BATCH_SIZE] for k in range(0, len(training_data), BATCH_SIZE)]# 定義內層循環(huán)for iter_id, mini_batch in enumerate(mini_batches):x = np.array(mini_batch[:, :-1]).astype('float32') # 獲得當前批次訓練數據y = np.array(mini_batch[:, -1:]).astype('float32') # 獲得當前批次訓練標簽(真實房價)# 將numpy數據轉為飛槳動態(tài)圖variable形式house_features = dygraph.to_variable(x)prices = dygraph.to_variable(y)# 前向計算predicts = model(house_features)# 計算損失# 損失函數采用均方誤差函數loss = fluid.layers.square_error_cost(predicts, label=prices)avg_loss = fluid.layers.mean(loss)# 計算20個樣本打印一次lossif iter_id%20==0:print("epoch: {}, iter: {}, loss is: {}".format(epoch_id, iter_id, avg_loss.numpy()))# 反向傳播avg_loss.backward()# 最小化loss,更新參數opt.minimize(avg_loss)# 清除梯度model.clear_gradients()# 保存模型fluid.save_dygraph(model.state_dict(), 'LR_model') 輸出: epoch: 0, iter: 0, loss is: [0.2819261] epoch: 0, iter: 20, loss is: [0.09325473] epoch: 0, iter: 40, loss is: [0.31836104] epoch: 1, iter: 0, loss is: [0.06697255] epoch: 1, iter: 20, loss is: [0.14381303] epoch: 1, iter: 40, loss is: [0.02925108] epoch: 2, iter: 0, loss is: [0.03091546] epoch: 2, iter: 20, loss is: [0.17063697] epoch: 2, iter: 40, loss is: [0.1874596] epoch: 3, iter: 0, loss is: [0.12090156] epoch: 3, iter: 20, loss is: [0.0605287] epoch: 3, iter: 40, loss is: [0.06634661] epoch: 4, iter: 0, loss is: [0.06475429] epoch: 4, iter: 20, loss is: [0.06778971] epoch: 4, iter: 40, loss is: [0.32411507] epoch: 5, iter: 0, loss is: [0.08117181] epoch: 5, iter: 20, loss is: [0.06476147] epoch: 5, iter: 40, loss is: [0.00810404] epoch: 6, iter: 0, loss is: [0.02915803] epoch: 6, iter: 20, loss is: [0.10254985] epoch: 6, iter: 40, loss is: [0.07706425] epoch: 7, iter: 0, loss is: [0.10288523] epoch: 7, iter: 20, loss is: [0.12237016] epoch: 7, iter: 40, loss is: [0.0179625] epoch: 8, iter: 0, loss is: [0.03814844] epoch: 8, iter: 20, loss is: [0.1533469] epoch: 8, iter: 40, loss is: [0.0867041] epoch: 9, iter: 0, loss is: [0.08161684] epoch: 9, iter: 20, loss is: [0.09394293] epoch: 9, iter: 40, loss is: [0.24671933]我們可以很明顯看到loss在不斷減小,我們的工作是有效果的!
模型保存
? 我們可以將我們訓練好的模型參數保存,下次直接拿來使用
# 定義飛槳動態(tài)圖工作環(huán)境 with fluid.dygraph.guard():# 保存模型參數,文件名為LR_modelfluid.save_dygraph(model.state_dict(), 'LR_model')print("模型保存成功,模型參數保存在LR_model中")模型測試
模型測試其實跟訓練類似,不過少了反向更新梯度
# 從測試集中加載數據 def load_one_example(data_dir):f = open(data_dir, 'r')datas = f.readlines()# 選擇倒數第10條數據用于測試tmp = datas[-10]tmp = tmp.strip().split()one_data = [float(v) for v in tmp]# 對數據進行歸一化處理for i in range(len(one_data)-1):one_data[i] = (one_data[i] - avg_values[i]) / (max_values[i] - min_values[i])data = np.reshape(np.array(one_data[:-1]), [1, -1]).astype(np.float32)label = one_data[-1]return data, label # 加載模型進行預測 with dygraph.guard():# 參數為保存模型參數的文件地址model_dict, _ = fluid.load_dygraph('LR_model')model.load_dict(model_dict)model.eval()# 參數為數據集的文件地址test_data, label = load_one_example('./work/housing.data')# 將數據轉為動態(tài)圖的variable格式test_data = dygraph.to_variable(test_data)results = model(test_data)# 對結果做反歸一化處理,即還原成之前的數值results = results * (max_values[-1] - min_values[-1]) + avg_values[-1]print("Inference result is {}, the corresponding label is {}".format(results.numpy(), label)) Inference result is [[17.563766]], the corresponding label is 19.7我們可以看出,預測輸出跟真實輸出十分接近。
四、小結
我們使用飛槳框架,搭建了一個只有一層全連接層的網絡,了解了深度學習的五步驟,但是每個步驟都有極大的研究空間,大家有興趣可以選擇一個深度學習的方向進行研究,學到更多的知識!
總結
以上是生活随笔為你收集整理的教你使用百度深度学习框架PaddlePaddle完成波士顿房价预测(新手向)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 支付系统设计:对账处理(二)
- 下一篇: 用C语言撸线性表