網站首頁 編程語言 正文
摘要
RepVgg通過結構重參數化讓VGG再次偉大。 所謂“VGG式”指的是:
- 沒有任何分支結構。即通常所說的plain或feed-forward架構。
- 僅使用3x3卷積。
- 僅使用ReLU作為激活函數。
RepVGG的更深版本達到了84.16%正確率!反超若干transformer!
RepVgg是如何到的呢?簡單地說就是:
- 首先, 訓練一個多分支模型
- 然后,將多分支模型等價轉換為單路模型
- 最在,在部署的時候,部署轉換后單路模型
我這篇文章主要講解如何使用RepVgg完成圖像分類任務,接下來我們一起完成項目的實戰。
通過這篇文章能讓你學到:
- 如何使用數據增強,包括transforms的增強、CutOut、MixUp、CutMix等增強手段?
- 如何實現RepVGG模型實現訓練?
- 如何將多分支模型等價轉換為單路模型?
- 如何使用pytorch自帶混合精度?
- 如何使用梯度裁剪防止梯度爆炸?
- 如何使用DP多顯卡訓練?
- 如何繪制loss和acc曲線?
- 如何生成val的測評報告?
- 如何編寫測試腳本測試測試集?
- 如何使用余弦退火策略調整學習率?
- 如何使用AverageMeter類統計ACC和loss等自定義變量?
- 如何理解和統計ACC1和ACC5?
- 如何使用EMA?
安裝包
安裝timm
使用pip就行,命令:
pip install timm
數據增強Cutout和Mixup
為了提高成績我在代碼中加入Cutout和Mixup這兩種增強方式。實現這兩種增強需要安裝torchtoolbox。安裝命令:
pip install torchtoolbox
Cutout實現,在transforms中。
from torchtoolbox.transform import Cutout
# 數據預處理
transform = transforms.Compose([
transforms.Resize((224, 224)),
Cutout(),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
需要導入包:from timm.data.mixup import Mixup,
定義Mixup,和SoftTargetCrossEntropy
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=12)
criterion_train = SoftTargetCrossEntropy()
參數詳解:
mixup_alpha (float): mixup alpha 值,如果 > 0,則 mixup 處于活動狀態。
cutmix_alpha (float):cutmix alpha 值,如果 > 0,cutmix 處于活動狀態。
cutmix_minmax (List[float]):cutmix 最小/最大圖像比率,cutmix 處于活動狀態,如果不是 None,則使用這個 vs alpha。
如果設置了 cutmix_minmax 則cutmix_alpha 默認為1.0
prob (float): 每批次或元素應用 mixup 或 cutmix 的概率。
switch_prob (float): 當兩者都處于活動狀態時切換cutmix 和mixup 的概率 。
mode (str): 如何應用 mixup/cutmix 參數(每個'batch','pair'(元素對),'elem'(元素)。
correct_lam (bool): 當 cutmix bbox 被圖像邊框剪裁時應用。 lambda 校正
label_smoothing (float):將標簽平滑應用于混合目標張量。
num_classes (int): 目標的類數。
EMA
EMA(Exponential Moving Average)是指數移動平均值。在深度學習中的做法是保存歷史的一份參數,在一定訓練階段后,拿歷史的參數給目前學習的參數做一次平滑。具體實現如下:
class EMA():
def __init__(self, model, decay):
self.model = model
self.decay = decay
self.shadow = {}
self.backup = {}
def register(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
self.shadow[name] = param.data.clone()
def update(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.shadow
new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[name]
self.shadow[name] = new_average.clone()
def apply_shadow(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.shadow
self.backup[name] = param.data
param.data = self.shadow[name]
def restore(self):
for name, param in self.model.named_parameters():
if param.requires_grad:
assert name in self.backup
param.data = self.backup[name]
self.backup = {}
加入到模型中。
# 初始化
ema = EMA(model, 0.999)
ema.register()
# 訓練過程中,更新完參數后,同步update shadow weights
def train():
optimizer.step()
ema.update()
# eval前,apply shadow weights;eval之后,恢復原來模型的參數
def evaluate():
ema.apply_shadow()
# evaluate
ema.restore()
這個ema最好放在微調的時候使用,否則驗證集不上分,或者上分很慢。
項目結構
RepVgg_demo
├─data1
│ ├─Black-grass
│ ├─Charlock
│ ├─Cleavers
│ ├─Common Chickweed
│ ├─Common wheat
│ ├─Fat Hen
│ ├─Loose Silky-bent
│ ├─Maize
│ ├─Scentless Mayweed
│ ├─Shepherds Purse
│ ├─Small-flowered Cranesbill
│ └─Sugar beet
├─models
│ ├─__init__.py
│ ├─repvgg.py
│ └─se_block.py
├─mean_std.py
├─makedata.py
├─ema.py
├─train.py
└─test.py
mean_std.py:計算mean和std的值。 makedata.py:生成數據集。 ema.py:EMA腳本 models文件夾下的repvgg.py和se_block.py:來自官方的pytorch版本的代碼。 - repvgg.py:網絡文件。 - se_block.py:SE注意力機制。
為了能在DP方式中使用混合精度,還需要在模型的forward函數前增加@autocast()。
計算mean和std
為了使模型更加快速的收斂,我們需要計算出mean和std的值,新建mean_std.py,插入代碼:
from torchvision.datasets import ImageFolder
import torch
from torchvision import transforms
def get_mean_and_std(train_data):
train_loader = torch.utils.data.DataLoader(
train_data, batch_size=1, shuffle=False, num_workers=0,
pin_memory=True)
mean = torch.zeros(3)
std = torch.zeros(3)
for X, _ in train_loader:
for d in range(3):
mean[d] += X[:, d, :, :].mean()
std[d] += X[:, d, :, :].std()
mean.div_(len(train_data))
std.div_(len(train_data))
return list(mean.numpy()), list(std.numpy())
if __name__ == '__main__':
train_dataset = ImageFolder(root=r'data1', transform=transforms.ToTensor())
print(get_mean_and_std(train_dataset))
數據集結構:
運行結果:
([0.3281186, 0.28937867, 0.20702125], [0.09407319, 0.09732835, 0.106712654])
把這個結果記錄下來,后面要用!
生成數據集
我們整理還的圖像分類的數據集結構是這樣的
data
├─Black-grass
├─Charlock
├─Cleavers
├─Common Chickweed
├─Common wheat
├─Fat Hen
├─Loose Silky-bent
├─Maize
├─Scentless Mayweed
├─Shepherds Purse
├─Small-flowered Cranesbill
└─Sugar beet
pytorch和keras默認加載方式是ImageNet數據集格式,格式是
├─data
│ ├─val
│ │ ├─Black-grass
│ │ ├─Charlock
│ │ ├─Cleavers
│ │ ├─Common Chickweed
│ │ ├─Common wheat
│ │ ├─Fat Hen
│ │ ├─Loose Silky-bent
│ │ ├─Maize
│ │ ├─Scentless Mayweed
│ │ ├─Shepherds Purse
│ │ ├─Small-flowered Cranesbill
│ │ └─Sugar beet
│ └─train
│ ├─Black-grass
│ ├─Charlock
│ ├─Cleavers
│ ├─Common Chickweed
│ ├─Common wheat
│ ├─Fat Hen
│ ├─Loose Silky-bent
│ ├─Maize
│ ├─Scentless Mayweed
│ ├─Shepherds Purse
│ ├─Small-flowered Cranesbill
│ └─Sugar beet
新增格式轉化腳本makedata.py,插入代碼:
import glob
import os
import shutil
image_list=glob.glob('data1/*/*.png')
print(image_list)
file_dir='data'
if os.path.exists(file_dir):
print('true')
#os.rmdir(file_dir)
shutil.rmtree(file_dir)#刪除再建立
os.makedirs(file_dir)
else:
os.makedirs(file_dir)
from sklearn.model_selection import train_test_split
trainval_files, val_files = train_test_split(image_list, test_size=0.3, random_state=42)
train_dir='train'
val_dir='val'
train_root=os.path.join(file_dir,train_dir)
val_root=os.path.join(file_dir,val_dir)
for file in trainval_files:
file_class=file.replace("\\","/").split('/')[-2]
file_name=file.replace("\\","/").split('/')[-1]
file_class=os.path.join(train_root,file_class)
if not os.path.isdir(file_class):
os.makedirs(file_class)
shutil.copy(file, file_class + '/' + file_name)
for file in val_files:
file_class=file.replace("\\","/").split('/')[-2]
file_name=file.replace("\\","/").split('/')[-1]
file_class=os.path.join(val_root,file_class)
if not os.path.isdir(file_class):
os.makedirs(file_class)
shutil.copy(file, file_class + '/' + file_name)
完成上面的內容就可以開啟訓練和測試了。
原文鏈接:https://juejin.cn/post/7153196236080676895
相關推薦
- 2023-03-26 C#?try?catch代碼塊不起效果的解決方法_C#教程
- 2022-12-04 Android自定義View繪制貝塞爾曲線實現流程_Android
- 2022-07-03 C#并行編程之信號量_C#教程
- 2022-04-07 代碼詳解Python的函數基礎(1)_python
- 2022-05-08 python列表的構造方法list()_python
- 2022-04-11 C#實現簡單的計算器功能(窗體)_C#教程
- 2022-07-16 Electron項目中的NSIS配置項
- 2022-07-18 SQL?Server中的文本函數和圖像函數介紹_MsSql
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支