细数一行代码改变结局的炼丹骚操作
文 |?陀飛輪&圈圈&年年的鏟屎官
源 | 知乎
tips總結
知乎答主:陀飛輪
談一下自己知道的。盡量避開優化器、激活函數、數據增強等改進。。先上完整列表:
Deep Learning:?Cyclic LR、Flooding
Image classification:?ResNet、GN、Label Smoothing、ShuffleNet
Object Detection:?Soft-NMS、Focal Loss、GIOU、OHEM
Instance Segmentation:?PointRend
Domain Adaptation:?BNM
GAN:?Wasserstein GAN
Deep Learning
Standard LR -> Cyclic LR
SNAPSHOT ENSEMBLES: TRAIN 1, GET M FOR FREE
每隔一段時間重啟學習率,這樣在單位時間內能收斂到多個局部最小值,可以得到很多個模型做集成。
#CYCLE=8000, LR_INIT=0.1, LR_MIN=0.001 scheduler = lambda x: ((LR_INIT-LR_MIN)/2)*(np.cos(PI*(np.mod(x-1,CYCLE)/(CYCLE)))+1)+LR_MINWithout Flooding -> With Flooding
Do We Need Zero Training Loss After Achieving Zero Training Error?
Flooding方法:當training loss大于一個閾值時,進行正常的梯度下降;當training loss低于閾值時,會反過來進行梯度上升,讓training loss保持在一個閾值附近,讓模型持續進行“random walk”,并期望模型能被優化到一個平坦的損失區域,這樣發現test loss進行了double decent!
flood = (loss - b).abs() + bImage classification
VGGNet -> ResNet
Deep Residual Learning for Image Recognition
ResNet相比于VGGNet多了一個skip connect,網絡優化變的更加容易
H(x) = F(x) + xBN -> GN
Group Normalization
在小batch size下BN掉點嚴重,而GN更加魯棒,性能穩定。
x = x.view(N, G, -1) mean, var = x.mean(-1, keepdim=True), x.var(-1, keepdim=True) x = (x - mean) / (var + self.eps).sqrt() x = x.view(N, C, H, W)Hard Label -> Label Smoothing
Bag of Tricks for Image Classification with Convolutional Neural Networks
label smoothing將hard label轉變成soft label,使網絡優化更加平滑。
targets = (1 - label_smooth) * targets + label_smooth / num_classesMobileNet -> ShuffleNet
ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices
將組卷積的輸出feature map的通道順序打亂,增加不同組feature map的信息交互。
channels_per_group = num_channels // groups x = x.view(batch_size, groups, channels_per_group, height, width) x = torch.transpose(x, 1, 2).contiguous() x = x.view(batch_size, -1, height, width)Object Detection
NMS -> Soft-NMS
Improving Object Detection With One Line of Code
Soft-NMS將重疊率大于設定閾值的框分類置信度降低,而不是直接置為0,可以增加召回率。
#以線性降低分類置信度為例 if iou > threshold:weight = 1 - iouCE Loss -> Focal Loss
Focal Loss for Dense Object Detection
Focal loss對CE loss增加了一個調制系數來降低容易樣本的權重值,使得訓練過程更加關注困難樣本。
loss = -np.log(p) # 原始交叉熵損失, p是模型預測的真實類別的概率, loss = (1-p)**GAMMA * loss # GAMMA是調制系數IOU -> GIOU
Generalized Interp over Union: A Metric and A Loss for Bounding Box Regression
GIOU loss避免了IOU loss中兩個bbox不重合時Loss為0的情況,解決了IOU loss對物體大小敏感的問題。
#area_C閉包面積,add_area并集面積 end_area = (area_C - add_area)/area_C #閉包區域中不屬于兩個框的區域占閉包區域的比重 giou = iou - end_areaHard Negative Mining -> OHEM
Training Region-based Object Detectors with Online Hard Example Mining
OHEM通過選擇損失較大的候選ROI進行梯度更新解決類別不平衡問題。
#只對難樣本產生的loss更新 index = torch.argsort(loss.sum(1))[int(num * ohem_rate):] loss = loss[index, :]Instance Segmentation
Mask R-CNN -> PointRend
PointRend: Image Segmentation as Rendering
每次從粗粒度預測出來的mask中選擇TopN個最不確定的位置進行細粒度預測,以非常的少的計算代價下獲得巨大的性能提升。
points = sampling_points(out, x.shape[-1] // 16, self.k, self.beta) coarse = point_sample(out, points, align_corners=False) fine = point_sample(res2, points, align_corners=False) feature_representation = torch.cat([coarse, fine], dim=1)Domain Adaptation
EntMin -> BNM
Towards Discriminability and Diversity: Batch Nuclear-norm Maximization under Label Insufficient Situations
類別預測的判別性與多樣性同時指向矩陣的核范數,可以通過最大化矩陣核范數(BNM)來提升預測的性能。
L_BNM = -torch.norm(X,'nuc')GAN
GAN -> Wasserstein GAN
Wasserstein GAN
WGAN引入了Wasserstein距離,既解決了GAN訓練不穩定的問題,也提供了一個可靠的訓練進程指標,而且該指標確實與生成樣本的質量高度相關。
Wasserstein GAN相比GAN只改了四點: 判別器最后一層去掉sigmoid 生成器和判別器的loss不取對數 每次更新把判別器參數的絕對值按閾值截斷 使用RMSProp或者SGD優化器知乎答主:圈圈
relu:用極簡的方式實現非線性激活,還緩解了梯度消失
x = max(x, 0)
normalization:提高網絡訓練穩定性
x = (x - x.mean()) / x.std()
gradient clipping:直擊靶心 避免梯度爆炸
hhhgrad [grad > THRESHOLD] = THRESHOLD # THRESHOLD是設定的最大梯度閾值
dropout:隨機丟棄,抑制過擬合,提高模型魯棒性
x = torch.nn.functional.dropout(x, p=p, training=training) # 哈哈哈調皮了,因為實際dropout還有很多其他操作,不夠僅丟棄這一步確實可以一行搞定
x = x * np.random.binomial(n=1, p=p, size=x.shape) # 這里p是想保留的概率,上面那是丟棄的概率
skip connection(residual learning):提供恒等映射的能力,保證模型不會因網絡變深而退化
F(x) = F(x) + x
focal loss:用預測概率對不同類別的loss進行加權,緩解類別不平衡問題
loss = -np.log(p) # 原始交叉熵損失, p是模型預測的真實類別的概率
loss = (1-p)**GAMMA * loss # GAMMA是調制系數
attention mechanism:用query和原始特征的相似度對原始特征進行加權,關注想要的信息
attn = torch.softmax(torch.matmul(q, k), dim) #用Transformer里KQV那套范式為例
v = torch.matmul(attn, v)
subword embedding(char或char ngram):基本解決OOV(out of vocabulary)問題、分詞問題。這個對encode應該比較有效,但對decode不太友好
x = [char for char in sentence] # char-level
知乎答主:年年的鏟屎官
只改1行代碼,bleu提高2個點。用pytorch的時候,計算loss,使用最多的是label_smoothed_cross_encropy或者cross_encropy,推薦把設置reduction為'sum',效果可能會比默認的reduction='mean'好一些(我自己的嘗試是可以提高2個BLEU左右),以最常用的cross_entropy為例:
from torch import nn self.criterion = nn.CrossEntropyLoss(ignore_index=pad_id) # reduction默認為'mean'
改為:
from torch import nn self.criterion = nn.CrossEntropyLoss( ignore_index=pad_id, reduction='sum')
發生的變化,實際上就是計算一個sequence的所有token,其loss是否平均(字不好看,請見諒~):
我的理解(不對請輕噴),這個trick之所以在一些任務中有用,是因為其在多任務學習中平衡了不同的loss的權重,至少在我自己做的image caption任務中看到的結果是這樣的。
beam search添加length_penalty
這一點多虧 @高一帆 的提醒,解碼階段,如果beam search不加任何約束,那么很容易導致生成的最終序列長度偏短,效果可能還不如greedy search。原因的話就是beam size大于1,比較容易在不同的beam中生成較短的序列,且短序列得分往往比長序列高。舉個例子的話請看下圖(假設beam size為2):
那么我們需要對較短的序列進行懲罰,我們只需一行代碼就可以改善這個問題:
# 假設原始生成序列的最終累積得分為accumulate_score,length_penalty是超參數,默認為1 accumulate_score /= num_tokens ** length_penalty
假設encoder輸出為encoder_out,是一個tensor(比如一個768的embedding,而非一組embedding),那么我們喂給rnn的輸入,input除了上一步的 ?, 拼接上encoder_out,效果會漲不少。即:
我自己的實驗,每一個timestep給rnn的輸入都拼接encoderout,bleu提高3個點(數據量4萬)。
針對多層rnn,比如多層lstm,input feeding也是一個能提高模型表現的trick。就是lstm的第一層,其輸入除了前一時刻的輸出,還有最高一層前一時刻的隱狀態 ?,用圖來表示就是:
變為:
表現在代碼上,就是:
input = torch.cat((y[t-1], hiddens[t-1]), dim=1) # 原始的只有y[t-1]
后臺回復關鍵詞【入群】
加入賣萌屋NLP/IR/Rec與求職討論群
有頂會審稿人、大廠研究員、知乎大V和妹紙
等你來撩哦~
總結
以上是生活随笔為你收集整理的细数一行代码改变结局的炼丹骚操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法工程师怎样提升业务理解能力?
- 下一篇: 一个励志PM小哥哥的Java转型之路