手把手帶你實(shí)現(xiàn)基于深度學(xué)習(xí)的垃圾分類(lèi)器

隨著PaddlePaddle2.0的更新叉袍,PaddleClas圖像分類(lèi)套件也更新到了2.0-rc1版本次绘。新版本的PaddleClas套件已經(jīng)默認(rèn)使用動(dòng)態(tài)圖來(lái)進(jìn)行模型訓(xùn)練”窀螅現(xiàn)在我們使用PaddleClas套件從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)單的垃圾分類(lèi)器。來(lái)體驗(yàn)一下新版本的PaddleClas的的方便快捷邮偎,即使初學(xué)者也能快速的訓(xùn)練出高精度的模型管跺。本篇文章分為上下兩部分,上部講解如何從零開(kāi)始訓(xùn)練禾进,下部講解部分核心代碼以及深度學(xué)習(xí)訓(xùn)練過(guò)程中使用到的技術(shù)豁跑。

1.準(zhǔn)備數(shù)據(jù)集

數(shù)據(jù)集下載地址:
https://aistudio.baidu.com/aistudio/datasetdetail/64185
下載好數(shù)據(jù)集之后,首先需要解壓壓縮包命迈。

mkdir dataset
cd dataset
unzip garbage_classify.zip

數(shù)據(jù)集中共包含43個(gè)分類(lèi)贩绕,例如:9代表"廚余垃圾/水果果肉"火的、22代表"可回收物/舊衣服壶愤、39代表有害垃圾/過(guò)期藥物"淑倾。具體類(lèi)別可以查看garbage_classify中的garbage_classify_rule.json文件。

有了數(shù)據(jù)集之后征椒,需要對(duì)數(shù)據(jù)集進(jìn)行劃分娇哆。在dataset目錄下創(chuàng)建process_dataset.py文件,使用下列代碼將數(shù)據(jù)集劃分為訓(xùn)練集勃救、驗(yàn)證集和測(cè)試集碍讨,劃分比例為8:1:1。

import os
import glob
import numpy as np
file_list = glob.glob('./garbage_classify/train_data/*.txt')
np.random.shuffle(file_list)
train_len = len(file_list) // 10 * 8
val_len = len(file_list) // 10
train_list = []

for txt_file in file_list[:train_len]:
    with open(txt_file, 'r') as f:
        line = f.readlines()[0]

        line = line.strip()
        image_file,label = line.split(',')
        image_file = image_file.strip()
        label = label.strip()
        image_path = os.path.join('./garbage_classify/train_data/', image_file)
        train_list.append(image_path + ' ' + label + '\n')
with open('train_list.txt', 'w') as f:
    f.writelines(train_list)

val_list = []
for txt_file in file_list[train_len:train_len + val_len]:
    with open(txt_file, 'r') as f:
        line = f.readlines()[0]

        line = line.strip()
        image_file,label = line.split(',')
        image_file = image_file.strip()
        label = label.strip()
        image_path os.path.join('./garbage_classify/train_data/', image_file)
        val_list.append(image_path + ' ' + label + '\n')
with open('val_list.txt', 'w') as f:
    f.writelines(val_list)

test_list = []
for txt_file in file_list[train_len + val_len:]:
    with open(txt_file, 'r') as f:
        line = f.readlines()[0]

        line = line.strip()
        image_file,label = line.split(',')
        image_file = image_file.strip()
        label = label.strip()
        image_path = os.path.join('./garbage_classify/train_data/', image_file)
        test_list.append(image_path + ' ' + label + '\n')
with open('test_list.txt', 'w') as f:
    f.writelines(test_list)

以上代碼運(yùn)行結(jié)束后蒙秒,目錄結(jié)構(gòu)如下:

├── garbage_classify
├── process_dataset.py
├── test_list.txt
├── train_list.txt
└── val_list.txt

2.下載PaddleClas套件

下載PaddleClas源代碼勃黍,并切換到2.0-rc1版本。安裝該套件依賴軟件可參考以下文檔:
https://github.com/PaddlePaddle/PaddleClas/blob/release/2.0-rc1/docs/en/tutorials/install_en.md

git clone https://github.com/PaddlePaddle/PaddleClas.git
git fetch
git branch release/2.0-rc1 origin/release/2.0-rc1

3.修改配置文件

PaddleClas套件中包含了多種神經(jīng)網(wǎng)絡(luò)模型晕讲,也包含了模型對(duì)應(yīng)的訓(xùn)練參數(shù)覆获,配置參數(shù)保存在configs路徑下。本次的垃圾分類(lèi)器我選擇一個(gè)工業(yè)界常用的ResNet50網(wǎng)絡(luò)作為分類(lèi)器瓢省。首先通過(guò)拷貝的方式新建一個(gè)垃圾分類(lèi)器的配置文件弄息。

cd PaddleClas/configs/ResNet/
cp ResNet50_vd.yaml garbage_ResNet50_vd.yaml

然后修改garbage_ResNet50_vd.yaml內(nèi)容如下:

mode: 'train'
ARCHITECTURE:
    name: 'ResNet50_vd'

pretrained_model: ""
model_save_dir: "./output/"
classes_num: 43
total_images: 1281167
save_interval: 1
validate: True
valid_interval: 1
epochs: 200
topk: 5
image_shape: [3, 224, 224]

use_mix: False
ls_epsilon: 0.1

LEARNING_RATE:
    function: 'Cosine'          
    params:                   
        lr: 0.001               

OPTIMIZER:
    function: 'Momentum'
    params:
        momentum: 0.9
    regularizer:
        function: 'L2'
        factor: 0.000070

TRAIN:
    batch_size: 256
    num_workers: 0
    #這里改成dataset的真實(shí)路徑,推薦使用絕對(duì)路徑
    file_list: "../dataset/train_list.txt" 
    data_dir: "../dataset/"
    shuffle_seed: 0
    transforms:
        - DecodeImage:
            to_rgb: True
            to_np: False
            channel_first: False
        - RandCropImage:
            size: 224
        - RandFlipImage:
            flip_code: 1
        - NormalizeImage:
            scale: 1./255.
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''
        - ToCHWImage:
    mix:                       
        - MixupOperator:    
            alpha: 0.2      

VALID:
    batch_size: 64
    num_workers: 0
    #這里改成dataset的真實(shí)路徑勤婚,推薦使用絕對(duì)路徑
    file_list: "../dataset/val_list.txt"
    data_dir: "../dataset/aistudio/"
    shuffle_seed: 0
    transforms:
        - DecodeImage:
            to_rgb: True
            to_np: False
            channel_first: False
        - ResizeImage:
            resize_short: 256
        - CropImage:
            size: 224
        - NormalizeImage:
            scale: 1.0/255.0
            mean: [0.485, 0.456, 0.406]
            std: [0.229, 0.224, 0.225]
            order: ''
        - ToCHWImage:

4.開(kāi)始訓(xùn)練

為了加快模型的收斂摹量,同時(shí)提升模型的精度,這里我選擇先加載預(yù)訓(xùn)練模型馒胆,然后對(duì)模型進(jìn)行微調(diào)缨称。首先需要下載預(yù)訓(xùn)練權(quán)重。

wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/ResNet50_vd_pretrained.pdparams

然后開(kāi)始訓(xùn)練模型:

python tools/train.py \
    -c configs/ResNet/garbage_ResNet50_vd.yaml \
    -o pretrained_model="ResNet50_vd_pretrained" \
    -o use_gpu=True

訓(xùn)練過(guò)程中輸入日志如下:

W1214 20:29:28.872682  1473 device_context.cc:338] Please NOTE: device: 0, CUDA Capability: 70, Driver API Version: 10.1, Runtime API Version: 10.1
W1214 20:29:28.877846  1473 device_context.cc:346] device: 0, cuDNN Version: 7.6.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1175: UserWarning: Skip loading for out.weight. out.weight receives a shape [2048, 1000], but the expected shape is [2048, 43].
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1175: UserWarning: Skip loading for out.bias. out.bias receives a shape [1000], but the expected shape is [43].
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
2020-12-14 20:29:33 INFO: Finish initing model from ResNet50_vd_pretrained
2020-12-14 20:29:36 INFO: epoch:0  , train step:0   , loss: 3.78009, top1: 0.00781, top5: 0.11328, lr: 0.001000, batch_cost: 2.94361 s, reader_cost: 2.13878 s, ips: 86.96806 images/sec.
2020-12-14 20:30:01 INFO: epoch:0  , train step:10  , loss: 3.70998, top1: 0.06641, top5: 0.26953, lr: 0.001000, batch_cost: 2.42268 s, reader_cost: 1.62624 s, ips: 105.66822 images/sec.
2020-12-14 20:30:25 INFO: epoch:0  , train step:20  , loss: 3.62013, top1: 0.10938, top5: 0.35938, lr: 0.001000, batch_cost: 2.43433 s, reader_cost: 1.63609 s, ips: 105.16244 images/sec.
2020-12-14 20:30:50 INFO: epoch:0  , train step:30  , loss: 3.53434, top1: 0.21484, top5: 0.41406, lr: 0.001000, batch_cost: 2.46094 s, reader_cost: 1.66256 s, ips: 104.02520 images/sec.

5.模型評(píng)估

為了可以快速的看到效果祝迂,訓(xùn)練100個(gè)epoch之后睦尽,可以先停止訓(xùn)練。當(dāng)前最優(yōu)模型在驗(yàn)證集上的精度為top1: 0.90589, top5: 0.98966液兽。

然后我們?cè)跍y(cè)試集上評(píng)估一下最優(yōu)模型的精度骂删。

將PaddleClas/configs/ResNet/garbage_ResNet50_vd.yaml文件中驗(yàn)證集的路徑改為測(cè)試集。

VALID:
    batch_size: 64
    num_workers: 0
    file_list: "/home/aistudio/test_list.txt"
    data_dir: "/home/aistudio/"

開(kāi)始評(píng)估模型四啰,

python tools/eval.py -c \
./configs/ResNet/garbage_ResNet50_vd.yaml -o \
pretrained_model="./output/ResNet50_vd/best_model/ppcls"

運(yùn)行結(jié)果如下:

2020-12-15 09:08:25 INFO: epoch:0  , valid step:0   , loss: 1.05716, top1: 0.89062, top5: 1.00000, lr: 0.000000, batch_cost: 0.75766 s, reader_cost: 0.68446 s, ips: 84.47009 images/sec.
2020-12-15 09:08:31 INFO: epoch:0  , valid step:10  , loss: 0.89015, top1: 0.92188, top5: 1.00000, lr: 0.000000, batch_cost: 0.58153 s, reader_cost: 0.51459 s, ips: 110.05544 images/sec.
2020-12-15 09:08:36 INFO: epoch:0  , valid step:20  , loss: 0.91526, top1: 0.90625, top5: 1.00000, lr: 0.000000, batch_cost: 0.58075 s, reader_cost: 0.51361 s, ips: 110.20320 images/sec.
2020-12-15 09:08:42 INFO: epoch:0  , valid step:30  , loss: 0.83382, top1: 0.92857, top5: 1.00000, lr: 0.000000, batch_cost: 0.55392 s, reader_cost: 0.48895 s, ips: 25.27445 images/sec.
2020-12-15 09:08:42 INFO: END epoch:0   valid loss: 0.96556, top1: 0.90331, top5: 0.99018,  batch_cost: 0.55392 s, reader_cost: 0.48895 s, batch_cost_sum: 11.63230 s, ips: 25.27445 images/sec.

可以看出當(dāng)前的最優(yōu)模型在測(cè)試集上的精度為top1: 0.90331, top5: 0.99018宁玫。準(zhǔn)確率可以達(dá)到90%,當(dāng)然這個(gè)精度還是可以繼續(xù)提升的柑晒∨繁瘢可以通過(guò)調(diào)參、更換模型和數(shù)據(jù)增強(qiáng)進(jìn)一步提升模型精度匙赞。

下一篇會(huì)解析一下PaddleClas套件中的核心代碼佛掖,以及一些調(diào)優(yōu)的策略妖碉。

PaddleClas倉(cāng)庫(kù)地址:https://github.com/PaddlePaddle/PaddleClas

本文已被收錄:
https://blog.aistudyclub.com/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芥被,隨后出現(xiàn)的幾起案子欧宜,更是在濱河造成了極大的恐慌,老刑警劉巖拴魄,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冗茸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡匹中,警方通過(guò)查閱死者的電腦和手機(jī)夏漱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)顶捷,“玉大人挂绰,你說(shuō)我怎么就攤上這事》辏” “怎么了葵蒂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)专肪。 經(jīng)常有香客問(wèn)我刹勃,道長(zhǎng),這世上最難降的妖魔是什么嚎尤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任荔仁,我火速辦了婚禮,結(jié)果婚禮上芽死,老公的妹妹穿的比我還像新娘乏梁。我一直安慰自己,他們只是感情好关贵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布遇骑。 她就那樣靜靜地躺著,像睡著了一般揖曾。 火紅的嫁衣襯著肌膚如雪落萎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天炭剪,我揣著相機(jī)與錄音练链,去河邊找鬼。 笑死奴拦,一個(gè)胖子當(dāng)著我的面吹牛媒鼓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绿鸣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼疚沐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起潮模,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亮蛔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后再登,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尔邓,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晾剖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年锉矢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片齿尽。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沽损,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出循头,到底是詐尸還是另有隱情绵估,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布卡骂,位于F島的核電站国裳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏全跨。R本人自食惡果不足惜缝左,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浓若。 院中可真熱鬧渺杉,春花似錦、人聲如沸挪钓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)碌上。三九已至倚评,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馏予,已是汗流浹背天梧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吗蚌,地道東北人腿倚。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親敷燎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子暂筝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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