RDNet實戰:使用RDNet實現圖像分類任務(一)

論文提出的模型主要基于對傳統DenseNet架構的改進和復興,通過一系列創新設計,旨在提升模型性能并優化其計算效率,提出了RDNet模型。該模型的主要特點和改進點:

1. 強調并優化連接操作(Concatenation)

論文首先強調了DenseNet中連接操作(Concatenation)的重要性,并通過廣泛的實驗驗證了連接操作在性能上能夠超越傳統的加法快捷連接(Additive Shortcut)。這一發現促使研究者們重新審視并優化DenseNet的連接機制。

2. 擴大中間通道維度

為了進一步提升模型性能,論文提出通過調整擴展比(Expansion Ratio, ER)來增大中間張量(Tensor)的尺寸,使其超過輸入維度。傳統方法中,ER主要用于調整輸入和輸出維度,但在這篇論文中,ER被重新設計為與輸入維度成比例,即ER與增長率(Growth Rate, GR)解耦。這種設計使得在非線性處理之前能夠更充分地豐富特征,同時為了管理由此產生的計算需求,將GR減半(例如從120減少到60),從而在不影響準確性的前提下控制計算量。

3. 記憶高效的DenseNet設計

為了優化DenseNet的架構設計,論文采用了更加內存高效的設計策略,通過丟棄無效組件并增強架構和塊設計,同時保持DenseNet的核心連接機制不變。這種設計使得模型在保持高性能的同時,也減少了內存占用,提升了處理大規模數據集的能力。

在這里插入圖片描述

本文使用RDNet模型實現圖像分類任務,模型選擇rdnet_tiny,在植物幼苗分類任務ACC達到了97%+。

在這里插入圖片描述

在這里插入圖片描述

通過這篇文章能讓你學到:

  1. 如何使用數據增強,包括transforms的增強、CutOut、MixUp、CutMix等增強手段?
  2. 如何實現RDNet模型實現訓練?
  3. 如何使用pytorch自帶混合精度?
  4. 如何使用梯度裁剪防止梯度爆炸?
  5. 如何使用DP多顯卡訓練?
  6. 如何繪制loss和acc曲線?
  7. 如何生成val的測評報告?
  8. 如何編寫測試腳本測試測試集?
  9. 如何使用余弦退火策略調整學習率?
  10. 如何使用AverageMeter類統計ACC和loss等自定義變量?
  11. 如何理解和統計ACC1和ACC5?
  12. 如何使用EMA?

如果基礎薄弱,對上面的這些功能難以理解可以看我的專欄:經典主干網絡精講與實戰
這個專欄,從零開始時,一步一步的講解這些,讓大家更容易接受。

安裝包

安裝timm

使用pip就行,命令:

pip install timm

mixup增強和EMA用到了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 是一種在圖像分類任務中常用的數據增強技術,它通過將兩張圖像以及其對應的標簽進行線性組合來生成新的數據和標簽。
參數詳解:

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)是指數移動平均值。在深度學習中的做法是保存歷史的一份參數,在一定訓練階段后,拿歷史的參數給目前學習的參數做一次平滑。具體實現如下:


import logging
from collections import OrderedDict
from copy import deepcopy
import torch
import torch.nn as nn_logger = logging.getLogger(__name__)class ModelEma:def __init__(self, model, decay=0.9999, device='', resume=''):# make a copy of the model for accumulating moving average of weightsself.ema = deepcopy(model)self.ema.eval()self.decay = decayself.device = device  # perform ema on different device from model if setif device:self.ema.to(device=device)self.ema_has_module = hasattr(self.ema, 'module')if resume:self._load_checkpoint(resume)for p in self.ema.parameters():p.requires_grad_(False)def _load_checkpoint(self, checkpoint_path):checkpoint = torch.load(checkpoint_path, map_location='cpu')assert isinstance(checkpoint, dict)if 'state_dict_ema' in checkpoint:new_state_dict = OrderedDict()for k, v in checkpoint['state_dict_ema'].items():# ema model may have been wrapped by DataParallel, and need module prefixif self.ema_has_module:name = 'module.' + k if not k.startswith('module') else kelse:name = knew_state_dict[name] = vself.ema.load_state_dict(new_state_dict)_logger.info("Loaded state_dict_ema")else:_logger.warning("Failed to find state_dict_ema, starting from loaded model weights")def update(self, model):# correct a mismatch in state dict keysneeds_module = hasattr(model, 'module') and not self.ema_has_modulewith torch.no_grad():msd = model.state_dict()for k, ema_v in self.ema.state_dict().items():if needs_module:k = 'module.' + kmodel_v = msd[k].detach()if self.device:model_v = model_v.to(device=self.device)ema_v.copy_(ema_v * self.decay + (1. - self.decay) * model_v)

加入到模型中。

#初始化
if use_ema:model_ema = ModelEma(model_ft,decay=model_ema_decay,device='cpu',resume=resume)# 訓練過程中,更新完參數后,同步update shadow weights
def train():optimizer.step()if model_ema is not None:model_ema.update(model)# 將model_ema傳入驗證函數中
val(model_ema.ema, DEVICE, test_loader)

針對沒有預訓練的模型,容易出現EMA不上分的情況,這點大家要注意啊!

項目結構

RDNet_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
│  └─rdnet.py
├─mean_std.py
├─makedata.py
├─train.py
└─test.py

mean_std.py:計算mean和std的值。
makedata.py:生成數據集。
train.py:訓練RDNet模型
models:來源官方代碼。

計算mean和std

為了使模型更加快速的收斂,我們需要計算出mean和std的值,新建mean_std.py,插入代碼:

from torchvision.datasets import ImageFolder
import torch
from torchvision import transformsdef 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))

數據集結構:

image-20220221153058619

運行結果:

([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 shutilimage_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)

完成上面的內容就可以開啟訓練和測試了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/44279.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/44279.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/44279.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CF328A IQ Test 題解

思路 依題意模擬即可。 注意要保證是整數。 代碼 #include<bits/stdc.h> #include<cstring> #include<queue> #include<set> #include<stack> #include<vector> #include<map> #define ll long long #define lhs printf("\n…

kotlin flow collect collectLatest 區別

在 Kotlin 協程庫中&#xff0c;collect 和 collectLatest 都是用于收集 Flow 中發射的數據的方法&#xff0c;但它們在處理數據和響應新數據的方式上有所不同。 collect collect 是一個掛起函數&#xff0c;用于收集 Flow 中發射的所有數據。它會按順序處理每一個發射的數據…

UML圖書管理系統用例圖示例

新書速覽|《UML 2.5基礎、建模與設計實踐》新書速覽|《UML 2.5基礎、建模與設計實踐 【例4.4】圖書管理系統用例圖。 圖書管理系統按其業務功能分成借閱者管理、圖書管理、借書、還書和用戶管理等幾部分&#xff0c;這些職能對應于系統的不同組織部門。 1&#xff09;系統參…

echarts 中國地圖json文件

阿里云地理網址 DataV.GeoAtlas地理小工具系列 (aliyun.com) 地圖cp 修改參考 {"type": "FeatureCollection","features": [{"type": "Feature","properties": { "id": "65", "size&…

Actor-Critic 算法

在強化學習&#xff08;Reinforcement Learning, RL&#xff09;中&#xff0c;Actor-Critic 算法是一類強大的策略梯度方法&#xff0c;結合了策略&#xff08;Policy&#xff09;和價值函數&#xff08;Value Function&#xff09;兩種方法的優點。本文將詳細介紹 Actor-Crit…

[TypeScript]手擼LFU

[TypeScript]手擼LFU 最近做筆試的時候遇到了要手擼LFU的題目&#xff0c;LFU在vue源碼里還是有使用的&#xff0c;例如keep-alive的實現機制就是基于它來搞的。不多說了&#xff0c;直接上代碼。 代碼 // 雙向鏈表node class DoubleLinkNode {key: number;val: number;freq…

阿一課代表今日分享之使用dnscat2 進行dns隧道反彈shell(直連模式linux對linux)

DNS介紹 DNS是域名系統(Domain Name System)的縮寫&#xff0c;是因特網的一項核心服務&#xff0c;它作為可以將域名和IP地址相互映射的一個分布式數據庫&#xff0c;能夠使人更方便的訪問互聯網&#xff0c;而不用去記住能夠被機器直接讀取的IP數串。 DNS的記錄類型有很多&a…

歸并排序算法Python實現

歸并排序原理和步驟 1. 將數組分成兩半&#xff0c;直到每個子數組的長度為1 首先&#xff0c;將數組分成兩半。如果數組的長度大于1&#xff0c;將其從中間分割為兩個子數組。對每個子數組繼續進行這個過程&#xff0c;直到每個子數組的長度為1。此時&#xff0c;所有子數組…

L4 Persistence and Streaming

參考自https://www.deeplearning.ai/short-courses/ai-agents-in-langgraph&#xff0c;以下為代碼的實現。 這里主要是加入了memory&#xff0c;這樣通過self.graph graph.compile(checkpointercheckpointer)就可以加入持久性的檢查點通過thread {"configurable"…

項目實戰--Spring Boot + GraphQL實現實時數據推送

背景 用戶體驗不斷提升而3對實時數據的需求日益增長&#xff0c;傳統的數據獲取方式無法滿足實時數據的即時性和個性化需求。 GraphQL作為新興的API查詢語言&#xff0c;提供更加靈活、高效的數據獲取方案。結合Spring Boot作為后端框架&#xff0c;利用GraphQL實現實時數據推…

Java筆試|面試 —— 對多態性的理解

談談對多態性的理解&#xff1a; 一個事物的多種形態&#xff08;編譯和運行時狀態不一致性&#xff09; 實現機制&#xff1a;通過繼承、重寫和向上轉型&#xff08;Object obj new 子類()&#xff09;來實現。 1.廣義上的理解 子類對象的多態性&#xff0c;方法的重寫&am…

visual studio 2022 在使用open3d出現的問題及解決方式

當出現以下問題&#xff1a; 使用open3d::utility::LogInfo系列出現LNK2001問題&#xff0c;如下所示&#xff1a;LNK2001 無法解析的外部符號 “char __cdecl fmt::v6::internal::decimal_point_impl(class fmt::v6::internal::locale_ref)” LNK2001 無法解析的外部符號 “p…

【C/C++】SDKDDKVer.h和WinSDKVer.h詳解及二者區別

一.SDKDDKVer.h介紹 SDKDDKVer.h 是一個在 Windows 軟件開發中常見的頭文件&#xff0c;它用于定義軟件開發工具包&#xff08;SDK&#xff09;和驅動開發工具包&#xff08;DDK&#xff09;的版本信息。這個文件通常位于 Visual Studio 安裝目錄下的 Include 子目錄中。 …

GD32MCU如何實現掉電數據保存?

大家在GD32 MCU應用時&#xff0c;是否會碰到以下應用需求&#xff1a;希望在MCU掉電時保存一定的數據或標志&#xff0c;用以記錄一些關鍵的數據。 以GD32E103為例&#xff0c;數據的存儲介質可以選擇內部Flash或者備份數據寄存器。 如下圖所示&#xff0c;片內Flash具有10年…

學習數據庫的增刪改查

一、創建數據庫和表 在進行增刪改查操作之前&#xff0c;我們需要創建一個數據庫和表。 1. 創建數據庫 使用 CREATE DATABASE 語句創建數據庫&#xff1a; CREATE DATABASE test_db;2. 選擇數據庫 使用 USE 語句選擇數據庫&#xff1a; USE test_db;3. 創建表 使用 CREA…

詳解C語言結構體

文章目錄 1.結構體的聲明1.1 結構體的基礎知識1.2 結構的聲明1.3 結構成員的類型 1.4結構體變量的定義和初始化2.結構體成員的訪問3.結構體傳參 1.結構體的聲明 1.1 結構體的基礎知識 結構是一些值的集合&#xff0c;這些值稱為成員變量。結構的每個成員可以是不同類型的變量 …

【密碼學】分組密碼概述

一、分組密碼的定義 分組密碼和流密碼都是對稱密碼體制。 流密碼&#xff1a;是將明文視為連續的比特流&#xff0c;對每個比特或字節進行實時加密&#xff0c;而不將其分割成固定的塊。流密碼適用于加密實時數據流&#xff0c;如網絡通信。分組密碼&#xff1a;是將明文數據…

【React】Ant Design -- Table分頁功能實現

實現步驟 為Table組件指定pagination屬性來展示分頁效果在分頁切換事件中獲取到篩選表單中選中的數據使用當前頁數據修改params參數依賴引起接口重新調用獲取最新數據 const pageChange (page) > {// 拿到當前頁參數 修改params 引起接口更新setParams({...params,page})…

翰德恩咨詢賦能材料行業上市公司,共筑IPD管理體系新篇章

賦能背景概覽 坐落于江蘇的某材料行業領軍企業&#xff0c;作為國內無機陶瓷膜元件及成套設備領域的佼佼者&#xff0c;以其龐大的生產規模、豐富的產品系列及卓越的研發實力&#xff0c;屹立行業之巔二十余年。公司不僅在新材料研發、技術創新、工藝設計、設備制造及整體解決…

【VUE進階】安裝使用Element Plus組件

Element Plus組件 安裝引入組件使用Layout 布局button按鈕行內表單菜單 安裝 包管理安裝 # 選擇一個你喜歡的包管理器# NPM $ npm install element-plus --save# Yarn $ yarn add element-plus# pnpm $ pnpm install element-plus瀏覽器直接引入 例如 <head><!-- I…