來源:百度PaddlePaddle
不久之前,機器之心聯(lián)合百度推出 PaddlePaddle 專欄,為想要學習這一平臺的技術人員推薦相關教程與資源。在框架解析和安裝教程的介紹之后,本次專欄將教你如何在 PaddlePaddle 上實現 MNIST 手寫數字識別。
目錄
數據集的介紹
定義神經網絡
開始訓練模型
導入依賴包
初始化 Paddle
獲取訓練器
開始訓練
使用參數預測
初始化 PaddlePaddle
獲取訓練好的參數
讀取圖片
開始預測
所有代碼
項目代碼
參考閱讀
數據集的介紹
如題目所示, 本次訓練使用到的是 MNIST 數據庫的手寫數字, 這個數據集包含 60,000 個示例的訓練集以及 10,000 個示例的測試集. 圖片是 28x28 的像素矩陣,標簽則對應著 0~9 的 10 個數字。每張圖片都經過了大小歸一化和居中處理. 該數據集的圖片是一個黑白的單通道圖片, 其中圖片如下:
該數據集非常小, 很適合圖像識別的入門使用, 該數據集一共有 4 個文件, 分別是訓練數據和其對應的標簽, 測試數據和其對應的標簽. 文件如表所示:
這個數據集針對 170 多 M 的 CIFAR 數據集來說, 實在是小太多了. 這使得我們訓練起來非??? 這能一下子激發(fā)開發(fā)者的興趣。
在訓練時, 開發(fā)者不需要單獨去下載該數據集,PaddlePaddle 已經幫我們封裝好了, 在我們調用 paddle.dataset.mnist 的時候, 會自動在下載到緩存目錄/home/username/.cache/paddle/dataset/mnist 下, 當以后再使用的時候, 可以直接在緩存中獲取, 就不會去下載了。
定義神經網絡
我們這次使用的是卷積神經網絡 LeNet-5,官方一共提供了 3 個分類器,分別是 Softmax 回歸,多層感知器,卷積神經網絡 LeNet-5,在圖像識別問題上,一直是使用卷積神經網絡較多。我們創(chuàng)建一個 cnn.py 的 Python 文件來定義一個 LeNet-5 神經網絡,代碼如下:
# coding=utf-8
import paddle.v2 as paddle
# 卷積神經網絡 LeNet-5, 獲取分類器
def convolutional_neural_network():
# 定義數據模型, 數據大小是 28*28, 即 784
img = paddle.layer.data(name='pixel',
type=paddle.data_type.dense_vector(784))
# 第一個卷積--池化層
conv_pool_1 = paddle.networks.simple_img_conv_pool(input=img,
filter_size=5,
num_filters=20,
num_channel=1,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
# 第二個卷積--池化層
conv_pool_2 = paddle.networks.simple_img_conv_pool(input=conv_pool_1,
filter_size=5,
num_filters=50,
num_channel=20,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
# 以 softmax 為激活函數的全連接輸出層,輸出層的大小必須為數字的個數 10
predict = paddle.layer.fc(input=conv_pool_2,
size=10,
act=paddle.activation.Softmax())
return predict
開始訓練模型
我們創(chuàng)建一個 train.py 的 Python 文件來做訓練模型。
導入依賴包
首先要先導入依賴包, 其中就包含了最重要的 PaddlePaddle 的 V2 包
# encoding:utf-8
import os
import sys
import paddle.v2 as paddle
from cnn import convolutional_neural_network
初始化 Paddle
然后我們創(chuàng)建一個類, 再在類中創(chuàng)建一個初始化函數, 在初始化函數中來初始化我們的 PaddlePaddle,在初始化 PaddlePaddle 的時候,就要指定是否使用 GPU 來訓練我們的模型,同時使用多少個線程來訓練。
class TestMNIST:
def __init__(self):
# 該模型運行在 CUP 上,CUP 的數量為 2
paddle.init(use_gpu=False, trainer_count=2)
獲取訓練器
通過上面一步獲取的分類器和圖片的標簽來生成一個損失函數, 通過損失函數就可以創(chuàng)建訓練參數了。
之后也要創(chuàng)建一個優(yōu)化方法,這個優(yōu)化方法是定義學習率等等在訓練中的處理。
最后通過訓練參數,優(yōu)化方法,損失函數這 3 個參數創(chuàng)建訓練器
# *****************獲取訓練器********************************
def get_trainer(self):
# 獲取分類器
out = convolutional_neural_network()
# 定義標簽
label = paddle.layer.data(name='label',
type=paddle.data_type.integer_value(10))
# 獲取損失函數
cost = paddle.layer.classification_cost(input=out, label=label)
# 獲取參數
parameters = paddle.parameters.create(layers=cost)
'''
定義優(yōu)化方法
learning_rate 迭代的速度
momentum 跟前面動量優(yōu)化的比例
regularzation 正則化, 防止過擬合
:leng re
'''
optimizer = paddle.optimizer.Momentum(learning_rate=0.1 / 128.0,
momentum=0.9,
regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128))
'''
創(chuàng)建訓練器
cost 損失函數
parameters 訓練參數, 可以通過創(chuàng)建, 也可以使用之前訓練好的參數
update_equation 優(yōu)化方法
'''
trainer = paddle.trainer.SGD(cost=cost,
parameters=parameters,
update_equation=optimizer)
return trainer
開始訓練
最后就可以的開始訓練了, 通過上一步得到的訓練器開始訓練, 訓練的時候要用到 3 個參數.
第一個是訓練數據, 這個訓練數據就是我們的 MNIST 數據集。
第二個是訓練的輪數, 表示我們要訓練多少輪, 次數越多準確率越高, 最終會穩(wěn)定在一個固定的準確率上。
第三個是訓練過程中的一些事件處理, 比如會在每個 batch 打印一次日志, 在每個 pass 之后保存一下參數和測試一下測試數據集的預測準確率。
# *****************開始訓練********************************
def start_trainer(self):
# 獲取訓練器
trainer = self.get_trainer()
# 定義訓練事件
def event_handler(event):
lists = []
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 100 == 0:
print '\nPass %d, Batch %d, Cost %f, %s' % (
event.pass_id, event.batch_id, event.cost, event.metrics)
else:
sys.stdout.write('.')
sys.stdout.flush()
if isinstance(event, paddle.event.EndPass):
# 保存訓練好的參數
model_path = '../model'
if not os.path.exists(model_path):
os.makedirs(model_path)
with open(model_path '/model.tar', 'w') as f:
trainer.save_parameter_to_tar(f=f)
result = trainer.test(reader=paddle.batch(paddle.dataset.mnist.test(), batch_size=128))
print '\nTest with Pass %d, Cost %f, %s\n' % (event.pass_id, result.cost, result.metrics)
lists.append((event.pass_id, result.cost, result.metrics['classification_error_evaluator']))
# 獲取數據
reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=20000),
batch_size=128)
'''
開始訓練
reader 訓練數據
num_passes 訓練的輪數
event_handler 訓練的事件, 比如在訓練的時候要做一些什么事情
'''
trainer.train(reader=reader,
num_passes=100,
event_handler=event_handler)
然后在 main 入口中調用我們的訓練函數, 就可以訓練了
if __name__ == '__main__':
testMNIST = TestMNIST()
# 開始訓練
testMNIST.start_trainer()
在訓練過程中會輸出這樣的日志:
Pass 0, Batch 0, Cost 2.991905, {'classification_error_evaluator': 0.859375}
...................................................................................................
Pass 0, Batch 100, Cost 0.891881, {'classification_error_evaluator': 0.3046875}
...................................................................................................
Pass 0, Batch 200, Cost 0.309183, {'classification_error_evaluator': 0.0859375}
...................................................................................................
Pass 0, Batch 300, Cost 0.289464, {'classification_error_evaluator': 0.078125}
...................................................................................................
Pass 0, Batch 400, Cost 0.131645, {'classification_error_evaluator': 0.03125}
....................................................................
Test with Pass 0, Cost 0.117626, {'classification_error_evaluator': 0.03790000081062317}
使用參數預測
我們創(chuàng)建一個 infer.py 的 Python 文件,用來做模型預測的。
初始化 PaddlePaddle
在預測的時候也是要初始化 PaddlePaddle 的
class TestMNIST:
def __init__(self):
# 該模型運行在 CUP 上,CUP 的數量為 2
paddle.init(use_gpu=False, trainer_count=2)
獲取訓練好的參數
在訓練的時候, 我們在 pass 訓練結束后都會保存他的參數, 保存這些參數我們現在就可以使用它來預測了
# *****************獲取參數********************************
def get_parameters(self):
with open('../model/model.tar', 'r') as f:
parameters = paddle.parameters.Parameters.from_tar(f)
return parameters
讀取圖片
在使用圖片進行預測時,我們要對圖片進行處理,,處理成跟訓練的圖片一樣,28*28 的灰度圖,最后圖像會轉化成一個浮點數組。
# *****************獲取你要預測的參數********************************
def get_TestData(self):
def load_images(file):
# 對圖進行灰度化處理
im = Image.open(file).convert('L')
# 縮小到跟訓練數據一樣大小
im = im.resize((28, 28), Image.ANTIALIAS)
im = np.array(im).astype(np.float32).flatten()
im = im / 255.0
return im
test_data = []
test_data.append((load_images('../images/infer_3.png'),))
return
開始預測
通過傳入分類器,訓練好的參數,預測數據這個 3 個參數就可以進行預測了。這個分類器就是我們之前定義的。
# *****************使用訓練好的參數進行預測********************************
def to_prediction(self, out, parameters, test_data):
# 開始預測
probs = paddle.infer(output_layer=out,
parameters=parameters,
input=test_data)
# 處理預測結果并打印
lab = np.argsort(-probs)
print '預測結果為: %d' % lab[0][0]
在 main 入口中調用預測函數
if __name__ == '__main__':
testMNIST = TestMNIST()
out = convolutional_neural_network()
parameters = testMNIST.get_parameters()
test_data = testMNIST.get_TestData()
# 開始預測
testMNIST.to_prediction(out=out, parameters=parameters, test_data=test_data)
輸出的預測結果是:
預測結果為: 3
所有代碼
infer.py 代碼:
# coding=utf-8
import paddle.v2 as paddle
# 卷積神經網絡 LeNet-5, 獲取分類器
def convolutional_neural_network():
# 定義數據模型, 數據大小是 28*28, 即 784
img = paddle.layer.data(name='pixel',
type=paddle.data_type.dense_vector(784))
# 第一個卷積--池化層
conv_pool_1 = paddle.networks.simple_img_conv_pool(input=img,
filter_size=5,
num_filters=20,
num_channel=1,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
# 第二個卷積--池化層
conv_pool_2 = paddle.networks.simple_img_conv_pool(input=conv_pool_1,
filter_size=5,
num_filters=50,
num_channel=20,
pool_size=2,
pool_stride=2,
act=paddle.activation.Relu())
# 以 softmax 為激活函數的全連接輸出層,輸出層的大小必須為數字的個數 10
predict = paddle.layer.fc(input=conv_pool_2,
size=10,
act=paddle.activation.Softmax())
return predict
train.py 代碼:
# encoding:utf-8
import os
import sys
import paddle.v2 as paddle
from cnn import convolutional_neural_network
class TestMNIST:
def __init__(self):
# 該模型運行在 CUP 上,CUP 的數量為 2
paddle.init(use_gpu=False, trainer_count=2)
# *****************獲取訓練器********************************
def get_trainer(self):
# 獲取分類器
out = convolutional_neural_network()
# 定義標簽
label = paddle.layer.data(name='label',
type=paddle.data_type.integer_value(10))
# 獲取損失函數
cost = paddle.layer.classification_cost(input=out, label=label)
# 獲取參數
parameters = paddle.parameters.create(layers=cost)
'''
定義優(yōu)化方法
learning_rate 迭代的速度
momentum 跟前面動量優(yōu)化的比例
regularzation 正則化, 防止過擬合
:leng re
'''
optimizer = paddle.optimizer.Momentum(learning_rate=0.1 / 128.0,
momentum=0.9,
regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128))
'''
創(chuàng)建訓練器
cost 分類器
parameters 訓練參數, 可以通過創(chuàng)建, 也可以使用之前訓練好的參數
update_equation 優(yōu)化方法
'''
trainer = paddle.trainer.SGD(cost=cost,
parameters=parameters,
update_equation=optimizer)
return trainer
# *****************開始訓練********************************
def start_trainer(self):
# 獲取訓練器
trainer = self.get_trainer()
# 定義訓練事件
def event_handler(event):
lists = []
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 100 == 0:
print '\nPass %d, Batch %d, Cost %f, %s' % (
event.pass_id, event.batch_id, event.cost, event.metrics)
else:
sys.stdout.write('.')
sys.stdout.flush()
if isinstance(event, paddle.event.EndPass):
# 保存訓練好的參數
model_path = '../model'
if not os.path.exists(model_path):
os.makedirs(model_path)
with open(model_path '/model.tar', 'w') as f:
trainer.save_parameter_to_tar(f=f)
# 使用測試進行測試
result = trainer.test(reader=paddle.batch(paddle.dataset.mnist.test(), batch_size=128))
print '\nTest with Pass %d, Cost %f, %s\n' % (event.pass_id, result.cost, result.metrics)
lists.append((event.pass_id, result.cost, result.metrics['classification_error_evaluator']))
# 獲取數據
reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=20000),
batch_size=128)
'''
開始訓練
reader 訓練數據
num_passes 訓練的輪數
event_handler 訓練的事件, 比如在訓練的時候要做一些什么事情
'''
trainer.train(reader=reader,
num_passes=100,
event_handler=event_handler)
if __name__ == '__main__':
testMNIST = TestMNIST()
# 開始訓練
testMNIST.start_trainer()
infer.py 代碼:
# encoding:utf-8
import numpy as np
import paddle.v2 as paddle
from PIL import Image
from cnn import convolutional_neural_network
class TestMNIST:
def __init__(self):
# 該模型運行在CUP上,CUP的數量為2
paddle.init(use_gpu=False, trainer_count=2)
# *****************獲取參數********************************
def get_parameters(self):
with open('../model/model.tar', 'r') as f:
parameters = paddle.parameters.Parameters.from_tar(f)
return parameters
# *****************獲取你要預測的參數********************************
def get_TestData(self ,path):
def load_images(file):
# 對圖進行灰度化處理
im = Image.open(file).convert('L')
# 縮小到跟訓練數據一樣大小
im = im.resize((28, 28), Image.ANTIALIAS)
im = np.array(im).astype(np.float32).flatten()
im = im / 255.0
return im
test_data = []
test_data.append((load_images(path),))
return test_data
# *****************使用訓練好的參數進行預測********************************
def to_prediction(self, out, parameters, test_data):
# 開始預測
probs = paddle.infer(output_layer=out,
parameters=parameters,
input=test_data)
# 處理預測結果并打印
lab = np.argsort(-probs)
print '預測結果為: %d' % lab[0][0]
if __name__ == '__main__':
testMNIST = TestMNIST()
# 開始預測
out = convolutional_neural_network()
parameters = testMNIST.get_parameters()
test_data = testMNIST.get_TestData('../images/infer_3.png')
testMNIST.to_prediction(out=out, parameters=parameters, test_data=test_data)
項目代碼
GitHub 地址:https://github.com/yeyupiaoling/LearnPaddle
聯(lián)系客服