Transformers 加速的一些常用技巧

CV技术指南(公众号)發表於2024-05-18
前言 本文介紹了一些Transformers常用的加速策略。

本文轉載自Deephub Imba

僅用於學術分享,若侵權請聯絡刪除

歡迎關注公眾號CV技術指南,專注於計算機視覺的技術總結、最新技術跟蹤、經典論文解讀、CV招聘資訊。

CV方向的準研究生們,未來三年如何度過?

招聘高光譜影像、語義分割、diffusion等方向論文指導老師

Transformers 是一個強大的架構,但模型因其採用的自注意力機制,雖然能夠有效地處理序列資料並捕獲長距離依賴關係,但同時也容易導致在訓練過程中出現OOM(Out of Memory,記憶體不足)或者達到GPU的執行時限制。

主要是因為

  1. 引數數量龐大:Transformer模型通常包含大量的引數,尤其是在模型層面進行擴充套件時(例如,增加層數或頭數)。這些引數需要大量的記憶體來儲存權重和梯度。
  2. 自注意力計算:自注意力機制需要對輸入序列的每個元素與其他所有元素計算其相互關係,導致計算複雜度和記憶體需求隨著輸入長度的增加而顯著增加。對於非常長的序列,這一點尤其突出。
  3. 啟用和中間狀態儲存:在訓練過程中,需要儲存前向傳播中的中間啟用狀態,以便於反向傳播時使用。這增加了額外的記憶體負擔。

為了解決這些問題,我們今天來總結以下一些常用的加速策略

Transformers 加速的一些常用技巧

固定長度填充

Transformers 加速的一些常用技巧

在處理文字資料時,由於文字序列的長度可能各不相同,但許多機器學習模型(尤其是基於Transformer的模型)需要輸入資料具有固定的尺寸,因此需要對文字序列進行固定長度填充(padding)。

在使用Transformer模型時,填充部分不應影響到模型的學習。因此通常需要使用注意力掩碼(attention mask)來指示模型在自注意力計算時忽略這些填充位置。透過這種固定長度填充和相應的處理方法,可以使得基於Transformer的模型能夠有效地處理不同長度的序列資料。在實際應用中,這種方法是處理文字輸入的常見策略。

 def fixed_pad_sequences(sequences, max_length, padding_value=0):
    padded_sequences = []
    for sequence in sequences:
        if len(sequence) >= max_length:
            padded_sequence = sequence[:max_length] # Trim the sequence if it exceeds max_length
        else:
            padding = [padding_value] * (max_length - len(sequence)) # Calculate padding
            padded_sequence = sequence + padding # Pad the sequence
        padded_sequences.append(padded_sequence)
    return padded_sequences

這種方式會將所有的序列填充成一個長度,這樣雖然長度相同了,但是因為序列的實際大小本來就不同,同一批次很可能出現有很多填充的情況,所以就出現了動態填充策略。

動態填充是在每個批處理中動態填充輸入序列到最大長度。與固定長度填充不同,在固定長度填充中,所有序列都被填充以匹配整個資料集中最長序列的長度,動態填充根據該批中最長序列的長度單獨填充每個批中的序列。

Transformers 加速的一些常用技巧

這樣雖然每個批次的長度是不同的,但是批次內部的長度是相同的,可以加快處理速度。

 def pad_sequences_dynamic(sequences, padding_value=0):
    max_length = max(len(seq) for seq in sequences) # Find the maximum length in the sequences
    padded_sequences = []
    for sequence in sequences:
        padding = [padding_value] * (max_length - len(sequence)) # Calculate padding
        padded_sequence = sequence + padding # Pad the sequence
        padded_sequences.append(padded_sequence)
    return padded_sequences

等長匹配

等長匹配是在訓練或推理過程中將長度相近的序列分組成批處理的過程。等長匹配透過基於序列長度將資料集劃分為桶,然後從這些桶中取樣批次來實現的。

Transformers 加速的一些常用技巧

從上圖可以看到,透過等長匹配的策略,減少了填充量,這樣也可以加速計算

 def uniform_length_batching(sequences, batch_size, padding_value=0):
    # Sort sequences based on their lengths
    sequences.sort(key=len)
     
    # Divide sequences into buckets based on length
    buckets = [sequences[i:i+batch_size] for i in range(0, len(sequences), batch_size)]
     
    # Pad sequences within each bucket to the length of the longest sequence in the bucket
    padded_batches = []
    for bucket in buckets:
        max_length = len(bucket[-1]) # Get the length of the longest sequence in the bucket
        padded_bucket = []
        for sequence in bucket:
            padding = [padding_value] * (max_length - len(sequence)) # Calculate padding
            padded_sequence = sequence + padding # Pad the sequence
            padded_bucket.append(padded_sequence)
        padded_batches.append(padded_bucket)
     
    return padded_batches

自動混合精度

Transformers 加速的一些常用技巧

自動混合精度(AMP)是一種透過使用單精度(float32)和半精度(float16)演算法的組合來加速深度學習模型訓練的技術。它利用了現代gpu的功能,與float32相比,使用float16資料型別可以更快地執行計算,同時使用更少的記憶體。

 import torch
 from torch.cuda.amp import autocast, GradScaler
 
 # Define your model
 model = YourModel()
 
 # Define optimizer and loss function
 optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
 criterion = torch.nn.CrossEntropyLoss()
 
 # Create a GradScaler object for gradient scaling
 scaler = GradScaler()
 
 # Inside the training loop
 for inputs, targets in dataloader:
    # Clear previous gradients
    optimizer.zero_grad()
     
    # Cast inputs and targets to the appropriate device
    inputs, targets = inputs.to(device), targets.to(device)
     
    # Enable autocasting for forward pass
    with autocast():
        # Forward pass
        outputs = model(inputs)
        loss = criterion(outputs, targets)
     
    # Backward pass
    # Scale the loss value
    scaler.scale(loss).backward()
     
    # Update model parameters
    scaler.step(optimizer)
     
    # Update the scale for next iteration
    scaler.update()

AMP在訓練過程中動態調整計算精度,允許模型在大多數計算中使用float16,同時自動將某些計算提升為float32,以防止下流或溢位等數值不穩定問題。

Transformers 加速的一些常用技巧

Fp16 vs Fp32

Transformers 加速的一些常用技巧

雙精度(FP64)消耗64位。符號值為1位,指數值為11位,有效精度為52位。

單精度(FP32)消耗32位。符號值為1位,指數值為8位,有效精度為23位。

半精度(FP16)消耗16位。符號值為1位,指數值為5位,有效精度為10位。

所以Fp16可以提高記憶體節省,並可以大大提高模型訓練的速度。考慮到Fp16的優勢和它在模型使用方面的主導區域,它非常適合推理任務。但是fp16會產生數值精度的損失,導致計算或儲存的值不準確,考慮到這些值的精度至關重要。

另外就是這種最佳化師針對於分類任務的,對於迴歸這種需要精確數值的任務Fp16的表現並不好。

總結

以上這些方法,可以在一定程度上緩解記憶體不足和計算資源的限制,但是對於大型的模型我們還是需要一個強大的GPU。

歡迎關注公眾號CV技術指南,專注於計算機視覺的技術總結、最新技術跟蹤、經典論文解讀、CV招聘資訊。

計算機視覺入門1v3輔導班

【技術文件】《從零搭建pytorch模型教程》122頁PDF下載

QQ交流群:470899183。群內有大佬負責解答大家的日常學習、科研、程式碼問題。

其它文章

分享一個CV知識庫,上千篇文章、專欄,CV所有資料都在這了

明年畢業,還不知道怎麼做畢設的請抓緊機會了

LSKA注意力 | 重新思考和設計大卷積核注意力,效能優於ConvNeXt、SWin、RepLKNet以及VAN

CVPR 2023 | TinyMIM:微軟亞洲研究院用知識蒸餾改進小型ViT

ICCV2023|漲點神器!目標檢測蒸餾學習新方法,浙大、海康威視等提出

ICCV 2023 Oral | 突破性影像融合與分割研究:全時多模態基準與多互動特徵學習

聽我說,Transformer它就是個支援向量機

HDRUNet | 深圳先進院董超團隊提出帶降噪與反量化功能的單幀HDR重建演算法

南科大提出ORCTrack | 解決DeepSORT等跟蹤方法的遮擋問題,即插即用真的很香

1800億引數,世界頂級開源大模型Falcon官宣!碾壓LLaMA 2,效能直逼GPT-4

SAM-Med2D:打破自然影像與醫學影像的領域鴻溝,醫療版 SAM 開源了!

GhostSR|針對影像超分的特徵冗餘,華為諾亞&北大聯合提出GhostSR

Meta推出畫素級動作追蹤模型,簡易版線上可玩 | GitHub 1.4K星

CSUNet | 完美縫合Transformer和CNN,效能達到UNet家族的巔峰!

AI最全資料彙總 | 基礎入門、技術前沿、工業應用、部署框架、實戰教程學習

計算機視覺入門1v3輔導班

計算機視覺交流群

相關文章