1. 程式人生 > >PaddlePaddle 系列之三行程式碼從入門到精通

PaddlePaddle 系列之三行程式碼從入門到精通

本文介紹 PaddlePaddle 系列之三行程式碼從入門到精通。

前言

這將是 PaddlePaddle 系列教程的開篇,屬於非官方教程。既然是非官方,自然會從一個使用者的角度出發,來教大家怎麼用,會有哪些坑,以及如何上手並用到實際專案中去。

我之前寫過一些關於 tensorflow 的教程,在我的簡書上可以找到,非常簡單基礎的一個教程,但是備受好評,因為國內實在是很難找到一個系列的關於這些深度學習框架的教程。因此在這裡,我來給 PaddlePaddle 也寫一個類似的教程,不復雜,三行程式碼入門。

三行程式碼 PaddlePaddle 從入門到精通

PaddlePaddle 是百度大力推出的一個框架,不得不說相比於 tensorflow,PaddlePaddle 會簡單很多,接下來我會細說。同時百度在人工智慧方面的功底還是非常深厚,我曾經在騰訊實習,類似於 AT 這樣的公司,甚至沒有一個非常成型的框架存在。

既然是三行程式碼精通 PaddlePaddle,那麼得安裝一下 PaddlePaddle。就目前來說,最好的辦法是 build from source。步驟如下 (注意,這裡是 CPU 版本,GPU 版本的原始碼編譯過程後續補充,我們先用 CPU 來熟悉 API):

# clone 最新程式碼到 paddle
git clone https://github.com/PaddlePaddle/Paddle paddle
cd paddle
mkdir build
cd build
make all -j8
sudo make install

# 安裝 python 介面,注意 paddlepaddle 目前貌似只支援 python2,因此在寫指令碼的時候一定要相容一下 python3
# 這裡是 mac 的情況下,如果是 ubuntu /usr/local/opt 應該直接是/opt/ sudo python -m pip install /usr/local/opt/paddle/share/wheels/*.whl # 或者直接 sudo pip2 install /usr/local/opt/paddle/share/wheels/*.whl

好了,看上去應該算是安裝完了。接下來我們用三行程式碼來測試一下?

PaddlePaddle 在 python API 上 0.10 有較大的變化,所以直接 import 一下 v2 版本的 API。如果可以說明 PaddlePaddle 安裝沒有問題。這裡贊一下百度的技術功底和使用者體驗,這尼瑪要是 caffe 或者 caffe2 編譯出錯概率 100%不說,python 安裝了也不能 import,PaddlePaddle 一步到位,非常牛逼。

閒話不多說,直接三行程式碼來熟悉一下 PaddlePaddle 的 API。

三行程式碼來了

接下來要做的事情是,用 PaddlePaddle 搭建一個 3 層 MLP 網路,跑一個二維的 numpy 隨機資料,來了解一下 PaddlePaddle 從資料喂入到訓練的整個 pipeline 吧。

首先我們這個教程先給大家展示一個圖片分類器,用到的資料集是 Stanford Dogs 資料集,下載連結,大概 800M, 同時下載一下 annotations, 大概 21M。下載好了我們用一個 paddle_test 的資料夾來做這個教程吧。

mkdir paddle_test
cd paddle_test
mkdir data

把所有的 images 和 annotations 扔到 data 裡面去,解壓一下:

paddle_test
└── data
    ├── annotation.tar
    └── images.tar

順便說一下,這裡的 annotations 是為後面用 paddlepaddle 做分割做準備,本次分類任務,只需要一個 images.tar 就可以了,所有圖片被放在了該類別的資料夾下面,以後處理其他分類任務時,只需要把不同類別放在資料夾就 OK 了,甚至不用改程式碼,非常方便,這比 MXNet 要有道理很多,多數情況下我們根本不需要海量圖片訓練,也沒有必要搞個什麼 imrecord 的資料格式,MXNet 匯入圖片真心蛋疼,沒有 Pytorch 方便,但是 Pytorch 得執行速度堪憂。

OK,將 images.tar 解壓,會得到 120 個資料夾,也就是 120 個類別,每個類別裡面都是一種狗狗圖片。比如這張是一隻 Beagle:

我們現在要來處理一下這些蠢狗。

開始寫三行程式碼

好了,開始寫三行程式碼了。

def vgg_bn_drop(input_data):
def event_handler(event):
def train():

實際上 PaddlePaddle 的使用也就是三行程式碼的事情,首先是網路構建,這裡我們構建一個 VGG 網路,其次是 event 的處理函式,這個機制是 PaddlePaddle 獨有的,PaddlePaddle 把所有的訓練過程都包裝成了一個 trainer,然後呼叫這個 event_handler 來處理比如列印 loss 資訊這樣的事情。OK,我們一步一步來,先來看一下 train 的過程吧:

def train():
    data_dim = 3 * 32 * 32
    class_dim = 10
    image = paddle.layer.data(
        name="image", type=paddle.data_type.dense_vector(data_dim))
    net = vgg_bn_drop(image)
    out = paddle.layer.fc(input=net,
                          size=class_dim,
                          act=paddle.activation.Softmax())
    lbl = paddle.layer.data(
        name="label", type=paddle.data_type.integer_value(class_dim))
    cost = paddle.layer.classification_cost(input=out, label=lbl)
    parameters = paddle.parameters.create(cost)
    print(parameters.keys())
    momentum_optimizer = paddle.optimizer.Momentum(
        momentum=0.9,
        regularization=paddle.optimizer.L2Regularization(rate=0.0002 * 128),
        learning_rate=0.1 / 128.0,
        learning_rate_decay_a=0.1,
        learning_rate_decay_b=50000 * 100,
        learning_rate_schedule='discexp')
    # Create trainer
    trainer = paddle.trainer.SGD(cost=cost,
                                 parameters=parameters,
                                 update_equation=momentum_optimizer)
    reader = paddle.batch(
        paddle.reader.shuffle(
            paddle.dataset.cifar.train10(), buf_size=50000),
        batch_size=128)
    feeding = {'image': 0,
               'label': 1}
    trainer.train(
        reader=reader,
        num_passes=200,
        event_handler=event_handler,
        feeding=feeding)

PaddlePaddle 的網路訓練流程分為幾個步驟:

  • 首先定義網路,這裡的網路不包括最後一層的 softmax;
  • 建立一個 cost,cost 當然就需要一個網路的輸出和 lable 了;
  • 通過這個 cost 來建立網路訓練的引數,非常簡單明瞭;
  • 最後是優化器,這裡定義反向傳播的正則項,學習速率調整策略等;
  • 通過上面這些建立一個 trainer;
  • 最後這個 trainer 要訓練起來,還需要持續的資料喂入,時間處理函式,和喂入的方式。

接著我們看一下網路定義和事件處理函式:

# define VGG network
def vgg_bn_drop(input_data):
    def convolution_block(ipt, num_filter, groups, dropouts, num_channels=None):
        return paddle.networks.img_conv_group(
            input=ipt,
            num_channels=num_channels,
            pool_size=2,
            pool_stride=2,
            conv_num_filter=[num_filter] * groups,
            conv_filter_size=3,
            conv_act=paddle.activation.Relu(),
            conv_with_batchnorm=True,
            conv_batchnorm_drop_rate=dropouts,
            pool_type=paddle.pooling.Max())
    convolution_1 = convolution_block(input_data, 64, 2, [0.3, 0], 3)
    convolution_2 = convolution_block(convolution_1, 128, 2, [0.4, 0])
    convolution_3 = convolution_block(convolution_2, 256, 3, [0.4, 0.4, 0])
    convolution_4 = convolution_block(convolution_3, 512, 3, [0.4, 0.4, 0])
    convolution_5 = convolution_block(convolution_4, 512, 3, [0.4, 0.4, 0])
    drop = paddle.layer.dropout(input=convolution_5, dropout_rate=0.5)
    fc1 = paddle.layer.fc(input=drop, size=512, act=paddle.activation.Linear())
    bn = paddle.layer.batch_norm(
        input=fc1,
        act=paddle.activation.Relu(),
        layer_attr=paddle.attr.Extra(drop_rate=0.5))
    fc2 = paddle.layer.fc(input=bn, size=512, act=paddle.activation.Linear())
    return fc2
def event_handler(event):
    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()

這裡我們先用 PaddlePaddle 內建的 cifar10 來測試一下能否訓練起來,把上面的程式碼加上 import 之後:

from __future__ import print_function, division
import paddle.v2 as paddle
import sys
paddle.init(use_gpu=False, trainer_count=1)
if __name__ == '__main__':
    train()

在主函式裡面執行 train()。見證奇蹟的時刻到了。。

PaddlePaddle 開始下載資料,並打印出了網路結構!

so far so good,PaddlePaddle 開始訓練網路!!!

牛逼了我的哥。接下來我們用這個程式碼來儲存網路訓練之後的權重:

try:
    trainer.train(
        reader=reader,
        num_passes=200,
        event_handler=event_handler,
        feeding=feeding)
except KeyboardInterrupt:
    with open('params_model.tar', 'w') as f:
        parameters.to_tar(f)

最後,模型 train 好之後,匯入模型進行預測:

from __future__ import print_function
from PIL import Image
import numpy as np
import os
def load_image(file):
    im = Image.open(file)
    im = im.resize((32, 32), Image.ANTIALIAS)
    im = np.array(im).astype(np.float32)
    # PIL 開啟圖片儲存順序為 H(高度),W(寬度),C(通道)。
    # PaddlePaddle 要求資料順序為 CHW,所以需要轉換順序。
    im = im.transpose((2, 0, 1)) # CHW
    # CIFAR 訓練圖片通道順序為 B(藍),G(綠),R(紅),
    # 而 PIL 開啟圖片預設通道順序為 RGB,因為需要交換通道。
    im = im[(2, 1, 0),:,:] # BGR
    im = im.flatten()
    im = im / 255.0
    return im
test_data = []
cur_dir = os.getcwd()
test_data.append((load_image(cur_dir + '/image/dog.png'),))
# with open('params_pass_50.tar', 'r') as f:
#    parameters = paddle.parameters.Parameters.from_tar(f)
probs = paddle.infer(
    output_layer=out, parameters=parameters, input=test_data)
lab = np.argsort(-probs) # probs and lab are the results of one batch data
print("Label of image/dog.png is: %d" % lab[0][0])

OK, 本次列車到此結束,對於 PaddlePaddle 如何訓練一個圖片分類器,應該有了一個清醒的認識,下一步,我們將繼續….用 PaddlePaddle 實現一個 NLP 情感分類器!

本文由在當地較為英俊的男子金天大神原創,版權所有,歡迎轉載,本文首發地址 https://jinfagang.github.io 。但請保留這段版權資訊,多謝合作,有任何疑問歡迎通過微信聯絡我交流:jintianiloveu。