百度PaddlePaddle >>> 5. Boston房價預測

在這裏插入圖片描述
本文基於百度PaddlePaddle教程:https://aistudio.baidu.com/aistudio/projectdetail/350646

在這裏插入圖片描述

一、準備數據

  1. uci-housing 數據集介紹
    數據集共506行,每行14列。前13列用來描述房屋的各種信息,最後一列爲該類房屋的價格中位數。

PaddlePaddle提供了讀取uci-housing 訓練集和測試集的接口,分別爲paddle.dataset.uci_housing.train()paddle.dataset.uci_housing.test()

  1. train_readertest_reader
    paddle.reader.shuffle()表示每次緩存BUF_SIZE個數據項,並進行打亂。

paddle.batch()表示每BATCH_SIZE組成一個batch。

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)

在這裏插入圖片描述

二、網絡配置

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: 激活函數
hidden1 = fluid.layers.fc(input=x, size=100, act="relu")
y_predict = fluid.layers.fc(input=hidden1, size=1, act=None)

2. 定義損失函數

這裏使用均方差損失函數。

square_error_cost(input,lable) 接收輸入預測值和目標值,並返回方差估計,即爲**(y-y_predict)**的平方

# 定義損失函數
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_cost = fluid.layers.mean(cost)

3. 定義優化函數

這裏使用隨機梯度下降。

# 定義優化函數
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.005)
opts = optimizer.minimize(avg_cost)
test_program = fluid.default_main_program().clone(for_test=True)

上述模型配置完畢後,得到兩個fluid.Program

  1. fluid.default_startup_program()
    參數初始化操作會被寫入該Program 中。

  2. fluid.default_main_program()
    此Program 用於獲取默認或全局main program(主程序),該主程序用於訓練和測試模型

fluid.layers 中所有layer函數可以向default_main_program 中添加算子和變量。
default_main_programfluid 的許多編程接口(API)的Program 參數的默認值(當用戶program 沒有傳入的時候,Executor.run()會默認執行 default_main_program
在這裏插入圖片描述

三、模型訓練 和 模型評估

1. 創建Executor

定義運算場所fluid.CPUPlace()fluid.CUDAPlace(0) 分別表示運算場所爲CPU和GPU。

Executor:接收傳入的program,通過run()方法運行program。

# 創建Executor
use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
exe = fluid.Executor(place)                 # 創建一個Executor實例exe
exe.run(fluid.default_startup_program())    # 參數初始化

2. 定義輸入數據維度

DataFeeder負責將數據提供器(train_reader, test_reader)返回的數據轉成一種特殊的數據結構,使其可以輸入到Executor中。

# 定義輸入數據維度
# feed_list: 向模型輸入的變量表或變量表名
feeder = fluid.DataFeeder(place=place, feed_list=[x, y])

3. 定義繪製訓練過程中的損失值變化趨勢

由於我這由於某些未知原因,導致plt 圖像不能顯示,所以我只能將其保存在本地進行查看。

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.savefig("C:/Users/waao_wuyou/Desktop/pic.jpg")

4. 訓練並保存模型

Executor 接收傳入的program, 並根據feed map(輸入映射表)和fetch_list(結果獲取表) 向program中添加feed operators(數據輸入算子)和fetch operators(結果獲取算子)。
feed map爲該program提供輸入數據。fetch_list提供program訓練結束後用戶預期的變量。

enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合爲一個索引序列,同時列出數據和數據下標

# 訓練並保存模型
EPOCH_NUM = 100
model_save_dir = "C:/Users/waao_wuyou/Desktop/fit_a_line.inference.model"
for pass_id in range(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,
                            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'],          # 推理需要feed 的數據
                                [y_predict],    # 保存推理結果的Variables
                                exe)            # exe 保存inference model
draw_train_process(iters, train_costs)

輸出結果:

Pass:90, Cost:23.69488
Test:90, Cost:17.02254
Pass:91, Cost:6.22767
Test:91, Cost:12.09491
Pass:92, Cost:7.67705
Test:92, Cost:95.80173
Pass:93, Cost:5.76839
Test:93, Cost:7.67893
Pass:94, Cost:14.50994
Test:94, Cost:6.25279
Pass:95, Cost:34.86055
Test:95, Cost:29.38514
Pass:96, Cost:19.19988
Test:96, Cost:15.92449
Pass:97, Cost:27.39356
Test:97, Cost:4.28481
Pass:98, Cost:5.60616
Test:98, Cost:0.79274
Pass:99, Cost:9.20047
Test:99, Cost:15.64438

在這裏插入圖片描述
在這裏插入圖片描述

四、模型預測

1. 創建預測用的Executor

# 模型預測
infer_exe = fluid.Executor(place)       # 創建推測用的executor
inference_scope = fluid.core.Scope()    # Scope 指定作用域

2. 可視化真實值與預測值方法定義

# 可視化真實值與預測值方法定義
infer_results = []
ground_truths = []

# 繪製真實值和預測值對比圖
def draw_infer_result(ground_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(ground_truths, infer_results, color='green', label='training cost')
    plt.grid()
    plt.savefig("C:/Users/waao_wuyou/Desktop/result.jpg")

3. 開始預測

通過fluid.io.load_inference_model,預測器會從params_dirname中讀取已經訓練好的模型,來對從未遇見過的數據進行預測。

# 開始預測
with fluid.scope_guard(inference_scope):    # 修改全局/默認作用域,運行時中的所有變量都將分配給新的scope
    # 從指定目錄中加載 推理model(inference model)
    [inference_program,                                 # 推理的program
     feed_target_names,                                 # 需要在推理program中提供數據的變量名稱
     fetch_targets] = fluid.io.load_inference_model(    # 推斷結果
                                        model_save_dir, # 模型路徑
                                        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: %0.2f" % (idx, val))
        infer_results.append(val)
    print("ground truth:")
    for idx, val in enumerate(test_y):
        print("%d: %.2f" % (idx, val))
        ground_truths.append(val)
    draw_infer_result(ground_truths, infer_results)

輸出結果:

90: 24.50
91: 23.10
92: 19.70
93: 18.30
94: 21.20
95: 17.50
96: 16.80
97: 22.40
98: 20.60
99: 23.90
100: 22.00
101: 11.90

在這裏插入圖片描述
在這裏插入圖片描述

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