MicroNet實戰(zhàn)分享!使用MicroNet實現圖像分類(二)
來源:投稿 作者:AI浩
編輯:學姐
上回我們說到了MicroNet實戰(zhàn):使用MicroNet實現圖像分類(一),完成了前期的準備工作今天第二部也來了。廢話不多,這就來學。(文末福利)
配置參數
本次訓練采用的參數是M3的配置參數,詳細的配置參數在utils/defaults.py文件,參數如下:
訓練
完成上面的步驟后,就開始train腳本的編寫,新建train.py.
導入項目使用的庫
設置全局參數
設置學習率、BatchSize、epoch等參數,判斷環(huán)境中是否存在GPU,如果沒有則使用CPU。建議使用GPU,CPU太慢了。
設置存放權重文件的文件夾,如果文件夾存在刪除再建立。
接下來,查看全局參數:
model_lr:學習率,根據實際情況做調整。
BATCH_SIZE:batchsize,根據顯卡的大小設置。
EPOCHS:epoch的個數,一般300夠用。
use_amp:是否使用混合精度。
classes:類別個數。
resume:是否接著上次模型繼續(xù)訓練。
model_path:模型的路徑。如果resume設置為True時,就采用model_path定義的模型繼續(xù)訓練。
CLIP_GRAD:梯度的最大范數,在梯度裁剪里設置。
Best_ACC:記錄最高ACC得分。
圖像預處理與增強
數據處理比較簡單,加入了Cutout、做了Resize和歸一化,定義Mixup函數。
這里注意下Resize的大小,由于MixNet的輸入是224×224的大小,所以要Resize為224×224。
讀取數據
使用pytorch默認讀取數據的方式,然后將dataset_train.class_to_idx打印出來,預測的時候要用到。
將dataset_train.class_to_idx保存到txt文件或者json文件中。
class_to_idx的結果:{‘Black-grass’: 0, ‘Charlock’: 1, ‘Cleavers’: 2, ‘Common Chickweed’: 3, ‘Common wheat’: 4, ‘Fat Hen’: 5, ‘Loose Silky-bent’: 6, ‘Maize’: 7, ‘Scentless Mayweed’: 8, ‘Shepherds Purse’: 9, ‘Small-flowered Cranesbill’: 10, ‘Sugar beet’: 11}
設置模型
設置loss函數,train的loss為:SoftTargetCrossEntropy,val的loss:nn.CrossEntropyLoss()。
設置模型為MicroNet,num_classes設置為12。如果resume為True,則加載模型接著上次訓練。
優(yōu)化器設置為adamW。
學習率調整策略選擇為余弦退火。
開啟混合精度訓練,聲明pytorch自帶的混合精度 torch.cuda.amp.GradScaler()。
檢測可用顯卡的數量,如果大于1,并且開啟多卡訓練的情況下,則要用torch.nn.DataParallel加載模型,開啟多卡訓練。
注:torch.nn.DataParallel方式,默認不能開啟混合精度訓練的,如果想要開啟混合精度訓練,則需要在模型的forward前面加上@autocast()函數。

如果不開啟混合精度則要將@autocast()去掉,否則loss一直試nan。
定義訓練和驗證函數
訓練函數 訓練的主要步驟:
1、使用AverageMeter保存自定義變量,包括loss,ACC1,ACC5。
2、判斷迭代的數據是否是奇數,由于mixup_fn只能接受偶數,所以如果不是偶數則要減去一位,讓其變成偶數。但是有可能最后一次迭代只有一條數據,減去后就變成了0,所以還要判斷不能小于2,如果小于2則直接中斷本次循環(huán)。
3、將數據輸入mixup_fn生成mixup數據,然后輸入model計算loss。
4、optimizer.zero_grad() 梯度清零,把loss關于weight的導數變成0。
5、如果使用混合精度,則 with torch.cuda.amp.autocast(),開啟混合精度。 計算loss。 scaler.scale(loss).backward(),梯度放大。 torch.nn.utils.clip_grad_norm_,梯度裁剪,放置梯度爆炸。 scaler.step(optimizer) ,首先把梯度值unscale回來,如果梯度值不是inf或NaN,則調用optimizer.step()來更新權重,否則,忽略step調用,從而保證權重不更新。 更新下一次迭代的scaler。 否則,直接反向傳播求梯度。torch.nn.utils.clip_grad_norm_函數執(zhí)行梯度裁剪,防止梯度爆炸。
6、torch.cuda.synchronize(),等待上面所有的操作執(zhí)行完成。
7、接下來,更新loss,ACC1,ACC5的值。
等待一個epoch訓練完成后,計算平均loss和平均acc
驗證函數
驗證集和訓練集大致相似,主要步驟:
定義參數,test_loss測試的loss,total_num總的驗證集的數量,val_list驗證集的label,pred_list預測的label。
在val的函數上面添加@torch.no_grad(),作用:所有計算得出的tensor的requires_grad都自動設置為False。即使一個tensor(命名為x)的requires_grad = True,在with torch.no_grad計算,由x得到的新tensor(命名為w-標量)requires_grad也為False,且grad_fn也為None,即不會對w求導。
使用驗證集的loss函數求出驗證集的loss。
調用accuracy函數計算ACC1和ACC5
更新loss_meter、acc1_meter、acc5_meter的參數。
本次epoch循環(huán)完成后,求得本次epoch的acc、loss。
如果acc比Best_ACC大,則保存模型。
調用訓練和驗證方法
調用訓練函數和驗證函數的主要步驟:
1、定義參數:
is_set_lr,是否已經設置了學習率,當epoch大于一定的次數后,會將學習率設置到一定的值,并將其置為True。
log_dir:記錄log用的,將有用的信息保存到字典中,然后轉為json保存起來。
train_loss_list:保存每個epoch的訓練loss。
val_loss_list:保存每個epoch的驗證loss。
train_acc_list:保存每個epoch的訓練acc。
val_acc_list:保存么每個epoch的驗證acc。
epoch_list:存放每個epoch的值。
循環(huán)epoch:
調用train函數,得到 train_loss, train_acc,并將分別放入train_loss_list,train_acc_list,然后存入到logdir字典中。
調用驗證函數,得到val_list, pred_list, val_loss, val_acc。將val_loss, val_acc分別放入val_loss_list和val_acc_list中,然后存入到logdir字典中。
保存log。
打印本次的測試報告。
如果epoch大于600,將學習率設置為固定的1e-6。
繪制loss曲線和acc曲線。
運行以及結果查看
完成上面的所有代碼就可以開始運行了。點擊右鍵,然后選擇“run train.py”即可,運行結果如下:

在每個epoch測試完成之后,打印驗證集的acc、recall等指標。

繪制acc曲線

繪制loss曲線:訓練了1000個epoch,最好的成績能達到93.X%
測試
測試,我們采用一種通用的方式。
測試集存放的目錄如下圖:
測試的主要邏輯:
定義類別,這個類別的順序和訓練時的類別順序對應,一定不要改變順序?。。?!
定義transforms,transforms和驗證集的transforms一樣即可,別做數據增強。
加載model,并將模型放在DEVICE里,
循環(huán) 讀取圖片并預測圖片的類別,在這里注意,讀取圖片用PIL庫的Image。不要用CV2,transforms不支持。
循環(huán)里面的主要邏輯:
使用Image.open讀取圖片
使用transform_test對圖片做歸一化和標椎化。
img.unsqueeze_(0) 增加一個維度,由(3,224,224)變?yōu)椋?,3,224,224)
Variable(img).to(DEVICE):將數據放入DEVICE中。
model(img):執(zhí)行預測。
_, pred = torch.max(out.data, 1):獲取預測值的最大下角標。
運行結果:

圖像分類的論文資料有同學需要嗎!都是CVPR高分論文!
關注【學姐帶你玩AI】公眾號
回復“CVPR”免費獲取~注意看規(guī)則