一般通用的trick都被寫進論文和代碼庫里了
像優秀的優化器,學習率調度方法,數據增強,dropout,初始化,BN,LN,確實是調參大師的寶貴經驗,大家平常用的也很多。
這里主要有幾個,我們分成三部分,穩定有用型trick,場景受限型trick,性能加速型trick。
穩定有用型trick
0.模型融合
懂得都懂,打比賽必備,做文章沒卵用的人人皆知trick,早年模型小的時候還用stacking,直接概率融合效果也不錯。
-
對抗訓練
對抗訓練就是在輸入的層次增加擾動,根據擾動產生的樣本,來做一次反向傳播。以FGM為例,在NLP上,擾動作用于embedding層。給個即插即用代碼片段吧,引用了知乎id:Nicolas的代碼,寫的不錯,帶著看原理很容易就明白了。
#初始化
fgm=FGM(model)
forbatch_input,batch_labelindata:
#正常訓練
loss=model(batch_input,batch_label)
loss.backward()#反向傳播,得到正常的grad
#對抗訓練
fgm.attack()#在embedding上添加對抗擾動
loss_adv=model(batch_input,batch_label)
loss_adv.backward()#反向傳播,并在正常的grad基礎上,累加對抗訓練的梯度
fgm.restore()#恢復embedding參數
#梯度下降,更新參數
optimizer.step()
model.zero_grad()
具體FGM的實現
importtorch
classFGM():
def__init__(self,model):
self.model=model
self.backup={}
defattack(self,epsilon=1.,emb_name='emb.'):
#emb_name這個參數要換成你模型中embedding的參數名
forname,paraminself.model.named_parameters():
ifparam.requires_gradandemb_nameinname:
self.backup[name]=param.data.clone()
norm=torch.norm(param.grad)
ifnorm!=0andnottorch.isnan(norm):
r_at=epsilon*param.grad/norm
param.data.add_(r_at)
defrestore(self,emb_name='emb.'):
#emb_name這個參數要換成你模型中embedding的參數名
forname,paraminself.model.named_parameters():
ifparam.requires_gradandemb_nameinname:
assertnameinself.backup
param.data=self.backup[name]
self.backup={}
2.EMA/SWA
移動平均,保存歷史的一份參數,在一定訓練階段后,拿歷史的參數給目前學習的參數做一次平滑。這個東西,我之前在earhian的祖傳代碼里看到的。他喜歡這東西+衰減學習率。確實每次都有用。
#初始化
ema=EMA(model,0.999)
ema.register()
#訓練過程中,更新完參數后,同步updateshadowweights
deftrain():
optimizer.step()
ema.update()
# eval前,apply shadow weights;eval之后,恢復原來模型的參數
defevaluate():
ema.apply_shadow()
#evaluate
ema.restore()
具體EMA實現,即插即用:
classEMA():
def__init__(self,model,decay):
self.model=model
self.decay=decay
self.shadow={}
self.backup={}
defregister(self):
forname,paraminself.model.named_parameters():
ifparam.requires_grad:
self.shadow[name]=param.data.clone()
defupdate(self):
forname,paraminself.model.named_parameters():
ifparam.requires_grad:
assertnameinself.shadow
new_average=(1.0-self.decay)*param.data+self.decay*self.shadow[name]
self.shadow[name]=new_average.clone()
defapply_shadow(self):
forname,paraminself.model.named_parameters():
ifparam.requires_grad:
assertnameinself.shadow
self.backup[name]=param.data
param.data=self.shadow[name]
defrestore(self):
forname,paraminself.model.named_parameters():
ifparam.requires_grad:
assertnameinself.backup
param.data=self.backup[name]
self.backup={}
這兩個方法的問題就是跑起來會變慢,并且提分點都在前分位,不過可以是即插即用類型
3.Rdrop等對比學習方法
有點用,不會變差,實現起來也很簡單
#訓練過程上下文
ce=CrossEntropyLoss(reduction='none')
kld=nn.KLDivLoss(reduction='none')
logits1=model(input)
logits2=model(input)
#下面是訓練過程中對比學習的核心實現!?。?!
kl_weight=0.5#對比loss權重
ce_loss=(ce(logits1,target)+ce(logits2,target))/2
kl_1=kld(F.log_softmax(logits1,dim=-1),F.softmax(logits2,dim=-1)).sum(-1)
kl_2=kld(F.log_softmax(logits2,dim=-1),F.softmax(logits1,dim=-1)).sum(-1)
loss=ce_loss+kl_weight*(kl_1+kl_2)/2
大家都知道,在訓練階段。dropout是開啟的,你多次推斷dropout是有隨機性的。
模型如果魯棒的話,你同一個樣本,即使推斷時候,開著dropout,結果也應該差不多。好了,那么它的原理也呼之欲出了。用一張圖來形容就是:
隨便你怎么踹(dropout),本AI穩如老狗。
KLD loss是衡量兩個分布的距離的,所以說他就是在原始的loss上,加了一個loss,這個loss刻畫了模型經過兩次推斷,抵抗因dropout造成擾動的能力。
4.TTA
這個一句話說明白,測試時候構造靠譜的數據增強,簡單一點的數據增強方式比較好,然后把預測結果加起來算個平均。
5.偽標簽
代碼和原理實現也不難,代價也是訓練變慢,畢竟多了一些數據一句話說明白,就是用訓練的模型,把測試數據,或者沒有標簽的數據,推斷一遍。構成偽標簽,然后拿回去訓練。注意不要leak。
聽起來挺離譜的,我們把步驟用偽代碼實現一下。
model1.fit(train_set,label,val=validation_set)#step1
pseudo_label=model.pridict(test_set)#step2
new_label=concat(pseudo_label,label)#step3
new_train_set=concat(test_set,train_set)#step3
model2.fit(new_train_set,new_label,val=validation_set)#step4
final_predict=model2.predict(test_set)#step5
用網上一個經典的圖來說就是。
6.神經網絡自動填空值
表數據在NN上的trick,快被tabnet 集大成了,這個方法是把缺失值的位置之外的地方mask,本身當成1這樣可以學習出一個參數,再加回這個feature的輸入上??梢钥纯此恼碌膶崿F。
場景受限型trick
有用但場景受限或者不穩定
1.PET或者其他prompt的方案
在一些特定場景上有用,比如zeroshot,或者小樣本的監督訓練,在數據量充足情況下拿來做模型融合有點用,單模型不一定干的過硬懟。
2.Focalloss
偶爾有用,大部分時候用處不大,看指標,在一些對長尾,和稀有類別特別關注的任務和指標上有所作為。
3.mixup/cutmix等數據增強
挑數據,大部分數據和任務用處不大,局部特征比較敏感的任務有用,比如音頻分類等
4人臉等一些改動softmax的方式
在數據量偏少的時候有用,在工業界數據量巨大的情況下用處不大
5.領域后預訓練
把自己的數據集,在Bert base上用MLM任務再過一遍,代價也是變慢,得益于huggingface可用性極高的代碼,實現起來也非常簡單,適用于和預訓練預料差別比較大的一些場景,比如中藥,ai4code等,在一些普通的新聞文本分類數據集上用處不大。
6.分類變檢索
這算是小樣本分類問題的標準解法了,類似于人臉領域的baseline,在這上面有很多圍繞類間可分,類內聚集的loss改進,像aa-softmax,arcface,am-softmax等
在文本分類,圖像分類上效果都不錯。
突破性能型trick
1.混合精度訓練
AMP即插即用,立竿見影。
2.梯度累積
在優化器更新參數之前,用相同的模型參數進行幾次前后向傳播。在每次反向傳播時計算的梯度被累積(加總)。不過這種方法會影響BN的計算,可以用來突破batchsize上限。
3.Queue或者memery bank
可以讓batchsize突破天際,可以參考MoCo用來做對比學習的那個實現方式
4.非必要不同步
多卡ddp訓練的時候,用到梯度累積時,可以使用no_sync減少不必要的梯度同步,加快速度
審核編輯 :李倩
-
代碼
+關注
關注
30文章
4813瀏覽量
68832 -
深度學習
+關注
關注
73文章
5511瀏覽量
121350 -
nlp
+關注
關注
1文章
489瀏覽量
22065
原文標題:深度學習刷SOTA的一堆trick
文章出處:【微信號:zenRRan,微信公眾號:深度學習自然語言處理】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論