HW-202337458-transformer-decoder / transformer_decoder.py
hf-june's picture
Upload transformer decoder assignment
c780b5d verified
Raw
History Blame Contribute Delete
8.38 kB
import torch
import torch.nn as nn
from transformers import PretrainedConfig
class CustomDecoderConfig(PretrainedConfig):
model_type = "custom-transformer-decoder"
def __init__(
self,
vocab_size=30522,
max_position_embeddings=128,
hidden_size=256,
num_attention_heads=8,
intermediate_size=1024,
num_hidden_layers=4,
hidden_dropout_prob=0.1,
attention_probs_dropout_prob=0.1,
**kwargs
):
super().__init__(**kwargs)
# ์–ดํœ˜ ํฌ๊ธฐ(vocab size): ์ž…๋ ฅ token id์˜ ์ „์ฒด ๊ฐœ์ˆ˜
self.vocab_size = vocab_size
# ์ตœ๋Œ€ ์œ„์น˜ ์ž„๋ฒ ๋”ฉ(max position embeddings): ์ž…๋ ฅ sequence์˜ ์ตœ๋Œ€ ๊ธธ์ด
self.max_position_embeddings = max_position_embeddings
# ์€๋‹‰ ์ฐจ์›(hidden size): ๊ฐ token vector์˜ ์ฐจ์›
self.hidden_size = hidden_size
# attention head ๊ฐœ์ˆ˜(num attention heads): Multi-Head Attention์˜ head ์ˆ˜
self.num_attention_heads = num_attention_heads
# FFN ๋‚ด๋ถ€ ์ฐจ์›(intermediate size): Feed Forward Network์˜ ์ค‘๊ฐ„ ์ฐจ์›
self.intermediate_size = intermediate_size
# decoder layer ๊ฐœ์ˆ˜(num hidden layers): DecoderBlock ๋ฐ˜๋ณต ํšŸ์ˆ˜
self.num_hidden_layers = num_hidden_layers
# dropout ๋น„์œจ(hidden dropout probability): ๊ณผ์ ํ•ฉ(overfitting) ๋ฐฉ์ง€
self.hidden_dropout_prob = hidden_dropout_prob
# attention dropout ๋น„์œจ(attention probabilities dropout probability)
self.attention_probs_dropout_prob = attention_probs_dropout_prob
class PositionWiseFeedForward(nn.Module):
def __init__(self, hidden_size, intermediate_size, dropout_prob):
super().__init__()
# ์ฒซ ๋ฒˆ์งธ ์„ ํ˜•์ธต(first linear layer): hidden size๋ฅผ intermediate size๋กœ ํ™•์žฅ
self.linear_1 = nn.Linear(hidden_size, intermediate_size)
# ํ™œ์„ฑํ™” ํ•จ์ˆ˜(activation function): ๋น„์„ ํ˜•์„ฑ ์ถ”๊ฐ€
self.activation = nn.GELU()
# ๋‘ ๋ฒˆ์งธ ์„ ํ˜•์ธต(second linear layer): intermediate size๋ฅผ hidden size๋กœ ์ถ•์†Œ
self.linear_2 = nn.Linear(intermediate_size, hidden_size)
# ๋“œ๋กญ์•„์›ƒ(dropout): ๊ณผ์ ํ•ฉ(overfitting) ๋ฐฉ์ง€
self.dropout = nn.Dropout(dropout_prob)
def forward(self, x):
# Position-wise FFN: ๊ฐ ์œ„์น˜(position)์˜ token์— ๋…๋ฆฝ์ ์œผ๋กœ ์ ์šฉ
x = self.linear_1(x)
x = self.activation(x)
x = self.dropout(x)
x = self.linear_2(x)
return x
class DecoderBlock(nn.Module):
def __init__(self, config):
super().__init__()
# Masked Self-Attention: ๋ฏธ๋ž˜ token์„ ๋ณด์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” attention
self.masked_self_attention = nn.MultiheadAttention(
embed_dim=config.hidden_size,
num_heads=config.num_attention_heads,
dropout=config.attention_probs_dropout_prob,
batch_first=True
)
# ์ฒซ ๋ฒˆ์งธ ์ •๊ทœํ™”(layer normalization): self-attention ์ถœ๋ ฅ ์•ˆ์ •ํ™”
self.norm_1 = nn.LayerNorm(config.hidden_size)
# Cross-Attention: encoder output๊ณผ decoder input ์‚ฌ์ด์˜ ๊ด€๊ณ„ ํ•™์Šต
self.cross_attention = nn.MultiheadAttention(
embed_dim=config.hidden_size,
num_heads=config.num_attention_heads,
dropout=config.attention_probs_dropout_prob,
batch_first=True
)
# ๋‘ ๋ฒˆ์งธ ์ •๊ทœํ™”(layer normalization): cross-attention ์ถœ๋ ฅ ์•ˆ์ •ํ™”
self.norm_2 = nn.LayerNorm(config.hidden_size)
# Position-Wise Feed Forward Network: token๋ณ„ ๋น„์„ ํ˜• ๋ณ€ํ™˜
self.feed_forward = PositionWiseFeedForward(
hidden_size=config.hidden_size,
intermediate_size=config.intermediate_size,
dropout_prob=config.hidden_dropout_prob
)
# ์„ธ ๋ฒˆ์งธ ์ •๊ทœํ™”(layer normalization): FFN ์ถœ๋ ฅ ์•ˆ์ •ํ™”
self.norm_3 = nn.LayerNorm(config.hidden_size)
# ๋“œ๋กญ์•„์›ƒ(dropout): residual connection ์ „์— ์ ์šฉ
self.dropout = nn.Dropout(config.hidden_dropout_prob)
def forward(self, x, encoder_output=None, self_attention_mask=None, cross_attention_mask=None):
# ์ž”์ฐจ ์—ฐ๊ฒฐ(residual connection)์„ ์œ„ํ•ด ์ž…๋ ฅ ์ €์žฅ
residual = x
# Masked Self-Attention ๊ณ„์‚ฐ
self_attention_output, _ = self.masked_self_attention(
query=x,
key=x,
value=x,
attn_mask=self_attention_mask
)
# Add & Norm: residual connection + layer normalization
x = self.norm_1(residual + self.dropout(self_attention_output))
if encoder_output is not None:
# ์ž”์ฐจ ์—ฐ๊ฒฐ(residual connection)์„ ์œ„ํ•ด ์ž…๋ ฅ ์ €์žฅ
residual = x
# Cross-Attention ๊ณ„์‚ฐ
cross_attention_output, _ = self.cross_attention(
query=x,
key=encoder_output,
value=encoder_output,
key_padding_mask=cross_attention_mask
)
# Add & Norm: residual connection + layer normalization
x = self.norm_2(residual + self.dropout(cross_attention_output))
# ์ž”์ฐจ ์—ฐ๊ฒฐ(residual connection)์„ ์œ„ํ•ด FFN ์ž…๋ ฅ ์ €์žฅ
residual = x
# Position-Wise Feed Forward ๊ณ„์‚ฐ
ff_output = self.feed_forward(x)
# Add & Norm: residual connection + layer normalization
x = self.norm_3(residual + self.dropout(ff_output))
return x
class TransformerDecoder(nn.Module):
def __init__(self, config):
super().__init__()
# ํ† ํฐ ์ž„๋ฒ ๋”ฉ(token embedding): token id๋ฅผ vector๋กœ ๋ณ€ํ™˜
self.token_embedding = nn.Embedding(
config.vocab_size,
config.hidden_size
)
# ์œ„์น˜ ์ž„๋ฒ ๋”ฉ(position embedding): token์˜ ์ˆœ์„œ ์ •๋ณด ์ถ”๊ฐ€
self.position_embedding = nn.Embedding(
config.max_position_embeddings,
config.hidden_size
)
# DecoderBlock stack: N๊ฐœ์˜ DecoderBlock ๋ฐ˜๋ณต
self.layers = nn.ModuleList([
DecoderBlock(config) for _ in range(config.num_hidden_layers)
])
# ๋“œ๋กญ์•„์›ƒ(dropout): embedding ์ดํ›„ ์ ์šฉ
self.dropout = nn.Dropout(config.hidden_dropout_prob)
# ์ตœ์ข… ์ •๊ทœํ™”(final layer normalization)
self.final_norm = nn.LayerNorm(config.hidden_size)
# ์ถœ๋ ฅ์ธต(lm head): hidden vector๋ฅผ vocab size๋กœ ๋ณ€ํ™˜
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size)
self.config = config
def make_causal_mask(self, seq_length, device):
# Causal mask: ํ˜„์žฌ token์ด ๋ฏธ๋ž˜ token์„ ๋ณด์ง€ ๋ชปํ•˜๊ฒŒ ํ•จ
mask = torch.triu(
torch.ones(seq_length, seq_length, device=device),
diagonal=1
).bool()
return mask
def forward(self, input_ids, encoder_output=None, cross_attention_mask=None):
batch_size, seq_length = input_ids.size()
# ์œ„์น˜ ๋ฒˆํ˜ธ(position ids) ์ƒ์„ฑ
position_ids = torch.arange(
seq_length,
dtype=torch.long,
device=input_ids.device
).unsqueeze(0).expand(batch_size, seq_length)
# token embedding๊ณผ position embedding์„ ๋”ํ•จ
x = self.token_embedding(input_ids) + self.position_embedding(position_ids)
x = self.dropout(x)
# ๋ฏธ๋ž˜ token ์ฐจ๋‹จ์šฉ causal mask ์ƒ์„ฑ
self_attention_mask = self.make_causal_mask(seq_length, input_ids.device)
# DecoderBlock ๋ฐ˜๋ณต ์ ์šฉ
for layer in self.layers:
x = layer(
x,
encoder_output=encoder_output,
self_attention_mask=self_attention_mask,
cross_attention_mask=cross_attention_mask
)
x = self.final_norm(x)
# logits: ๊ฐ token ์œ„์น˜์—์„œ vocab ์ „์ฒด์— ๋Œ€ํ•œ ์ ์ˆ˜
logits = self.lm_head(x)
return logits
if __name__ == "__main__":
config = CustomDecoderConfig()
model = TransformerDecoder(config)
input_ids = torch.randint(0, config.vocab_size, (2, 10))
encoder_output = torch.randn(2, 10, config.hidden_size)
logits = model(input_ids, encoder_output=encoder_output)
print("Input shape:", input_ids.shape)
print("Logits shape:", logits.shape)