> 原文博客:Doi技術團隊
鏈接地址:https://blog.doiduoyi.com/authors/1584446358138
初心:記錄優秀的Doi技術團隊學習經歷
*本篇文章基於 PaddlePaddle 0.11.0、Python 2.7
數據集的介紹¶
如題目所示,本次訓練使用到的是MNIST數據庫的手寫數字,這個數據集包含60,000個示例的訓練集以及10,000個示例的測試集.圖片是28x28的像素矩陣,標籤則對應着0~9的10個數字。每張圖片都經過了大小歸一化和居中處理.該數據集的圖片是一個黑白的單通道圖片,其中圖片如下:

該數據集非常小,很適合圖像識別的入門使用,該數據集一共有4個文件,分別是訓練數據和其對應的標籤,測試數據和其對應的標籤.文件如表所示:
|文件名稱 |大小|說明|
| :—: |:—:| :—:|
|train-images-idx3-ubyte|9.9M|訓練數據圖片,60,000條數據|
|train-labels-idx1-ubyte|28.9K|訓練數據標籤,60,000條數據|
|t10k-images-idx3-ubyte|1.6M|測試數據圖片,10,000條數據|
|t10k-labels-idx1-ubyte|4.5K|測試數據標籤,10,000條數據|
這個數據集針對170多M的CIFAR數據集來說,實在是小太多了.這使得我們訓練起來非常快,這能一下子激發開發者的興趣.
在訓練時,開發者不需要單獨去下載該數據集,PaddlePaddle已經幫我們封裝好了,在我們調用paddle.dataset.mnist的時候,會自動在下載到緩存目錄/home/username/.cache/paddle/dataset/mnist下,當以後再使用的時候,可以直接在緩存中獲取,就不會去下載了。
定義神經網絡¶
我們這次使用的是卷積神經網絡LeNet-5,官方一共提供了3個分類器,分別是Softmax迴歸,多層感知器,卷積神經網絡LeNet-5,在圖像識別問題上,一直是使用卷積神經網絡較多。我們創建一個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
開始訓練模型¶
我們創建一個train.py的Python文件來做訓練模型。
導入依賴包¶
首先要先導入依賴包,其中就包含了最重要的PaddlePaddle的V2包
# encoding:utf-8
import os
import sys
import paddle.v2 as paddle
from cnn import convolutional_neural_network
初始化Paddle¶
然後我們創建一個類,再在類中創建一個初始化函數,在初始化函數中來初始化我們的PaddlePaddle,在初始化PaddlePaddle的時候,就要指定是否使用GPU來訓練我們的模型,同時使用多少個線程來訓練。
class TestMNIST:
def __init__(self):
# 該模型運行在CUP上,CUP的數量爲2
paddle.init(use_gpu=False, trainer_count=2)
獲取訓練器¶
通過上面一步獲取的分類器和圖片的標籤來生成一個損失函數,通過損失函數就可以創建訓練參數了。
之後也要創建一個優化方法,這個優化方法是定義學習率等等在訓練中的處理。
最後通過訓練參數,優化方法,損失函數這3個參數創建訓練器
# *****************獲取訓練器********************************
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)
"""
定義優化方法
learning_rate 迭代的速度
momentum 跟前面動量優化的比例
regularzation 正則化,防止過擬合
:leng re
"""
optimizer = paddle.optimizer.Momentum(learning_rate=0.1 / 128.0,
momentum=0.9,
regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128))
'''
創建訓練器
cost 損失函數
parameters 訓練參數,可以通過創建,也可以使用之前訓練好的參數
update_equation 優化方法
'''
trainer = paddle.trainer.SGD(cost=cost,
parameters=parameters,
update_equation=optimizer)
return trainer
開始訓練¶
最後就可以的開始訓練了,通過上一步得到的訓練器開始訓練,訓練的時候要用到3個參數.
第一個是訓練數據,這個訓練數據就是我們的MNIST數據集.
第二個是訓練的輪數,表示我們要訓練多少輪,次數越多準確率越高,最終會穩定在一個固定的準確率上.
第三個是訓練過程中的一些事件處理,比如會在每個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}
使用參數預測¶
我們創建一個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
所有代碼¶
cnn.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)
"""
定義優化方法
learning_rate 迭代的速度
momentum 跟前面動量優化的比例
regularzation 正則化,防止過擬合
:leng re
"""
optimizer = paddle.optimizer.Momentum(learning_rate=0.1 / 128.0,
momentum=0.9,
regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128))
'''
創建訓練器
cost 分類器
parameters 訓練參數,可以通過創建,也可以使用之前訓練好的參數
update_equation 優化方法
'''
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)
上一章:《我的PaddlePaddle學習之路》筆記一——PaddlePaddle的安裝¶
下一章:《我的PaddlePaddle學習之路》筆記三——CIFAR彩色圖像識別¶
項目代碼¶
GitHub地址:https://github.com/yeyupiaoling/LearnPaddle
參考資料¶
- http://paddlepaddle.org/
- http://yann.lecun.com/exdb/mnist/