在本次我們將使用PaddlePaddle來搭建一個簡單的線性迴歸模型,並利用這一模型預測你的儲蓄(在某地區)可以購買多大面積的房子。並且在學習模型搭建的過程中,瞭解到機器學習的若干重要概念,掌握一個機器學習預測的基本流程。
線性迴歸的基本概念
線性迴歸是機器學習中最簡單也是最重要的模型之一,其模型建立遵循此流程:獲取數據、數據預處理、訓練模型、應用模型。
迴歸模型可以理解爲:存在一個點集,用一條曲線去擬合它分佈的過程。如果擬合曲線是一條直線,則稱爲線性迴歸。如果是一條二次曲線,則被稱爲二次迴歸。線性迴歸是迴歸模型中最簡單的一種。
在線性迴歸中有幾個基本的概念需要掌握:
- 假設函數(Hypothesis Function)
- 損失函數(Loss Function)
- 優化算法(Optimization Algorithm)
假設函數:
假設函數是指,用數學的方法描述自變量和因變量之間的關係,它們之間可以是一個線性函數或非線性函數。 在本次線性回顧模型中,我們的假設函數爲 Y^=aX1+b ,其中,Y^表示模型的預測結果(預測房價),用來和真實的Y區分。模型要學習的參數即:a,b。
損失函數:
損失函數是指,用數學的方法衡量假設函數預測結果與真實值之間的誤差。這個差距越小預測越準確,而算法的任務就是使這個差距越來越小。
建立模型後,我們需要給模型一個優化目標,使得學到的參數能夠讓預測值Y^儘可能地接近真實值Y。輸入任意一個數據樣本的目標值yi和模型給出的預測值\hat{Y_i,損失函數輸出一個非負的實值。這個實值通常用來反映模型誤差的大小。
對於線性模型來講,最常用的損失函數就是均方誤差(Mean Squared Error, MSE)。
MSE=n1∑i=1n(Yi^−Yi)2
即對於一個大小爲n的測試集,MSE是n個數據預測結果誤差平方的均值。
優化算法:
在模型訓練中優化算法也是至關重要的,它決定了一個模型的精度和運算速度。本章的線性迴歸實例中主要使用了梯度下降法進行優化。
現在,讓我們正式進入實驗吧!
首先導入必要的包,分別是:
paddle.fluid--->PaddlePaddle深度學習框架
numpy---------->python基本庫,用於科學計算
os------------------>python的模塊,可使用該模塊對操作系統進行操作
matplotlib----->python繪圖庫,可方便繪製折線圖、散點圖等圖形
import paddle.fluid as fluid
import paddle
import numpy as np
import os
import matplotlib.pyplot as plt
BUF_SIZE=500
BATCH_SIZE=20
#用於訓練的數據提供器,每次從緩存中隨機讀取批次大小的數據
train_reader = paddle.batch(
paddle.reader.shuffle(paddle.dataset.uci_housing.train(),
buf_size=BUF_SIZE),
batch_size=BATCH_SIZE)
#用於測試的數據提供器,每次從緩存中隨機讀取批次大小的數據
test_reader = paddle.batch(
paddle.reader.shuffle(paddle.dataset.uci_housing.test(),
buf_size=BUF_SIZE),
batch_size=BATCH_SIZE)
#用於打印,查看uci_housing數據
train_data=paddle.dataset.uci_housing.train();
sampledata=next(train_data())
print(sampledata)
#(1)網絡搭建:對於線性迴歸來講,它就是一個從輸入到輸出的簡單的全連接層。
#定義張量變量x,表示13維的特徵值
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
#定義張量y,表示目標值
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
#定義一個簡單的線性網絡,連接輸入和輸出的全連接層
#input:輸入tensor;
#size:該層輸出單元的數目
#act:激活函數
y_predict=fluid.layers.fc(input=x,size=1,act=None)
#(2)定義損失函數,此處使用均方差損失函數。
# square_error_cost(input,lable):接受輸入預測值和目標值,並返回方差估計,即爲(y-y_predict)的平方
cost = fluid.layers.square_error_cost(input=y_predict, label=y) #求一個batch的損失值
avg_cost = fluid.layers.mean(cost)
#(3)定義優化函數,此處使用的是隨機梯度下降。
test_program = fluid.default_main_program().clone(for_test=True)
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.001)
opts = optimizer.minimize(avg_cost)
use_cuda = False #use_cuda爲False,表示運算場所爲CPU;use_cuda爲True,表示運算場所爲GPU
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
exe = fluid.Executor(place) #創建一個Executor實例exe
exe.run(fluid.default_startup_program()) #Executor的run()方法執行startup_program(),進行參數初始化
# 定義輸入數據維度
feeder = fluid.DataFeeder(place=place, feed_list=[x, y])#feed_list:向模型輸入的變量表或變量表名
#定義繪製訓練過程的損失值變化趨勢的方法draw_train_process
iter=0;
iters=[]
train_costs=[]
def draw_train_process(iters,train_costs):
title="training cost"
plt.title(title, fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost", fontsize=14)
plt.plot(iters, train_costs,color='red',label='training cost')
plt.grid()
plt.show()
EPOCH_NUM=50
model_save_dir = "/home/aistudio/work/fit_a_line.inference.model"
for pass_id in range(EPOCH_NUM): #訓練EPOCH_NUM輪
# 開始訓練並輸出最後一個batch的損失值
train_cost = 0
for batch_id, data in enumerate(train_reader()): #遍歷train_reader迭代器
train_cost = exe.run(program=fluid.default_main_program(),#運行主程序
feed=feeder.feed(data), #喂入一個batch的訓練數據,根據feed_list和data提供的信息,將輸入數據轉成一種特殊的數據結構
fetch_list=[avg_cost])
if batch_id % 40 == 0:
print("Pass:%d, Cost:%0.5f" % (pass_id, train_cost[0][0])) #打印最後一個batch的損失值
iter=iter+BATCH_SIZE
iters.append(iter)
train_costs.append(train_cost[0][0])
# 開始測試並輸出最後一個batch的損失值
test_cost = 0
for batch_id, data in enumerate(test_reader()): #遍歷test_reader迭代器
test_cost= exe.run(program=test_program, #運行測試cheng
feed=feeder.feed(data), #喂入一個batch的測試數據
fetch_list=[avg_cost]) #fetch均方誤差
print('Test:%d, Cost:%0.5f' % (pass_id, test_cost[0][0])) #打印最後一個batch的損失值
#保存模型
# 如果保存路徑不存在就創建
if not os.path.exists(model_save_dir):
os.makedirs(model_save_dir)
print ('save models to %s' % (model_save_dir))
#保存訓練參數到指定路徑中,構建一個專門用預測的program
fluid.io.save_inference_model(model_save_dir, #保存推理model的路徑
['x'], #推理(inference)需要 feed 的數據
[y_predict], #保存推理(inference)結果的 Variables
exe) #exe 保存 inference model
draw_train_process(iters,train_costs)
infer_exe = fluid.Executor(place) #創建推測用的executor
inference_scope = fluid.core.Scope() #Scope指定作用域
infer_results=[]
groud_truths=[]
#繪製真實值和預測值對比圖
def draw_infer_result(groud_truths,infer_results):
title='Boston'
plt.title(title, fontsize=24)
x = np.arange(1,20)
y = x
plt.plot(x, y)
plt.xlabel('ground truth', fontsize=14)
plt.ylabel('infer result', fontsize=14)
plt.scatter(groud_truths, infer_results,color='green',label='training cost')
plt.grid()
plt.show()
with fluid.scope_guard(inference_scope):#修改全局/默認作用域(scope), 運行時中的所有變量都將分配給新的scope。
#從指定目錄中加載 推理model(inference model)
[inference_program, #推理的program
feed_target_names, #需要在推理program中提供數據的變量名稱
fetch_targets] = fluid.io.load_inference_model(#fetch_targets: 推斷結果
model_save_dir, #model_save_dir:模型訓練路徑
infer_exe) #infer_exe: 預測用executor
#獲取預測數據
infer_reader = paddle.batch(paddle.dataset.uci_housing.test(), #獲取uci_housing的測試數據
batch_size=200) #從測試數據中讀取一個大小爲200的batch數據
#從test_reader中分割x
test_data = next(infer_reader())
test_x = np.array([data[0] for data in test_data]).astype("float32")
test_y= np.array([data[1] for data in test_data]).astype("float32")
results = infer_exe.run(inference_program, #預測模型
feed={feed_target_names[0]: np.array(test_x)}, #喂入要預測的x值
fetch_list=fetch_targets) #得到推測結果
print("infer results: (House Price)")
for idx, val in enumerate(results[0]):
print("%d: %.2f" % (idx, val))
infer_results.append(val)
print("ground truth:")
for idx, val in enumerate(test_y):
print("%d: %.2f" % (idx, val))
groud_truths.append(val)
draw_infer_result(groud_truths,infer_results)