100行代碼入門PaddlePaddle圖像識別(無痛看代碼)

??導(dǎo)語:PaddlePaddle是由百度研發(fā)蛮放,國內(nèi)首個(gè)開源的深度學(xué)習(xí)框架渺绒。你在學(xué)了N多機(jī)器學(xué)習(xí)課程后签餐,發(fā)現(xiàn)要手寫一個(gè)深度學(xué)習(xí)程序的時(shí)候仍會(huì)無從下手。本文目的是解決這種入門問題愚战,適合有深度學(xué)習(xí)基礎(chǔ)但不會(huì)寫程序娇唯,或者會(huì)使用其他深度學(xué)習(xí)框架但想學(xué)習(xí)PaddlePaddle使用方式的人群。本文將帶領(lǐng)大家將大腦中的想法及模型用PaddlePaddle框架實(shí)現(xiàn)出來寂玲。

設(shè)想一下塔插,如果要實(shí)現(xiàn)一個(gè)圖像分類的深度學(xué)習(xí)程序,有哪些必要的模塊拓哟?首先想到的是他一定要有一個(gè)描述想许、定義網(wǎng)絡(luò)結(jié)構(gòu)的模塊。在本文中我們就用VGG來描述網(wǎng)絡(luò)結(jié)構(gòu)断序,那第一個(gè)模塊就是Vgg_bn_drop流纹。有了這個(gè)網(wǎng)絡(luò)模塊我們可以推想出一定需要一個(gè)推理程序,這個(gè)程序會(huì)驅(qū)動(dòng)網(wǎng)絡(luò)模塊產(chǎn)生一個(gè)輸出逢倍,我們就叫這個(gè)輸出為Predict捧颅。那第二個(gè)模塊就是推理程序(Inference_Program)。我們有了Predict之后较雕,在訓(xùn)練過程中自然需要將Predict與數(shù)據(jù)集中的Label進(jìn)行比較,并通過損失函數(shù)來計(jì)算比較的差值挚币。那第三個(gè)模塊就是將Predict實(shí)例亮蒋、Label定義、cost函數(shù)計(jì)算整合在一起的程序妆毕,它在PaddlePaddle里我們將它成為train_func慎玖,那在這里我們將第三個(gè)模塊起名為train_program。在第三個(gè)模塊里我們定義了cost笛粘,cost存在的意義是計(jì)算當(dāng)前參數(shù)的推理與label的差值趁怔,從而調(diào)整網(wǎng)絡(luò)中的參數(shù)湿硝,那我們就需要定義一個(gè)優(yōu)化器來調(diào)整網(wǎng)絡(luò)中的參數(shù)。所以第四個(gè)模塊就是Optimizer润努。有了以上的四個(gè)模塊关斜,就將整個(gè)網(wǎng)絡(luò)運(yùn)轉(zhuǎn)的流程(從推理到反向調(diào)整)都定義好了。


上述結(jié)構(gòu)圖

我們將框架定義好之后铺浇,需要一個(gè)程序?qū)⑦@個(gè)框架給驅(qū)動(dòng)起來痢畜。這個(gè)驅(qū)動(dòng)程序還有一個(gè)作用是數(shù)據(jù)灌入框架中,讓數(shù)據(jù)再里面流動(dòng)起來(這也是Fluid這個(gè)詞的由來)鳍侣。在PaddlePaddle中丁稀,可以使用Trainer這個(gè)方法來實(shí)現(xiàn)這個(gè)功能。之后我們只需要將數(shù)據(jù)準(zhǔn)備好倚聚,做成reader的格式线衫,就可以使用Trainer中的train函數(shù)來執(zhí)行訓(xùn)練啦。
千里之行惑折,至于足下桶雀。我們來看一下第一步代碼該怎么寫。
一唬复、第一步除了導(dǎo)入各種庫之外矗积,

import paddle
import paddle.fluid as fluid
import numpy
import sys
from __future__ import print_function #用于提供Python3標(biāo)準(zhǔn)的print特性

自然是要將我們的第一個(gè)模塊——網(wǎng)絡(luò)結(jié)構(gòu)定義給實(shí)現(xiàn)出來。所以我們定義一個(gè)vgg_bn_drop的函數(shù):

def vgg_bn_drop(input):

??我們觀察一下VGG的網(wǎng)絡(luò)結(jié)構(gòu)


vgg16

??可以發(fā)現(xiàn)VGG網(wǎng)絡(luò)中有很多重復(fù)的部分敞咧,如果我們把這些重復(fù)的卷積操作化為一組棘捣,那么VGG中卷積的部分可以分為五組。在PaddlePaddle中對于這種連續(xù)的卷積操作可以用img_conv_group函數(shù)來實(shí)現(xiàn)休建。

····def conv_block(參數(shù)先空著):
········return fluid.nets.img_conv_group()

??img_conv_group是整合了卷積層乍恐、池化層、BatchNorm和DropOut的復(fù)合函數(shù)测砂,并且可以很方便的支持連續(xù)卷及操作茵烈。我們想一下,對于每組連續(xù)卷積砌些,我們需要定義哪些內(nèi)容呢呜投?首先它必須接受一個(gè)數(shù)據(jù)輸入input。在卷積層方面存璃,我們可以想到的是要定義卷積核大小仑荐、卷積核數(shù)量、卷積層激活函數(shù)纵东;在池化層方面我們可以想到要定義池化區(qū)域的大小粘招、池化窗口的步長以及池化的方法。那關(guān)于DropOut的功能我們需要提供一個(gè)DropOut的概率偎球,在img_conv_group的參數(shù)中還有一個(gè)是否打開batchnorm的開關(guān)洒扎,需要指定一下辑甜。那么我們關(guān)img_conv_group的參數(shù)定義如下:

········return fluid.nets.img_conv_group(
           input=ipt,
           conv_filter_size=3,
           conv_num_filter=[num_filter] * groups,
           conv_act='relu',
           pool_size=2,
           pool_stride=2,
           pool_type='max'
           conv_with_batchnorm=True,
           conv_batchnorm_drop_rate=dropouts)

根據(jù)VGG的網(wǎng)絡(luò)圖我們發(fā)現(xiàn)所有卷積層的卷積核都為3*3,那么我們在參數(shù)中就直接指定一個(gè)參數(shù)3袍冷,如果在此處給定兩個(gè)參數(shù)磷醋,PaddlePaddle會(huì)認(rèn)為這是個(gè)WH格式的矩形卷積核。conv_num_filte參數(shù)需要給定這組連續(xù)卷積操作中所有的卷積核數(shù)量难裆,以用來統(tǒng)一初始化子檀,所以這里需要在num_filter后乘上group的數(shù)量。根據(jù)論文我們可以知道激活函數(shù)為'relu'乃戈。根據(jù)VGG的網(wǎng)絡(luò)圖我們看到是二分之一池化褂痰,所以pool_size和pool_stride都定義為2。之后使用最大池化方法症虑、打開batchnorm選項(xiàng)缩歪、指定dropout的概率。需要注意的是這里給到的dropout需要以Python中List數(shù)據(jù)結(jié)構(gòu)給出谍憔,這個(gè)list存放的是連續(xù)卷積中每一層卷積的dropout概率匪蝙。到這里img_conv_group的定義就完成。根據(jù)這些參數(shù)习贫,去除硬編碼的參數(shù)我們發(fā)現(xiàn)input逛球、num_filter、groups苫昌、dropouts需要在上層函數(shù)中傳遞颤绕。所以conv_block參數(shù)如下:

····def conv_block(ipt, num_filter, groups, dropouts):

所以在這一步我們的連續(xù)卷積定義就完成啦。但是我們的conv_block不能只有連續(xù)卷積的定義祟身,還需要將他按照VGG模型的樣子給組裝起來奥务。那么卷積層的組裝代碼為:

····conv1 = conv_block(input, 64, 2, [0.3, 0])
    conv2 = conv_block(conv1, 128, 2, [0.4, 0])
    conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0])
    conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0])
    conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0])

從第二層開始,每一層接受上一層的輸出袜硫,第二個(gè)參數(shù)根據(jù)VGG結(jié)構(gòu)定義每一層輸出的維度氯葬,第三個(gè)參數(shù)定義連續(xù)卷積的次數(shù),第四個(gè)參數(shù)定義dropout的概率婉陷,最后一層不進(jìn)行dropout操作帚称。根據(jù)網(wǎng)絡(luò)結(jié)構(gòu),后面需要做三層全連接操作憨攒,定義如下:

····drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
    fc1 = fluid.layers.fc(input=drop, size=512, act=None)
    bn = fluid.layers.batch_norm(input=fc1, act='relu')
    drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.5)
    fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
    predict = fluid.layers.fc(input=fc2, size=10, act='softmax')

這里用到了PaddlePaddle內(nèi)置的算子世杀,有全連接layers.fc,batch_norm和dropout肝集。所以整個(gè)vgg_bn_drop代碼如下:

def vgg_bn_drop(input):
    def conv_block(ipt, num_filter, groups, dropouts):
        return fluid.nets.img_conv_group(
            input=ipt,
            pool_size=2,
            pool_stride=2,
            conv_num_filter=[num_filter] * groups,
            conv_filter_size=3,
            conv_act='relu',
            conv_with_batchnorm=True,
            conv_batchnorm_drop_rate=dropouts,
            pool_type='max')

    conv1 = conv_block(input, 64, 2, [0.3, 0])
    conv2 = conv_block(conv1, 128, 2, [0.4, 0])
    conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0])
    conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0])
    conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0])

    drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
    fc1 = fluid.layers.fc(input=drop, size=512, act=None)
    bn = fluid.layers.batch_norm(input=fc1, act='relu')
    drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.5)
    fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
    predict = fluid.layers.fc(input=fc2, size=10, act='softmax')
    return predict

二、定義好網(wǎng)絡(luò)結(jié)構(gòu)以后蛛壳,我們需要將網(wǎng)絡(luò)的輸出Predict給接住杏瞻,并且將它的奶嘴(輸入格式)給備好所刀,所以我們定義

def inference_program():

方法時(shí)要先接住輸出:

    predict = vgg_bn_drop(images) 

再喂上奶嘴:

    data_shape = [3, 32, 32]
    images = fluid.layers.data(name='pixel', shape=data_shape, dtype='float32')
    predict = vgg_bn_drop(images) # un-comment to use vgg net

在PaddlePaddle中,無論是圖像數(shù)據(jù)捞挥,張量數(shù)據(jù)還是標(biāo)簽數(shù)據(jù)浮创,都可以用layers.data容器來存放。在data函數(shù)中砌函,'name'參數(shù)是可以自定義指定的斩披。因?yàn)楸緦?shí)驗(yàn)是使用cifar10的數(shù)據(jù),是3通道32x32的圖片讹俊。所以inference_program的代碼如下:

def inference_program():
    # The image is 32 * 32 with RGB representation.
    data_shape = [3, 32, 32]
    images = fluid.layers.data(name='pixel', shape=data_shape, dtype='float32')

    #predict = resnet_cifar10(images, 32)
    predict = vgg_bn_drop(images) # un-comment to use vgg net
    return predict

三垦沉、根據(jù)開頭講的思路,我們有了推理模塊后仍劈,需要將Predict和label進(jìn)行交叉對比計(jì)算厕倍,所以我們需要一個(gè)train_program。train_program起到的作用是定義label贩疙、計(jì)算損失函數(shù)讹弯、計(jì)算準(zhǔn)確率。他需要將每一批的平均cost和準(zhǔn)確率轉(zhuǎn)給下一步的優(yōu)化器这溅。所以train_program的定義如下:

def train_program():
    predict = inference_program()
    label = fluid.layers.data(name='label', shape=[1], dtype='int64')
    cost = fluid.layers.cross_entropy(input=predict, label=label)
    avg_cost = fluid.layers.mean(cost)
    accuracy = fluid.layers.accuracy(input=predict, label=label)
    return [avg_cost, accuracy]

我們得到cost之后组民,在訓(xùn)練過程需要根據(jù)cost返回的數(shù)據(jù)來反向調(diào)整神經(jīng)網(wǎng)絡(luò)中的參數(shù),那反向調(diào)整參數(shù)的模塊就叫optimizer_program悲靴,我們對optimizer_program的定義只需要返回指定的optimizer即可(在這里指定學(xué)習(xí)率超參數(shù)):

def optimizer_program():
    return fluid.optimizer.Adam(learning_rate=0.001)

四臭胜、有了以上三個(gè)模塊,訓(xùn)練-推理-調(diào)整這一個(gè)有向循環(huán)圖就構(gòu)成了《钥ⅲ現(xiàn)在我們就像已經(jīng)將自來水管道修好庇楞,需要往里通水的狀態(tài)。那我們整個(gè)循環(huán)系統(tǒng)的中控程序是什么呢否纬?是fluid.Trainer吕晌。在PaddlePaddle中fluid.Trainer是一個(gè)較高層的API,使用時(shí)只需將fluid.Trainer這個(gè)類實(shí)例化即可临燃,啟動(dòng)實(shí)例化對象中的.train()方法即可啟動(dòng)網(wǎng)絡(luò)訓(xùn)練睛驳。那這就涉及到了兩個(gè)步驟:實(shí)例化對象和啟動(dòng)訓(xùn)練。

五膜廊、在實(shí)例化對象時(shí)需要指定3個(gè)參數(shù):train_func乏沸、optimizer和place。train_func就是我們剛才定義的train_program爪瓜,它包含了網(wǎng)絡(luò)正向推理及cost的所有信息蹬跃,只需將train_program傳遞給train_func參數(shù)就好。optimizer如同一轍铆铆。place的含義是整個(gè)訓(xùn)練程序在哪個(gè)設(shè)備上運(yùn)行蝶缀,不用多說丹喻,計(jì)算機(jī)中進(jìn)行大規(guī)模計(jì)算的硬件只有CPU和GPU。為了程序設(shè)計(jì)規(guī)范翁都,我們設(shè)置一個(gè)指定設(shè)備的開關(guān):

use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()

這樣我們就可以將Trainer實(shí)例化部分給寫出來了:

use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer(
    train_func=train_program,
    optimizer_func=optimizer_program,
    place=place)

六碍论、讀到這里是不是想趕緊運(yùn)行一下trainer.train()趕緊讓他先跑起來?且慢柄慰,我們發(fā)現(xiàn)鳍悠,我們只定義了數(shù)據(jù)的容器(杯子),且從沒有處理讓真正數(shù)據(jù)讀進(jìn)網(wǎng)絡(luò)的代碼(水)坐搔。所以我們還需要寫一個(gè)數(shù)據(jù)讀取藏研、預(yù)處理的模塊。因?yàn)閳D像識別的網(wǎng)絡(luò)都是將圖片一批一批訓(xùn)練的薯蝎,所以顯而易見我們需要數(shù)據(jù)讀入和分批這兩個(gè)操作遥倦。PaddlePaddle在daraset包里存放個(gè)各種各樣公開數(shù)據(jù)庫的API,一句話就可以調(diào)用這些數(shù)據(jù)包占锯,并返回Python reader格式的數(shù)據(jù)袒哥。所以我們的流程是先將數(shù)據(jù)從API中讀出來,然后做亂序處理消略,之后用batch函數(shù)進(jìn)行分批操作(在這里指定BATCH_SIZE超參數(shù)):

# Each batch will yield 128 images
BATCH_SIZE = 128

# Reader for training
train_reader = paddle.batch(
    paddle.reader.shuffle(paddle.dataset.cifar.train10(), buf_size=50000),
    batch_size=BATCH_SIZE)

# Reader for testing. A separated data set for testing.
test_reader = paddle.batch(
    paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE)

七堡称、是不是覺得有了數(shù)據(jù)就可以跑起來了?Naive~ 在trainer中艺演,必須指定一個(gè)事件處理函數(shù)才可以運(yùn)行却紧。這個(gè)函數(shù)的作用是觀察、調(diào)試參數(shù)胎撤,保存參數(shù)模型晓殊。這里我們用畫圖的方式來觀察網(wǎng)絡(luò)中cost參數(shù)的變化過程:

params_dirname = "image_classification_resnet.inference.model"

from paddle.v2.plot import Ploter

train_title = "Train cost"
test_title = "Test cost"
cost_ploter = Ploter(train_title, test_title)

step = 0
def event_handler_plot(event):
    global step
    if isinstance(event, fluid.EndStepEvent):
        cost_ploter.append(train_title, step, event.metrics[0])
        cost_ploter.plot()
        step += 1
    if isinstance(event, fluid.EndEpochEvent):
        avg_cost, accuracy = trainer.test(
            reader=test_reader,
            feed_order=['pixel', 'label'])
        cost_ploter.append(test_title, step, avg_cost)

        # save parameters
        if params_dirname is not None:
            trainer.save_params(params_dirname)

使用paddle.v2.plot可以輕松在ipython notebook中將參數(shù)點(diǎn)在圖像中畫出來,核心代碼只有一個(gè) cost_ploter.append()伤提。本塊代碼的核心是定義一個(gè)事件處理函數(shù)event_handler_plot巫俺。在這個(gè)函數(shù)中,對每批次訓(xùn)練和每一輪訓(xùn)練進(jìn)行不同的操作肿男。在每輪結(jié)束后介汹,event接口會(huì)收到fluid.EndStepEvent類的對象。在批次訓(xùn)練完成后event會(huì)收到fluid.EndEpochEvent類的對象舶沛,通過isinstance方法可以判斷event是哪個(gè)事件對象的實(shí)例嘹承。最后在完成每一輪數(shù)據(jù)的訓(xùn)練時(shí),我們將模型保存在第一行指定的地址如庭。
八叹卷、現(xiàn)在可以執(zhí)行訓(xùn)練了,啟動(dòng)trainer.train方法需要指定4個(gè)必要參數(shù):reader(Python reader格式的數(shù)據(jù)流)、num_epochs(對數(shù)據(jù)集訓(xùn)練輪次的超參數(shù))豪娜、event_handler(事件處理函數(shù))餐胀、feed_order(存放訓(xùn)練數(shù)據(jù)和標(biāo)簽的容器)哟楷。所以代碼如下:

trainer.train(
    reader=train_reader,
    num_epochs=2,
    event_handler=event_handler_plot,
    feed_order=['pixel', 'label'])

等待一會(huì)就可以看到輸出不斷變化的cost值了:


橫坐標(biāo)為訓(xùn)練批次數(shù)瘤载,縱坐標(biāo)為cost的批次均值

九、在訓(xùn)練一輪數(shù)據(jù)集之后卖擅,模型便保存在我們制定的路徑中了鸣奔。那如何使用這個(gè)模型來進(jìn)行預(yù)測呢?PaddlePaddle的預(yù)測代碼很簡單惩阶,先實(shí)例化一個(gè)預(yù)測引擎inferencer = fluid.Inferencer()挎狸,然后使用inferencer.infer()啟動(dòng)引擎就可以了。所以我們想一下断楷,預(yù)測引擎啟動(dòng)前需要哪些參數(shù)呢锨匆?首先,推理程序是必不可少的冬筒,我們就使用之前寫的inference_program就可以恐锣,其次還要指定剛剛保存的模型存放路徑params_dirname。最后和trainer一樣舞痰,要指定一下計(jì)算運(yùn)行的設(shè)備place土榴。所以代碼如下:

inferencer = fluid.Inferencer(infer_func=inference_program, param_path=params_dirname, place=place)
results = inferencer.infer({'pixel': img})

我們從results中取到的是由每一分類的似然值構(gòu)成的List。ifar.train10是10分類數(shù)據(jù)响牛,所以我們將這個(gè)分類的名稱用人類的語言來描述一下:

label_list = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"]

然后result這個(gè)List中用np.argmax取最大概率的位置值玷禽,將其對應(yīng)的label輸出就得到了我們想要的分類了:

print("infer results: %s" % label_list[np.argmax(results[0])])

你以為大功告成了嗎?仔細(xì)看一下results = inferencer.infer({'pixel': img})發(fā)現(xiàn)我們還沒有對要預(yù)測的圖像進(jìn)行處理呀打、定義矢赁。要符合PaddlePaddle的格式圖像應(yīng)為CHW格式(通道、高度贬丛、寬度)撩银,每個(gè)像素的顏色表示應(yīng)在[-1,1]的閉區(qū)間內(nèi)。所以我們使用Python內(nèi)置的PIL包來處理讀入的圖像:

# Prepare testing data.
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)#浮點(diǎn)精度轉(zhuǎn)換
    im = im.transpose((2, 0, 1))  # 轉(zhuǎn)為CHW順序
    im = im / 255.0 #歸一化在[-1,1]的區(qū)間內(nèi)

    # Add one dimension to mimic the list format.
    im = numpy.expand_dims(im, axis=0)
    return im

cur_dir = os.getcwd()#拼接為絕對地址
img = load_image( './image/dog.png')#要預(yù)測圖像的地址

所以我們的整段預(yù)測代碼為:

# Prepare testing data.
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)
    # The storage order of the loaded image is W(width),
    # H(height), C(channel). PaddlePaddle requires
    # the CHW order, so transpose them.
    im = im.transpose((2, 0, 1))  # CHW
    im = im / 255.0 #-1 - 1

    # Add one dimension to mimic the list format.
    im = numpy.expand_dims(im, axis=0)
    return im

cur_dir = os.getcwd()
img = load_image(cur_dir + '/03.image_classification/image/dog.png')
#img = load_image( './image/dog.png')

inferencer = fluid.Inferencer(infer_func=inference_program, param_path=params_dirname, place=place)

label_list = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"]
# inference
results = inferencer.infer({'pixel': img})
#print(results[0])
print("infer results: %s" % label_list[np.argmax(results[0])+1])

十瘫寝、附整個(gè)過程的完整代碼:

import paddle
import paddle.fluid as fluid
import numpy
import sys
from __future__ import print_function

def vgg_bn_drop(input):
   def conv_block(ipt, num_filter, groups, dropouts):
       return fluid.nets.img_conv_group(
           input=ipt,
           pool_size=2,
           pool_stride=2,
           conv_num_filter=[num_filter] * groups,
           conv_filter_size=3,
           conv_act='relu',
           conv_with_batchnorm=True,
           conv_batchnorm_drop_rate=dropouts,
           pool_type='max')

   conv1 = conv_block(input, 64, 2, [0.3, 0])
   conv2 = conv_block(conv1, 128, 2, [0.4, 0])
   conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0])
   conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0])
   conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0])

   drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
   fc1 = fluid.layers.fc(input=drop, size=512, act=None)
   bn = fluid.layers.batch_norm(input=fc1, act='relu')
   drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.5)
   fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
   predict = fluid.layers.fc(input=fc2, size=10, act='softmax')
   return predict

def inference_program():
   # The image is 32 * 32 with RGB representation.
   data_shape = [3, 32, 32]
   images = fluid.layers.data(name='pixel', shape=data_shape, dtype='float32')

   #predict = resnet_cifar10(images, 32)
   predict = vgg_bn_drop(images) # un-comment to use vgg net
   return predict

def train_program():
   predict = inference_program()

   label = fluid.layers.data(name='label', shape=[1], dtype='int64')
   cost = fluid.layers.cross_entropy(input=predict, label=label)
   avg_cost = fluid.layers.mean(cost)
   accuracy = fluid.layers.accuracy(input=predict, label=label)
   return [avg_cost, accuracy]

def optimizer_program():
   return fluid.optimizer.Adam(learning_rate=0.001)

use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer(
   train_func=train_program,
   optimizer_func=optimizer_program,
   place=place)

# Each batch will yield 128 images
BATCH_SIZE = 128

# Reader for training
train_reader = paddle.batch(
   paddle.reader.shuffle(paddle.dataset.cifar.train10(), buf_size=50000),
   batch_size=BATCH_SIZE)

# Reader for testing. A separated data set for testing.
test_reader = paddle.batch(
   paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE)


params_dirname = "image_classification_resnet.inference.model"

from paddle.v2.plot import Ploter

train_title = "Train cost"
test_title = "Test cost"
cost_ploter = Ploter(train_title, test_title)

step = 0
def event_handler_plot(event):
   global step
   if isinstance(event, fluid.EndStepEvent):
       cost_ploter.append(train_title, step, event.metrics[0])
       cost_ploter.plot()
       step += 1
   if isinstance(event, fluid.EndEpochEvent):
       avg_cost, accuracy = trainer.test(
           reader=test_reader,
           feed_order=['pixel', 'label'])
       cost_ploter.append(test_title, step, avg_cost)

       # save parameters
       if params_dirname is not None:
           trainer.save_params(params_dirname)

trainer.train(
   reader=train_reader,
   num_epochs=2,
   event_handler=event_handler_plot,
   feed_order=['pixel', 'label'])

# Prepare testing data.
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)
   # The storage order of the loaded image is W(width),
   # H(height), C(channel). PaddlePaddle requires
   # the CHW order, so transpose them.
   im = im.transpose((2, 0, 1))  # CHW
   im = im / 255.0 #-1 - 1

   # Add one dimension to mimic the list format.
   im = numpy.expand_dims(im, axis=0)
   return im

cur_dir = os.getcwd()
img = load_image(cur_dir + '/03.image_classification/image/dog.png')
#img = load_image( './image/dog.png')

inferencer = fluid.Inferencer(infer_func=inference_program, param_path=params_dirname, place=place)

label_list = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"]
# inference
results = inferencer.infer({'pixel': img})
#print(results[0])
print("infer results: %s" % label_list[np.argmax(results[0])+1])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜒蕾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子焕阿,更是在濱河造成了極大的恐慌咪啡,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暮屡,死亡現(xiàn)場離奇詭異撤摸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門准夷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钥飞,“玉大人,你說我怎么就攤上這事衫嵌《林妫” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵楔绞,是天一觀的道長结闸。 經(jīng)常有香客問我,道長酒朵,這世上最難降的妖魔是什么桦锄? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蔫耽,結(jié)果婚禮上结耀,老公的妹妹穿的比我還像新娘。我一直安慰自己匙铡,他們只是感情好图甜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慰枕,像睡著了一般具则。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上具帮,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天博肋,我揣著相機(jī)與錄音,去河邊找鬼蜂厅。 笑死匪凡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掘猿。 我是一名探鬼主播病游,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼稠通!你這毒婦竟也來了衬衬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤改橘,失蹤者是張志新(化名)和其女友劉穎滋尉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體飞主,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狮惜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年高诺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碾篡。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虱而,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出开泽,到底是詐尸還是另有隱情牡拇,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布眼姐,位于F島的核電站诅迷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏众旗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一趟畏、第九天 我趴在偏房一處隱蔽的房頂上張望贡歧。 院中可真熱鬧,春花似錦赋秀、人聲如沸利朵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绍弟。三九已至,卻和暖如春著洼,著一層夾襖步出監(jiān)牢的瞬間樟遣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工身笤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豹悬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓液荸,卻偏偏與公主長得像瞻佛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子娇钱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 蘋果------水蜜桃 剛剛在吃蘋果的時(shí)候伤柄,突然吃出了一股水蜜桃的味道。 可能是我想要吃桃子了…… 其實(shí)文搂,說實(shí)話适刀,...
    格筆閱讀 178評論 0 0
  • 雪絮 倘若周圍的煩惱瑣事都像雪絮一樣清晰明了地飄落在地面上,等到太陽出來時(shí)细疚,一齊全部融化了就好了川梅。 人們像雪花一樣...
    夏止于葉閱讀 553評論 0 1
  • test 這個(gè)是全部公開的么?
    小黑兄閱讀 154評論 0 0