今天小編分享的科學經驗:即插即用!清華國科大等推出視覺微調框架,僅需調整5%骨幹網絡參數,歡迎閱讀。
僅調整 5% 的骨幹網絡參數,就能超越全參數微調效果?!
還是在實例分割、目标檢測、旋轉目标檢測這樣的經典視覺任務場景。
這是來自清華、國科大、上海交大、阿裡巴巴的一項研究,相關論文已被 CVPR2025 接受。
他們提出了Mona(Multi-cognitive Visual Adapter)這種新型視覺适配器微調方法,目标是打破傳統全參數微調(full fine-tuning)在視覺識别任務中的性能瓶頸。
Mona 方法通過引入多認知視覺濾波器和優化輸入分布,僅調整 5% 的骨幹網絡參數,就能在實例分割、目标檢測、旋轉目标檢測等多個經典視覺任務中超越全參數微調的效果。
這一方法顯著降低了适配和存儲成本,為視覺模型的高效微調提供了新的思路。
Mona 首次突破了全量微調性能枷鎖
随着現代深度學習的發展,訓練數據和模型規模的增加成為模型性能的重要增長點,但随之而來的是模型的垂直應用和微調成本和難度的提升。
傳統全量微調需要更新模型所有參數(如 GPT-3 的 1750 億參數 ),計算成本極高。即使以早期的 BERT 為例,單卡訓練 100 萬數據也需 5-7 小時,對硬體資源和時間的要求限制了研究復現和實際應用。
同時,随着模型參數從億級邁向萬億級,直接微調不僅成本高昂,還可能因過拟合導致性能下降。此外,多任務場景下需為每個任務保存完整模型副本,存儲成本劇增加。
參數高效微調(Parameter Efficient Fine-Tuning,PEFT)通過保持預訓練模型參數凍結,僅調整少量參數就可實現大模型在垂直應用領網域的高效适配。
但目前大多數 PEFT 方法,尤其是視覺領網域的 PEFT 方法的性能相較于全量微調而言還存在劣勢。
Mona 通過更适合視覺信号處理的設計以及對預訓練特征分布的動态優化,在小于 5% 的參數成本下首次突破了全量微調的性能枷鎖,為視覺微調提供了新的解決方案。
團隊核心想通過研究強調:
(1)PEFT 對于視覺模型性能上限的提升(尤其是參數量較大的模型);
(2)視覺模型在全微調(尤其是少樣本情況)會存在嚴重的過拟合問題;
(3)1LVM+nAdapter 模式在實際業務中潛在的性能和效率優勢。
對于具體業務來說,有些用到 LVM 或者多模态大模型(如 OCR 等任務)的任務會對視覺編碼器部分進行固定或僅微調 linear 層來适應下遊數據。
Mona 的存在理論上可以進一步提升 LVM、多模态大模型對視覺特征的理解和重構,尤其是對于一些少樣本 post-training 問題。
核心引入多認知視覺濾波器
Mona 包含降維、多認知視覺濾波器、激活函數和升維等模塊,并在适配器内部加入了跳躍連接(Skip-Connections),以增強模型的适應能力。
這種結構設計使得 Mona 能夠在保持高效的同時,顯著提升視覺任務的性能。
Mona 方法的核心在于引入了多認知視覺濾波器,這些濾波器通過深度可分離卷積(Depth-Wise Convolution)和多尺度卷積核(3 × 3、5 × 5、7 × 7)來增強适配器對視覺信号的處理能力。
與傳統的線性适配器不同,Mona 專門針對視覺任務設計,能夠更好地處理二維視覺特征,通過多尺度特征融合提升模型對視覺信息的理解能力。
另外,Mona 在适配器的前端加入了分布适配層(Scaled LayerNorm),用于調整輸入特征的分布。
這種設計能夠優化從固定層傳遞過來的特征分布,使其更适合适配器的處理,從而提高微調效率。
實驗結果
先來看實驗設定。
論文在多個代表性視覺任務上進行了實驗,包括:
實例分割(COCO)
語義分割(ADE20K)
目标檢測(Pascal VOC)
旋轉目标檢測(DOTA/STAR)
影像分類(Flowers102、Oxford-IIIT Pet、VOC2007)
實驗使用了SwinTransformer 系列作為骨幹網絡,并基于 ImageNet-22k 數據集進行預訓練。
實驗結果顯示,在 COCO 數據集上,Mona 方法相比全參數微調提升了 1% 的 mAP,僅調整了不到 5% 的參數。
在 ADE20K 數據集上,Mona 提升了 0.18% 的 mIoU,表現出色。
同時,在 Pascal VOC 數據集上,Mona 提升了 3.6% 的 APbox,顯示出顯著的性能提升。
在旋轉目标檢測任務(DOTA/STAR)中,Mona 在多個框架下均優于其他方法。
在影像分類任務上,Mona 也有不俗的性能。
在所有方法中, Mona 收斂速度更快,并且明顯超過了全微調。
以下為 Mona 即插即用模塊:
import torch.nn asnnimporttorch.nn.functionalasF# ------------------------------Mona 模塊 ------------------------------INNER_DIM = 64class MonaOp ( nn.Module ) :def __init__ ( self, in_features ) :super ( ) .__init__ ( ) self.conv1 = nn.Conv2d ( in_features, in_features, kernel_size=3, padding=3 // 2, groups=in_features ) self.conv2 = nn.Conv2d ( in_features, in_features, kernel_size=5, padding=5 // 2, groups=in_features ) self.conv3 = nn.Conv2d ( in_features, in_features, kernel_size=7, padding=7 // 2, groups=in_features ) self.projector = nn.Conv2d ( in_features, in_features, kernel_size=1, ) def forward ( self, x ) :identity = xconv1_x = self.conv1 ( x ) conv2_x = self.conv2 ( x ) conv3_x = self.conv3 ( x ) x = ( conv1_x + conv2_x + conv3_x ) / 3.0 + identityidentity = xx = self.projector ( x ) return identity + xclass Mona ( BaseModule ) :def __init__ ( self,in_dim,factor=4 ) :super ( ) .__init__ ( ) self.project1 = nn.Linear ( in_dim, INNER_DIM ) self.nonlinear = F.geluself.project2 = nn.Linear ( INNER_DIM, in_dim ) self.dropout = nn.Dropout ( p=0.1 ) self.adapter_conv = MonaOp ( INNER_DIM ) self.norm = nn.LayerNorm ( in_dim ) self.gamma = nn.Parameter ( torch.ones ( in_dim ) * 1e-6 ) self.gammax = nn.Parameter ( torch.ones ( in_dim ) ) def forward ( self, x, hw_shapes=None ) :identity = xx = self.norm ( x ) * self.gamma + x * self.gammaxproject1 = self.project1 ( x ) b, n, c = project1.shapeh, w = hw_shapesproject1 = project1.reshape ( b, h, w, c ) .permute ( 0, 3, 1, 2 ) project1 = self.adapter_conv ( project1 ) project1 = project1.permute ( 0, 2, 3, 1 ) .reshape ( b, n, c ) nonlinear = self.nonlinear ( project1 ) nonlinear = self.dropout ( nonlinear ) project2 = self.project2 ( nonlinear ) return identity + project2#------------------------------ 插入模式 ------------------------------# 此處省略部分 Swin 組件實現,僅提供 Mona 插入模式。class SwinBlock ( BaseModule ) :""""Args:embed_dims ( int ) : The feature dimension.num_heads ( int ) : Parallel attention heads.feedforward_channels ( int ) : The hidden dimension for FFNs.window_size ( int, optional ) : The local window scale. Default: 7.shift ( bool, optional ) : whether to shift window or not. Default False.qkv_bias ( bool, optional ) : enable bias for qkv if True. Default: True.qk_scale ( float | None, optional ) : Override default qk scale ofhead_dim ** -0.5 if set. Default: None.drop_rate ( float, optional ) : Dropout rate. Default: 0.attn_drop_rate ( float, optional ) : Attention dropout rate. Default: 0.drop_path_rate ( float, optional ) : Stochastic depth rate. Default: 0.act_cfg ( dict, optional ) : The config dict of activation function.Default: dict ( type='GELU' ) .norm_cfg ( dict, optional ) : The config dict of normalization.Default: dict ( type='LN' ) .with_cp ( bool, optional ) : Use checkpoint or not. Using checkpointwill save some memory while slowing down the training speed.Default: False.init_cfg ( dict | list | None, optional ) : The init config.Default: None."""def __init__ ( self,embed_dims,num_heads,feedforward_channels,window_size=7,shift=False,qkv_bias=True,qk_scale=None,drop_rate=0.,attn_drop_rate=0.,drop_path_rate=0.,act_cfg=dict ( type='GELU' ) ,norm_cfg=dict ( type='LN' ) ,with_cp=False,init_cfg=None ) :super ( SwinBlock, self ) .__init__ ( ) self.init_cfg = init_cfgself.with_cp = with_cpself.norm1 = build_norm_layer ( norm_cfg, embed_dims ) [ 1 ] self.attn = ShiftWindowMSA ( embed_dims=embed_dims,num_heads=num_heads,window_size=window_size,shift_size=window_size // 2 if shift else 0,qkv_bias=qkv_bias,qk_scale=qk_scale,attn_drop_rate=attn_drop_rate,proj_drop_rate=drop_rate,dropout_layer=dict ( type='DropPath', drop_prob=drop_path_rate ) ,init_cfg=None ) self.norm2 = build_norm_layer ( norm_cfg, embed_dims ) [ 1 ] self.ffn = FFN ( embed_dims=embed_dims,feedforward_channels=feedforward_channels,num_fcs=2,ffn_drop=drop_rate,dropout_layer=dict ( type='DropPath', drop_prob=drop_path_rate ) ,act_cfg=act_cfg,add_identity=True,init_cfg=None ) self.mona1 = Mona ( embed_dims, 8 ) self.mona2 = Mona ( embed_dims, 8 ) def forward ( self, x, hw_shape ) :def _inner_forward ( x ) :identity = xx = self.norm1 ( x ) x = self.attn ( x, hw_shape ) x = x + identityx = self.mona1 ( x, hw_shape ) identity = xx = self.norm2 ( x ) x = self.ffn ( x, identity=identity ) x = self.mona2 ( x, hw_shape ) return xif self.with_cp and x.requires_grad:x = cp.checkpoint ( _inner_forward, x ) else:x = _inner_forward ( x ) return x
最後小結一下,Mona 方法通過多認知視覺濾波器和輸入優化,顯著提升了視覺任務的微調性能,同時大幅減少了參數調整量。
這一方法不僅在多個視覺任務中超越了傳統全參數微調,還為未來視覺模型的高效微調提供了新的方向。
預印版期間,Mona 已被復旦、中科大、南大、武大等多家部門的工作視為 SOTA 方法運用在醫學、遙感等領網域。
Mona 的開源代碼将進一步推動這一領網域的研究和應用。
附論文引用格式:
@misc{yin20245100breakingperformanceshackles, title={5%>100%: Breaking Performance Shackles of Full Fine-Tuning on Visual Recognition Tasks}, author={Dongshuo Yin and Leiyi Hu and Bin Li and Youqun Zhang and Xue Yang}, year={2024}, eprint={2408.08345}, archivePrefix={arXiv}, primaryClass={cs.CV}, url={https://arxiv.org/abs/2408.08345}, }
論文地址:https://arxiv.org/pdf/2408.08345
代碼:https://github.com/Leiyi-Hu/mona
一鍵三連「點贊」「轉發」「小心心」
歡迎在評論區留下你的想法!
— 完 —
學術投稿請于工作日發郵件到:
标題注明【投稿】,告訴我們:
你是誰,從哪來,投稿内容
附上論文 / 項目主頁鏈接,以及聯系方式哦
我們會(盡量)及時回復你
點亮星标
科技前沿進展每日見