PaddlePaddle實現線性迴歸

在本次我們將使用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)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章