【深度學習入門】基於PaddleX的駕駛員狀態識別和Paddle-Lite部署

項目簡介:

該項目使用PaddleX提供的圖像分類模型,在 kaggle 駕駛員狀態檢測數據集進行訓練;

訓練得到的模型能夠區分駕駛員正常駕駛、打電話、喝水等等不同動作,準確率爲0.979;

並使用PaddleLite進行模型的量化和壓縮;

該項目使用CPU環境或GPU環境運行,PaddleX會自動選擇合適的環境;

目錄:

  1. PaddleX工具簡介;
  2. 數據集簡介;
  3. 定義數據加載器;
  4. 定義並訓練模型;
  5. 評估模型性能;
  6. 使用PaddleLite進行模型壓縮;
  7. 總結

一、PaddleX 工具簡介:

PaddleX簡介:PaddleX是飛槳全流程開發工具,集飛槳核心框架、模型庫、工具及組件等深度學習開發所需全部能力於一身,打通深度學習開發全流程,並提供簡明易懂的Python API,方便用戶根據實際生產需求進行直接調用或二次開發,爲開發者提供飛槳全流程開發的最佳實踐。目前,該工具代碼已開源於GitHub,同時可訪問PaddleX在線使用文檔,快速查閱讀使用教程和API文檔說明。

PaddleX代碼GitHub鏈接:https://github.com/PaddlePaddle/PaddleX/tree/develop

PaddleX文檔鏈接:https://paddlex.readthedocs.io/zh_CN/latest/index.html

PaddleX官網鏈接:https://www.paddlepaddle.org.cn/paddle/paddlex

二、數據集簡介:

數據集地址:https://www.kaggle.com/c/state-farm-distracted-driver-detection

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ex1qr7ru-1590022154854)(https://storage.googleapis.com/kaggle-competitions/kaggle/5048/media/output_DEb8oT.gif)]

該數據集由kaggle提供,共包括十個類別:

    'c0': 'normal driving',

    'c1': 'texting-right',
    
    'c2': 'talking on the phone-right',
    
    'c3': 'texting-left',
    
    'c4': 'talking on the phone-left',
    
    'c5': 'operating the radio',
    
    'c6': 'drinking',
    
    'c7': 'reaching behind',
    
    'c8': 'hair and makeup',
    
    'c9': 'talking to passenger'
#解壓數據集
# !unzip /home/aistudio/data/data35503/imgs.zip -d /home/aistudio/work/imgs
# !cp /home/aistudio/data/data35503/lbls.csv /home/aistudio/work/

安裝paddleX和1.7.0版本的paddlepaddle(這是由於paddlex並不支持最新版本)

!pip install paddlex -i https://mirror.baidu.com/pypi/simple
!pip install paddlepaddle-gpu==1.7.0.post107 -i https://mirror.baidu.com/pypi/simple
import os
# 設置使用0號GPU卡(如無GPU,執行此代碼後仍然會使用CPU訓練模型)
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.chdir('/home/aistudio/work/')
# jupyter中使用paddlex需要設置matplotlib
import matplotlib
matplotlib.use('Agg') 
import paddlex as pdx

三、定義數據加載器:

這裏主要是通過 pdx.datasets.ImageNet 類定義用於識別任務的數據加載器;

import paddlehub as hub
import paddle.fluid as fluid
import numpy as np

base = './data/'

datas = []
for i in range(10):
    c_base = base+'train/c{}/'.format(i)
    for im in os.listdir(c_base):
        pt = os.path.join('train/c{}/'.format(i), im)
        line = '{} {}'.format(pt, i)
        # print(line)
        datas.append(line)

np.random.seed(10)
np.random.shuffle(datas)

total_num = len(datas)
train_num = int(0.8*total_num)
test_num = int(0.1*total_num)
valid_num = total_num - train_num - test_num

print('train:', train_num)
print('valid:', valid_num)
print('test:', test_num)

with open(base+'train_list.txt', 'w') as f:
    for v in datas[:train_num]:
        f.write(v+'\n')

with open(base+'test_list.txt', 'w') as f:
    for v in datas[-test_num:]:
        f.write(v+'\n')

with open(base+'val_list.txt', 'w') as f:
    for v in datas[train_num:-test_num]:
        f.write(v+'\n')
train: 17939
valid: 2243
test: 2242
from paddlex.cls import transforms
train_transforms = transforms.Compose([
    transforms.RandomCrop(crop_size=224),
    transforms.RandomHorizontalFlip(),
    transforms.Normalize()
])
eval_transforms = transforms.Compose([
    transforms.ResizeByShort(short_size=256),
    transforms.CenterCrop(crop_size=224),
    transforms.Normalize()
])
train_dataset = pdx.datasets.ImageNet(
    data_dir='data',
    file_list='data/train_list.txt',
    label_list='data/labels.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.ImageNet(
    data_dir='data',
    file_list='data/val_list.txt',
    label_list='data/labels.txt',
    transforms=eval_transforms)
2020-05-18 07:57:03 [INFO]	Starting to read file list from dataset...
2020-05-18 07:57:03 [INFO]	17939 samples in file data/train_list.txt
2020-05-18 07:57:03 [INFO]	Starting to read file list from dataset...
2020-05-18 07:57:03 [INFO]	2243 samples in file data/val_list.txt
num_classes = len(train_dataset.labels)
print(num_classes)
10

四、定義並訓練模型:

這裏使用 MobileNetv3 進行訓練;

MobileNetv3詳細介紹可以看我的這一篇博客:

https://blog.csdn.net/weixin_44936889/article/details/104243853

這裏簡單複述一下:

在這裏插入圖片描述

在這裏插入圖片描述

琦玉老師 和 龍捲(阿姨)小姐姐 告訴我一個道理——畫風越簡單,實力越強悍;

這篇論文只有四個詞,我只能說:不!簡!單!

MobileNet簡介:

爲了使深度學習神經網絡能夠用於移動和嵌入式設備,

MobileNet 提出了使用深度分離卷積減少參數的方法;

DW Conv:

在這裏插入圖片描述

即先將特徵層的每個channel分開,然後分別做卷積,這樣參數大約少了N倍(N是輸出特徵層的channel數);

PW Conv:

就是1×1卷積,用於融合不同channel的特徵;

(一)論文地址:

《Searching for MobileNet V3》

(二)核心思想:

  1. 使用了兩個黑科技:NAS 和 NetAdapt 互補搜索技術,其中 NAS 負責搜索網絡的模塊化結構,NetAdapt 負責微調每一層的 channel 數,從而在延遲和準確性中達到一個平衡;
  2. 提出了一個對於移動設備更適用的非線性函數 hswish[x]=xReLU6(x+3)6h-swish[x]=x\frac{ReLU6(x+3)}{6}
  3. 提出了 MobileNetV3LargeMobileNetV3-LargeMobileNetV3SmallMobileNetV3-Small 兩個新的高效率網絡;
  4. 提出了一個新的高效分割(指像素級操作,如語義分割)的解碼器(decoderdecoder);

(三)Platform-Aware NAS for Block-wise Search:

3.1 MobileNetV3-Large:

對於有較大計算能力的平臺,作者提出了 MobileNetV3-Large,並使用了跟 MnanNet-A1 相似的基於 RNN 控制器和分解分層搜索空間的 NAS 搜索方法;

3.1 MobileNetV3-Small:

對於有計算能力受限制的平臺,作者提出了 MobileNetV3-Small;

這裏作者發現,原先的優化方法並不適用於小的網絡,因此作者提出了改進方法;

用於近似帕累托最優解的多目標獎勵函數定義如下:

ACC(m)×[LAT(m)/TAR]wACC(m)×[LAT(m)/TAR]^w

其中 mm 是第 mm 個模型的索引,ACCACC 是模型的準確率,LATLAT 是模型的延遲,TARTAR 是目標延遲;

作者在這裏將權重因數 w=0.07w=-0.07 改成了 w=0.15w=-0.15,最後得到了一個期望的種子模型(initial seed model);

(四)NetAdapt for Layer-wise Search:

第二個黑科技就是 NetAdapt 搜索方法,用於微調上一步生成的種子模型;

NetAdapt 的基本方法是循環迭代以下步驟:

  1. 生成一系列建議模型(proposals),每個建議模型代表了一種結構改進,滿足延遲至少比上一步的模型減小了 δ\delta,其中 δ=0.01L\delta=0.01|L|LL 是種子模型的延遲;
  2. 對於每一個建議模型,使用上一步的預訓練模型,刪除並隨機初始化改進後丟失的權重,繼續訓練 TT 步來粗略估計建議模型的準確率,其中 T=10000T=10000
  3. 根據某種度量,選取最合適的建議模型,直到達到了目標延遲 TARTAR

作者將度量方法改進爲最小化(原文是最大化,感覺是筆誤):ΔAccΔlatency\frac{\Delta Acc}{\Delta latency}

其中建議模型的提取方法爲:

  1. 減小 Expansion Layer 的大小;
  2. 同時減小 BottleNeck 模塊中的前後殘差項的 channel 數;

(五)Efficient Mobile Building Blocks:

在這裏插入圖片描述

作者在 BottleNet 的結構中加入了SE結構,並且放在了depthwise filter之後;

由於SE結構會消耗一定的計算時間,所以作者在含有SE的結構中,將 Expansion Layer 的 channel 數變爲原來的1/4;

在這裏插入圖片描述

其中 SE 模塊首先對卷積得到的特徵圖進行 Squeeze 操作,得到特徵圖每個 channel 上的全局特徵,

然後對全局特徵進行 Excitation 操作,學習各個 channel 間的關係,

從而得到不同channel的權重,最後乘以原來的特徵圖得到最終的帶有權重的特徵;

(六)Redesigning Expensive Layers:

作者在研究時發現,網絡開頭和結尾處的模塊比較耗費計算能力,因此作者提出了改進這些模塊的優化方法,從而在保證準確度不變的情況下減小延遲;

6.1 Last Stage:

在這裏插入圖片描述

在這裏作者刪掉了 Average pooling 前的一個逆瓶頸模塊(包含三個層,用於提取高維特徵),並在 Average pooling 之後加上了一個 1×1 卷積提取高維特徵;

這樣使用 Average pooling 將大小爲 7×7 的特徵圖降維到 1×1 大小,再用 1×1 卷積提取特徵,就減小了 7×7=49 倍的計算量,並且整體上減小了 11% 的運算時間;

6.2 Initial Set of Filters:

之前的 MobileNet 模型開頭使用的都是 32 組 3×3 大小的卷積核並使用 ReLU 或者 swish 函數作爲激活函數;

作者在這裏提出,可以使用 h-switch 函數作爲激勵函數,從而刪掉多餘的卷積核,使得初始的卷積核組數從 32 下降到了 16;

(七)hard switch 函數:

之前有論文提出,可以使用 swishswish 函數替代 ReLU 函數,並且能夠提升準確率;

在這裏插入圖片描述
其中 switch 函數定義爲:

swish[x]=x×σ(x)swish[x]=x×\sigma(x),其中 σ(x)=sigmoid(x)=1/1+ex\sigma(x)=sigmoid(x)=1/(1+e^{-x})

由於 sigmaoid 函數比較複雜,在嵌入式設備和移動設備計算消耗較大,作者提出了兩個解決辦法:

7.1 h-swish 函數:

將 swish 中的 sigmoid 函數替換爲一個線性函數,將其稱爲 h-swish:

hh-swish[x]=xReLU6(x+3)6swish[x]=x\frac{ReLU6(x+3)}{6}

在這裏插入圖片描述

7.2 going deeper:

作者發現 swish 函數的作用主要是在網絡的較深層實現的,因此只需要在網絡的第一層和後半段使用 h-swish 函數;

(八)網絡結構:

8.1 MobileNetV3-Large:

在這裏插入圖片描述

8.2 MobileNetV3-Small:

在這裏插入圖片描述

(九)訓練細節:

使用了 Tensorflow 的 RMSPropOptimizer 優化器,並附加 0.9 的動量項;

初始化學習率爲 0.1,batch 大小爲 4096(每個 GPU 128);

每 3 個 epoch 學習率衰減 0.01;

使用了 0.8 的 dropout 和 1e-5 的 weight decay;

(十)實驗結果:

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

# 定義並訓練模型
model = pdx.cls.MobileNetV3_small_ssld(num_classes=num_classes)
model.train(num_epochs=2,
            train_dataset=train_dataset,
            train_batch_size=32,
            log_interval_steps=20,
            eval_dataset=eval_dataset,
            lr_decay_epochs=[1],
            save_interval_epochs=1,
            learning_rate=0.01,
            save_dir='output/mobilenetv3')

五、評估模型性能

save_dir = 'output/mobilenetv3/best_model'
model = pdx.load_model(save_dir)
model.evaluate(eval_dataset, batch_size=1, epoch_id=None, return_details=False)
2020-05-18 09:25:35 [INFO]	Model[MobileNetV3_small_ssld] loaded.
2020-05-18 09:25:35 [INFO]	Start to evaluating(total_samples=2243, total_steps=2243)...


100%|██████████| 2243/2243 [00:58<00:00, 38.38it/s]





OrderedDict([('acc1', 0.9790459206419974), ('acc5', 1.0)])

六、使用PaddleLite進行模型壓縮

PaddleLite 是 paddle 提供的模型壓縮和量化工具;

文檔地址:

https://paddle-lite.readthedocs.io/zh/latest/index.html#

簡介:
Paddle-Lite 框架是 PaddleMobile 新一代架構,重點支持移動端推理預測,特點爲高性能、多硬件、輕量級 。

支持PaddleFluid/TensorFlow/Caffe/ONNX模型的推理部署,目前已經支持 ARM CPU, Mali GPU, Adreno GPU, Huawei NPU 等多種硬件,

正在逐步增加 X86 CPU, Nvidia GPU 等多款硬件,相關硬件性能業內領先。

# 進行模型量化並保存量化模型
pdx.slim.export_quant_model(model, eval_dataset, save_dir='./quant_mobilenet')
print('done.')
# 加載量化後的模型並進行評估
quant_model = pdx.load_model('./quant_mobilenet')
load_model('./quant_mobilenet')
quant_model.evaluate(eval_dataset, batch_size=1, epoch_id=None, return_details=False)

七、總結:

在本項目中我們完成了以下任務:

  1. 使用PaddleX在駕駛員狀態識別數據集訓練了MobileNetv3模型;

  2. 使用PaddleLite實現了模型的量化;

關於作者:

北京理工大學 大二在讀

感興趣的方向爲:目標檢測、人臉識別、EEG識別等

也歡迎大家fork、評論交流

作者博客主頁:https://blog.csdn.net/weixin_44936889

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章