iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
生成式 AI

LLM 學習筆記 - 從 LLM 輸入問題,按下 Enter 後會發生什麼事?系列 第 17

Day 17. Layer Normalization & GELU:從做 LLM 實做 Feed Foward

  • 分享至 

  • xImage
  •  

Layer normalization

這一層實做的目的,是希望可以讓神經網路層的輸出調整到平方差為 1 平均值為 0。因為每一層的神經網路經過訓練,可能訊號會越傳越大或越小,而 normalization 可以將輸出統一尺度。

batch_example = torch.randn(2, 5) 

layer = nn.Sequential(nn.Linear(5, 6), nn.ReLU())
out = layer(batch_example)

舉一個 2 段的 5 維資料為例,透過 PyTorch 的 Sequential 來處理兩層計算,第一層做線性轉換,將 5 維轉 6 維,第二層 ReLU 將負值轉為 0 正值保持不變。

在這樣情況下,計算目前的平均值與平方差,目前還不為 0 跟 1。

mean = out.mean(dim=-1, keepdim=True)
var = out.var(dim=-1, keepdim=True)

如果要達到這個結果我們需要將每一個結果減去平均,並除以標準差,經過中間這一層計算,就可以做到 Normalization。

out_norm = (out - mean) / torch.sqrt(var)
mean = out_norm.mean(dim=-1, keepdim=True)
var = out_norm.var(dim=-1, keepdim=True)

最後將這段封裝進另一個 Layer Class :

class LayerNorm(nn.Module):
    def __init__(self, emb_dim):
        super().__init__()
        self.eps = 1e-5
        self.scale = nn.Parameter(torch.ones(emb_dim))
        self.shift = nn.Parameter(torch.zeros(emb_dim))

    def forward(self, x):
        mean = x.mean(dim=-1, keepdim=True)
        var = x.var(dim=-1, keepdim=True, unbiased=False)
        norm_x = (x - mean) / torch.sqrt(var + self.eps)
        return self.scale * norm_x + self.shift

而我們也可以在原本的 DummyGPTModel class 中引入:

class DummyGPTModel(nn.Module):
    def __init__(self, cfg):
        ## ... add final_norm
        self.final_norm = DummyLayerNorm(cfg["emb_dim"])
        self.out_head = nn.Linear(
            cfg["emb_dim"], cfg["vocab_size"], bias=False
        )

    def forward(self, in_idx):
        batch_size, seq_len = in_idx.shape
        tok_embeds = self.tok_emb(in_idx)
        pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))
        x = tok_embeds + pos_embeds
        x = self.drop_emb(x)
        ## ... add final_norm
        x = self.final_norm(x)
        logits = self.out_head(x)
        return logits

GELU Layer

前一段略提到了神經網路的 activation function ReLU,但現在更多的使用的是另一個名為 GELU 的 activation function,關於 ReLU 與 GELU 都大量的與數學有關,會在第三段落更多的著墨。

但現階段,可以先暫時回憶之前提到的模型三階段,Model → Loss → Optimization,之前舉了一個最簡單的 y = ax + b 作為 Model 架構的案例。實際上,一個可以更彈性解釋的模型形狀,就是 ReLU 或 GELU,透過曲線擬合來取近似值。

而一樣先開一個 GELU class 來實做數學式:

class GELU(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        return 0.5 * x * (1 + torch.tanh(
            torch.sqrt(torch.tensor(2.0 / torch.pi)) * 
            (x + 0.044715 * torch.pow(x, 3))
        ))

接著將此模組用來實做一個小型的神經網路模組 FeedFoward,這個模組會讓輸入的矩陣,經過一次線性層,將維度增加 4 倍、接著透過 GELU 將訊號中,讓很大的正數原樣通過、接近 0 的數只通過一部分,大負數則趨於 0。最後再進行一次線性轉換縮小 4 倍。

class FeedForward(nn.Module):
    def __init__(self, cfg):
        super().__init__()
        self.layers = nn.Sequential(
            nn.Linear(cfg["emb_dim"], 4 * cfg["emb_dim"]),
            GELU(),
            nn.Linear(4 * cfg["emb_dim"], cfg["emb_dim"]),
        )

    def forward(self, x):
        return self.layers(x)

中間維度縮放的過程,有助於讓模型可以在更高為的空間中,找到更深層的特徵抽取,可以理解為像是將視野拉遠,來看有沒有某些共同 pattern。


上一篇
Day 16. Layer:從做 LLM 實做 GPT 架構
下一篇
Day 18. Shorted Connection: 從做 LLM 避免梯度消失
系列文
LLM 學習筆記 - 從 LLM 輸入問題,按下 Enter 後會發生什麼事?19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言