前言
最近在學習百度PaddlePaddle飛漿深度學習框架,做的第一個例子就是房屋價格預測。儘管官方在實例代碼中做了些講解,但是仍然有很多沒有照顧到的地方。下面,我將通過這個例子,帶大家掌握這個模型。
項目結構
模型:
加載數據
#每次緩存500個數據
BUF_SIZE=500
#每20個組成一個訓練批次
BATCH_SIZE=20
#一次緩存500個數據,其中每次讀取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
)
代碼解析:
- paddle.reader.shuffle(reader,buf_size)作用:將reader中的數據讀取到緩衝區,讀取數據個數是buf_size。
- paddle.batch(data,batch_size) 數據打包器,將shuffle方法讀取的數據按照batch_size大小,進行打包。上述例子中,共有404個訓練數據,batch_size=20,共可分得21份(404/20)。
定義模型結構
#定義輸入輸出變量
x = fluid.layers.data(name='x',shape=[13],dtype='float32')
y = fluid.layers.data(name='y',shape=[1],dtype='float32')
y_predict = fluid.layers.fc(input=x,size=1,act=None)#全連接層。
#定義損失值計算方式,這裏使用的是平方差損失函數
cost = fluid.layers.square_error_cost(input=y,label=y_predict)
avg_cost = fluid.layers.mean(cost)
#定義優化器,這裏使用隨機梯度下降優化器
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01)
opts = optimizer.minimize(avg_cost)
#克隆上述過程。
test_program = fluid.default_main_program().clone(for_test=True)
#創建CPU解釋器
place = fluid.CPUPlace()
exe = fluid.Executor(place)#創建執行器
#初始化參數
exe.run(fluid.default_startup_program())
#向模型輸入變量,轉化成一種特殊的數據結構,可以輸入到Executor
feeder = fluid.DataFeeder(place=place,feed_list=[x,y])
代碼解析:
- fluid.layers.data(name,shape,dtype)創建一個全局變量,也可以理解爲一個佔位符,在訓練模型得時候通過name進行數據賦值。shape是變量得形狀,dtype是該變量得數據類型。
- fluid.layers.fc(input,size,act)神經網絡中的全連接層,在此例子中也是作爲預測結果得輸出。size是改連接層大小,act是用於輸出得激活函數。由於我們最終需要預測的是房價,所以這裏size值爲1.
- fluid.layers.square_error_cost(input,label)預測值和準確值的方差估計,作爲計算誤差的一種方式。Out=(input−label)²
- fluid.layers.mean(data) paddlepaddle框架自帶的取平均值函數,返回值是data數據的平均值,這裏用來計算每一批數據訓練所得誤差的平均值。
- fluid.optimizer.SGDOptimizer(learning_rate)隨機梯度下降優化器,參數是學習率。
- optimizer.minimize()爲網絡添加反向計算過程,並根據反向計算所得的梯度,最小化網絡損失值loss。也就是更新模型中的W權值。
- fluid.default_main_program().clone(for_test=True)paddle框架採取類似於流程圖的形式。program會記錄用戶定義的操作。這裏將用戶操作進行賦值,用於之後測試。
- fluid.CPUPlace()指定一個解釋器,我這裏指定的是CPU,當然也可以指定GPU。
- fluid.Executor(place)創建執行器,這個執行器用於執行program。
- exe.run(fluid.default_startup_program())執行program。
- fluid.DataFeeder()向模型輸入變量,轉化成一種特殊的數據結構,可以輸入到Executor。
訓練過程可視化
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()
代碼解析:
- 這裏定義一個方法,參數分別是迭代次數和誤差值。這裏具體涉及到matplotlib的知識,大家可以參考
- matplotlib畫圖教程系列之-折線圖
訓練模型
EPOCH_NUM = 30
for pass_id in range(EPOCH_NUM):#遍歷數,也就是訓練次數
trian_cost=0
for batch_id,data in enumerate(train_reader()):
train_cost = exe.run(program=fluid.default_main_program(),
feed=feeder.feed(data),#喂數據#這裏對比之前的例子feed={'x':x,'y':y}
fetch_list=[avg_cost])#輸出
if batch_id % 40 ==0:#這裏只是batch_id==0時才觸發。
print("Pass:%d,Cost:%0.5f" %(pass_id,train_cost[0][0]))
iter = iter+BATCH_SIZE#記錄訓練次數,用作畫圖
iters.append(iter)
train_costs.append(train_cost[0][0])#將損失值保存下來,用於畫圖
test_cost = 0
for batch_id,data in enumerate(test_reader()):
test_cost = exe.run(program=test_program,
feed=feeder.feed(data),
fetch_list=[avg_cost])
print('Test:%d,Cost:%0.5f' % (pass_id,test_cost[0][0]))
代碼解析:
- EPOCH_NUM 定義訓練輪次。
- enumerate(train_reader())從之前獲取的數據集中,將鍵和值分別的遍歷出來。爲何這裏使用train_reader()而不是train_reader,請看這篇文章:今天終於弄明白了python迭代器是什麼
- exe.run(program,feed,fetch_list)program 這裏使用的是default_main_program(),這個program存儲着變量和算子。feed是用來傳入參數。這裏使用的是feeder.feed(data)傳入數據。目的是將數據轉化爲一種特殊的結構。fetch_list填入要輸出的值。
保存模型
mode_save_dir="model/house_bosdun.model"
if not os.path.exists(mode_save_dir):#路徑不存在創建路徑
os.makedirs(mode_save_dir)
print('save models to %s '% (mode_save_dir))
fluid.io.save_inference_model(mode_save_dir,
['x'],
[y_predict],
exe)
代碼詳情:
- save_inference_model(dirname,feeded_var_names,target_vars, executor,)第一個參數是保存地址,第二個參數是所有輸入變量的名字,第三個參數是包含所有輸出變量的名字,第四個是用於保存預測模型的執行器
模型導入
infer_exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()
with fluid.scope_guard(inference_scope):#切換作用域
[inference_program,
feed_target_names,
fetch_targets] = fluid.io.load_inference_model(mode_save_dir,infer_exe)#參數1地址,參數2執行器(執行引擎)
infer_reader = paddle.batch(paddle.dataset.uci_housing.test(),batch_size=200)
代碼詳情:
- with fluid.scope_guard(inference_scope) 切換作用域,這裏切換作用域的原因:防止創建的變量污染全局。說白了,就是爲了使變量爲局部變量。
- fluid.io.load_inference_model(mode_save_dir,infer_exe)
參數1模型地址,參數2執行器(執行引擎)。返回的值是, 返回參數1:加載propram(之前描述的程序),參數2:所需要提供的變量名稱,參數3:所有輸出變量。
完整的代碼我就不放了,與官方的基本一致。這裏主要是更加詳細解釋一下一些方法的用法。覺得對你有幫助的話,點個👍吧。