From 8db3055f076094d3427f51eec72b2598a06154aa Mon Sep 17 00:00:00 2001 From: "Wang,Jeff" Date: Wed, 30 May 2018 15:19:20 -0700 Subject: [PATCH] Update the book chapter: recognize digits with new api --- 02.recognize_digits/README.cn.md | 154 ++++++++++------------- 02.recognize_digits/README.md | 196 +++++++++++++----------------- 02.recognize_digits/index.cn.html | 154 ++++++++++------------- 02.recognize_digits/index.html | 196 +++++++++++++----------------- 4 files changed, 294 insertions(+), 406 deletions(-) diff --git a/02.recognize_digits/README.cn.md b/02.recognize_digits/README.cn.md index 0d4d8c4..0077676 100644 --- a/02.recognize_digits/README.cn.md +++ b/02.recognize_digits/README.cn.md @@ -129,17 +129,18 @@ PaddlePaddle在API中提供了自动加载[MNIST](http://yann.lecun.com/exdb/mni ## 配置说明 -首先,加载PaddlePaddle的V2 api包。 +首先,加载PaddlePaddle的fluid api包。 ```python -import paddle.v2 as paddle +import paddle.fluid as fluid ``` 其次,定义三个不同的分类器: - Softmax回归:只通过一层简单的以softmax为激活函数的全连接层,就可以得到分类的结果。 ```python -def softmax_regression(img): +def softmax_regression(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') predict = paddle.layer.fc(input=img, size=10, act=paddle.activation.Softmax()) @@ -148,64 +149,59 @@ def softmax_regression(img): - 多层感知器:下面代码实现了一个含有两个隐藏层(即全连接层)的多层感知器。其中两个隐藏层的激活函数均采用ReLU,输出层的激活函数用Softmax。 ```python -def multilayer_perceptron(img): +def multilayer_perceptron(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') # 第一个全连接层,激活函数为ReLU - hidden1 = paddle.layer.fc(input=img, size=128, act=paddle.activation.Relu()) + hidden = fluid.layers.fc(input=img, size=200, act='relu') # 第二个全连接层,激活函数为ReLU - hidden2 = paddle.layer.fc(input=hidden1, - size=64, - act=paddle.activation.Relu()) + hidden = fluid.layers.fc(input=hidden, size=200, act='relu') # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10 - predict = paddle.layer.fc(input=hidden2, - size=10, - act=paddle.activation.Softmax()) - return predict + prediction = fluid.layers.fc(input=hidden, size=10, act='softmax') + return prediction ``` - 卷积神经网络LeNet-5: 输入的二维图像,首先经过两次卷积层到池化层,再经过全连接层,最后使用以softmax为激活函数的全连接层作为输出层。 ```python -def convolutional_neural_network(img): +def convolutional_neural_network(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') # 第一个卷积-池化层 - conv_pool_1 = paddle.networks.simple_img_conv_pool( + conv_pool_1 = fluid.nets.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()) + act="relu") + conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) # 第二个卷积-池化层 - conv_pool_2 = paddle.networks.simple_img_conv_pool( + conv_pool_2 = fluid.nets.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()) + act="relu") # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10 - predict = paddle.layer.fc(input=conv_pool_2, - size=10, - act=paddle.activation.Softmax()) - return predict + prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax') + return prediction ``` 接着,通过`layer.data`调用来获取数据,然后调用分类器(这里我们提供了三个不同的分类器)得到分类结果。训练时,对该结果计算其损失函数,分类问题常常选择交叉熵损失函数。 ```python -# 该模型运行在单个CPU上 -paddle.init(use_gpu=False, trainer_count=1) +def train_program(): + label = fluid.layers.data(name='label', shape=[1], dtype='int64') -images = paddle.layer.data( - name='pixel', type=paddle.data_type.dense_vector(784)) -label = paddle.layer.data( - name='label', type=paddle.data_type.integer_value(10)) + # predict = softmax_regression(images) # uncomment for Softmax回归 + # predict = multilayer_perceptron() # uncomment for 多层感知器 + predict = convolutional_neural_network() # uncomment for LeNet5卷积神经网络 + cost = fluid.layers.cross_entropy(input=predict, label=label) + avg_cost = fluid.layers.mean(cost) + acc = fluid.layers.accuracy(input=predict, label=label) + return [avg_cost, acc] -# predict = softmax_regression(images) # Softmax回归 -# predict = multilayer_perceptron(images) #多层感知器 -predict = convolutional_neural_network(images) #LeNet5卷积神经网络 -cost = paddle.layer.classification_cost(input=predict, label=label) +# 该模型运行在单个CPU上 ``` 然后,指定训练相关的参数。 @@ -214,16 +210,16 @@ cost = paddle.layer.classification_cost(input=predict, label=label) - 正则化(regularization): 是防止网络过拟合的一种手段,此处采用L2正则化。 ```python -parameters = paddle.parameters.create(cost) - +# 该模型运行在单个CPU上 +use_cude = False # set to True if training with GPU +place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() optimizer = paddle.optimizer.Momentum( learning_rate=0.1 / 128.0, momentum=0.9, regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) -trainer = paddle.trainer.SGD(cost=cost, - parameters=parameters, - update_equation=optimizer) +trainer = fluid.Trainer( + train_func=train_program, place=place, optimizer=optimizer) ``` 下一步,我们开始训练过程。`paddle.dataset.movielens.train()`和`paddle.dataset.movielens.test()`分别做训练和测试数据集。这两个函数各自返回一个reader——PaddlePaddle中的reader是一个Python函数,每次调用的时候返回一个Python yield generator。 @@ -232,38 +228,18 @@ trainer = paddle.trainer.SGD(cost=cost, `batch`是一个特殊的decorator,它的输入是一个reader,输出是一个batched reader —— 在PaddlePaddle里,一个reader每次yield一条训练数据,而一个batched reader每次yield一个minibatch。 -`event_handler_plot`可以用来在训练过程中画图如下: - -![png](./image/train_and_test.png) - ```python -from paddle.v2.plot import Ploter - -train_title = "Train cost" -test_title = "Test cost" -cost_ploter = Ploter(train_title, test_title) - -step = 0 - -# event_handler to plot a figure -def event_handler_plot(event): - global step - if isinstance(event, paddle.event.EndIteration): - if step % 100 == 0: - cost_ploter.append(train_title, step, event.cost) - cost_ploter.plot() - step += 1 - if isinstance(event, paddle.event.EndPass): - # save parameters - with open('params_pass_%d.tar' % event.pass_id, 'w') as f: - trainer.save_parameter_to_tar(f) +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=500), + batch_size=64) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) - cost_ploter.append(test_title, step, result.cost) +test_reader = paddle.batch( + paddle.dataset.mnist.test(), batch_size=64) ``` `event_handler` 用来在训练过程中输出训练结果 + ```python lists = [] @@ -285,14 +261,14 @@ def event_handler(event): result.metrics['classification_error_evaluator'])) ``` +Now that we setup the event_handler and the reader, we can start training the model. `feed_order` is used to map the data dict to the train_program + ```python trainer.train( - reader=paddle.batch( - paddle.reader.shuffle( - paddle.dataset.mnist.train(), buf_size=8192), - batch_size=128), - event_handler=event_handler_plot, - num_passes=5) + num_epochs=1, + event_handler=event_handler, + reader=train_reader, + feed_order=['img', 'label']) ``` 训练过程是完全自动的,event_handler里打印的日志类似如下所示: @@ -311,27 +287,25 @@ trainer.train( ## 应用模型 -可以使用训练好的模型对手写体数字图片进行分类,下面程序展示了如何使用paddle.infer接口进行推断。 +可以使用训练好的模型对手写体数字图片进行分类,下面程序展示了如何使用 `fluid.Inferencer` 接口进行推断。 ```python -from PIL import Image -import numpy as np -import os -def load_image(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 * 2.0 - 1.0 - return im - -test_data = [] -cur_dir = os.getcwd() -test_data.append((load_image(cur_dir + '/image/infer_3.png'),)) - -probs = paddle.infer( - output_layer=predict, parameters=parameters, input=test_data) -lab = np.argsort(-probs) # probs and lab are the results of one batch data -print "Label of image/infer_3.png is: %d" % lab[0][0] +inferencer = fluid.Inferencer( + # infer_func=softmax_regression, # uncomment for softmax regression + # infer_func=multilayer_perceptron, # uncomment for MLP + infer_func=convolutional_neural_network, # uncomment for LeNet5 + param_path=params_dirname, + place=place) + +batch_size = 1 +import numpy +tensor_img = numpy.random.uniform(-1.0, 1.0, + [batch_size, 1, 28, 28]).astype("float32") + +results = inferencer.infer({'img': tensor_img}) + +print("infer results: ", results[0]) + ``` ## 总结 diff --git a/02.recognize_digits/README.md b/02.recognize_digits/README.md index 6292be0..0c15f51 100644 --- a/02.recognize_digits/README.md +++ b/02.recognize_digits/README.md @@ -129,15 +129,17 @@ PaddlePaddle provides a Python module, `paddle.dataset.mnist`, which downloads a A PaddlePaddle program starts from importing the API package: ```python -import paddle.v2 as paddle +import paddle.fluid as fluid ``` -We want to use this program to demonstrate three different classifiers, each defined as a Python function: +We want to use this program to demonstrate three different classifiers, each defined as a Python function. We need to feed image data to the classifier. +PaddlePaddle provides a special layer `layer.data` for reading data. Let us create a data layer for reading images and connect it to a classification network. - Softmax regression: the network has a fully-connection layer with softmax activation: ```python -def softmax_regression(img): +def softmax_regression(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') predict = paddle.layer.fc(input=img, size=10, act=paddle.activation.Softmax()) @@ -147,77 +149,67 @@ def softmax_regression(img): - Multi-Layer Perceptron: this network has two hidden fully-connected layers, one with ReLU and the other with softmax activation: ```python -def multilayer_perceptron(img): - hidden1 = paddle.layer.fc(input=img, size=128, act=paddle.activation.Relu()) - hidden2 = paddle.layer.fc(input=hidden1, - size=64, - act=paddle.activation.Relu()) - predict = paddle.layer.fc(input=hidden2, - size=10, - act=paddle.activation.Softmax()) - return predict +def multilayer_perceptron(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') + hidden = fluid.layers.fc(input=img, size=200, act='relu') + hidden = fluid.layers.fc(input=hidden, size=200, act='relu') + prediction = fluid.layers.fc(input=hidden, size=10, act='softmax') + return prediction ``` - Convolution network LeNet-5: the input image is fed through two convolution-pooling layers, a fully-connected layer, and the softmax output layer: ```python -def convolutional_neural_network(img): - - conv_pool_1 = paddle.networks.simple_img_conv_pool( +def convolutional_neural_network(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') + conv_pool_1 = fluid.nets.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( + act="relu") + conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) + conv_pool_2 = fluid.nets.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()) - - predict = paddle.layer.fc(input=conv_pool_2, - size=10, - act=paddle.activation.Softmax()) - return predict + act="relu") + prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax') + return prediction ``` -PaddlePaddle provides a special layer `layer.data` for reading data. Let us create a data layer for reading images and connect it to a classification network created using one of above three functions. We also need a cost layer for training the model. +Then we need to setup the the `train_program`. It takes the prediction from the classifier first. During the training, it will calculate the `avg_loss` from the prediction. ```python -paddle.init(use_gpu=False, trainer_count=1) - -images = paddle.layer.data( - name='pixel', type=paddle.data_type.dense_vector(784)) -label = paddle.layer.data( - name='label', type=paddle.data_type.integer_value(10)) - -# predict = softmax_regression(images) -# predict = multilayer_perceptron(images) # uncomment for MLP -predict = convolutional_neural_network(images) # uncomment for LeNet5 - -cost = paddle.layer.classification_cost(input=predict, label=label) +def train_program(): + label = fluid.layers.data(name='label', shape=[1], dtype='int64') + + # predict = softmax_regression(images) # uncomment for Softmax + # predict = multilayer_perceptron() # uncomment for MLP + predict = convolutional_neural_network() # uncomment for LeNet5 + cost = fluid.layers.cross_entropy(input=predict, label=label) + avg_cost = fluid.layers.mean(cost) + acc = fluid.layers.accuracy(input=predict, label=label) + return [avg_cost, acc] ``` -Now, it is time to specify training parameters. In the following `Momentum` optimizer, `momentum=0.9` means that 90% of the current momentum comes from that of the previous iteration. The learning rate relates to the speed at which the network training converges. Regularization is meant to prevent over-fitting; here we use the L2 regularization. - -```python -parameters = paddle.parameters.create(cost) +Now, we need to setup the trainer. The trainer need to take in `train_program`, `place`, and `optimizer`. +In the following `Momentum` optimizer, `momentum=0.9` means that 90% of the current momentum comes from that of the previous iteration. The learning rate relates to the speed at which the network training converges. Regularization is meant to prevent over-fitting; here we use the L2 regularization. -optimizer = paddle.optimizer.Momentum( - learning_rate=0.1 / 128.0, - momentum=0.9, - regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) + ```python + use_cude = False # set to True if training with GPU + place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() + optimizer = paddle.optimizer.Momentum( + learning_rate=0.1 / 128.0, + momentum=0.9, + regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) -trainer = paddle.trainer.SGD(cost=cost, - parameters=parameters, - update_equation=optimizer) -``` +trainer = fluid.Trainer( + train_func=train_program, place=place, optimizer=optimizer) + ``` Then we specify the training data `paddle.dataset.mnist.train()` and testing data `paddle.dataset.mnist.test()`. These two methods are *reader creators*. Once called, a reader creator returns a *reader*. A reader is a Python method, which, once called, returns a Python generator, which yields instances of data. @@ -225,35 +217,14 @@ Then we specify the training data `paddle.dataset.mnist.train()` and testing dat `batch` is a special decorator, which takes a reader and outputs a *batch reader*, which doesn't yield an instance, but a minibatch at a time. -`event_handler_plot` is used to plot a figure like below: - -![png](./image/train_and_test.png) - ```python -from paddle.v2.plot import Ploter - -train_title = "Train cost" -test_title = "Test cost" -cost_ploter = Ploter(train_title, test_title) - -step = 0 - -# event_handler to plot a figure -def event_handler_plot(event): - global step - if isinstance(event, paddle.event.EndIteration): - if step % 100 == 0: - cost_ploter.append(train_title, step, event.cost) - cost_ploter.plot() - step += 1 - if isinstance(event, paddle.event.EndPass): - # save parameters - with open('params_pass_%d.tar' % event.pass_id, 'w') as f: - trainer.save_parameter_to_tar(f) +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=500), + batch_size=64) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) - cost_ploter.append(test_title, step, result.cost) +test_reader = paddle.batch( + paddle.dataset.mnist.test(), batch_size=64) ``` `event_handler` is used to plot some text data when training. @@ -261,6 +232,9 @@ def event_handler_plot(event): ```python lists = [] +# Save the parameter into a directory. The Inferencer can load the parameters from it to do infer +params_dirname = "recognize_digits_network.inference.model" + # event handler to print the progress def event_handler(event): if isinstance(event, paddle.event.EndIteration): @@ -272,35 +246,33 @@ def event_handler(event): with open('params_pass_%d.tar' % event.pass_id, 'w') as f: trainer.save_parameter_to_tar(f) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) + result = trainer.test(reader=train_reader) print "Test 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'])) ``` +Now that we setup the event_handler and the reader, we can start training the model. `feed_order` is used to map the data dict to the train_program ```python # Train the model now trainer.train( - reader=paddle.batch( - paddle.reader.shuffle( - paddle.dataset.mnist.train(), buf_size=8192), - batch_size=128), - event_handler=event_handler_plot, - num_passes=5) + num_epochs=1, + event_handler=event_handler, + reader=train_reader, + feed_order=['img', 'label']) ``` During training, `trainer.train` invokes `event_handler` for certain events. This gives us a chance to print the training progress. -``` -# Pass 0, Batch 0, Cost 2.780790, {'classification_error_evaluator': 0.9453125} -# Pass 0, Batch 100, Cost 0.635356, {'classification_error_evaluator': 0.2109375} -# Pass 0, Batch 200, Cost 0.326094, {'classification_error_evaluator': 0.1328125} -# Pass 0, Batch 300, Cost 0.361920, {'classification_error_evaluator': 0.1015625} -# Pass 0, Batch 400, Cost 0.410101, {'classification_error_evaluator': 0.125} -# Test with Pass 0, Cost 0.326659, {'classification_error_evaluator': 0.09470000118017197} -``` + ``` + # Pass 0, Batch 0, Cost 2.780790, {'classification_error_evaluator': 0.9453125} + # Pass 0, Batch 100, Cost 0.635356, {'classification_error_evaluator': 0.2109375} + # Pass 0, Batch 200, Cost 0.326094, {'classification_error_evaluator': 0.1328125} + # Pass 0, Batch 300, Cost 0.361920, {'classification_error_evaluator': 0.1015625} + # Pass 0, Batch 400, Cost 0.410101, {'classification_error_evaluator': 0.125} + # Test with Pass 0, Cost 0.326659, {'classification_error_evaluator': 0.09470000118017197} + ``` After the training, we can check the model's prediction accuracy. @@ -315,27 +287,25 @@ Usually, with MNIST data, the softmax regression model achieves an accuracy arou ## Application -After training, users can use the trained model to classify images. The following code shows how to inference MNIST images through `paddle.infer` interface. +After training, users can use the trained model to classify images. The following code shows how to inference MNIST images through `fluid.Inferencer`. ```python -from PIL import Image -import numpy as np -import os -def load_image(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 * 2.0 - 1.0 - return im - -test_data = [] -cur_dir = os.getcwd() -test_data.append((load_image(cur_dir + '/image/infer_3.png'),)) - -probs = paddle.infer( - output_layer=predict, parameters=parameters, input=test_data) -lab = np.argsort(-probs) # probs and lab are the results of one batch data -print "Label of image/infer_3.png is: %d" % lab[0][0] +inferencer = fluid.Inferencer( + # infer_func=softmax_regression, # uncomment for softmax regression + # infer_func=multilayer_perceptron, # uncomment for MLP + infer_func=convolutional_neural_network, # uncomment for LeNet5 + param_path=params_dirname, + place=place) + +batch_size = 1 +import numpy +tensor_img = numpy.random.uniform(-1.0, 1.0, + [batch_size, 1, 28, 28]).astype("float32") + +results = inferencer.infer({'img': tensor_img}) + +print("infer results: ", results[0]) + ``` diff --git a/02.recognize_digits/index.cn.html b/02.recognize_digits/index.cn.html index 2a8fed2..33ae076 100644 --- a/02.recognize_digits/index.cn.html +++ b/02.recognize_digits/index.cn.html @@ -171,17 +171,18 @@ PaddlePaddle在API中提供了自动加载[MNIST](http://yann.lecun.com/exdb/mni ## 配置说明 -首先,加载PaddlePaddle的V2 api包。 +首先,加载PaddlePaddle的fluid api包。 ```python -import paddle.v2 as paddle +import paddle.fluid as fluid ``` 其次,定义三个不同的分类器: - Softmax回归:只通过一层简单的以softmax为激活函数的全连接层,就可以得到分类的结果。 ```python -def softmax_regression(img): +def softmax_regression(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') predict = paddle.layer.fc(input=img, size=10, act=paddle.activation.Softmax()) @@ -190,64 +191,59 @@ def softmax_regression(img): - 多层感知器:下面代码实现了一个含有两个隐藏层(即全连接层)的多层感知器。其中两个隐藏层的激活函数均采用ReLU,输出层的激活函数用Softmax。 ```python -def multilayer_perceptron(img): +def multilayer_perceptron(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') # 第一个全连接层,激活函数为ReLU - hidden1 = paddle.layer.fc(input=img, size=128, act=paddle.activation.Relu()) + hidden = fluid.layers.fc(input=img, size=200, act='relu') # 第二个全连接层,激活函数为ReLU - hidden2 = paddle.layer.fc(input=hidden1, - size=64, - act=paddle.activation.Relu()) + hidden = fluid.layers.fc(input=hidden, size=200, act='relu') # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10 - predict = paddle.layer.fc(input=hidden2, - size=10, - act=paddle.activation.Softmax()) - return predict + prediction = fluid.layers.fc(input=hidden, size=10, act='softmax') + return prediction ``` - 卷积神经网络LeNet-5: 输入的二维图像,首先经过两次卷积层到池化层,再经过全连接层,最后使用以softmax为激活函数的全连接层作为输出层。 ```python -def convolutional_neural_network(img): +def convolutional_neural_network(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') # 第一个卷积-池化层 - conv_pool_1 = paddle.networks.simple_img_conv_pool( + conv_pool_1 = fluid.nets.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()) + act="relu") + conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) # 第二个卷积-池化层 - conv_pool_2 = paddle.networks.simple_img_conv_pool( + conv_pool_2 = fluid.nets.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()) + act="relu") # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10 - predict = paddle.layer.fc(input=conv_pool_2, - size=10, - act=paddle.activation.Softmax()) - return predict + prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax') + return prediction ``` 接着,通过`layer.data`调用来获取数据,然后调用分类器(这里我们提供了三个不同的分类器)得到分类结果。训练时,对该结果计算其损失函数,分类问题常常选择交叉熵损失函数。 ```python -# 该模型运行在单个CPU上 -paddle.init(use_gpu=False, trainer_count=1) +def train_program(): + label = fluid.layers.data(name='label', shape=[1], dtype='int64') -images = paddle.layer.data( - name='pixel', type=paddle.data_type.dense_vector(784)) -label = paddle.layer.data( - name='label', type=paddle.data_type.integer_value(10)) + # predict = softmax_regression(images) # uncomment for Softmax回归 + # predict = multilayer_perceptron() # uncomment for 多层感知器 + predict = convolutional_neural_network() # uncomment for LeNet5卷积神经网络 + cost = fluid.layers.cross_entropy(input=predict, label=label) + avg_cost = fluid.layers.mean(cost) + acc = fluid.layers.accuracy(input=predict, label=label) + return [avg_cost, acc] -# predict = softmax_regression(images) # Softmax回归 -# predict = multilayer_perceptron(images) #多层感知器 -predict = convolutional_neural_network(images) #LeNet5卷积神经网络 -cost = paddle.layer.classification_cost(input=predict, label=label) +# 该模型运行在单个CPU上 ``` 然后,指定训练相关的参数。 @@ -256,16 +252,16 @@ cost = paddle.layer.classification_cost(input=predict, label=label) - 正则化(regularization): 是防止网络过拟合的一种手段,此处采用L2正则化。 ```python -parameters = paddle.parameters.create(cost) - +# 该模型运行在单个CPU上 +use_cude = False # set to True if training with GPU +place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() optimizer = paddle.optimizer.Momentum( learning_rate=0.1 / 128.0, momentum=0.9, regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) -trainer = paddle.trainer.SGD(cost=cost, - parameters=parameters, - update_equation=optimizer) +trainer = fluid.Trainer( + train_func=train_program, place=place, optimizer=optimizer) ``` 下一步,我们开始训练过程。`paddle.dataset.movielens.train()`和`paddle.dataset.movielens.test()`分别做训练和测试数据集。这两个函数各自返回一个reader——PaddlePaddle中的reader是一个Python函数,每次调用的时候返回一个Python yield generator。 @@ -274,38 +270,18 @@ trainer = paddle.trainer.SGD(cost=cost, `batch`是一个特殊的decorator,它的输入是一个reader,输出是一个batched reader —— 在PaddlePaddle里,一个reader每次yield一条训练数据,而一个batched reader每次yield一个minibatch。 -`event_handler_plot`可以用来在训练过程中画图如下: - -![png](./image/train_and_test.png) - ```python -from paddle.v2.plot import Ploter - -train_title = "Train cost" -test_title = "Test cost" -cost_ploter = Ploter(train_title, test_title) - -step = 0 - -# event_handler to plot a figure -def event_handler_plot(event): - global step - if isinstance(event, paddle.event.EndIteration): - if step % 100 == 0: - cost_ploter.append(train_title, step, event.cost) - cost_ploter.plot() - step += 1 - if isinstance(event, paddle.event.EndPass): - # save parameters - with open('params_pass_%d.tar' % event.pass_id, 'w') as f: - trainer.save_parameter_to_tar(f) +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=500), + batch_size=64) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) - cost_ploter.append(test_title, step, result.cost) +test_reader = paddle.batch( + paddle.dataset.mnist.test(), batch_size=64) ``` `event_handler` 用来在训练过程中输出训练结果 + ```python lists = [] @@ -327,14 +303,14 @@ def event_handler(event): result.metrics['classification_error_evaluator'])) ``` +Now that we setup the event_handler and the reader, we can start training the model. `feed_order` is used to map the data dict to the train_program + ```python trainer.train( - reader=paddle.batch( - paddle.reader.shuffle( - paddle.dataset.mnist.train(), buf_size=8192), - batch_size=128), - event_handler=event_handler_plot, - num_passes=5) + num_epochs=1, + event_handler=event_handler, + reader=train_reader, + feed_order=['img', 'label']) ``` 训练过程是完全自动的,event_handler里打印的日志类似如下所示: @@ -353,27 +329,25 @@ trainer.train( ## 应用模型 -可以使用训练好的模型对手写体数字图片进行分类,下面程序展示了如何使用paddle.infer接口进行推断。 +可以使用训练好的模型对手写体数字图片进行分类,下面程序展示了如何使用 `fluid.Inferencer` 接口进行推断。 ```python -from PIL import Image -import numpy as np -import os -def load_image(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 * 2.0 - 1.0 - return im - -test_data = [] -cur_dir = os.getcwd() -test_data.append((load_image(cur_dir + '/image/infer_3.png'),)) - -probs = paddle.infer( - output_layer=predict, parameters=parameters, input=test_data) -lab = np.argsort(-probs) # probs and lab are the results of one batch data -print "Label of image/infer_3.png is: %d" % lab[0][0] +inferencer = fluid.Inferencer( + # infer_func=softmax_regression, # uncomment for softmax regression + # infer_func=multilayer_perceptron, # uncomment for MLP + infer_func=convolutional_neural_network, # uncomment for LeNet5 + param_path=params_dirname, + place=place) + +batch_size = 1 +import numpy +tensor_img = numpy.random.uniform(-1.0, 1.0, + [batch_size, 1, 28, 28]).astype("float32") + +results = inferencer.infer({'img': tensor_img}) + +print("infer results: ", results[0]) + ``` ## 总结 diff --git a/02.recognize_digits/index.html b/02.recognize_digits/index.html index edfee10..bf08bb4 100644 --- a/02.recognize_digits/index.html +++ b/02.recognize_digits/index.html @@ -171,15 +171,17 @@ PaddlePaddle provides a Python module, `paddle.dataset.mnist`, which downloads a A PaddlePaddle program starts from importing the API package: ```python -import paddle.v2 as paddle +import paddle.fluid as fluid ``` -We want to use this program to demonstrate three different classifiers, each defined as a Python function: +We want to use this program to demonstrate three different classifiers, each defined as a Python function. We need to feed image data to the classifier. +PaddlePaddle provides a special layer `layer.data` for reading data. Let us create a data layer for reading images and connect it to a classification network. - Softmax regression: the network has a fully-connection layer with softmax activation: ```python -def softmax_regression(img): +def softmax_regression(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') predict = paddle.layer.fc(input=img, size=10, act=paddle.activation.Softmax()) @@ -189,77 +191,67 @@ def softmax_regression(img): - Multi-Layer Perceptron: this network has two hidden fully-connected layers, one with ReLU and the other with softmax activation: ```python -def multilayer_perceptron(img): - hidden1 = paddle.layer.fc(input=img, size=128, act=paddle.activation.Relu()) - hidden2 = paddle.layer.fc(input=hidden1, - size=64, - act=paddle.activation.Relu()) - predict = paddle.layer.fc(input=hidden2, - size=10, - act=paddle.activation.Softmax()) - return predict +def multilayer_perceptron(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') + hidden = fluid.layers.fc(input=img, size=200, act='relu') + hidden = fluid.layers.fc(input=hidden, size=200, act='relu') + prediction = fluid.layers.fc(input=hidden, size=10, act='softmax') + return prediction ``` - Convolution network LeNet-5: the input image is fed through two convolution-pooling layers, a fully-connected layer, and the softmax output layer: ```python -def convolutional_neural_network(img): - - conv_pool_1 = paddle.networks.simple_img_conv_pool( +def convolutional_neural_network(): + img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32') + conv_pool_1 = fluid.nets.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( + act="relu") + conv_pool_1 = fluid.layers.batch_norm(conv_pool_1) + conv_pool_2 = fluid.nets.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()) - - predict = paddle.layer.fc(input=conv_pool_2, - size=10, - act=paddle.activation.Softmax()) - return predict + act="relu") + prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax') + return prediction ``` -PaddlePaddle provides a special layer `layer.data` for reading data. Let us create a data layer for reading images and connect it to a classification network created using one of above three functions. We also need a cost layer for training the model. +Then we need to setup the the `train_program`. It takes the prediction from the classifier first. During the training, it will calculate the `avg_loss` from the prediction. ```python -paddle.init(use_gpu=False, trainer_count=1) - -images = paddle.layer.data( - name='pixel', type=paddle.data_type.dense_vector(784)) -label = paddle.layer.data( - name='label', type=paddle.data_type.integer_value(10)) - -# predict = softmax_regression(images) -# predict = multilayer_perceptron(images) # uncomment for MLP -predict = convolutional_neural_network(images) # uncomment for LeNet5 - -cost = paddle.layer.classification_cost(input=predict, label=label) +def train_program(): + label = fluid.layers.data(name='label', shape=[1], dtype='int64') + + # predict = softmax_regression(images) # uncomment for Softmax + # predict = multilayer_perceptron() # uncomment for MLP + predict = convolutional_neural_network() # uncomment for LeNet5 + cost = fluid.layers.cross_entropy(input=predict, label=label) + avg_cost = fluid.layers.mean(cost) + acc = fluid.layers.accuracy(input=predict, label=label) + return [avg_cost, acc] ``` -Now, it is time to specify training parameters. In the following `Momentum` optimizer, `momentum=0.9` means that 90% of the current momentum comes from that of the previous iteration. The learning rate relates to the speed at which the network training converges. Regularization is meant to prevent over-fitting; here we use the L2 regularization. - -```python -parameters = paddle.parameters.create(cost) +Now, we need to setup the trainer. The trainer need to take in `train_program`, `place`, and `optimizer`. +In the following `Momentum` optimizer, `momentum=0.9` means that 90% of the current momentum comes from that of the previous iteration. The learning rate relates to the speed at which the network training converges. Regularization is meant to prevent over-fitting; here we use the L2 regularization. -optimizer = paddle.optimizer.Momentum( - learning_rate=0.1 / 128.0, - momentum=0.9, - regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) + ```python + use_cude = False # set to True if training with GPU + place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() + optimizer = paddle.optimizer.Momentum( + learning_rate=0.1 / 128.0, + momentum=0.9, + regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128)) -trainer = paddle.trainer.SGD(cost=cost, - parameters=parameters, - update_equation=optimizer) -``` +trainer = fluid.Trainer( + train_func=train_program, place=place, optimizer=optimizer) + ``` Then we specify the training data `paddle.dataset.mnist.train()` and testing data `paddle.dataset.mnist.test()`. These two methods are *reader creators*. Once called, a reader creator returns a *reader*. A reader is a Python method, which, once called, returns a Python generator, which yields instances of data. @@ -267,35 +259,14 @@ Then we specify the training data `paddle.dataset.mnist.train()` and testing dat `batch` is a special decorator, which takes a reader and outputs a *batch reader*, which doesn't yield an instance, but a minibatch at a time. -`event_handler_plot` is used to plot a figure like below: - -![png](./image/train_and_test.png) - ```python -from paddle.v2.plot import Ploter - -train_title = "Train cost" -test_title = "Test cost" -cost_ploter = Ploter(train_title, test_title) - -step = 0 - -# event_handler to plot a figure -def event_handler_plot(event): - global step - if isinstance(event, paddle.event.EndIteration): - if step % 100 == 0: - cost_ploter.append(train_title, step, event.cost) - cost_ploter.plot() - step += 1 - if isinstance(event, paddle.event.EndPass): - # save parameters - with open('params_pass_%d.tar' % event.pass_id, 'w') as f: - trainer.save_parameter_to_tar(f) +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=500), + batch_size=64) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) - cost_ploter.append(test_title, step, result.cost) +test_reader = paddle.batch( + paddle.dataset.mnist.test(), batch_size=64) ``` `event_handler` is used to plot some text data when training. @@ -303,6 +274,9 @@ def event_handler_plot(event): ```python lists = [] +# Save the parameter into a directory. The Inferencer can load the parameters from it to do infer +params_dirname = "recognize_digits_network.inference.model" + # event handler to print the progress def event_handler(event): if isinstance(event, paddle.event.EndIteration): @@ -314,35 +288,33 @@ def event_handler(event): with open('params_pass_%d.tar' % event.pass_id, 'w') as f: trainer.save_parameter_to_tar(f) - result = trainer.test(reader=paddle.batch( - paddle.dataset.mnist.test(), batch_size=128)) + result = trainer.test(reader=train_reader) print "Test 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'])) ``` +Now that we setup the event_handler and the reader, we can start training the model. `feed_order` is used to map the data dict to the train_program ```python # Train the model now trainer.train( - reader=paddle.batch( - paddle.reader.shuffle( - paddle.dataset.mnist.train(), buf_size=8192), - batch_size=128), - event_handler=event_handler_plot, - num_passes=5) + num_epochs=1, + event_handler=event_handler, + reader=train_reader, + feed_order=['img', 'label']) ``` During training, `trainer.train` invokes `event_handler` for certain events. This gives us a chance to print the training progress. -``` -# Pass 0, Batch 0, Cost 2.780790, {'classification_error_evaluator': 0.9453125} -# Pass 0, Batch 100, Cost 0.635356, {'classification_error_evaluator': 0.2109375} -# Pass 0, Batch 200, Cost 0.326094, {'classification_error_evaluator': 0.1328125} -# Pass 0, Batch 300, Cost 0.361920, {'classification_error_evaluator': 0.1015625} -# Pass 0, Batch 400, Cost 0.410101, {'classification_error_evaluator': 0.125} -# Test with Pass 0, Cost 0.326659, {'classification_error_evaluator': 0.09470000118017197} -``` + ``` + # Pass 0, Batch 0, Cost 2.780790, {'classification_error_evaluator': 0.9453125} + # Pass 0, Batch 100, Cost 0.635356, {'classification_error_evaluator': 0.2109375} + # Pass 0, Batch 200, Cost 0.326094, {'classification_error_evaluator': 0.1328125} + # Pass 0, Batch 300, Cost 0.361920, {'classification_error_evaluator': 0.1015625} + # Pass 0, Batch 400, Cost 0.410101, {'classification_error_evaluator': 0.125} + # Test with Pass 0, Cost 0.326659, {'classification_error_evaluator': 0.09470000118017197} + ``` After the training, we can check the model's prediction accuracy. @@ -357,27 +329,25 @@ Usually, with MNIST data, the softmax regression model achieves an accuracy arou ## Application -After training, users can use the trained model to classify images. The following code shows how to inference MNIST images through `paddle.infer` interface. +After training, users can use the trained model to classify images. The following code shows how to inference MNIST images through `fluid.Inferencer`. ```python -from PIL import Image -import numpy as np -import os -def load_image(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 * 2.0 - 1.0 - return im - -test_data = [] -cur_dir = os.getcwd() -test_data.append((load_image(cur_dir + '/image/infer_3.png'),)) - -probs = paddle.infer( - output_layer=predict, parameters=parameters, input=test_data) -lab = np.argsort(-probs) # probs and lab are the results of one batch data -print "Label of image/infer_3.png is: %d" % lab[0][0] +inferencer = fluid.Inferencer( + # infer_func=softmax_regression, # uncomment for softmax regression + # infer_func=multilayer_perceptron, # uncomment for MLP + infer_func=convolutional_neural_network, # uncomment for LeNet5 + param_path=params_dirname, + place=place) + +batch_size = 1 +import numpy +tensor_img = numpy.random.uniform(-1.0, 1.0, + [batch_size, 1, 28, 28]).astype("float32") + +results = inferencer.infer({'img': tensor_img}) + +print("infer results: ", results[0]) + ``` -- GitLab