鲍鱼年龄预测
經(jīng)典的線性回歸模型主要用來預(yù)測一些存在著線性關(guān)系的數(shù)據(jù)集。回歸模型可以理解為:存在一個(gè)點(diǎn)集,用一條曲線去擬合它分布的過程。如果擬合曲線是一條直線,則稱為線性回歸。如果是一條二次曲線,則被稱為二次回歸。線性回歸是回歸模型中最簡單的一種。 本教程使用PaddlePaddle建立起一個(gè)鮑魚年齡預(yù)測模型。
在線性回歸中:
(1)假設(shè)函數(shù)是指,用數(shù)學(xué)的方法描述自變量和因變量之間的關(guān)系,它們之間可以是一個(gè)線性函數(shù)或非線性函數(shù)。 在本次線性回顧模型中,我們的假設(shè)函數(shù)為 Y’= wX+b ,其中,Y’表示模型的預(yù)測結(jié)果(預(yù)測的鮑魚年齡),用來和真實(shí)的Y區(qū)分。模型要學(xué)習(xí)的參數(shù)即:w,b。
(2)損失函數(shù)是指,用數(shù)學(xué)的方法衡量假設(shè)函數(shù)預(yù)測結(jié)果與真實(shí)值之間的誤差。這個(gè)差距越小預(yù)測越準(zhǔn)確,而算法的任務(wù)就是使這個(gè)差距越來越小。 建立模型后,我們需要給模型一個(gè)優(yōu)化目標(biāo),使得學(xué)到的參數(shù)能夠讓預(yù)測值Y’盡可能地接近真實(shí)值Y。這個(gè)實(shí)值通常用來反映模型誤差的大小。不同問題場景下采用不同的損失函數(shù)。 對于線性模型來講,最常用的損失函數(shù)就是均方誤差(Mean Squared Error, MSE)。
(3)優(yōu)化算法:神經(jīng)網(wǎng)絡(luò)的訓(xùn)練就是調(diào)整權(quán)重(參數(shù))使得損失函數(shù)值盡可能得小,在訓(xùn)練過程中,將損失函數(shù)值逐漸收斂,得到一組使得神經(jīng)網(wǎng)絡(luò)擬合真實(shí)模型的權(quán)重(參數(shù))。所以,優(yōu)化算法的最終目標(biāo)是找到損失函數(shù)的最小值。而這個(gè)尋找過程就是不斷地微調(diào)變量w和b的值,一步一步地試出這個(gè)最小值。 常見的優(yōu)化算法有隨機(jī)梯度下降法(SGD)、Adam算法等等
# # **Step1.數(shù)據(jù)準(zhǔn)備** # # **認(rèn)識數(shù)據(jù):** # # # 數(shù)據(jù)集共4177行,每行9列 # # 前8列用來描述鮑魚的各種信息,分別是性別、長度、直徑、高度、總重量、皮重、內(nèi)臟重量、克重,最后一列為該鮑魚的年齡 # # # **數(shù)據(jù)準(zhǔn)備:** # # 1.從文件中加載數(shù)據(jù) # # 2.對數(shù)據(jù)進(jìn)行歸一化 # # 3.構(gòu)造數(shù)據(jù)集提供器# 讀取文件 import numpy as np import os import matplotlib.pyplot as pltdata_X = [] data_Y = [] # 將性別(M:雄性,F:雌性,I:未成年)映射成數(shù)字 sex_map = {'I': 0, 'M': 1, 'F': 2} with open('data/data361/AbaloneAgePrediction.txt') as f:for line in f.readlines():line = line.split(',')line[0] = sex_map[line[0]]data_X.append(line[:-1])data_Y.append(line[-1:]) # 轉(zhuǎn)換為nparray data_X = np.array(data_X, dtype='float32') data_Y = np.array(data_Y, dtype='float32') # 檢查大小 print('data shape', data_X.shape, data_Y.shape) print('data_x shape[1]', data_X.shape[1]) # 歸一化 for i in range(data_X.shape[1]):_min = np.min(data_X[:, i]) # 每一列的最小值_max = np.max(data_X[:, i]) # 每一列的最大值data_X[:, i] = (data_X[:, i] - _min) / (_max - _min) # 歸一化到0-1之間import paddle import paddle.fluid as fluid from sklearn.model_selection import train_test_split# 分割訓(xùn)練集、測試集 X_train, X_test, y_train, y_test = train_test_split(data_X, # 被劃分的樣本特征集data_Y, # 被劃分的樣本標(biāo)簽test_size=0.2, # 測試集占比random_state=0) # 隨機(jī)數(shù)種子,在需要重復(fù)試驗(yàn)的時(shí)候,保證得到一組一樣的隨機(jī)數(shù)# 自定義reader,每次返回一個(gè)樣本數(shù)據(jù) def reader_creator(_X, _Y):def reader():for _x, _y in zip(_X, _Y):yield [_x, _y] # 返回Iterable對象return reader# 一個(gè)minibatch中有16個(gè)數(shù)據(jù) BATCH_SIZE = 20# 定義了用于訓(xùn)練與驗(yàn)證的數(shù)據(jù)提供器。提供器每次讀入一個(gè)大小為BATCH_SIZE的數(shù)據(jù)批次。 # BATCH_SIZE個(gè)數(shù)據(jù)項(xiàng)組成一個(gè)mini batch。 train_reader = paddle.batch(reader_creator(X_train, y_train),batch_size=BATCH_SIZE) test_reader = paddle.batch(reader_creator(X_test, y_test),batch_size=BATCH_SIZE)# # **Step2.網(wǎng)絡(luò)配置** # # **(1)網(wǎng)絡(luò)搭建**:對于線性回歸來講,它就是一個(gè)從輸入到輸出的簡單的全連接層。 # # 對于鮑魚年齡預(yù)測數(shù)據(jù)集,假設(shè)鮑魚屬性和年齡之間的關(guān)系可以被屬性間的線性組合描述。# 定義輸入的形狀和數(shù)據(jù)類型,張量變量x,表示8維的特征值 x = fluid.layers.data(name='x', shape=[8], dtype='float32')# 定義輸出的形狀和數(shù)據(jù)類型,張量y,表示目標(biāo)值 y = fluid.layers.data(name='y', shape=[1], dtype='float32')# 定義一個(gè)簡單的線性網(wǎng)絡(luò),連接輸入和輸出的全連接層 # input:輸入; # size:該層輸出單元的數(shù)目 # act:激活函數(shù) fc2 = fluid.layers.fc(input=x, size=200, bias_attr=True) drop = fluid.layers.dropout(x=fc2, dropout_prob=0.5) fc3 = fluid.layers.fc(input=drop, size=800, bias_attr=True, act='relu') drop = fluid.layers.dropout(x=fc3, dropout_prob=0.5) fc4 = fluid.layers.fc(input=drop, size=800, bias_attr=True, act='relu') drop = fluid.layers.dropout(x=fc4, dropout_prob=0.5) fc5 = fluid.layers.fc(input=drop, size=100, bias_attr=True, act='relu') y_predict = fluid.layers.fc(input=fc5, size=1, bias_attr=True, act=None)# **(2)定義損失函數(shù)** # # 此處使用均方差損失函數(shù)。 # # square_error_cost(input,lable):接受輸入預(yù)測值和目標(biāo)值,并返回方差估計(jì),即為(y-y_predict)的平方 cost = fluid.layers.square_error_cost(input=y_predict, label=y) # 求方差 avg_cost = fluid.layers.mean(cost) # 對方差求平均值,得到平均損失 # 克隆main_program得到test_program,使用參數(shù)for_test來區(qū)分該程序是用來訓(xùn)練還是用來測試,該api請?jiān)趏ptimization之前使用. test_program = fluid.default_main_program().clone(for_test=True) # **(3)定義優(yōu)化函數(shù)**# 此處使用的是隨機(jī)梯度下降。 optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.0001) opts = optimizer.minimize(avg_cost)# 完成上述定義,也就是完成了 fluid.default_main_program 的構(gòu)建過程,fluid.default_main_program 中承載著神經(jīng)網(wǎng)絡(luò)模型,前向反向計(jì)算,以及優(yōu)化算法對網(wǎng)絡(luò)中可學(xué)習(xí)參數(shù)的更新。# **fluid的設(shè)計(jì)思想:** # 用戶編寫一段python程序,通過調(diào)用 Fluid 提供的算子,向一段 Program 中添加**變量**以及**對變量的操作**(Operators )。 # # 用戶**只需要描述核心的前向計(jì)算**,不需要關(guān)心反向計(jì)算、分布式下以及異構(gòu)設(shè)備下如何計(jì)算。 # # Fluid 的 Program 的形式上類似一段 C++ 或 Java 程序。 # # 包含: # # 1.本地變量的定義 # # 2.一系列的operator # # # **用戶完成網(wǎng)絡(luò)定義后,一段 Fluid 程序中通常存在 2 段 Program:** # # 1.**fluid.default_startup_program**:定義了創(chuàng)建模型參數(shù),輸入輸出,以及模型中可學(xué)習(xí)參數(shù)的初始化等各種操作 # # default_startup_program 可以由框架自動(dòng)生成,使用時(shí)無需顯示地創(chuàng)建 # # # 2.**fluid.default_main_program** :定義了神經(jīng)網(wǎng)絡(luò)模型,前向反向計(jì)算,以及優(yōu)化算法對網(wǎng)絡(luò)中可學(xué)習(xí)參數(shù)的更新 # # 使用Fluid的核心就是構(gòu)建起 default_main_program# # **Step3.網(wǎng)絡(luò)訓(xùn)練 & Step4.網(wǎng)絡(luò)評估**# **(1)創(chuàng)建Executor** # # 首先定義運(yùn)算場所 fluid.CPUPlace()和 fluid.CUDAPlace(0)分別表示運(yùn)算場所為CPU和GPU # # Executor:接收傳入的program,通過run()方法運(yùn)行program。# use_cuda為False,表示運(yùn)算場所為CPU;use_cuda為True,表示運(yùn)算場所為GPU use_cuda = False place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()# 創(chuàng)建一個(gè)Executor實(shí)例exe exe = fluid.Executor(place)# 正式進(jìn)行網(wǎng)絡(luò)訓(xùn)練前,需先執(zhí)行參數(shù)初始化 exe.run(fluid.default_startup_program())# **(2)定義輸入數(shù)據(jù)維度** # # DataFeeder負(fù)責(zé)將數(shù)據(jù)提供器(train_reader,test_reader)返回的數(shù)據(jù)轉(zhuǎn)成一種特殊的數(shù)據(jù)結(jié)構(gòu),使其可以輸入到Executor中。 # # feed_list設(shè)置向模型輸入的向變量表或者變量表名# In[ ]:# 告知網(wǎng)絡(luò)傳入的數(shù)據(jù)分為兩部分,第一部分是x值,第二部分是y值 feeder = fluid.DataFeeder(place=place, feed_list=[x, y])# **(3)定義繪制訓(xùn)練過程的損失值變化趨勢的方法draw_train_process**# In[ ]: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()# **(4)訓(xùn)練并保存模型** # # Executor接收傳入的program,并根據(jù)feed map(輸入映射表)和fetch_list(結(jié)果獲取表) 向program中添加feed operators(數(shù)據(jù)輸入算子)和fetch operators(結(jié)果獲取算子)。 feed map為該program提供輸入數(shù)據(jù)。fetch_list提供program訓(xùn)練結(jié)束后用戶預(yù)期的變量。 # # 使用feed方式送入訓(xùn)練數(shù)據(jù),先將reader數(shù)據(jù)轉(zhuǎn)換為PaddlePaddle可識別的Tensor數(shù)據(jù),傳入執(zhí)行器進(jìn)行訓(xùn)練。 # # 注:enumerate() 函數(shù)用于將一個(gè)可遍歷的數(shù)據(jù)對象(如列表、元組或字符串)組合為一個(gè)索引序列,同時(shí)列出數(shù)據(jù)和數(shù)據(jù)下標(biāo)# In[ ]:# 訓(xùn)練輪數(shù):所有訓(xùn)練數(shù)據(jù)的一個(gè)前向傳遞和一個(gè)后向傳遞為一輪 EPOCH_NUM = 100 # 模型保存路徑 model_save_dir = "/home/aistudio/work/fit_a_line.inference.model"for pass_id in range(EPOCH_NUM): # 訓(xùn)練EPOCH_NUM輪# 開始訓(xùn)練for batch_id, data in enumerate(train_reader()): # 遍歷train_reader迭代器train_cost = exe.run(program=fluid.default_main_program(), # 運(yùn)行主程序feed=feeder.feed(data), # 喂入一個(gè)batch的訓(xùn)練數(shù)據(jù)fetch_list=[avg_cost]) # fetch 誤差、準(zhǔn)確率,fetch_list中設(shè)置要獲取的值if batch_id % 100 == 0:print("Pass:%d, Cost:%0.5f" % (pass_id, train_cost[0])) # 每訓(xùn)練100次,打印一次平均損失值iter = iter + 1iters.append(iter)train_costs.append(train_cost[0])# 開始驗(yàn)證,并輸出驗(yàn)證集經(jīng)過一輪的平均損失test_costs = []for batch_id, data in enumerate(test_reader()): # 遍歷test_reader迭代器test_cost = exe.run(program=test_program, # 運(yùn)行測試programfeed=feeder.feed(data), # 喂入一個(gè)batch的測試數(shù)據(jù)fetch_list=[avg_cost]) # fetch均方誤差,fetch_list中設(shè)置要獲取的值test_costs.append(test_cost[0])test_cost = (sum(test_costs) / len(test_costs)) # 每輪的平均誤差print('Test:%d, Cost:%0.5f' % (pass_id, test_cost)) # 打印平均損失# 保存模型# 如果保存路徑不存在就創(chuàng)建 if not os.path.exists(model_save_dir):os.makedirs(model_save_dir) print('save models to %s' % (model_save_dir))# 保存訓(xùn)練參數(shù)到指定路徑中,構(gòu)建一個(gè)專門用預(yù)測的program fluid.io.save_inference_model(model_save_dir, # 保存預(yù)測model的路徑['x'], # 預(yù)測需要 feed 的數(shù)據(jù)[y_predict], # 保存預(yù)測結(jié)果的變量exe) # exe 保存 inference model # 繪制訓(xùn)練過程,損失隨迭代次數(shù)的變化 draw_train_process(iters, train_costs)# # **Step5.模型預(yù)測** # **(1)創(chuàng)建預(yù)測用的Executor**# In[ ]:infer_exe = fluid.Executor(place) # 創(chuàng)建推測用的executor inference_scope = fluid.core.Scope() # Scope指定作用域# **(2)可視化真實(shí)值與預(yù)測值方法定義** def draw_infer_result(groud_truths, infer_results):title = 'abalone'plt.title(title, fontsize=24)x = np.arange(1, 20)y = xplt.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()# **(3)開始預(yù)測** # # 通過fluid.io.load_inference_model,預(yù)測器會從params_dirname中讀取已經(jīng)訓(xùn)練好的模型,來對從未遇見過的數(shù)據(jù)進(jìn)行預(yù)測。with fluid.scope_guard(inference_scope): # 修改全局/默認(rèn)作用域(scope), 運(yùn)行時(shí)中的所有變量都將分配給新的scope。# 從指定目錄中加載預(yù)測模型[inference_program, # 預(yù)測用的programfeed_target_names, # 一個(gè)str列表,它包含需要在預(yù)測 Program 中提供數(shù)據(jù)的變量的名稱。fetch_targets] = fluid.io.load_inference_model( # fetch_targets: 從中可以得到預(yù)測結(jié)果。model_save_dir, # model_save_dir:模型保存路徑infer_exe) # infer_exe: 預(yù)測用executor# 獲取預(yù)測數(shù)據(jù)INFER_BATCH_SIZE = 10infer_reader = paddle.batch(reader_creator(X_test, y_test), batch_size=INFER_BATCH_SIZE)# 從infer_reader中分割xinfer_data = next(infer_reader())infer_x = np.array([data[0] for data in infer_data]).astype("float32")infer_y = np.array([data[1] for data in infer_data]).astype("float32")results = infer_exe.run(inference_program, # 預(yù)測模型feed={feed_target_names[0]: np.array(infer_x)}, # 喂入要預(yù)測的x值fetch_list=fetch_targets) # 得到推測結(jié)果infer_results = [] # 預(yù)測值groud_truths = [] # 真實(shí)值sum_cost = 0for i in range(INFER_BATCH_SIZE):infer_result = results[0][i] # 經(jīng)過預(yù)測后的值ground_truth = infer_y[i] # 真實(shí)值infer_results.append(infer_result)groud_truths.append(ground_truth)print("No.%d: infer result is %.2f,ground truth is %.2f" % (i, infer_result, ground_truth))cost = np.power(infer_result - ground_truth, 2)sum_cost += costprint("平均誤差為:", sum_cost / INFER_BATCH_SIZE)draw_infer_result(groud_truths, infer_results)結(jié)果:
總結(jié)
- 上一篇: 基于PaddlePaddle框架的BP神
- 下一篇: 奇瑞鲍思语:未来新能源小车出行发展潜力巨