真香!使用飛槳PaddlePaddle2.0高層API高效完成基於VGG16的影像分類任務

Mr.鄭先生_發表於2020-12-22

本示例教程將會演示如何使用飛槳的卷積神經網路來完成目標檢測任務。這是一個較為簡單的示例,將會使用飛槳框架內建模型VGG16網路完成Cifar10資料集的影像分類任務。

一、PaddlePaddle2.0新亮點——高層API助力開發者快速上手深度學習

飛槳致力於讓深度學習技術的創新與應用更簡單

1.模型組網更簡單

對於新手來說,完全可以省去以往復雜的組網程式碼,一行程式碼便可以完成組網。

目前PaddlePaddle2.0-rc1的內建模型有:

‘ResNet’, ‘resnet18’, ‘resnet34’, ‘resnet50’, ‘resnet101’, ‘resnet152’, ‘VGG’, ‘vgg11’, ‘vgg13’, ‘vgg16’, ‘vgg19’, ‘MobileNetV1’, ‘mobilenet_v1’, ‘MobileNetV2’, ‘mobilenet_v2’, ‘LeNet’

使用一行程式碼便可以載入:

ModelName = paddle.vision.models.ModelName()

(將ModelName替換成上面的模型名稱即可,模型名稱後面別忘了加括號!!!)

2.模型訓練更簡單

PaddlePaddle2.0-rc1增加了paddle.Model高層API,大部分任務可以使用此API用於簡化訓練、評估、預測類程式碼開發。

使用兩句程式碼便可以訓練模型:

# 訓練前準備
ModelName.prepare(
    paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()),
    paddle.nn.CrossEntropyLoss(),
    paddle.metric.Accuracy(topk=(1, 2))
    )

# 啟動訓練
ModelName.fit(train_dataset, epochs=2, batch_size=64, log_freq=200)

二、使用飛槳快速載入VGG網路並檢視模型結構

Very Deep Convolutional Networks For Large-Scale Image Recognition 論文地址:https://arxiv.org/pdf/1409.1556.pdf

1.檢視飛槳框架內建模型

import paddle
print('飛槳框架內建模型:', paddle.vision.models.__all__)
飛槳框架內建模型: ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'VGG', 'vgg11', 'vgg13', 'vgg16', 'vgg19', 'MobileNetV1', 'mobilenet_v1', 'MobileNetV2', 'mobilenet_v2', 'LeNet']

2.一行程式碼載入VGG16

vgg16 = paddle.vision.models.vgg16()

3.檢視VGG16的網路結構及引數

paddle.summary(vgg16, (64, 3, 32, 32))
-------------------------------------------------------------------------------
   Layer (type)         Input Shape          Output Shape         Param #    
===============================================================================
     Conv2D-1        [[64, 3, 32, 32]]     [64, 64, 32, 32]        1,792     
      ReLU-1         [[64, 64, 32, 32]]    [64, 64, 32, 32]          0       
     Conv2D-2        [[64, 64, 32, 32]]    [64, 64, 32, 32]       36,928     
      ReLU-2         [[64, 64, 32, 32]]    [64, 64, 32, 32]          0       
    MaxPool2D-1      [[64, 64, 32, 32]]    [64, 64, 16, 16]          0       
     Conv2D-3        [[64, 64, 16, 16]]   [64, 128, 16, 16]       73,856     
      ReLU-3        [[64, 128, 16, 16]]   [64, 128, 16, 16]          0       
     Conv2D-4       [[64, 128, 16, 16]]   [64, 128, 16, 16]       147,584    
      ReLU-4        [[64, 128, 16, 16]]   [64, 128, 16, 16]          0       
    MaxPool2D-2     [[64, 128, 16, 16]]    [64, 128, 8, 8]           0       
     Conv2D-5        [[64, 128, 8, 8]]     [64, 256, 8, 8]        295,168    
      ReLU-5         [[64, 256, 8, 8]]     [64, 256, 8, 8]           0       
     Conv2D-6        [[64, 256, 8, 8]]     [64, 256, 8, 8]        590,080    
      ReLU-6         [[64, 256, 8, 8]]     [64, 256, 8, 8]           0       
     Conv2D-7        [[64, 256, 8, 8]]     [64, 256, 8, 8]        590,080    
      ReLU-7         [[64, 256, 8, 8]]     [64, 256, 8, 8]           0       
    MaxPool2D-3      [[64, 256, 8, 8]]     [64, 256, 4, 4]           0       
     Conv2D-8        [[64, 256, 4, 4]]     [64, 512, 4, 4]       1,180,160   
      ReLU-8         [[64, 512, 4, 4]]     [64, 512, 4, 4]           0       
     Conv2D-9        [[64, 512, 4, 4]]     [64, 512, 4, 4]       2,359,808   
      ReLU-9         [[64, 512, 4, 4]]     [64, 512, 4, 4]           0       
     Conv2D-10       [[64, 512, 4, 4]]     [64, 512, 4, 4]       2,359,808   
      ReLU-10        [[64, 512, 4, 4]]     [64, 512, 4, 4]           0       
    MaxPool2D-4      [[64, 512, 4, 4]]     [64, 512, 2, 2]           0       
     Conv2D-11       [[64, 512, 2, 2]]     [64, 512, 2, 2]       2,359,808   
      ReLU-11        [[64, 512, 2, 2]]     [64, 512, 2, 2]           0       
     Conv2D-12       [[64, 512, 2, 2]]     [64, 512, 2, 2]       2,359,808   
      ReLU-12        [[64, 512, 2, 2]]     [64, 512, 2, 2]           0       
     Conv2D-13       [[64, 512, 2, 2]]     [64, 512, 2, 2]       2,359,808   
      ReLU-13        [[64, 512, 2, 2]]     [64, 512, 2, 2]           0       
    MaxPool2D-5      [[64, 512, 2, 2]]     [64, 512, 1, 1]           0       
AdaptiveAvgPool2D-1  [[64, 512, 1, 1]]     [64, 512, 7, 7]           0       
     Linear-1          [[64, 25088]]          [64, 4096]        102,764,544  
      ReLU-14           [[64, 4096]]          [64, 4096]             0       
     Dropout-1          [[64, 4096]]          [64, 4096]             0       
     Linear-2           [[64, 4096]]          [64, 4096]        16,781,312   
      ReLU-15           [[64, 4096]]          [64, 4096]             0       
     Dropout-2          [[64, 4096]]          [64, 4096]             0       
     Linear-3           [[64, 4096]]          [64, 1000]         4,097,000   
===============================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
-------------------------------------------------------------------------------
Input size (MB): 0.75
Forward/backward pass size (MB): 309.99
Params size (MB): 527.79
Estimated Total Size (MB): 838.53
-------------------------------------------------------------------------------






{'total_params': 138357544, 'trainable_params': 138357544}

三、使用飛槳框架API載入資料集

飛槳框架將一些我們常用到的資料集作為領域API對使用者進行開放,對應API所在目錄為paddle.vision.datasets與paddle.text.datasets

目前已經收錄的資料集有:

視覺相關資料集: [‘DatasetFolder’, ‘ImageFolder’, ‘MNIST’, ‘FashionMNIST’, ‘Flowers’, ‘Cifar10’, ‘Cifar100’, ‘VOC2012’]

自然語言相關資料集: [‘Conll05st’, ‘Imdb’, ‘Imikolov’, ‘Movielens’, ‘UCIHousing’, ‘WMT14’, ‘WMT16’]

1.快速載入資料集

使用一行程式碼即可載入資料集到本機快取目錄~/.cache/paddle/dataset:

paddle.vision.datasets.DataSetName()

將DataSetName替換成上述資料集名稱即可,別忘了名稱後面跟一個小括號!

from paddle.vision.transforms import ToTensor

# 訓練資料集 用ToTensor將資料格式轉為Tensor
train_dataset = paddle.vision.datasets.Cifar10(mode='train', transform=ToTensor())

# 驗證資料集
val_dataset = paddle.vision.datasets.Cifar10(mode='test', transform=ToTensor())

2.對訓練資料做資料增強

訓練過程中有時會遇到過擬合的問題,其中一個解決方法就是對訓練資料做增強,對資料進行處理得到不同的影像,從而泛化資料集。

檢視飛槳框架提供的資料增強方法:

import paddle
print('資料處理方法:', paddle.vision.transforms.__all__)
資料處理方法: ['BaseTransform', 'Compose', 'Resize', 'RandomResizedCrop', 'CenterCrop', 'RandomHorizontalFlip', 'RandomVerticalFlip', 'Transpose', 'Normalize', 'BrightnessTransform', 'SaturationTransform', 'ContrastTransform', 'HueTransform', 'ColorJitter', 'RandomCrop', 'Pad', 'RandomRotation', 'Grayscale', 'ToTensor', 'to_tensor', 'hflip', 'vflip', 'resize', 'pad', 'rotate', 'to_grayscale', 'crop', 'center_crop', 'adjust_brightness', 'adjust_contrast', 'adjust_hue', 'normalize']
from paddle.vision.transforms import Compose, Resize, ColorJitter, ToTensor, RandomHorizontalFlip, RandomVerticalFlip, RandomRotation
import numpy as np
from PIL import Image

# 定義想要使用那些資料增強方式,這裡用到了隨機調整亮度、對比度和飽和度、影像翻轉等
transform = Compose([ColorJitter(), RandomHorizontalFlip(), ToTensor()])

# 通過transform引數傳遞定義好的資料增項方法即可完成對自帶資料集的應用
train_dataset = paddle.vision.datasets.Cifar10(mode='train', transform=transform)

# 驗證資料集
val_dataset = paddle.vision.datasets.Cifar10(mode='test', transform=transform)

這裡需要注意的坑是,一定要把ToTensor()放在最後,否則會報錯

檢查資料集:

train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
for batch_id, data in enumerate(train_loader()):
    x_data = data[0]
    y_data = data[1]
    break

print(x_data.numpy().shape)
print(y_data.numpy().shape)

(64, 3, 32, 32)
(64,)

四、使用高層API進行模型訓練、驗證與測試

飛槳框架提供了兩種訓練與預測的方法:

  • 一種是用paddle.Model對模型進行封裝,通過高層API如Model.fit()、Model.evaluate()、Model.predict()等完成模型的訓練與預測;
  • 另一種就是基於基礎API常規的訓練方式。

使用高層API只需要改動少量引數即可完成模型訓練,對新手小白真的特別友好!

1.呼叫fit()介面來啟動訓練過程

import paddle
from paddle.vision.transforms import ToTensor
from paddle.vision.models import vgg16

# build model
model = vgg16()

# build vgg16 model with batch_norm
model = vgg16(batch_norm=True)

# 使用高層API——paddle.Model對模型進行封裝
model = paddle.Model(model)

# 為模型訓練做準備,設定優化器,損失函式和精度計算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
                    loss=paddle.nn.CrossEntropyLoss(),
                    metrics=paddle.metric.Accuracy())

# 啟動模型訓練,指定訓練資料集,設定訓練輪次,設定每次資料集計算的批次大小,設定日誌格式
model.fit(train_dataset,
          epochs=10,
          batch_size=256,
          save_dir="vgg16/",
          save_freq=10,
          verbose=1)
The loss value printed in the log is the current step, and the metric is the average value of previous step.
Epoch 1/10
step 196/196 [==============================] - loss: 2.3752 - acc: 0.1054 - 202ms/step        
save checkpoint at /home/aistudio/vgg16/0
Epoch 2/10
step 196/196 [==============================] - loss: 2.2819 - acc: 0.1114 - 203ms/step        
Epoch 3/10
step 196/196 [==============================] - loss: 2.2614 - acc: 0.1306 - 201ms/step        
Epoch 4/10
step 196/196 [==============================] - loss: 2.2229 - acc: 0.1822 - 195ms/step        
Epoch 5/10
step 196/196 [==============================] - loss: 1.9132 - acc: 0.1846 - 198ms/step        
Epoch 6/10
step 196/196 [==============================] - loss: 1.7738 - acc: 0.2000 - 194ms/step        
Epoch 7/10
step 196/196 [==============================] - loss: 1.8450 - acc: 0.2286 - 195ms/step        
Epoch 8/10
step 196/196 [==============================] - loss: 1.5770 - acc: 0.2782 - 198ms/step        
Epoch 9/10
step 196/196 [==============================] - loss: 1.5743 - acc: 0.3446 - 195ms/step        
Epoch 10/10
step 196/196 [==============================] - loss: 1.4283 - acc: 0.4043 - 201ms/step        
save checkpoint at /home/aistudio/vgg16/final

看到loss在明顯下降、acc在明顯上升,說明模型效果還不錯,剩下需要慢慢調參優化

2.呼叫evaluate()在測試集上對模型進行驗證

對於訓練好的模型進行評估操作可以使用evaluate介面來實現,事先定義好用於評估使用的資料集後,可以簡單的呼叫evaluate介面即可完成模型評估操作,結束後根據prepare中loss和metric的定義來進行相關評估結果計算返回。

# 用 evaluate 在測試集上對模型進行驗證
eval_result = model.evaluate(val_dataset, verbose=1)
Eval begin...
The loss value printed in the log is the current batch, and the metric is the average value of previous step.
step 10000/10000 [==============================] - loss: 0.2509 - acc: 0.4379 - 10ms/step         
Eval samples: 10000

3.呼叫predict()介面進行模型測試

高層API中提供了predict介面來方便使用者對訓練好的模型進行預測驗證,只需要基於訓練好的模型將需要進行預測測試的資料放到介面中進行計算即可,介面會將經過模型計算得到的預測結果進行返回。

# 用 predict 在測試集上對模型進行測試
test_result = model.predict(val_dataset)
Predict begin...
step 10000/10000 [==============================] - 10ms/step         
Predict samples: 10000

五、總結與展望——PaddlePaddle2.0 rc1入手指南

給大家總結一下我在使用PaddlePaddle2.0 rc1時遇到的坑,希望大家可以避免:

  • 1.這個專案本來是使用VOC2012資料集進行目標檢測任務的訓練的,奈何VOC2012資料集的下載速度實在是太慢了,所以我果斷放棄,希望後期可以找到解決辦法
  • 2.最好結合PaddlePaddle2.0的文件和GitHub上的原始碼來使用,特別是新手小白,不然出現一些報錯可能會很難解決,可以多去GitHub上提issue
  • 3.使用資料增強 Compose()方法時,切記!一定要把ToTensor()放在最後,這個問題看看原始碼就能解決

六、個人介紹

北京聯合大學 機器人學院 自動化專業 2018級 本科生 鄭博培

百度飛槳開發者技術專家 PPDE

百度飛槳官方幫幫團、答疑團成員

深圳柴火創客空間 認證會員

百度大腦 智慧對話訓練師

來AI Studio互粉吧~ 等你哦~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/147378

歡迎大家fork喜歡評論三連,感興趣的朋友也可互相關注一下啊~

相關文章