最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

MobileOne實戰(zhàn):使用MobileOne實現(xiàn)圖像分類任務(wù)(二)

2023-04-11 19:38 作者:AI小浩  | 我要投稿

@[toc]

在上一篇文章中完成了前期的準(zhǔn)備工作,見鏈接:

[MobileOne實戰(zhàn):使用MobileOne實現(xiàn)圖像分類任務(wù)(一)](https://wanghao.blog.csdn.net/article/details/128106644?spm=1001.2014.3001.5502)

這篇主要是講解如何訓(xùn)練和測試


# 訓(xùn)練


完成上面的步驟后,就開始train腳本的編寫,新建train.py.


## 導(dǎo)入項目使用的庫


```python

import json

import os

import matplotlib.pyplot as plt

import torch

import torch.nn as nn

import torch.nn.parallel

import torch.optim as optim

import torch.utils.data

import torch.utils.data.distributed

import torchvision.transforms as transforms

from timm.utils import accuracy, AverageMeter, ModelEma

from sklearn.metrics import classification_report

from timm.data.mixup import Mixup

from timm.loss import SoftTargetCrossEntropy

from torch.autograd import Variable

from torchvision import datasets

from mobileone_pytorch import mobileone_s4

torch.backends.cudnn.benchmark = False

import warnings

warnings.filterwarnings("ignore")

```


## 設(shè)置全局參數(shù)


設(shè)置學(xué)習(xí)率、BatchSize、epoch等參數(shù),判斷環(huán)境中是否存在GPU,如果沒有則使用CPU。建議使用GPU,CPU太慢了。


```python

if __name__ == '__main__':

? ? #創(chuàng)建保存模型的文件夾

? ? file_dir = 'checkpoints/MobileOne'

? ? if os.path.exists(file_dir):

? ? ? ? print('true')


? ? ? ? os.makedirs(file_dir,exist_ok=True)

? ? else:

? ? ? ? os.makedirs(file_dir)


? ? # 設(shè)置全局參數(shù)

? ? model_lr = 1e-4

? ? BATCH_SIZE = 16

? ? EPOCHS = 1000

? ? DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

? ? use_amp = True? # 是否使用混合精度

? ? use_dp = False #是否開啟dp方式的多卡訓(xùn)練

? ? classes = 12

? ? resume =None

? ? CLIP_GRAD = 5.0

? ? Best_ACC = 0 #記錄最高得分

? ? use_ema=True

? ? model_ema_decay=0.9998

? ? start_epoch=1

```


設(shè)置存放權(quán)重文件的文件夾,如果文件夾存在刪除再建立。


接下來,查看全局參數(shù):


> model_lr:學(xué)習(xí)率,根據(jù)實際情況做調(diào)整。

>

> BATCH_SIZE:batchsize,根據(jù)顯卡的大小設(shè)置。

>

> EPOCHS:epoch的個數(shù),一般300夠用。

>

> use_amp:是否使用混合精度。

>

> classes:類別個數(shù)。

>

> resume:是否接著上次模型繼續(xù)訓(xùn)練,如果不為空,則按照resume的值加載模型。如果是None則表示不接著上次訓(xùn)練的模型訓(xùn)練。

>

> CLIP_GRAD:梯度的最大范數(shù),在梯度裁剪里設(shè)置。

>

> Best_ACC:記錄最高ACC得分。

> use_ema:是否使用ema

> model_ema_decay:ema衰減值,

> start_epoch:開始訓(xùn)練的epoch,默認(rèn)是1,如果再次訓(xùn)練的時候,加載模型的時候會自動對其設(shè)置。


## 圖像預(yù)處理與增強(qiáng)


數(shù)據(jù)處理比較簡單,加入了隨機(jī)10度的旋轉(zhuǎn)、高斯模糊、顏色的調(diào)整、做了Resize和歸一化,定義Mixup函數(shù)。


這里注意下Resize的大小,由于選用的Ghost模型輸入是224×224的大小,所以要Resize為224×224。


```python

# 數(shù)據(jù)預(yù)處理7

? ? transform = transforms.Compose([

? ? ? ? transforms.RandomRotation(10),

? ? ? ? transforms.GaussianBlur(kernel_size=(5,5),sigma=(0.1, 3.0)),

? ? ? ? transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5),

? ? ? ? transforms.Resize((224, 224)),

? ? ? ? transforms.ToTensor(),

? ? ? ? transforms.Normalize(mean=[0.44127703, 0.4712498, 0.43714803], std= [0.18507297, 0.18050247, 0.16784933])


? ? ])

? ? transform_test = transforms.Compose([

? ? ? ? transforms.Resize((224, 224)),

? ? ? ? transforms.ToTensor(),

? ? ? ? transforms.Normalize(mean=[0.44127703, 0.4712498, 0.43714803], std= [0.18507297, 0.18050247, 0.16784933])

? ? ])

? ? mixup_fn = Mixup(

? ? ? ? mixup_alpha=0.8, cutmix_alpha=1.0, cutmix_minmax=None,

? ? ? ? prob=0.1, switch_prob=0.5, mode='batch',

? ? ? ? label_smoothing=0.1, num_classes=classes)

```


##? 讀取數(shù)據(jù)


使用pytorch默認(rèn)讀取數(shù)據(jù)的方式,然后將dataset_train.class_to_idx打印出來,預(yù)測的時候要用到。


將dataset_train.class_to_idx保存到txt文件或者json文件中。


```python

? dataset_train = datasets.ImageFolder('data/train', transform=transform)

? ? dataset_test = datasets.ImageFolder("data/val", transform=transform_test)

? ? with open('class.txt', 'w') as file:

? ? ? ? file.write(str(dataset_train.class_to_idx))

? ? with open('class.json', 'w', encoding='utf-8') as file:

? ? ? ? file.write(json.dumps(dataset_train.class_to_idx))

? ? # 導(dǎo)入數(shù)據(jù)

? ? train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True,drop_last=True)

? ? test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=False)

```

在train_loader中將drop_last設(shè)置為True了,舍棄最后一次迭代,因為MixUp要求輸入的Batchsize是偶數(shù),但是最后一次迭代有可能是奇數(shù)所以就會報錯。

class_to_idx的結(jié)果:


{'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}


## 設(shè)置模型


?- 設(shè)置loss函數(shù),train的loss為:SoftTargetCrossEntropy,val的loss:nn.CrossEntropyLoss()。

- 設(shè)置模型為mobileone_s4,num_classes設(shè)置為12。如果resume為True,則加載模型接著上次訓(xùn)練。在val階段保存的模型,在這里要注意,我只保存了模型的權(quán)重參數(shù),沒有保存整個模型。Best模型只保存了權(quán)重參數(shù),在保存每個epoch的模型時,除了保存權(quán)重參數(shù)外,還保存了 Best_ACC和epoch信息,方便再次訓(xùn)練。

- 如果resume不為None,則表示再次載入模型訓(xùn)練,將模型的權(quán)重參數(shù)載入,再次訓(xùn)練。

- 優(yōu)化器設(shè)置為adamW。

- 學(xué)習(xí)率調(diào)整策略選擇為余弦退火。

- 開啟混合精度訓(xùn)練,聲明pytorch自帶的混合精度 torch.cuda.amp.GradScaler()。

- 檢測可用顯卡的數(shù)量,如果大于1,并且開啟多卡訓(xùn)練的情況下,則要用torch.nn.DataParallel加載模型,開啟多卡訓(xùn)練。

- use_ema,是否使用ema,如果為True,則初始化ema。


```python

? ? ?# 實例化模型并且移動到GPU

? ? criterion_train = SoftTargetCrossEntropy()

? ? criterion_val = torch.nn.CrossEntropyLoss()

? ? #設(shè)置模型

? ? model_ft = mobileone_s4()

? ? print(model_ft)

? ? num_ftrs = model_ft._linear.in_features

? ? model_ft._linear = nn.Linear(num_ftrs, classes)

? ? if resume:

? ? ? ? model=torch.load(resume)

? ? ? ? model_ft.load_state_dict(model['state_dict'])

? ? ? ? Best_ACC=model['Best_ACC']

? ? ? ? start_epoch=model['epoch']+1

? ? model_ft.to(DEVICE)

? ? # 選擇簡單暴力的Adam優(yōu)化器,學(xué)習(xí)率調(diào)低

? ? optimizer = optim.AdamW(model_ft.parameters(),lr=model_lr)

? ? cosine_schedule = optim.lr_scheduler.CosineAnnealingLR(optimizer=optimizer, T_max=20, eta_min=1e-6)

? ? if use_amp:

? ? ? ? scaler = torch.cuda.amp.GradScaler()

? ? if torch.cuda.device_count() > 1 and use_dp:

? ? ? ? print("Let's use", torch.cuda.device_count(), "GPUs!")

? ? ? ? model_ft = torch.nn.DataParallel(model_ft)

? ? if use_ema:

? ? ? ? model_ema = ModelEma(

? ? ? ? ? ? model_ft,

? ? ? ? ? ? decay=model_ema_decay,

? ? ? ? ? ? device=DEVICE,

? ? ? ? ? ? resume=resume)

? ? else:

? ? ? ? model_ema=None


```

注:torch.nn.DataParallel方式,默認(rèn)不能開啟混合精度訓(xùn)練的,如果想要開啟混合精度訓(xùn)練,則需要在模型的forward前面加上@autocast()函數(shù)。導(dǎo)入包from torch.cuda.amp import autocast,如果是cpu,則導(dǎo)入from torch.cpu.amp import autocast

![在這里插入圖片描述](https://img-blog.csdnimg.cn/dbd3a2785e284947ab820424394bfac0.png)





如果不開啟混合精度則要將@autocast()去掉,否則loss一直試nan。如果不開DP模式也要去掉。


## 定義訓(xùn)練和驗證函數(shù)


### 訓(xùn)練函數(shù)


訓(xùn)練的主要步驟:


> 1、使用AverageMeter保存自定義變量,包括loss,ACC1,ACC5。


> 2、將數(shù)據(jù)輸入mixup_fn生成mixup數(shù)據(jù),然后輸入model計算loss。


> 3、 optimizer.zero_grad() 梯度清零,把loss關(guān)于weight的導(dǎo)數(shù)變成0。


> 4、如果使用混合精度,則

>

> > - with torch.cuda.amp.autocast(),開啟混合精度。

> > - 計算loss。

> > - scaler.scale(loss).backward(),梯度放大。

> > - torch.nn.utils.clip_grad_norm_,梯度裁剪,放置梯度爆炸。

> > - scaler.step(optimizer) ,首先把梯度值unscale回來,如果梯度值不是inf或NaN,則調(diào)用optimizer.step()來更新權(quán)重,否則,忽略step調(diào)用,從而保證權(quán)重不更新。

> > - 更新下一次迭代的scaler。

>

> 否則,直接反向傳播求梯度。torch.nn.utils.clip_grad_norm_函數(shù)執(zhí)行梯度裁剪,防止梯度爆炸。

>?

>5、如果model_ema不為None,則執(zhí)行model_ema的updata函數(shù),更新模型。

>

> 6、 torch.cuda.synchronize(),等待上面所有的操作執(zhí)行完成。


> 7、接下來,更新loss,ACC1,ACC5的值。


等待一個epoch訓(xùn)練完成后,計算平均loss和平均acc


```python

# 定義訓(xùn)練過程

def train(model, device, train_loader, optimizer, epoch,model_ema):

? ? model.train()

? ? loss_meter = AverageMeter()

? ? acc1_meter = AverageMeter()

? ? acc5_meter = AverageMeter()

? ? total_num = len(train_loader.dataset)

? ? print(total_num, len(train_loader))

? ? for batch_idx, (data, target) in enumerate(train_loader):

? ? ? ? data, target = data.to(device, non_blocking=True), target.to(device, non_blocking=True)

? ? ? ? samples, targets = mixup_fn(data, target)

? ? ? ? output = model(samples)

? ? ? ? optimizer.zero_grad()

? ? ? ? if use_amp:

? ? ? ? ? ? with torch.cuda.amp.autocast():

? ? ? ? ? ? ? ? loss = criterion_train(output, targets)

? ? ? ? ? ? scaler.scale(loss).backward()

? ? ? ? ? ? torch.nn.utils.clip_grad_norm_(model.parameters(), CLIP_GRAD)

? ? ? ? ? ? # Unscales gradients and calls

? ? ? ? ? ? # or skips optimizer.step()

? ? ? ? ? ? scaler.step(optimizer)

? ? ? ? ? ? # Updates the scale for next iteration

? ? ? ? ? ? scaler.update()

? ? ? ? else:

? ? ? ? ? ? loss = criterion_train(output, targets)

? ? ? ? ? ? loss.backward()

? ? ? ? ? ? # torch.nn.utils.clip_grad_norm_(model.parameters(), CLIP_GRAD)

? ? ? ? ? ? optimizer.step()

? ? ? ? if model_ema is not None:

? ? ? ? ? ? model_ema.update(model)

? ? ? ? torch.cuda.synchronize()

? ? ? ? lr = optimizer.state_dict()['param_groups'][0]['lr']

? ? ? ? loss_meter.update(loss.item(), target.size(0))

? ? ? ? acc1, acc5 = accuracy(output, target, topk=(1, 5))

? ? ? ? loss_meter.update(loss.item(), target.size(0))

? ? ? ? acc1_meter.update(acc1.item(), target.size(0))

? ? ? ? acc5_meter.update(acc5.item(), target.size(0))

? ? ? ? if (batch_idx + 1) % 10 == 0:

? ? ? ? ? ? print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}\tLR:{:.9f}'.format(

? ? ? ? ? ? ? ? epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),

? ? ? ? ? ? ? ? ? ? ? ?100. * (batch_idx + 1) / len(train_loader), loss.item(), lr))

? ? ave_loss =loss_meter.avg

? ? acc = acc1_meter.avg

? ? print('epoch:{}\tloss:{:.2f}\tacc:{:.2f}'.format(epoch, ave_loss, acc))

? ? return ave_loss, acc

```


### 驗證函數(shù)


驗證集和訓(xùn)練集大致相似,主要步驟:


> 1、定義參數(shù),test_loss測試的loss,total_num總的驗證集的數(shù)量,val_list驗證集的label,pred_list預(yù)測的label。


> 2、在val的函數(shù)上面添加@torch.no_grad(),作用:所有計算得出的tensor的requires_grad都自動設(shè)置為False。即使一個tensor(命名為x)的requires_grad = True,在with torch.no_grad計算,由x得到的新tensor(命名為w-標(biāo)量)requires_grad也為False,且grad_fn也為None,即不會對w求導(dǎo)。


> 3、使用驗證集的loss函數(shù)求出驗證集的loss。


> 4、調(diào)用accuracy函數(shù)計算ACC1和ACC5

>

> 5、更新loss_meter、acc1_meter、acc5_meter的參數(shù)。


本次epoch循環(huán)完成后,求得本次epoch的acc、loss。


如果acc比Best_ACC大,則保存模型。

保存模型的邏輯:

> 如果ACC比Best_ACC高,則保存best模型

> 判斷模型是否為DP方式訓(xùn)練的模型。

> >如果是DP方式訓(xùn)練的模型,模型參數(shù)放在model.module,則需要保存model.module。

> >否則直接保存model。

> 這里注意:只保存了model的參數(shù),沒有整個模型,因為Rep模型還要經(jīng)歷轉(zhuǎn)換,轉(zhuǎn)換代碼里面使用load_state_dict加載的,所以只能保存模型的參數(shù)。

> 接下來保存每個epoch的模型。

> 判斷模型是否為DP方式訓(xùn)練的模型。

> >如果是DP方式訓(xùn)練的模型,模型參數(shù)放在model.module,則需要保存model.module.state_dict()。

> >新建個字典,放置Best_ACC、epoch和 model.module.state_dict()等參數(shù)。然后將這個字典保存。

> >否則,新建個字典,放置Best_ACC、epoch和 model.state_dict()等參數(shù)。然后將這個字典保存。

在這里注意:對于每個epoch的模型只保存了state_dict參數(shù),沒有保存整個模型文件。

```python

# 驗證過程

@torch.no_grad()

def val(model, device, test_loader):

? ? global Best_ACC

? ? model.eval()

? ? loss_meter = AverageMeter()

? ? acc1_meter = AverageMeter()

? ? acc5_meter = AverageMeter()

? ? total_num = len(test_loader.dataset)

? ? print(total_num, len(test_loader))

? ? val_list = []

? ? pred_list = []


? ? for data, target in test_loader:

? ? ? ? for t in target:

? ? ? ? ? ? val_list.append(t.data.item())

? ? ? ? data, target = data.to(device,non_blocking=True), target.to(device,non_blocking=True)

? ? ? ? output = model(data)

? ? ? ? loss = criterion_val(output, target)

? ? ? ? _, pred = torch.max(output.data, 1)

? ? ? ? for p in pred:

? ? ? ? ? ? pred_list.append(p.data.item())

? ? ? ? acc1, acc5 = accuracy(output, target, topk=(1, 5))

? ? ? ? loss_meter.update(loss.item(), target.size(0))

? ? ? ? acc1_meter.update(acc1.item(), target.size(0))

? ? ? ? acc5_meter.update(acc5.item(), target.size(0))

? ? acc = acc1_meter.avg

? ? print('\nVal set: Average loss: {:.4f}\tAcc1:{:.3f}%\tAcc5:{:.3f}%\n'.format(

? ? ? ? loss_meter.avg,? acc,? acc5_meter.avg))


? ? if acc > Best_ACC:

? ? ? ? if isinstance(model, torch.nn.DataParallel):

? ? ? ? ? ? torch.save(model.module.state_dict(), file_dir + '/' + 'best.pth')

? ? ? ? else:

? ? ? ? ? ? torch.save(model.state_dict(), file_dir + '/' + 'best.pth')

? ? ? ? Best_ACC = acc

? ? if isinstance(model, torch.nn.DataParallel):

? ? ? ? state = {


? ? ? ? ? ? 'epoch': epoch,

? ? ? ? ? ? 'state_dict': model.module.state_dict(),

? ? ? ? ? ? 'Best_ACC':Best_ACC

? ? ? ? }

? ? ? ? torch.save(state, file_dir + "/" + 'model_' + str(epoch) + '_' + str(round(acc, 3)) + '.pth')

? ? else:

? ? ? ? state = {

? ? ? ? ? ? 'epoch': epoch,

? ? ? ? ? ? 'state_dict': model.state_dict(),

? ? ? ? ? ? 'Best_ACC': Best_ACC

? ? ? ? }

? ? ? ? torch.save(state, file_dir + "/" + 'model_' + str(epoch) + '_' + str(round(acc, 3)) + '.pth')

? ? return val_list, pred_list, loss_meter.avg, acc


```

### 調(diào)用訓(xùn)練和驗證方法


調(diào)用訓(xùn)練函數(shù)和驗證函數(shù)的主要步驟:


> 1、定義參數(shù):

>

> - is_set_lr,是否已經(jīng)設(shè)置了學(xué)習(xí)率,當(dāng)epoch大于一定的次數(shù)后,會將學(xué)習(xí)率設(shè)置到一定的值,并將其置為True。

> - log_dir:記錄log用的,將有用的信息保存到字典中,然后轉(zhuǎn)為json保存起來。

> - train_loss_list:保存每個epoch的訓(xùn)練loss。

> - val_loss_list:保存每個epoch的驗證loss。

> - train_acc_list:保存每個epoch的訓(xùn)練acc。

> - val_acc_list:保存么每個epoch的驗證acc。

> - epoch_list:存放每個epoch的值。

>

>?


> 循環(huán)epoch

>

> > 1、調(diào)用train函數(shù),得到 train_loss, train_acc,并將分別放入train_loss_list,train_acc_list,然后存入到logdir字典中。

> >2、如果use_ema為True,則使用ema,所以將ema模型傳入驗證函數(shù),否則將model_ft模型傳入驗證函數(shù)。

> > 3、調(diào)用驗證函數(shù),得到val_list, pred_list, val_loss, val_acc。將val_loss, val_acc分別放入val_loss_list和val_acc_list中,然后存入到logdir字典中。

> >

> > 4、保存log。

> >

> > 5、打印本次的測試報告。

> >

> >6、如果epoch大于600,將學(xué)習(xí)率設(shè)置為固定的1e-6。

> >

> > 7、繪制loss曲線和acc曲線。




```python

? ? ? # 訓(xùn)練與驗證

? ? is_set_lr = False

? ? log_dir = {}

? ? train_loss_list, val_loss_list, train_acc_list, val_acc_list, epoch_list = [], [], [], [], []

? ? for epoch in range(1, EPOCHS + 1):

? ? ? ? epoch_list.append(epoch)

? ? ? ? train_loss, train_acc = train(model_ft, DEVICE, train_loader, optimizer, epoch,model_ema)

? ? ? ? train_loss_list.append(train_loss)

? ? ? ? train_acc_list.append(train_acc)

? ? ? ? log_dir['train_acc'] = train_acc_list

? ? ? ? log_dir['train_loss'] = train_loss_list

? ? ? ? if use_ema:

? ? ? ? ? ? val_list, pred_list, val_loss, val_acc = val(model_ema.ema, DEVICE, test_loader)

? ? ? ? else:

? ? ? ? ? ? val_list, pred_list, val_loss, val_acc = val(model_ft, DEVICE, test_loader)

? ? ? ? val_loss_list.append(val_loss)

? ? ? ? val_acc_list.append(val_acc)

? ? ? ? log_dir['val_acc'] = val_acc_list

? ? ? ? log_dir['val_loss'] = val_loss_list

? ? ? ? log_dir['best_acc'] = Best_ACC

? ? ? ? with open(file_dir + '/result.json', 'w', encoding='utf-8') as file:

? ? ? ? ? ? file.write(json.dumps(log_dir))

? ? ? ? print(classification_report(val_list, pred_list, target_names=dataset_train.class_to_idx))

? ? ? ? if epoch < 600:

? ? ? ? ? ? cosine_schedule.step()

? ? ? ? else:

? ? ? ? ? ? if not is_set_lr:

? ? ? ? ? ? ? ? for param_group in optimizer.param_groups:

? ? ? ? ? ? ? ? ? ? param_group["lr"] = 1e-6

? ? ? ? ? ? ? ? ? ? is_set_lr = True

? ? ? ? fig = plt.figure(1)

? ? ? ? plt.plot(epoch_list, train_loss_list, 'r-', label=u'Train Loss')

? ? ? ? # 顯示圖例

? ? ? ? plt.plot(epoch_list, val_loss_list, 'b-', label=u'Val Loss')

? ? ? ? plt.legend(["Train Loss", "Val Loss"], loc="upper right")

? ? ? ? plt.xlabel(u'epoch')

? ? ? ? plt.ylabel(u'loss')

? ? ? ? plt.title('Model Loss ')

? ? ? ? plt.savefig(file_dir + "/loss.png")

? ? ? ? plt.close(1)

? ? ? ? fig2 = plt.figure(2)

? ? ? ? plt.plot(epoch_list, train_acc_list, 'r-', label=u'Train Acc')

? ? ? ? plt.plot(epoch_list, val_acc_list, 'b-', label=u'Val Acc')

? ? ? ? plt.legend(["Train Acc", "Val Acc"], loc="lower right")

? ? ? ? plt.title("Model Acc")

? ? ? ? plt.ylabel("acc")

? ? ? ? plt.xlabel("epoch")

? ? ? ? plt.savefig(file_dir + "/acc.png")

? ? ? ? plt.close(2)


```



然后,就可以開始運行了。點擊右鍵,然后選擇“run train.py”即可,運行結(jié)果如下:

![在這里插入圖片描述](https://img-blog.csdnimg.cn/08c92e050b7e46878e2f757812df4979.png)




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


![在這里插入圖片描述](https://img-blog.csdnimg.cn/03426135bdf34f2f84aea616ab00c129.png)





繪制acc曲線


![在這里插入圖片描述](https://img-blog.csdnimg.cn/b43a56cdeadb46afa4f8d80932e09ae8.png)






繪制loss曲線


訓(xùn)練了100個epoch,最好的成績能達(dá)到90+%

# 再次訓(xùn)練

如果在訓(xùn)練的過程中,各種情況造成的意外中斷,這時候就需要接著上次訓(xùn)練的結(jié)果再次訓(xùn)練。

再次訓(xùn)練給resume附上模型路徑即可。

例:


```python

resume ='checkpoints/MobileOne/model_3_10.581.pth'

```

## 再次訓(xùn)練的模型為什么只保存model.state_dict()

我在嘗試用完整的模型載入訓(xùn)練時候,由于開啟了混合精度訓(xùn)練,就開始各種報錯。比如:https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/128060221?spm=1001.2014.3001.5501

還有l(wèi)oss為Nan的問題。只有關(guān)閉了混合精度訓(xùn)練才能避免這些。如果只保存model.state_dict(),再次載入模型的時候,我們會先定義模型,這樣就避免了這些問題。這是我多次嘗試得出的結(jié)論。

#? 關(guān)于加入EMA后驗證集不得分的問題

由于沒有使用預(yù)訓(xùn)練模型,我們使用EMA后,就會發(fā)現(xiàn)驗證集的ACC一直不增長,那么我們應(yīng)該怎么辦呢?

?

?我的解決方法是,現(xiàn)將use_ema設(shè)置為false,訓(xùn)練幾個epoch,然后再將use_ema設(shè)置為True,然后將載入訓(xùn)練的模型繼續(xù)訓(xùn)練。這樣驗證集的ACC就可以正常上升了。

?如果將EMA設(shè)置為True之后,還是不上分,則去掉EMA。



?

# 測試


測試,我們采用一種通用的方式。


測試集存放的目錄如下圖:


```

MobileOne_demo

├─test

│? ├─1.jpg

│? ├─2.jpg

│? ├─3.jpg

│? ├ ......

└─test.py

```


```python

import torch.utils.data.distributed

import torchvision.transforms as transforms

from PIL import Image

from torch.autograd import Variable

import os

from mobileone_pytorch import mobileone_s4

classes = ('Black-grass', 'Charlock', 'Cleavers', 'Common Chickweed',

? ? ? ? ? ?'Common wheat', 'Fat Hen', 'Loose Silky-bent',

? ? ? ? ? ?'Maize', 'Scentless Mayweed', 'Shepherds Purse', 'Small-flowered Cranesbill', 'Sugar beet')

transform_test = transforms.Compose([

? ? transforms.Resize((224, 224)),

? ? transforms.ToTensor(),

? ? transforms.Normalize(mean=[0.51819474, 0.5250407, 0.4945761], std=[0.24228974, 0.24347611, 0.2530049])

])


DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

model_ft = mobileone_s4()

print(model_ft)

num_ftrs = model_ft._linear.in_features

model_ft._linear = torch.nn.Linear(num_ftrs, 12)

model=torch.load('checkpoints/MobileOne/best.pth')

model_ft.load_state_dict(model)

deployed = model_ft.reparametrize()

deployed.eval()

model_ft.eval()

model_ft.to(DEVICE)

deployed.to(DEVICE)


path = 'test/'

testList = os.listdir(path)

for file in testList:

? ? img = Image.open(path + file)

? ? img = transform_test(img)

? ? img.unsqueeze_(0)

? ? img = Variable(img).to(DEVICE)

? ? out = deployed(img)

? ? # Predict

? ? _, pred = torch.max(out.data, 1)

? ? print('Image Name:{},predict:{}'.format(file, classes[pred.data.item()]))


```


測試的主要邏輯:


>? 1、定義類別,這個類別的順序和訓(xùn)練時的類別順序?qū)?yīng),一定不要改變順序!?。?!


> 2、定義transforms,transforms和驗證集的transforms一樣即可,別做數(shù)據(jù)增強(qiáng)。


>3、 定義mobileone模型,然后加載best模型的參數(shù)。

> deployed = model_ft.reparametrize(),定義轉(zhuǎn)換后的模型。

>然后將deployed 加入到DEVICE上。


>4、循環(huán) 讀取圖片并預(yù)測圖片的類別,在這里注意,讀取圖片用PIL庫的Image。不要用CV2,transforms不支持。循環(huán)里面的主要邏輯:

>

>> - 使用Image.open讀取圖片

>> - 使用transform_test對圖片做歸一化和標(biāo)椎化。

>> - img.unsqueeze_(0) 增加一個維度,由(3,224,224)變?yōu)椋?,3,224,224)

>> - Variable(img).to(DEVICE):將數(shù)據(jù)放入DEVICE中。

>> - deployed(img):執(zhí)行預(yù)測。

>> - _, pred = torch.max(out.data, 1):獲取預(yù)測值的最大下角標(biāo)。


運行結(jié)果:


![在這里插入圖片描述](https://img-blog.csdnimg.cn/807ae7ab39064706b0bee094e3829c06.png)






# 總結(jié)

到這里,MobileOne的實戰(zhàn)案例就完成了。通過這篇文章,你可以學(xué)到:

>1. 如何使用數(shù)據(jù)增強(qiáng),包括transforms的增強(qiáng)、CutOut、MixUp、CutMix等增強(qiáng)手段?

>2. 如何實現(xiàn)MobileOne模型實現(xiàn)訓(xùn)練?

>3. 如何使用pytorch自帶混合精度?

>4. 如何使用梯度裁剪防止梯度爆炸?

>5. 如何使用DP多顯卡訓(xùn)練?

>6. 如何繪制loss和acc曲線?

>7. 如何生成val的測評報告?

>8. 如何編寫測試腳本測試測試集?

>9. 如何使用余弦退火策略調(diào)整學(xué)習(xí)率?

>10. 如何使用AverageMeter類統(tǒng)計ACC和loss等自定義變量?

>11. 如何理解和統(tǒng)計ACC1和ACC5?

>12. 如何使用EMA?



本例用到的代碼和數(shù)據(jù)集詳見:

https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/87218460


MobileOne實戰(zhàn):使用MobileOne實現(xiàn)圖像分類任務(wù)(二)的評論 (共 條)

分享到微博請遵守國家法律
剑阁县| 湖北省| 赣州市| 亳州市| 扎囊县| 汉寿县| 松桃| 潜山县| 兴海县| 同德县| 娱乐| 措勤县| 涪陵区| 逊克县| 台东县| 龙游县| 汝南县| 江都市| 铅山县| 洪湖市| 永登县| 八宿县| 麻江县| 丹寨县| 梅州市| 深州市| 昌平区| 时尚| 白银市| 镇康县| 淮滨县| 固原市| 榆林市| 贺州市| 汉阴县| 惠来县| 册亨县| 绍兴市| 澎湖县| 平乡县| 德阳市|