實戰 | 基於深度學習模型VGG的影象識別(附程式碼)
本文演示瞭如何使用百度公司的PaddlePaddle實現基於深度學習模型VGG的影象識別。
準備工作
VGG簡介
牛津大學VGG(Visual Geometry Group)組在2014年ILSVRC提出的模型被稱作VGG模型 。該模型相比以往模型進一步加寬和加深了網路結構,它的核心是五組卷積操作,每兩組之間做Max-Pooling空間降維。同一組內採用多次連續的3X3卷積,卷積核的數目由較淺組的64增多到最深組的512,同一組內的卷積核數目是一樣的。卷積之後接兩層全連線層,之後是分類層。由於每組內卷積層的不同,有11、13、16、19層這幾種模型,下圖展示一個16層的網路結構。VGG模型結構相對簡潔,提出之後也有很多文章基於此模型進行研究,如在ImageNet上首次公開超過人眼識別的模型就是借鑑VGG模型的結構。
資料準備
通用影象分類公開的標準資料集常用的有CIFAR、ImageNet、COCO等,常用的細粒度影象分類資料集包括CUB-200-2011、Stanford Dog、Oxford-flowers等。其中ImageNet資料集規模相對較大,如模型概覽一章所講,大量研究成果基於ImageNet。ImageNet資料從2010年來稍有變化,常用的是ImageNet-2012資料集,該資料集包含1000個類別:訓練集包含1,281,167張圖片,每個類別資料732至1300張不等,驗證集包含50,000張圖片,平均每個類別50張圖片。
由於ImageNet資料集較大,下載和訓練較慢,為了方便大家學習,我們使用CIFAR10資料集。CIFAR10資料集包含60,000張32x32的彩色圖片,10個類別,每個類包含6,000張。其中50,000張圖片作為訓練集,10000張作為測試集。圖11從每個類別中隨機抽取了10張圖片,展示了所有的類別。
Paddle API提供了自動載入cifar資料集模組 paddle.dataset.cifar。
程式碼實現思路
通過輸入python train.py,就可以開始訓練模型了,主要包括三個函式:
def vgg_bn_drop(input_data):
def event_handler(event):
def train():
第一步:vgg_bn_drop
首先介紹VGG模型結構,由於CIFAR10圖片大小和數量相比ImageNet資料小很多,因此這裡的模型針對CIFAR10資料做了一定的適配。卷積部分引入了BN和Dropout操作。
函式完整程式碼
VGG核心模組的輸入是資料層,vgg_bn_drop 定義了16層VGG結構,每層卷積後面引入BN層和Dropout層,詳細的定義如下:
def vgg_bn_drop(input):
def conv_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())
conv1 = conv_block(input, 64, 2, [0.3, 0], 3)
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 = paddle.layer.dropout(input=conv5, 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
VGG構造思路
(1) 首先定義了一組卷積網路,即conv_block。卷積核大小為3x3,池化視窗大小為2x2,視窗滑動大小為2,groups決定每組VGG模組是幾次連續的卷積操作,dropouts指定Dropout操作的概率。所使用的img_conv_group是在paddle.networks中預定義的模組,由若干組 Conv->BN->ReLu->Dropout 和 一組 Pooling 組成。
(2)五組卷積操作,即 5個conv_block。 第一、二組採用兩次連續的卷積操作。第三、四、五組採用三次連續的卷積操作。每組最後一個卷積後面Dropout概率為0,即不使用Dropout操作。
(3)最後接兩層512維的全連線。
第二步:event_handler
函式完整程式碼
# End batch and end pass event handler
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()
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)
result = trainer.test(
reader=paddle.batch(
paddle.dataset.cifar.test10(), batch_size=128),
feeding=feeding)
print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics)
函式解析
event_handler主要功能:
觀察訓練過程: print()
模型引數儲存:trainer.save_parameter_to_tar(f)
進行測試:trainer.test()
該回撥函式是trainer.train函式裡設定,event_handler_plot可以用來利用回撥資料來打點畫圖,也可以輸出日誌。輸出日誌的示例圖:
Pass 0, Batch 0, Cost 2.473182, {'classification_error_evaluator': 0.9140625}
...................................................................................................
Pass 0, Batch 100, Cost 1.913076, {'classification_error_evaluator': 0.78125}
...................................................................................................
Pass 0, Batch 200, Cost 1.783041, {'classification_error_evaluator': 0.7421875}
...................................................................................................
Pass 0, Batch 300, Cost 1.668833, {'classification_error_evaluator': 0.6875}
..........................................................................................
Test with Pass 0, {'classification_error_evaluator': 0.885200023651123}
第三步: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)
函式解析
1. 定義資料輸入及其維度
網路輸入定義為 data_layer (資料層),在影象分類中即為影象畫素資訊。CIFRAR10是RGB 3通道32x32大小的彩色圖,因此輸入資料大小為3072(3x32x32),類別大小為10,即10分類。
datadim = 3 * 32 * 32
classdim = 10
image = paddle.layer.data(
name="image", type=paddle.data_type.dense_vector(datadim))
2. 定義VGG網路核心模組
net = vgg_bn_drop(image)
3. 定義分類器
通過上面VGG網路提取高層特徵,然後經過全連線層對映到類別維度大小的向量,再通過Softmax歸一化得到每個類別的概率,也可稱作分類器。
out = paddle.layer.fc(input=net,
size=classdim,
act=paddle.activation.Softmax())
4. 定義網路輸出和損失函式
在有監督訓練中需要輸入影象對應的類別資訊,同樣通過paddle.layer.data來定義。訓練中採用多類交叉熵作為損失函式,並作為網路的輸出,預測階段定義網路的輸出為分類器得到的概率資訊。
lbl = paddle.layer.data(
name="label", type=paddle.data_type.integer_value(classdim))
cost = paddle.layer.classification_cost(input=out, label=lbl)
5. 定義引數
首先依據模型配置的cost定義模型引數。
# Create parameters
parameters = paddle.parameters.create(cost)
可以列印引數名字,如果在網路配置中沒有指定名字,則預設生成。
print parameters.keys()
6. 構造優化器
根據網路拓撲結構和模型引數來構造出trainer用來訓練,在構造時還需指定優化方法,這裡使用最基本的Momentum方法,同時設定了學習率、正則等。
# Create optimizer
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')
#####7. 建立訓練器
# Create trainer
trainer = paddle.trainer.SGD(cost=cost,
parameters=parameters,
update_equation=momentum_optimizer)
通過 learning_rate_decay_a、learning_rate_decay_b 和 learning_rate_schedule 指定學習率調整策略,這裡採用離散指數的方式調節學習率,計算公式如下,n 代表已經處理過的累計總樣本數,lr0 即為 settings 裡設定的 learning_rate。
7. 啟動訓練器
cifar.train10()每次產生一條樣本,在完成shuffle和batch之後,作為訓練的輸入。
reader=paddle.batch(
paddle.reader.shuffle(
paddle.dataset.cifar.train10(), buf_size=50000),
batch_size=128)
通過feeding來指定每一個資料和paddle.layer.data的對應關係。例如: cifar.train10()產生資料的第0列對應image層的特徵。
feeding={'image': 0,
'label': 1}
通過trainer.train函式訓練:
trainer.train(
reader=reader,
num_passes=200,
event_handler=event_handler,
feeding=feeding)
第四步:頭部和尾部
頭部:模型初始化
通過 paddle.init,初始化Paddle是否使用GPU,trainer的數目等等。
import sys
import paddle.v2 as paddle
from vgg import vgg_bn_drop
from resnet import resnet_cifar10
# PaddlePaddle init
paddle.init(use_gpu=False, trainer_count=1)
尾部:主函式
if __name__ == '__main__':
train()
推斷模型(測試)
可以使用訓練好的模型對圖片進行分類,下面程式展示瞭如何使用paddle.infer介面進行推斷,可以開啟註釋,更改載入的模型。
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]
參考文獻
[1]http://paddlepaddle.org/docs/develop/book/03.image_classification/index.cn.html
[2]http://geek.csdn.net/news/detail/239674
►延伸
作為深度學習方向的求職者,還在愁愁簡歷上沒有專案經驗,且沒人幫你內推BAT等公司,海投簡歷杳無音信麼?
作為深度學習方向的研究生,是否好奇學到的理論、模型、演算法在實際公司裡是如何應用的,且無GPU實戰平臺?
作為深度學習方向的工作者,是否在CTR預估、推薦系統等具體應用場景中感到技術乏力?
為解決以上困惑,七月線上特設《深度學習專案班》課程,課程包含:
影象分類和影象搜尋實戰、
自然語言處理與聊天機器人實戰、
CTR預估實戰
推薦系統實戰
四大實戰階段,且設定了畢業考試及1v1批改(考試優秀者內推BAT等各大公司),佈置作業且解答作業,輔助簡歷優化 專案包裝(本課程的近10個專案在實踐完成後都可以寫在簡歷裡)。
另,課程全程提供GPU雲實驗平臺(提前裝好tensorflow、caffe、mxnex等主流的DL框架和資料),及提供CPU雲實驗平臺(基於notebook定製,方便線上雲端實時編譯作業),一切為真槍實戰、助力跳槽漲薪。
掃碼或點選文末“閱讀原文”獲取試聽課程
相關文章
- [OpenCV實戰]1 基於深度學習識別人臉性別和年齡OpenCV深度學習
- 基於pytorch的深度學習實戰PyTorch深度學習
- 基於TensorFlow的深度學習實戰深度學習
- 【AI in 美團】如何基於深度學習實現影象的智慧稽核?AI深度學習
- 基於PaddlePaddle的影象分類實戰 | 深度學習基礎任務教程系列(一)深度學習
- 基於VGG的遷移學習遷移學習
- 深度學習基礎 - 基於Theano-MLP的字元識別實驗(MNIST)深度學習字元
- 基於深度學習的影象超解析度重建深度學習
- 基於深度學習的手勢識別系統(Python程式碼,UI介面版)深度學習PythonUI
- 基於深度學習的人臉性別識別系統(含UI介面,Python程式碼)深度學習UIPython
- 10分鐘搭建你的第一個影象識別模型(附步驟、程式碼)模型
- Action Recognition——基於深度學習的動作識別綜述深度學習
- 學習身份證影象識別
- 深度學習-行人重識別實戰(2020)深度學習
- 【深度學習-基於Tensorflow的實戰】公開課實況深度學習
- 基於深度學習的圖書管理推薦系統(附python程式碼)深度學習Python
- 基於深度學習的影象超解析度重建技術的研究深度學習
- 基於深度學習的機器人目標識別和跟蹤深度學習機器人
- 深度學習例項之基於mnist的手寫數字識別深度學習
- 深度學習--基於卷積神經網路的歌唱嗓音識別深度學習卷積神經網路
- 深度學習——性別識別深度學習
- 使用深度學習進行基於AI的面部識別的不同方法深度學習AI
- 【王曉剛】深度學習在影象識別中的研究進展與展望深度學習
- 基於深度學習的時間序列分類[含程式碼]深度學習
- 基於深度學習模型Wide&Deep的推薦深度學習模型IDE
- 【機器學習PAI實踐十】深度學習Caffe框架實現影象分類的模型訓練機器學習AI深度學習框架模型
- 「NLP-NER」命名實體識別中最常用的兩種深度學習模型深度學習模型
- 基於Keras和Gunicorn+Flask部署深度學習模型KerasFlask深度學習模型
- 基於PaddlePaddle的詞向量實戰 | 深度學習基礎任務教程系列深度學習
- 基於Keras/Python的深度學習模型Dropout正則項KerasPython深度學習模型
- 基於深度學習的影象語義分割技術概述之背景與深度網路架構深度學習架構
- 【實戰】基於OpenCV的水錶字元識別(OCR)OpenCV字元
- Sunny.Xia的深度學習(四)MMOE多工學習模型實戰演練深度學習模型
- 基於深度學習的人臉識別系統系列(Caffe+OpenCV+Dlib)——【六】設計人臉識別的識別類深度學習OpenCV
- 深度學習之影象簡史深度學習
- 基於PaddlePaddle的詞向量實戰 | 深度學習基礎任務教程系列(二)深度學習
- TF2.keras 實現基於深度可分離卷積網路的影象分類模型TF2Keras卷積模型
- 基於Sklearn機器學習程式碼實戰機器學習