0ããäœãLLMãŒLlama
æ¬èšäºã®å¯Ÿè±¡èªè ïŒ
- LLMïŒå€§èŠæš¡èšèªã¢ãã«ïŒã®è€éãªæ§é ãéå±€ãçè§£ããŠãããããããã©ã®ããã«çµã¿åãããããåãããªã人
- LlaMaã¢ãã«ã«é¢ãããã¹ãŠã®ãªãã¬ãŒã¿ãšã¢ãŒããã¯ãã£ïŒRMSNormãROPEãSwiGLUã®å®è£ ãå«ãïŒãäžè¡ãã€åè§£ããŸãã
- æ¬èšäºã§ã¯huggingfaceã®ã©ã€ãã©ãªã䜿çšããŠãããããã¹ãŠpytorchã§å®è£ ããŠããŸãããŸããäºååŠç¿æžã¿ã¢ãã«ã䜿çšããŠããŸããã
- ã¹ã¿ãŒãå°ç¹ã¯ãæºæ°ç©èªãã®åæã§ããããŽãŒã«å°ç¹ã¯ããªãèªèº«ããã¬ãŒãã³ã°ããå€§èŠæš¡ã¢ãã«ã§ãã
- pytorchãæºåããŠãã ãããGPUããªããŠã倧äžå€«ã§ããéèŠãªã®ã¯LLMã®åçãåŠã¶ããšã§ããããã®æç« ãèªãã ã ãã§æ°ããå€§èŠæš¡ã¢ãã«ã®ã¢ãŒããã¯ãã£ãäœããããã§ã¯ãããŸããã
- æ¬èšäºã§ã¯ãã§ããéãå¹³æãªèšèã䜿ã£ãŠåçã解説ããŠãããŸãã
åºæ
æ¬èšäºã®ãã¹ãŠã®ã³ãŒãã¯Google Colabã«å ±æãããŠããŸããã³ãŒãã«ã¯äžè¡ãã€ã³ã¡ã³ããä»ããŠããŸãã®ã§ãèšäºãèªãã®ãé¢åãªæ¹ã¯ãçŽæ¥Colabäžã§å®è¡ããŠã¿ãŠãã ãããGPUãªãœãŒã¹ã¯å¿ èŠãªããæå°æ§æã®CPUã§å®è¡ã§ããŸãã
ã·ã³ãã«ãªããã¹ãçæã¢ãã«ãæ§ç¯ãã
LlaMaãæ§ç¯ããåã«ããŸãã¯ã·ã³ãã«ãªSeq2seqã¢ãã«ãäœæãããã®åŸããã®åºæ¬çãªSeq2seqã¢ãã«ã«LlaMaã®ãªãã¬ãŒã¿ã§ããRMSãRopeãSwiGLUãé æ¬¡è¿œå ããŠãããŸããæçµçã«å®å šãªLlaMaã¢ãã«ãæ§ç¯ããŸãã
ãŸãã¯ãããã€ãã®ãŠãŒãã£ãªãã£é¢æ°ãå®è£ ããŸããç¹ã«é£ããã¯ãããŸããããäžéã確èªããããšããå§ãããŸããããŒã¿ã®åœ¢ç¶ãé ã®äžã§ã€ã¡ãŒãžããªããé²ãããšãã¢ãã«æ§ç¯ã®éã«ãã©ã®ãããªå ¥åãåŠçãããŠããã®ããçè§£ãããããªãããã£ãŒããã¥ãŒã©ã«ãããã¯ãŒã¯ã®çè§£ã«å€§ãã«åœ¹ç«ã¡ãŸãã
import
import torch
from torch import nn
from torch.nn import functional as F
import numpy as np
from matplotlib import pyplot as plt
import time
import pandas as pd
import urllib.request
äžèšã¯ã䜿çšããå¿ èŠããããã¹ãŠã®ã©ã€ãã©ãªã§ãã
次ã«ãèšå®ïŒconfigïŒãä¿åããããã®èŸæžãäœæããŸãã
# config ãæ ŒçŽããèŸæžãäœæããŸãã
MASTER_CONFIG = {
# ãã©ã¡ãŒã¿ãããã«é
眮
}
æºæ°ç©èªã®ããŒã¿ã»ãããããŠã³ããŒã
# æºæ°ç©èªããŒã¿ã»ãããããŠã³ããŒããã
url = "https://raw.githubusercontent.com/wooheum-xin/llama_form_zero_jp/main/02hahakigi.txt"
file_name = "The_Tale_of_Genji.txt"
urllib.request.urlretrieve(url, file_name)
ããŒã¿ã®èªã¿èŸŒã¿
# ããŒã¿ãèªã¿åºã
with open("The_Tale_of_Genji.txt", 'r', encoding='shift_jis', errors='replace') as f:
lines = f.read()
# ç°¡æèŸæžã®äœæïŒæåã¬ãã«ïŒ
vocab = sorted(list(set(lines)))
# æåã®næåã衚瀺
head_num=50
print('æåã®{}æå:'.format(head_num), vocab[:head_num])
print('ãµã€ãº:', len(vocab))
èªåœãæŽæ°ã«ãšã³ã³ãŒããã
éåžžã®æŽæ°ã«ãšã³ã³ãŒãããŸããäŸãã°ã"1":"ã"ã"2":"ã"ã"3":"ã"ã®ããã«ã次ã«ããŒãšå€ãå転ããããã®ãçšæããŸãã
# èŸæžãæ°åãæ®éã®æŽæ°ã«ãšã³ã³ãŒããã
itos = {i: ch for i, ch in enumerate(vocab)}
# åæ¹åãããã³ã°
stoi = {ch: i for i, ch in enumerate(vocab)}
次ã«ãç°¡æãªãšã³ã³ãŒããšãã³ãŒããäœæããŸããããã䜿çšããŠãã¢ãã«ã«å ¥åããåã«ããã¹ããæ°å€ã«å€æããåºåããåã«æ°å€ãããã¹ãã«å€æããŸãã
# ãšã³ã³ãŒã
def encode(s):
return [stoi[ch] for ch in s]
# ãã³ãŒã
def decode(l):
return ''.join([itos[i] for i in l])
decode(encode("æºæ°"))
encode("æºæ°")
# [681, 645]
åºåããã2ã€ã®æ°åã¯ããæºãåãšãæ°ãåã衚ããŠããããããã¯vocabèªåœè¡šã®äžã§ãšã³ã³ãŒããããŠããŸããããã¯ãšã³ã³ãŒããããã³ã°è¡šã®åçã§ãã
ä»å䜿çšããŠããã®ã¯æååäœã®ãšã³ã³ãŒãã§ãããBPEãä»ã®åœ¢åŒã®èªåœè¡šæ§ç¯ã§ã¯ãããŸããããã®éšåã¯ãtiktokenãä»ã®ãããã³ã°ææ³ã«çœ®ãæããããšãã§ããŸãããæ¬èšäºã§ã¯åçãçè§£ããããšãäž»ãªç®çãªã®ã§ãã§ããã ãã·ã³ãã«ãªæ¹æ³ã䜿çšããŠããŸãããã®ã»ããçè§£ããããã§ãã
# å
šæã笊å·åãïŒtensorã«ãããã³ã°
dataset = torch.tensor(encode(lines), dtype=torch.int16)
# 2.9äžæåã§ã
print(dataset.shape)
print(dataset)
äžèšã®ã³ãŒããããã¯ã§ã¯ããæºæ°ç©èªãå šäœããšã³ã³ãŒãããŠããã³ãœã«ã«å€æããŸãããæ¬èšäºã§ã¯ã2.9äžæå以äžãäžã€ã®1次å ãã³ãœã«ã«å€æããŸããã
次ã«ããããæ§ç¯ããŸãã
# batch ã®æ§ç¯
def get_batches(data, split, batch_size, context_window, config=MASTER_CONFIG):
# åå²èšç·Žã»ããïŒæ€èšŒã»ããïŒãã¹ãã»ããïŒæ¯çã¯ïŒèšç·Ž80%ïŒæ€èšŒ10%ïŒãã¹ã10%ã§ãã
train = data[:int(0.8 * len(data))]
val = data[int(0.8 * len(data)): int(0.9 * len(data))]
test = data[int(0.9 * len(data)):]
# ãã¹ãŠã®èšç·ŽããŒã¿ãbatchïŒæ€èšŒã»ããïŒãã¹ãã»ãããšããŠã倿°ããšã«æ ŒçŽããïŒåçŽã«èŠãããïŒ
batch_data = train
if split == 'val':
batch_data = val
if split == 'test':
batch_data = test
# ããã§torch.randintãåŠã¶å¿
èŠãããïŒãµã€ãºãbatch_sizeã§å
éšå€ãä¹±æ°ã®æŽæ°ã§ããtensorãçæãã.ä¹±æ°ãçæããæ°å€ãã£ãŒã«ãã¯ã[0, ãã¬ãŒãã³ã°ã»ããæåæ° - ã¹ã©ã€ããŠã£ã³ããŠãµã€ãº- 1] ã®æŽæ°ã§ãã
# 詳现ã¯ãå
¬åŒææžãåç
§ããããšãã§ãã
ix = torch.randint(0, batch_data.size(0) - context_window - 1, (batch_size,))
# print('ix:')
# print(ix)
# ããã§torch.stackãåŠã¶å¿
èŠããã, å®è¡æäœã¯pythonã®zipããŒã¯ãŒãã«äŒŒãŠãããïŒæäœå¯Ÿè±¡ãtensorãã³ãœã«ã§ããã ãã§ïŒä»»æã®æ¬¡å
ã®ãã³ãœã«ãæå®ããŠçµã¿åããã.
# 詳现ã¯ãå
¬åŒææžãåç
§ããããšãã§ãã
# ããã§ïŒxãçŽ æ§ïŒyãäºæž¬å€ãšãããšïŒææžçæã¿ã¹ã¯ã¯äžäœnæåããäžäœ1æåãæšè«ããããïŒyã®æ§é ã¯ãŠã£ã³ããŠãå
ã®ãµã€ãºã®ãŸãŸ1æ¡åŸãã«ç§»åããã.
# ãŠã£ã³ããŠãã¹ã©ã€ããããããšã«ããïŒbatch_dataäžã®èšç·ŽããŒã¿ãã©ã³ãã ã«ãµã³ããªã³ã°ãïŒèšç·ŽããŒã¿ãã©ã³ãã ã«éžæããããšã«çžåœãã.
# å
ã®çŽ2.9äžæåã®ãã¡ïŒã©ã³ãã ã«1æåãéå§ç¹ãšãïŒãã®éå§ç¹ããåŸæ¹ã«ã¹ã©ã€ããŠã£ã³ããŠã®åæ°åã®æåãéžæãïŒèšç·ŽããŒã¿ãšããŠåŸæ¹ã«1æ¡ç§»åãããããšãç®æšå€ã§ãã. ãããã£ãŠixã®æ§é ã¯indexãè¶
ããŠã¯ãªããªã.
x = torch.stack([batch_data[i:i+context_window] for i in ix]).long()
y = torch.stack([batch_data[i+1:i+context_window+1] for i in ix]).long()
# åºæå€ãç®æšå€ãæ»ããŸãã
return x, y
torch.randintãtorch.stackã«ã€ããŠã¯ãäžåºŠåŠãã§ãããšè¯ãã§ãããã®ãããªèšäºã¯ãããããããŸãã
泚ç®ãã¹ãã¯ã以äžã®2è¡ã®ã³ãŒãã§ãïŒ
x = torch.stack([batch_data[i:i+context_window] for i in ix]).long()
y = torch.stack([batch_data[i+1:i+context_window+1] for i in ix]).long()
ãã®ã³ãŒãã§ã¯ãã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠã®åœ¢åŒã§ããŒã¿ã®ç¹åŸŽå€ãšã¿ãŒã²ããå€ãååŸããŠããŸãããã¬ãŒãã³ã°æã«ã¯ãåã®Næåãåºã«æ¬¡ã®1æåãäºæž¬ãããããã¿ãŒã²ããå€yã®ã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠã¯ãå ã®ãµã€ãºïŒé·ãïŒãä¿æãããŸãŸå³ã«1ã€ã·ããããŸãã
# äžèšã§æ§ç¯ããget_batchs()颿°ã«åŸã£ãŠããã©ã¡ãŒã¿èŸæžãæŽæ°ããŸãã
MASTER_CONFIG.update({
'batch_size': 8,
'context_window': 8,
'vocab_size':1087 # æºæ°ç©èªèŸæžã®ãµã€ãº
})
èŸæžãäœæããŠãconfigãã©ã¡ãŒã¿ãä¿åããŸããäŸãã°ãã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠã®å€ã16ãšèšå®ãããšãããã¹ãããµã³ããªã³ã°ããéã«ãåããã¹ããé·ã16ã®ããŒã¿ã«åå²ããããšãæå³ããŸããvocab_sizeã¯å
ã»ã©ã®èª¬æã«ããéãããæºæ°ç©èªãã®ãã¹ãŠã®æåãéè€ãªãã§éèšããæåæ°ãã€ãŸãèªåœè¡šã®ãµã€ãºã衚ããŸãã
çè§£ãæ·±ããããã«ã颿°ãã¯ã©ã¹ãæ§ç¯ãããã³ã«ããã®éœåºŠå®è¡ããŠçµæã確èªããŸããããå€ãã®ã³ãŒããäžåºŠã«ãŸãšããŠå®è¡ãããšãæçµçµæãèŠãŠãæ··ä¹±ããå¯èœæ§ããããŸãã
ãããã£ãŠãå
ã»ã©ã®get_batches颿°ãå®è¡ããŠçµæã確èªããŸãã芳å¯ã容æã«ããããããã³ãŒãã䜿çšããŠçµæããã³ãŒãããŠã¿ãŸãã
# ãã¬ãŒãã³ã°ããŒã¿ã®ååŸ
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
# ã©ã³ãã ã«çæããããµã³ããªã³ã°ã§ãããããæã
ã¯ããŒã¿ãèŠãããšãã§ãããã®äžã®åãµã³ããªã³ã°ããŒã¿ã¯ãåæã®ã©ã³ãã ãªéå§ç¹ããæ¥ãŠãåã¿ãã«ã¯äžã€ã®ïŒxãyïŒã§ãããåxãšyã®å
é ã芳å¯ããŠããŠã£ã³ããŠãã¹ã©ã€ãããŠå®è¡ããæäœãçŽèгçã«æããããšãã§ããã
decoded_samples = [(decode(xs[i].tolist()), decode(ys[i].tolist())) for i in range(len(xs))]
print(decoded_samples)
# [('ãã¿ããªããšãèš', 'ã¿ããªããšãèšã'), ('ãã人ã®çŽèŠã§ã', 'ã人ã®çŽèŠã§ããª'), ('ãããšãã§ããã¯', 'ããšãã§ããã¯ã'), ('眮ãããçšåºŠã®ã', 'ãããçšåºŠã®ãã®'), ('ã§çœ®ãããæ°ã®ã', '眮ãããæ°ã®ãã'), ('ããããããã«ã', 'ãããããã«ãã'), ('æ¥å®¢ã«ãè¿ã¥ããŸ', '客ã«ãè¿ã¥ããŸã'), ('ã£ãŠããŠãæºæ°ã', 'ãŠããŠãæºæ°ãè¡')]
åºåçµæã¯ãªã¹ãã§ããã®ãªã¹ãã®èŠçŽ ã¯è€æ°ã®ã¿ãã«ã§ããåã¿ãã«ã¯ç¹åŸŽããŒã¿ãšã¿ãŒã²ããå€ãå«ãã§ããŸããåã¿ãã«ã®ããŒã¿ã®éå§ãšçµäºã芳å¯ããããšã§ãã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠã®å¹æã確èªã§ããŸãã
次ã«ãè©äŸ¡é¢æ°ãæ§ç¯ããŸãã
# è©äŸ¡é¢æ°ã®äœæ
@torch.no_grad()
def evaluate_loss(model, config=MASTER_CONFIG):
# è©äŸ¡çµæã¹ãã¬ãŒãžå€æ°
out = {}
# ã¢ãã«ãè©äŸ¡ã¢ãŒãã«èšå®ãã
model.eval()
# è©äŸ¡ããŒã¿ã¯ããããèšç·Žã»ãããšæ€èšŒã»ããã§get_batchs()颿°ã§ååŸããã
for split in ["train", "val"]:
losses = []
# 10åã®batchãè©äŸ¡
for _ in range(10):
# åºæå€ïŒå
¥åããŒã¿ïŒïŒããã³ç®æšå€ïŒåºåããŒã¿ïŒãååŸãã.
xb, yb = get_batches(dataset, split, config['batch_size'], config['context_window'])
# åŸãããããŒã¿ãã¢ãã«ã«æã蟌ã¿losså€ãåŸã.
_, loss = model(xb, yb)
# lossã¹ãã¬ãŒãžã®æŽæ°
losses.append(loss.item())
# ãããã³ã³ãœãŒã«ã§ããèŠããããtrain_lossããvalid_lossãã®ç±æ¥ã§ã
out[split] = np.mean(losses)
# è©äŸ¡ãçµãã£ãã®ã§ãæš¡åãåã³èšç·Žç¶æ
ã«æ»ãããšãå¿ããªãã§ã次ã®epochã¯èšç·Žãç¶ç¶ããªããã°ãªããªãã
model.train()
return out
ãããŸã§ã®æäœã§ã¯ãç¹ã«ãç®ã®åãçã£æã«ãªãããããªé£ããéšåã¯ãªãã£ãã¯ãã§ãã
ããã§1ã€åºåããšããŠãç¹ã«å€§ããªæå³ã¯ãããŸããããããäžèšã®å 容ãäžéã確èªããjupyterãcolabã§å®è¡ããŠåé¡ããªããã°ã次ã«é²ãã§ãã ããã
å°ãäœè«ã§ãããããããã®ã³ãŒããããã«äœ¿ãããããšèããŠãããªãããã®èšäºã¯ãããŸã§äžèœã§ã¯ãªããããããŸããïŒçµå±ããæºæ°ç©èªãã®åæ2.9äžåã䜿ã£ãŠãäºååŠç¿ã¢ãã«ãªãã§é©ç°çãªå€§èŠæš¡ã¢ãã«ãäœããããã§ã¯ãããŸããïŒãLLMãåŠã³ãããšããã®ã§ããã°ãããäžåºŠåŒ·èª¿ããŸãããã³ãŒããäžè¡ãã€ãã£ããèªãã§ãã ãããããããªããšæ··ä¹±ããŠãäœèšã«é ãçããªããããããŸããã
LlaMaã¢ãŒããã¯ãã£ã®åæã«å ¥ãåã«ããŸãæãã·ã³ãã«ãªããã¹ãçæã¢ãã«ãäœæãããã®äžã«LlaMaã®RSMãRopeãªã©ãå°ããã€è¿œå ããŠãããŸãããããå®çŸããããã«ããŸã以äžãè¡ããŸãïŒ
- åé¡ã®ããïŒäžå®å šãªïŒã¢ãã«ã¢ãŒããã¯ãã£ãäœæ
class StupidModel(nn.Module):
def __init__(self, config=MASTER_CONFIG):
super().__init__()
self.config = config
# ãšã³ãããã·ã¬ã€ã€ãŒãå
¥å: èŸæžãµã€ãºãåºå: 次å
ãµã€ãº
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
# ãã£ãŒãã£ãŒã®ãªã¬ãŒã·ã§ã³ã«ã¹ãããããçŽç·ã¬ã€ã€ãŒãäœæ
# LlaMaã䜿çšããŠããæŽ»æ§å颿°ã¯SwiGLUã§ãããçŸåšãã®æããªã¢ãã«ã¢ãŒããã¯ãã£ã§ã¯ãŸãReluã䜿çšããŠããŸãã
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
nn.ReLU(),
nn.Linear(config['d_model'], config['vocab_size']),
)
# ãã®ã³ãã³ãã¯ã¢ãã«ã®ãã©ã¡ãŒã¿æ°ãçŽæ¥ç¢ºèªããã®ã«åœ¹ç«ã¡ãŸãã
# ãããªããã°èªåã§æèšç®ãããã誰ãã話ãã7Bãã20Bãã108Bãã®ãããªã¢ãã«ãèããããããŸãããããã®ã³ãã³ããããã°ãããªããäœæããã¢ãã«ã®ãã©ã¡ãŒã¿æ°ãçŽæ¥ç¢ºèªã§ããŸãã
print("ãã©ã¡ãŒã¿æ°ïŒ", sum([m.numel() for m in self.parameters()]))
ãããããã³ã¡ã³ããèŠãã°ååã ãšæããŸãããŸãã¯ãå°ã"stupid"ãªã¢ãã«ãäœæããŸããããã®ã¢ãã«ã®æ§é ã¯éåžžã«ã·ã³ãã«ã§ãåã蟌ã¿å±€ãç·åœ¢å€æã掻æ§å颿°ã®ã¿ã§æ§æãããŠããŸããå¯äžé¢çœãéšåã¯ã以äžã®ã³ãã³ãã§ãããããèŠããŠããã°ãä»åŸã¢ãã«ã®ãã©ã¡ãŒã¿æ°ã調ã¹ãã®ã«åœ¹ç«ã¡ãŸãã
print("ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
次ã«ãäžèšã®"stupid"ãªã¢ãã«ã«ååãäŒæïŒforwardïŒé¢æ°ã远å ããŸããååãå€ããŠããç°¡åãªç Žæã¢ãã«ããšã§ãããŸããããå®éã«ã¯"broken"ããåé¡ãããããšããæå³ã§ããããã®åé¡ã«ã€ããŠã¯ããã«èª¬æããŸãã
# æã
ãäœæããå°ããªã¢ãã«ã«ååãäŒæã远å
class SimpleBrokenModel(nn.Module):
# initã®å
容ã¯äžãšåãã§ã倿Žãªã
def __init__(self, config=MASTER_CONFIG):
super().__init__()
self.config = config
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
nn.ReLU(),
nn.Linear(config['d_model'], config['vocab_size']),
)
# ååãäŒæé¢æ°ã远å
def forward(self, idx, targets=None):
# embeddingå±€ãã€ã³ã¹ã¿ã³ã¹åããIDã«ãããã³ã°ãããããŒã¿ãå
¥åããŠãåã蟌ã¿åŸã®ããŒã¿ãåºå
x = self.embedding(idx)
# embeddingå±€ã®åºåããŒã¿ãç·åœ¢å±€ã«æž¡ã
a = self.linear(x)
# ç·åœ¢å±€ã®åºåããŒã¿ã«å¯ŸããŠãæåŸã®æ¬¡å
ã§softmaxãè¡ãã確çååžãåŸã
logits = F.softmax(a, dim=-1)
# ããã¿ãŒã²ããå€ïŒåè¿°ã®yïŒãããå Žåã¯ãã¯ãã¹ãšã³ããããŒæå€±ãçšããŠæå€±ãèšç®ãããåºåã®ç¢ºçãããªãã¯ã¹ã®åœ¢ç¶ãå€ããã¿ãŒã²ããå€ã®åœ¢ç¶ãå€ãããå
¥åãšåºåãçµ±äžããŠããæå€±ãèšç®ãããæåŸã®æ¬¡å
ã¯1ã€ã®ããŒã¿ã衚ããŠããã
# ããã§ãtensor.view()颿°ãçè§£ãã幟äœåŠçãªç©ºéæ³ååã§ãããªãã¯ã¹ã®åœ¢ç¶ãã€ã¡ãŒãžããå¿
èŠãããã
if targets is not None:
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
# ã¿ãŒã²ããå€ããªãå Žåã確çååžã®çµæã®ã¿ãè¿ã
else:
return logits
# ãã©ã¡ãŒã¿æ°ã確èª
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°ïŒ", sum([m.numel() for m in self.parameters()]))
ãã¬ãŒãã³ã°æ®µéã ãã§ãªããæšè«ïŒè©äŸ¡ïŒæ®µéã«ã€ããŠãèšèŒãããŠããŸããæ¡ä»¶åå²ã§ã¿ãŒã²ããå€ãååšãããã©ããã確èªããååšããªãå Žåã¯ã¢ãã«ã®åºåçµæã®ã¿ãè¿ããŸããã¿ãŒã²ããå€ãååšããå Žåã¯ãåºåçµæã«å ããŠæå€±ïŒlossïŒå€ãè¿ããŸãã
# ããã§ã¯ããã®ã¢ãã«ã®embeddingã128次å
ã«èšå®
MASTER_CONFIG.update({
'd_model': 128,
})
# ã¢ãã«ãã€ã³ã¹ã¿ã³ã¹åããåŒæ°ãæž¡ã
model = SimpleBrokenModel(MASTER_CONFIG)
# å床ãã©ã¡ãŒã¿æ°ã確èª
print("ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in model.parameters()]))
åãèŸŒã¿æ¬¡å ã128ã«èšå®ããŸããLlaMaã®åãèŸŒã¿æ¬¡å ã¯4096ã§ãããä»åã¯CPUäžã§ãã¬ãŒãã³ã°ãããããå°ããã«èšå®ããŸãããã®èšå®ã§ã29äžãã©ã¡ãŒã¿ãæã€ã¢ãã«ãåŸãããŸãã
次ã«ããã¬ãŒãã³ã°åã®ã¢ãã«ã®åºåçµæãšlossã確èªããŸããã¢ãã«ã®åºåçµæã¯æ°å€ã§ãããlossãèŠãã»ããåãããããã§ãããã
# èšç·Žçšã®ç¹åŸŽããŒã¿ãšã¿ãŒã²ããããŒã¿ãååŸ
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
# ã¢ãã«ã«æå
¥ããŠã確çååžãããªãã¯ã¹ãšæå€±ãååŸ
logits, loss = model(xs, ys)
loss
# tensor(6.9912, grad_fn=<NllLossBackward0>)
次ã«ãconfigã®ãã€ããŒãã©ã¡ãŒã¿ãæŽæ°ããã¢ãã«ãã€ã³ã¹ã¿ã³ã¹åããŠãªããã£ãã€ã¶ãèšå®ããŸãïŒ
# ãã©ã¡ãŒã¿ãæŽæ°ãèšç·Žãšããã¯æ°ãããããµã€ãºããã°åºåééãèšå®
MASTER_CONFIG.update({
'epochs': 1000,
'log_interval': 10, # 10ãããããšã«ãã°ãåºå
'batch_size': 32,
})
# ã¢ãã«ãã€ã³ã¹ã¿ã³ã¹å
model = SimpleBrokenModel(MASTER_CONFIG)
# Adamãªããã£ãã€ã¶ãäœæïŒåºç€ç¥èïŒ
optimizer = torch.optim.Adam(
model.parameters(), # ãªããã£ãã€ã¶ã¯ã¢ãã«ã®å
šãã©ã¡ãŒã¿ãæé©åãã
)
次ã«ããã¬ãŒãã³ã°é¢æ°ãæ§ç¯ããŠãã¬ãŒãã³ã°ãéå§ããŸãïŒ
# ãã¬ãŒãã³ã°é¢æ°ãæ§ç¯
def train(model, optimizer, scheduler=None, config=MASTER_CONFIG, print_logs=False):
# æå€±ãä¿å
losses = []
# èšç·Žéå§æéãèšé²
start_time = time.time()
# æå®ããããšããã¯æ°åãã¬ãŒãã³ã°ãç¹°ãè¿ã
for epoch in range(config['epochs']):
# ãªããã£ãã€ã¶ãåæåããªããšãæ¯åã®èšç·Žãååã®çµæãåºã«æé©åããã广ãã»ãšãã©ãããŸãã
optimizer.zero_grad()
# èšç·ŽããŒã¿ãååŸ
xs, ys = get_batches(dataset, 'train', config['batch_size'], config['context_window'])
# ååãäŒæã§ç¢ºçãããªãã¯ã¹ãšæå€±ãèšç®
logits, loss = model(xs, targets=ys)
# éäŒæã§éã¿ãã©ã¡ãŒã¿ãæŽæ°ããåŠç¿çã®æé©ååšãæŽæ°
loss.backward()
optimizer.step()
# ããåŠç¿çã¹ã±ãžã¥ãŒã©ãæäŸãããŠããã°ãã¹ã±ãžã¥ãŒã©ã䜿ã£ãŠåŠç¿çã倿ŽãããŸããäŸãã°ãåŠç¿çãåšæçã«å€åããããåŸé
ãæžå°ã»å¢å ãããããŸããå
·äœçãªæŠç¥ã¯æ
éã«èšå®ããå¿
èŠããããŸãã詳ããã¯ãlr_schedulerãã§æ€çŽ¢ããŠãã ããã
if scheduler:
scheduler.step()
# ãã°ãåºå
if epoch % config['log_interval'] == 0:
# èšç·Žæéãèšç®
batch_time = time.time() - start_time
# è©äŸ¡é¢æ°ãå®è¡ããèšç·Žã»ãããšæ€èšŒã»ããã§æå€±ãèšç®
x = evaluate_loss(model)
# æ€èšŒæå€±ãä¿å
losses += [x]
# 鲿ãã°ãåºå
if print_logs:
print(f"Epoch {epoch} | val loss {x['val']:.3f} | Time {batch_time:.3f} | ETA in seconds {batch_time * (config['epochs'] - epoch)/config['log_interval'] :.3f}")
# 次ã®ãšããã¯ã®èšç·Žæéãèšç®ãããããéå§æéããªã»ãã
start_time = time.time()
# åŠç¿çã¹ã±ãžã¥ãŒã©ã䜿çšããŠããå Žåãæ¬¡ã®ãšããã¯ã®åŠç¿çãåºå
if scheduler:
print("lr: ", scheduler.get_lr())
# å
šãšããã¯ã®ãã¬ãŒãã³ã°ãçµäºããæçµçµæãåºå
print("Validation loss: ", losses[-1]['val'])
# æå€±å€ã®ãªã¹ããè¿ããã°ã©ããæç»ãããããæå€±ã®æšç§»ãè¿ããŸãã
return pd.DataFrame(losses).plot()
# ãã¬ãŒãã³ã°ãéå§
train(model, optimizer)

1000ãšããã¯ã®ãã¬ãŒãã³ã°åŸãlosså€ã¯å ã®6.99ãã6.77ãŸã§æžå°ããŸããïŒ
ããã§ããªããã®ã¢ãã«ã¢ãŒããã¯ãã£ããstupidãããBrokenããšåŒã°ããã®ãåãããŸãããã
*** ã§ãïŒïŒïŒ***
çŽããïŒïŒ
åå ãåæããŸãããïŒ
äžèšã®ãã¬ãŒãã³ã°ãã¬ãŒã ã¯ãŒã¯ã«ã¯ããã€ãåé¡ããããŸããååãäŒæïŒforwardïŒã®ã³ãŒãã«æ»ããšãlogits = F.softmax(a, dim=-1)ã§ç·åœ¢å±€ã®åºåã«å¯ŸããŠç¢ºçååžãèšç®ããŠããŸããããããlossã®èšç®ã«ã¯äº€å·®ãšã³ããããŒæå€±ïŒcross entropyïŒã䜿çšããŠãããã¿ãŒã²ããå€ã¯èªåœã«ãããã³ã°ãããæŽæ°ã§ãã¢ãã«ã®åºålogitsã¯ç¢ºçãããªãã¯ã¹ã§ãã
ãã®2ã€ãèšç®ããããšã¯ãåœå ã®è¡ã§å€åœäººã«ãHey man, what's up?ããšèšã£ãããçžæããæ¥æ¬èªã§ããŸããïŒãïŒæ¥æ¬èªã話ããããã©ãããã®ïŒïŒãšçãããããªãã®ã§ããçè§£ã¯ã§ãããã®ã®ãåæãããã®ãå°ãé¢åã§ãã
lossã®èšç®ããã粟å¯ã«ããããã«ãsoftmaxãåãé€ãå¿
èŠããããŸããããã«ããã亀差ãšã³ããããŒæå€±ã®èšç®ããã广çã«ãªããŸãã
# softmaxãåãé€ããlogitsãæåŸã®ç·åœ¢å±€ã®åºåçµæãšããŠååŸãã確çååžã®èšç®ãè¡ããªãããã«ããŸãã
# ãã®ããããã®ã¢ãŒããã¯ãã£ããããã»ã©æãã§ã¯ãªãã¢ãã«ã¢ãŒããã¯ãã£ããšåœåããŸãã
class SimpleNotStupidModel(nn.Module):
def __init__(self, config=MASTER_CONFIG):
super().__init__()
self.config = config
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
nn.ReLU(),
nn.Linear(config['d_model'], config['vocab_size']),
)
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
def forward(self, idx, targets=None):
x = self.embedding(idx)
# ãããèŠãŠãã ãããç·åœ¢å±€ãçŽæ¥çµæãåºåãã確çãããªãã¯ã¹ã«å€æããããã®éšåã ãã倿ŽããŸããä»ã¯ãã®ãŸãŸã§ãã
logits = self.linear(x)
# print(logits.shape)
if targets is not None:
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
else:
return logits
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
ReRun!
# å床ãåçš®æ©èœãã€ã³ã¹ã¿ã³ã¹åããããäžåºŠãã¬ãŒãã³ã°ãéå§
model = SimpleNotStupidModel(MASTER_CONFIG)
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
logits, loss = model(xs, ys)
optimizer = torch.optim.Adam(model.parameters())
train(model, optimizer)
# æå€±ãããªãæžå°ãã

æ¬¡ã«æšè«é¢æ°ãæ§ç¯ããŸãïŒ
ããŒã¿ãå ¥åããæºåã¯ããŠããŸããã®ã§ãåŠç¿çšãšããŠã5ã€ã®0ïŒèªåœè¡šã§ãããšæ¹è¡ç¬Š '\n'ïŒã䜿ã£ãŠæšè«ããŸããæ¹è¡ç¬Šãéå§ç¹ãšããŠããããã20æåãæšæž¬ããã«ãŒããè¡ããŸãã
# æšè«é¢æ°ïŒåºåçµæã®ç²ŸåºŠã«ã€ããŠã¯æ°ã«ããªãã§ãã ãããéã¿ã¯ä¿åãããŠããããã¢ãã«ã®åæåã«ãã£ãŠçæãããã©ã³ãã ãªæ°å€ã§æ§æãããè¡åã䜿ã£ãŠæšè«ããŠããŸãïŒ
def generate(model, config=MASTER_CONFIG, max_new_tokens=20):
# ã©ã³ãã ãªæ°å€ãçæããå
¥åããŒã¿ãšããŸãã5è¡1åã§ã5ã€ã®æåãå
¥åããããšã衚ããŸãããã®éšåã¯ä»ã®ã©ã³ãã ãªæ°å€ã«çœ®ãæããŠãã¹ãããããšãã§ããŸãã
idx = torch.zeros(5, 1).long()
print(idx[:, -config['context_window']:])
for _ in range(max_new_tokens):
# æšè«æã«ã¯ãåŸãã®nåã®ããŒã¯ã³ã«äŸåãããããã¹ã©ã€ãã£ã³ã°ãŠã£ã³ããŠãåŸãããéžã³ãå
¥åããŒã¿ã®æåŸã®ããŒã¯ã³æ°åãéžæããŸããã€ãŸããããŒã¯ã³æ°ãè¶
ããå Žåãå
¥åãã«ããããŠæåŸã®æ°åã®ããŒã¯ã³ã®ã¿ãéžæããŸãïŒidx[:, -config['context_window']:]
logits = model(idx[:, -config['context_window']:])
# print(logits.size())
# ã¢ãã«åºåã®çµæããã³ãŒãããŸããããã§ã®logits[:, -1, :]ã¯ããæœè±¡çã§ããå®éã«ã¯ãæåã®æ¬¡å
ã¯å
¥åã®æåæ°ã2çªç®ã®æ¬¡å
ã¯æéã¹ãããã3çªç®ã®æ¬¡å
ã¯èªåœã§ãã
# åã¹ãããã®ãã³ãŒãçµæã«å¯ŸããŠãæåŸã®æéã¹ãããã®ããŒã¿ãåºåãšããŠååŸããŸãããã³ãŒãã®éçšã¯ã1åç®ã¯5ã€ã®ããŒã¯ã³ãå
¥åãã2åç®ã¯å
ã®5ã€ã®ããŒã¯ã³ã®æåŸã®4ã€ãšååã®ãã³ãŒãçµæã§çæããã1ã€ã®ããŒã¯ã³ã䜿ããåã³5ã€ã®ããŒã¯ã³ã§ãã³ãŒãããŸãããã®ããã«ã«ãŒãããŠãããŸãã
last_time_step_logits = logits[:, -1, :]
# print('last_time_step_logits')
# print(last_time_step_logits.shape)
# 確çååžãèšç®
p = F.softmax(last_time_step_logits, dim=-1)
# print('p_shape')
# print(p.shape)
# 確çååžã«åºã¥ããŠæ¬¡ã®ããŒã¯ã³ãèšç®ããŸããããã§ã¯ torch.multinomial ã䜿çšããŠã©ã³ãã ãµã³ããªã³ã°ãè¡ããŸãã
idx_next = torch.multinomial(p, num_samples=1)
# print('idx_next_shape')
# print(idx_next.shape)
# æ°ããidxããã³ãœã«ã®çµåã§ãã³ãŒãã·ãŒã±ã³ã¹ã«è¿œå
idx = torch.cat([idx, idx_next], dim=-1)
# åã«å®çŸ©ãããã³ãŒã颿°ã䜿ã£ãŠIDãæåã«å€æãã5è¡21åã®ããŒã¿ãååŸããŸããåå
¥åæåããéå§ãã20åã®æåãçæããŸããå
¥åããã5ã€ã®æ°å€ããã¹ãŠ0ã§ãããèªåœå
ã§0çªç®ã«è©²åœããã®ã¯'\n'ã§ãã
print(idx.shape)
return [decode(x) for x in idx.tolist()]
generate(model)
åºåçµæã¯ãäºæ³éãæåŸ éããããªãæªãçµæã§ããã
['\n\u3000ããªã£ãŠæãŸããããã®å€ã®ã§ããããã',
'\n\u3000ãç§ã¯æããã女ã§ããç·ã®è¥åãã¡ã«èš',
'\nããšããŠãã§ããã¯ãçžã®å€§äºããéãªãå®',
'\nãç¶èŠªã®ããšãèªåã«ãªæäžæã§ããªããã§',
'\n\u3000äžã®å§ã®ããæããã©ã¯ãšãç©ã¯çŽäŒå®è
']
OKããããŸã§ã§ç°¡åãªSeq2seqã¢ãã«ã®æ§ç¯ã¯å®äºã§ããäžèšã®ã³ãŒããäžåºŠå®è¡ããŠã¿ãŠãçè§£ããªãããè¡ããšã«èªåã§åæããŠã¿ãŠãã ãããããåãããªãç®æãããã°ãshapeãåºåããŠããŒã¿ã®åœ¢ç¶ãã©ã®ããã«å€åããŠãããã確èªããŠãã ããã
ãããŸã§ã®å 容ããã£ããçè§£ã§ããããæ¬¡ã«é²ã¿ãŸããæ¬é¡ã«å ¥ããäžèšã®ã·ã³ãã«ãªã¢ãã«ãåºã«ããŠãLlaMaã®ãªãã¬ãŒã¿ãäžã€ãã€è¿œå ããŠãããŸãããªãã¬ãŒã¿ã远å ãããã³ã«ããã®å¹æã確èªããŠãããŸãããã
æ¬ç¯ã¹ã¿ãŒãïŒ
LlaMaã®ãªãã¬ãŒã¿ãå ã»ã©ã®ç°¡æã¢ãã«ã¢ãŒããã¯ãã£ã«è¿œå ããŸããäž»ã«ä»¥äžãå«ã¿ãŸãïŒ
- RMS_Norm
- RoPE
- SwiGLU
RMSNormã®æŠèŠ
æšæºåïŒnormïŒãšã¯ããã¬ãŒãã³ã°äžã«ãã³ãœã«ãæšæºåããæäœã§ãå¹³åå€ãšåæ£ãèšç®ããŠãµã³ãã«ãæ£èŠåããŸãã
ãã®èšç®ã«ãã£ãŠãããŒã¿ãå¹³åã0ã忣ã1ã®ããŒã¿ã«å€æããããŒã¿ãæšæºæ£èŠååžã«åŸãããã«ããŸãã
å¹³åãšåæ£ã䜿ã£ãŠããŒã¿ã®æšæºåå·®ãèšç®ãããšãããŒã¿ã®å€ãå€ãä¿æããªããç°åžžãªæ§é ãç¶æããããšã§ãåŸé ãå®å®ããåŸé æ¶å€±ãççºã®åé¡ã軜æžããŸãããŸããç°åžžãªæ§é ãç¶æããããšã§éåŠç¿ãæå¶ãããæ±åèœåãåäžããŸãã
RMSNormã®ç»å Ž
RMSNormãç»å Žããåã¯ããããããšã®æšæºåãè¡ããbatch normalizationããåºã䜿ãããŠããŸãããããã¯ããããå šäœããµã³ãã«ã®éå£ãšããŠãå¹³åãšåæ£ãèšç®ããŸãã
ãã®åŸãåããŒã¯ã³ã®ç¹åŸŽãã¯ãã«ãæ£èŠåãããlayer normalizationããç»å ŽããŸããïŒç¹åŸŽãã¯ãã«ã«ã€ããŠã¯ã以åã®èšäºã§RoPEã«ã€ããŠèª¬æããŠããŸããããŒã¯ã³ãšç¹åŸŽãã¯ãã«ã®é¢ä¿ãçè§£ã§ããã¯ãã§ãïŒãlayer normalizationã§ãå¹³åãšåæ£ãå¿ èŠã§ãã
RMSNormãšLayerNormã®éã
RMSNormãšlayer_normã®äž»ãªéãã¯ãRMSNormã§ã¯å¹³åãšåæ£ã®äž¡æ¹ãèšç®ããå¿ èŠããªããåæ¹æ ¹ïŒRMSïŒã ããèšç®ããã°ããç¹ã§ããRMSNormã¯ãlayer_normãšã»ãŒåãããã©ãŒãã³ã¹ãç¶æããªããã7%-64%ã®èšç®ã³ã¹ããç¯çŽã§ããŸãã
RMSNormã®èšç®åŒïŒ

RMSNormã®åäœåç
- RMSã®èšç®: å ¥åãããç¹åŸŽïŒäŸãã°ããã¥ãŒãã³ã®åºåïŒã«å¯ŸããŠããã®RMSïŒRoot Mean SquareïŒå€ããŸãèšç®ããŸãã
- æ£èŠå: åç¹åŸŽã®å€ããã®RMSå€ã§å²ããããŒã¿ã®ã¹ã±ãŒã«ã調æŽããŠãå¹³åã0ãæšæºåå·®ã1ã«ããŸãã
- ã¹ã±ãŒãªã³ã°ãšã·ãã: æ£èŠåã®åŸãRMSNormã§ã¯éåžžãåŠç¿å¯èœãªãã©ã¡ãŒã¿ïŒã¹ã±ãŒã«ä¿æ°ãšãã€ã¢ã¹ïŒãå°å ¥ãããŸããããã«ãããã¢ãã«ã¯ç¹å®ã®ã¿ã¹ã¯ã«é©ããç¹åŸŽè¡šçŸãåŠç¿ã§ããŸãã
RMSã®åºæ¬çãªèª¬æã¯ãã®èŸºãã§çµäºã§ããããã§ã¯ãRMSNormã¢ãžã¥ãŒã«ã®å®è£ ã«ç§»ããŸãããïŒ
class RMSNorm(nn.Module):
def __init__(self, layer_shape, eps=1e-8, bias=False):
super(RMSNorm, self).__init__()
# torchã®register_parameter()æ©èœã¯ãç§ãã¡ãäœæãããããã¯ãŒã¯ã¢ãžã¥ãŒã«ã«parameterã远å ããããã®ãã®ã§ãã
# ãã®ãããpytorchã®å
¬åŒã«çšæãããRMSNormæ©èœã¢ãžã¥ãŒã«ã«ãèšç·Žå¯èœãªãã©ã¡ãŒã¿ã®å±€ã远å ããå¿
èŠããããŸãããããscaleãšåœåãã圢ç¶ãlayer_shapeã«åæåãããã¹ãŠã®å€ã1ã«èšå®ãããã³ãœã«ãããªãã¯ã¹ãšããŸãã
self.register_parameter("scale", nn.Parameter(torch.ones(layer_shape)))
def forward(self, x):
# Frobeniusãã«ã ïŒè¡åã®ãã¹ãŠã®èŠçŽ ã®å¹³æ¹åã®å¹³æ¹æ ¹ãæ±ãããã«ã ã§ãè¡åã®å€§ãããæž¬ãããã«äœ¿çšããŸããè©³çŽ°ã¯æ€çŽ¢ããŠãã ããïŒãRMS = 1/sqrt(N) * Frobenius
# å
·äœçã«ã¯ãtorch.linalg.norm(x, dim=(1, 2))ã¯xã®ç¬¬1ããã³ç¬¬2次å
ã«ããããã«ã ãèšç®ããŸãããã®åŸãçµæã«x[0].numel() ** -.5ãæããŸããx[0].numel()ã¯xã®æåã®èŠçŽ ïŒã€ãŸãxã®æåã®è¡ïŒã®èŠçŽ æ°ã瀺ãã** -.5ã¯å¹³æ¹æ ¹ã®éæ°ã衚ããŸãã
ff_rms = torch.linalg.norm(x, dim=(1,2)) * x[0].numel() ** -.5
# print(ff_rms.shape)
# ff_rmsæŒç®åãå
¥åãã³ãœã«xã«é©çšããåŒã«åºã¥ããŠé€ç®ãè¡ããŸããå
¥åãã¯ãã«xã¯3次å
ãªã®ã§ãff_rmsã2次å
ã«æ¡åŒµããŠ3次å
ãã³ãœã«ã«ããŸããããã«ããèŠçŽ éã®èšç®ãå¯èœã«ãªããŸãã
raw = x / ff_rms.unsqueeze(-1).unsqueeze(-1)
# print(raw.shape)
# scaleã§ã¹ã±ãŒãªã³ã°ããæ£èŠåããããã³ãœã«ãè¿ããŸãã
# print(self.scale[:x.shape[1], :].unsqueeze(0) * raw)
return self.scale[:x.shape[1], :].unsqueeze(0) * raw
泚æãã¹ãç¹ãšããŠãraw = x / ff_rms.unsqueeze(-1).unsqueeze(-1)ã®èšç®ã¯ããã³ãœã«ãããªãã¯ã¹ã®åèŠçŽ ã«å¯ŸããŠè¡ãããŠããŸããããã§èšç®ãããã®ã¯ãã«ã ã§ãããããã¯å®éã«ã¯åãªãæ°å€ã§ããããªãã¯ã¹ã§ã¯ãããŸãããå
ã®å
¥åããŒã¿ã®ãã³ãœã«ãããªãã¯ã¹å
ã®åèŠçŽ ãããã®æ£èŠåããããã«ã ã§å²ã£ãŠããŸããRMSNormã¯pytorchã®å
¬åŒnn.Moduleãç¶æ¿ããŠãããããå°ãã ãä¿®æ£ãå ããŠããŸãã
ç¶ããŠããã®RMS_Normãªãã¬ãŒã¿ãäžèšã®ç°¡æã¢ãã«ã«è¿œå ããŸããã³ãŒãã«ã¯ããã®ãªãã¬ãŒã¿ãã©ã®ããã«çµã¿èŸŒãããæç¢ºã«èšèŒãããŠããŸãïŒ
class SimpleNotStupidModel_RMS(nn.Module):
def __init__(self, config=MASTER_CONFIG):
super().__init__()
self.config = config
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
# ããã§RMSå±€ã远å ããŸã
self.rms = RMSNorm((config['context_window'], config['d_model']))
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
nn.ReLU(),
nn.Linear(config['d_model'], config['vocab_size']),
)
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
def forward(self, idx, targets=None):
x = self.embedding(idx)
# ããã§ãRMSå±€ã®ã€ã³ã¹ã¿ã³ã¹ã远å ããEmbeddingå±€ã®åºåãã³ãœã«ãåãåããŸã
x = self.rms(x)
logits = self.linear(x)
# print(logits.shape)
if targets is not None:
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
else:
return logits
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
# ããŠãããã§å
ã®NotStupidModelã«RMSNormã远å ããŸããããã£ããå®è¡ããŠã¿ãŸããã
model = SimpleNotStupidModel_RMS(MASTER_CONFIG)
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
logits, loss = model(xs, ys)
optimizer = torch.optim.Adam(model.parameters())
train(model, optimizer)
# åãèšç·Žãã€ããŒãã©ã¡ãŒã¿èšå®ã§ãRMSNormã远å ãããšèšç·Žé床ãæããã«éããªããŸããã

ããã³ãŒããå®è¡ããå Žåãèšç®é床ãéããªã£ãããšãæãããããããŸããã
ã§ãããæ¥ããªãã§ãã ãããæ¬¡ã®2ã€ã®ãªãã¬ãŒã¿ã¯èšç®é床ãããã«é ãããã§ããã(ç¬)ã
å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ïŒRoPEïŒãã¢ãã«ã«è¿œå ã
RoPEã¯ããã«ã«ã座æšç³»ã§ã®èšç®ã極座æšç©ºéã«ç§»è¡ãããšããå·§åŠãªæ¹æ³ã§ãã
ãŸããå転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãèšç®ããããã®é¢æ°ãå®çŸ©ããŸãïŒ
def get_rotary_matrix(context_window, embedding_dim):
# 圢ç¶ãïŒcontext_window, embedding_dim, embedding_dimïŒã®ãŒãã§åãããããã³ãœã«ãããªãã¯ã¹ãåæåããŸããcontext_windowã¯ããŒã¯ã³æ°ã衚ããåŸãã®2ã€ã®embedding_dimã¯æ£æ¹è¡åãæ§æããåŸã§attentionèšç®ã®åœ¢åŒã«åãããŸãã
R = torch.zeros((context_window, embedding_dim, embedding_dim), requires_grad=False)
# åäœçœ®ã®ããŒã¯ã³ãç¹°ãè¿ãåŠçããŸã
for position in range(context_window):
# ç§ã®ååã®èšäºã§è¿°ã¹ãããã«ãç¹åŸŽéã¯2ã€ãã€çµã¿åãããå¿
èŠããããããã«ãŒãã®åæ°ã¯embedding_dimã2ã§å²ã£ãæ°ã«ãªããŸãã
for i in range(embedding_dim // 2):
# Ξå€ããµã³ããªã³ã°åšæ³¢æ°ããŸãã¯åè»¢åšæ³¢æ°ãå転è§åºŠãèšå®ããŸããembedding_dimã§å²ãããšã§åŸé
åé¡ãé²ããŸãã
theta = 10000. ** (-2. * (i - 1) / embedding_dim)
# ãªã€ã©ãŒã®å
¬åŒã«åºã¥ããŠå転è§åºŠãèšç®ããããããsinãšcosã䜿çšããŠãèšç®çµæãè€çŽ æ°ç©ºéã«åŒã蟌ã¿ãå転è§åºŠãäžèšã®ãŒãã§åãããããããªãã¯ã¹ã«é©çšããŸãã
m_theta = position * theta
R[position, 2 * i, 2 * i] = np.cos(m_theta)
R[position, 2 * i, 2 * i + 1] = -np.sin(m_theta)
R[position, 2 * i + 1, 2 * i] = np.sin(m_theta)
R[position, 2 * i + 1, 2 * i + 1] = np.cos(m_theta)
# åŸãããçµæã¯å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãããªãã¯ã¹ã§ããããã§ã¯ãŸã attentionã«ã¯é¢ãã£ãŠããŸããã
return R
å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ïŒRoPEïŒã¯æ³šææ©æ§ã®QãšKãçµã¿åãããŠèšç®ãããããããŸãåäžã®ããããæã€æ³šææ©æ§ã®ãªãã¬ãŒã¿ãå®è£ ããŸãïŒ
# ããã¯åäžã®ããããæã€æ³šææ©æ§ã§ã
class RoPEMaskedAttentionHead(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
# Qéã¿è¡åãèšç®
self.w_q = nn.Linear(config['d_model'], config['d_model'], bias=False)
# Kéã¿è¡åãèšç®
self.w_k = nn.Linear(config['d_model'], config['d_model'], bias=False)
# Véã¿è¡åãèšç®
self.w_v = nn.Linear(config['d_model'], config['d_model'], bias=False)
# å転äœçœ®ãšã³ã³ãŒãã£ã³ã°è¡åãååŸããæ¬¡ã«QãšKã®éã¿è¡åãäžæžãããŸã
self.R = get_rotary_matrix(config['context_window'], config['d_model'])
# ããã§ãåã®ã³ãŒããããã¯ã§å®è£
ãããå転äœçœ®ãšã³ã³ãŒãã£ã³ã°ã®äœææ©èœããã®ãŸãŸäœ¿çšããŸã
def get_rotary_matrix(context_window, embedding_dim):
# 圢ç¶ãïŒcontext_window, embedding_dim, embedding_dimïŒã®ãŒãã§åãããããã³ãœã«ãããªãã¯ã¹ãåæåããŸããcontext_windowã¯ããŒã¯ã³æ°ã衚ããåŸãã®2ã€ã®embedding_dimã¯æ£æ¹è¡åãæ§æããåŸã§attentionèšç®ã®åœ¢åŒã«åãããŸãã
R = torch.zeros((context_window, embedding_dim, embedding_dim), requires_grad=False)
# åäœçœ®ã®ããŒã¯ã³ãç¹°ãè¿ãåŠçããŸã
for position in range(context_window):
# ç§ã®ååã®èšäºã§è¿°ã¹ãããã«ãç¹åŸŽéã¯2ã€ãã€çµã¿åãããå¿
èŠããããããã«ãŒãã®åæ°ã¯embedding_dimã2ã§å²ã£ãæ°ã«ãªããŸãã
for i in range(embedding_dim // 2):
# Ξå€ããµã³ããªã³ã°åšæ³¢æ°ããŸãã¯åè»¢åšæ³¢æ°ãå転è§åºŠãèšå®ããŸããembedding_dimã§å²ãããšã§åŸé
åé¡ãé²ããŸãã
theta = 10000. ** (-2. * (i - 1) / embedding_dim)
# ãªã€ã©ãŒã®å
¬åŒã«åºã¥ããŠå転è§åºŠãèšç®ããããããsinãšcosã䜿çšããŠãèšç®çµæãè€çŽ æ°ç©ºéã«åŒã蟌ã¿ãå転è§åºŠãäžèšã®ãŒãã§åãããããããªãã¯ã¹ã«é©çšããŸãã
m_theta = position * theta
R[position, 2 * i, 2 * i] = np.cos(m_theta)
R[position, 2 * i, 2 * i + 1] = -np.sin(m_theta)
R[position, 2 * i + 1, 2 * i] = np.sin(m_theta)
R[position, 2 * i + 1, 2 * i + 1] = np.cos(m_theta)
# åŸãããçµæã¯å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãããªãã¯ã¹ã§ããããã§ã¯ãŸã attentionã«ã¯é¢ãã£ãŠããŸããã
return R
def forward(self, x, return_attn_weights=False):
# åæ¹äŒææãå
¥åãããªãã¯ã¹ã®åœ¢ç¶ã¯(batch, sequence length, dimension)ã§ãã
b, m, d = x.shape # ããããµã€ãºãã·ãŒã±ã³ã¹é·ã次å
# Q, K, Vã®ç·åœ¢å€æãè¡ããŸã
q = self.w_q(x)
k = self.w_k(x)
v = self.w_v(x)
# å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãQãšKã«é©çšããŸããããã§torch.bmmã¯è¡åã®å€ç©ãè¡ããtransposeã¯è»¢çœ®ãè¡ããŸããQè¡åã転眮ããå転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãšå€ç©ãåããå
ã«æ»ããŸããããã«ãããQã«å転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãé©çšãããŸãã
# å
¥åããã¹ãã®é·ããèæ
®ããŠãäœçœ®ãšã³ã³ãŒãã£ã³ã°è¡åã®ç¬¬1次å
ãåãæšãŠãŸããé·ãããŠãæå³ããªããããããã¹ãé·ãšåãã«ããŸãã
q_rotated = (torch.bmm(q.transpose(0, 1), self.R[:m])).transpose(0, 1)
# åæ§ã«Kã«ãå転äœçœ®ãšã³ã³ãŒãã£ã³ã°ãé©çšããŠäžæžãããŸã
k_rotated = (torch.bmm(k.transpose(0, 1), self.R[:m])).transpose(0, 1)
# æ³šææ©æ§ã®å
ç©ã«å¯ŸããŠã¹ã±ãŒãªã³ã°ãè¡ããattentionãã³ãœã«ãé·ããªããããŠåŸé
ççºãèµ·ããã®ãé²ããŸã
activations = F.scaled_dot_product_attention(
q_rotated, k_rotated, v, dropout_p=0.1, is_causal=True
)
# return_attn_weightsã1ã«èšå®ãããŠããå Žåãattentionã«ãã¹ã¯ãé©çšããŸããããã¯ãã¢ãã«ãåã®nåã®ããŒã¯ã³ã«åºã¥ããŠæ¬¡ã®ããŒã¯ã³ãäºæž¬ããããã«åŠç¿ãããããã§ãã«ã³ãã³ã°ã®ãããªããšãé¿ããŸãã
if return_attn_weights:
# 泚æãã¹ã¯è¡åãäœæããŸããtorch.tril颿°ã¯ãè¡åã«å¯ŸããŠå·Šäžäžè§éšåãååŸãããã以å€ã®éšåã0ã«ããŸãã
attn_mask = torch.tril(torch.ones((m, m)), diagonal=0)
# æ³šææ©æ§ã®éã¿è¡åãèšç®ããæåŸã®æ¬¡å
ã«æ²¿ã£ãŠæ£èŠåããŸããïŒçªæãã§ãã¯ïŒãªãæåŸã®æ¬¡å
ãªã®ãïŒããã¯æåŸã®æ¬¡å
ãåããŒã¯ã³ã®ç¹åŸŽãã¯ãã«ã衚ããŠããããã§ãïŒ
attn_weights = torch.bmm(q_rotated, k_rotated.transpose(1, 2)) / np.sqrt(d) + attn_mask
attn_weights = F.softmax(attn_weights, dim=-1)
return activations, attn_weights
return activations
åäžã®æ³šææ©æ§ã®ããããå®è£ å®äºããã®ã§ã次ã«ãã«ããããæ³šææ©æ§ãå®è£ ããŸã
# åäžã®æ³šææ©æ§ã®ããããå®è£
å®äºããã®ã§ã次ã«ãã«ããããæ³šææ©æ§ãå®è£
ããŸã
class RoPEMaskedMultiheadAttention(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
# æ³šææ©æ§ã®ããããªããžã§ã¯ãã1ã€äœæããã®ã§ã次ã«ãã«ãããããå®è£
ããŸããè€æ°ã®æ³šææ©æ§ã®ããããäœæãããªã¹ãã«å
¥ããŸãã
self.heads = nn.ModuleList([
RoPEMaskedAttentionHead(config) for _ in range(config['n_heads'])
])
# ã¢ãã«æ§é äžãç·åœ¢å±€ïŒé ãå±€ïŒãäœæããæ³šææ©æ§ã®ãããã®åºåãã³ãœã«ãããªãã¯ã¹ãç·åœ¢åºåããŸããããã¯ããã«ããããéã®ç¹åŸŽãæ¢ãããã§ãããäž»ã«xããã«ããããèšç®ãçµãŠåœ¢ç¶ãå€ããããããã³ãœã«ãããªãã¯ã¹ãå
ã®åœ¢ç¶ã«æ»ãããã«äœæãããŸãã
# åæã«ãéåŠç¿ãé²ãããã«ãããããã¢ãŠãïŒ0.1ã®å²åã§ã©ã³ãã ã«ãã¥ãŒãã³ãç¡å¹åïŒã䜿çšããŸãã
# ç·åœ¢å±€ã®å
¥å圢ç¶ã¯ãæ³šææ©æ§ã®ãããæ°ã«ãããªãã¯ã¹ã®æ¬¡å
æ°ãæãããã®ã§ãç§ã®ååã®èšäºã§è¿°ã¹ãããã«ãkeyãããªãã¯ã¹ã¯ãã«ããããéã§éã¿ãå
±æããèšç®éãåæžããŸããåºåã¯ã¢ãã«ã®åãèŸŒã¿æ¬¡å
æ°ã«ãªããŸãã
self.linear = nn.Linear(config['n_heads'] * config['d_model'], config['d_model'])
self.dropout = nn.Dropout(0.1)
def forward(self, x):
# å
¥åãããªãã¯ã¹ã®åœ¢ç¶x: (batch, sequence length, dimension)
# 忳𿿩æ§ã®ãããã«xãæž¡ããŠèšç®ããŸããïŒããã䞊åå®è¡ãããšéããªããããããŸããããpytorchãèªåã§äžŠåå®è¡ãããã¯äžæã§ãïŒ
heads = [h(x) for h in self.heads]
# å
¥åãã³ãœã«xã¯è€æ°ã®ãããã§attentionèšç®ãè¡ãïŒåæã«attentionã«ã¯RoPEãé©çšãããŠããŸãïŒãæ°ãããããªãã¯ã¹ãšããŠå床çµåãã倿°xã«æ»ããŸãããã®æç¹ã§ããããªãã¯ã¹ã®åœ¢ç¶ãå€ãã£ãããšã«æ°ã¥ãã¯ãã§ãã
x = torch.cat(heads, dim=-1)
# ããã§ç·åœ¢å±€ã®åºçªã§ã
x = self.linear(x)
# ããããã¢ãŠãã§ã©ã³ãã ã«ãã¥ãŒãã³ãç¡å¹åããéåŠç¿ãé²ããŸã
x = self.dropout(x)
return x
ããã§äžèšã®æ©èœãå®è£ ã§ããŸããã®ã§ãconfigã®ãã€ããŒãã©ã¡ãŒã¿ãæŽæ°ããŠæ³šææ©æ§ã®ãããæ°ãèšå®ããŸããããLlaMaã§ã¯32åã®æ³šææ©æ§ãããããããŸãããä»åã¯8åã«èšå®ããŸãïŒ
# Llamaã«ã¯32åã®æ³šææ©æ§ãããããããŸãããããã§ã¯8åã«ããŠã¿ãŸããã
MASTER_CONFIG.update({
'n_heads': 8,
})
次ã«ã以åã«RMS_Normã远å ããã¢ãã«ãæŽæ°ããŸããä»åã¯ããã«å ããŠãROPEäœçœ®ãšã³ã³ãŒãã£ã³ã°ãçµã¿èŸŒãã ãã«ããããæ³šææ©æ§ã远å ããŸãïŒ
# å¿
èŠãªãªãã¬ãŒã¿ããã¹ãŠäœæããŸãããç©ã¿æšã¯å®æããŸããã®ã§ãããããçµã¿åãããŠãããŸãããïŒïŒïŒ
class RopeModel(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
# Embeddingå±€
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
# RMSNormå±€
self.rms = RMSNorm((config['context_window'], config['d_model']))
# å転äœçœ®ãšã³ã³ãŒã + æ³šææ©æ§
self.rope_attention = RoPEMaskedMultiheadAttention(config)
# ç·åœ¢å±€ + 掻æ§å颿°ã§éç·åœ¢åºåã«å€æïŒ
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
nn.ReLU(),
)
# æçµåºåããã³ãŒããå¿
èŠã§ãåºåã®æ¬¡å
ãèªåœãµã€ãºãšäžèŽããå¿
èŠããããŸãïŒïŒïŒ
self.last_linear = nn.Linear(config['d_model'], config['vocab_size'])
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
# ååãäŒæ
def forward(self, idx, targets=None):
# Embedding
x = self.embedding(idx)
# æ£èŠå
x = self.rms(x)
# è¶³ãç®ãattentionã¯å
ã®ãããªãã¯ã¹ã«é©çšãããããã圢ç¶ãåã2ã€ã®ãããªãã¯ã¹ããããšèããŠãã ãããå·Šæã«1æã®çŽã峿ã«ãã1æã®çŽããããäž¡æãåãããŠãããïŒããšéããŸããå ç®ã䜿ãããšã§ã2ã€ã®ãããªãã¯ã¹ã®èŠçŽ ãäœçœ®ããšã«å ç®ãããå€ãäžæžããããŸãïŒ
x = x + self.rope_attention(x)
# å床æ£èŠåïŒ
x = self.rms(x)
# çŽæ¥æ£èŠåãããå€ãèšç®ãããšåŸé
åé¡ãçºçããå¯èœæ§ããããããæ£èŠåãããå€ãè£æ£ä¿æ°ãšããŠååºŠäžæžãããŸãïŒ
x = x + self.linear(x)
# ããã§ããããæçµçã«vocabæ°ã®ãã¥ãŒãã³åºåãåŸãããŸãïŒïŒïŒïŒïŒïŒ
logits = self.last_linear(x)
# èšç·Žæ®µéã§ã¯ã¿ãŒã²ããå€ãããå Žå
if targets is not None:
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
# æ€èšŒãæšè«æ®µéã§ã¯ãã¿ãŒã²ããå€ïŒyïŒããªããããçµæã ããåŸãããlossã¯èšç®ãããŸããïŒ
else:
return logits
# å床å®è¡ããŠã¿ãŸãããïŒ
model = RopeModel(MASTER_CONFIG)
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
logits, loss = model(xs, ys)
optimizer = torch.optim.Adam(model.parameters())
train(model, optimizer)

ãããšãå®éã«ã¯attentionã®ãã¹ã¯ãèšå®ãããŠããªãç¶æ ã§ããæ©èœã¯å®è£ ãããŠããŸãããåŒã³åºãããŠããããããŒã«å€ã¯falseã«èšå®ãããŠããŸãã
SwiGLUã®å®è£
swishãšgluãçµã¿åãããŸãããããã®æŽ»æ§å颿°ã¯ããããåç¬ã§ãéåžžã«åŒ·åã§ãããçµã¿åãããããšã§ããã«å¹æãçºæ®ãããŸãã
ãã®çµã¿åããã¯å°ãç¥ç§çãªãšããããããŸããè¯ããªããšèšã人ãããŸããã確ãã«SwiGLUã¯ReLUãããå€ãã®æå³çç¹åŸŽãä¿æããReLUã®ããã«çªç¶å°ããªå€ã«ãªãããšã§éèŠãªç¹åŸŽãæ¶ããŠããŸãããšãå°ãªãã§ãããã ããèšç®éãããªã倧ããã®ãäºå®ã§ãã
swishã¯sigmoidã䜿ããGLUã¯ã²ãŒãæ§é ã䜿ããŸãïŒã²ãŒãæ§é ã®ã¢ã€ãã¢ã¯ãRNN, GRU, LSTMãªã©ãåŠã¶ãšããçè§£ã§ããã§ãããïŒã
class SwiGLU(nn.Module):
def __init__(self, size):
super().__init__()
# ã²ãŒãä»ãç·åœ¢å±€ãå®çŸ©ããå
¥åãšåºåã¯ã©ã¡ããã²ãŒãæ§é ã®ãµã€ãºã§ã
self.linear_gate = nn.Linear(size, size)
# ã²ãŒãæ§é ã®ã¡ã€ã³ã®ç·åœ¢å±€
self.linear = nn.Linear(size, size)
# ã©ã³ãã ãªæ°å€ãããŒã¿ä¿æ°ãšããŠåæå
self.beta = torch.randn(1, requires_grad=True)
# nn.Parameterã¯ãããå±€ã®ãã©ã¡ãŒã¿ãåŠç¿å¯èœã«ããããã«äœ¿çšãããŸããæ¬æ¥ã¯èšç·Žã«ãã£ãŠå€æŽãããªããã©ã¡ãŒã¿ããèšç·ŽãéããŠæŽæ°ã§ããããã«ããŸãã
self.beta = nn.Parameter(torch.ones(1))
# ã©ã³ãã ãªæ°å€betaããbetaããšããååã®ãã¥ãŒã©ã«ãããã¯ãŒã¯å±€ã«æå®ããŸã
self.register_parameter("beta", self.beta)
def forward(self, x):
# Swishã²ãŒãã®èšç®ïŒïŒæ¬åŒ§å
ããèšç®ãå§ããŸãïŒå
ã®å
¥åããŒã¿ãã³ãœã«ã¯ç·åœ¢å€æãããããŒã¿ä¿æ°ãæããããæ¬¡ã«sigmoid倿ã«ãã£ãŠ0ãã1ã®å€ã«å€æãããŸãããã®åŸãå
ã®ããŒã¿ãã²ãŒãä»ãç·åœ¢å€æãéããæçµçã«äž¡è
ãæãåããããŸããã€ãŸããç·åœ¢åºåãéç·åœ¢å€æããããã®çµæãç·åœ¢å€æã®åºåã«é©çšãããŸãããã®ããã»ã¹ã§ã¯ãèŠçŽ ããšã«äœçœ®ãåãããŠæãåãããå
ã®ããŒã¿ãã³ãœã«ãä¿®æ£ããã®ãã²ãŒãæ§é ã®åœ¹å²ã§ãã
swish_gate = self.linear_gate(x) * torch.sigmoid(self.beta * self.linear_gate(x))
# ã²ãŒãæ§é ã®åºåãç·åœ¢åºåã®å
ããŒã¿ãã³ãœã«ã«å床æãåãããŸã
# ãªãããããã®ãã¯åãããŸããããè«æã®åçŸã³ãŒãã§ã¯ãã®ããã«å®è£
ãããŠããŸããèå³ãããã°èª¿ã¹ãŠã¿ãŠãã ããã
out = swish_gate * self.linear(x)
return out
å ã»ã©å®çŸ©ããSwiGLUãªãã¬ãŒã¿ãã¢ãã«ã«è¿œå ããŸãããã®ã¢ãã«ã«ã¯ããã§ã«RMS RopeAttentionã远å ããŠããŸãã
# SwiGLUãäžèšã®ã¢ãã«ã«è¿œå ããŸã
class RopeModel(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
self.embedding = nn.Embedding(config['vocab_size'], config['d_model'])
self.rms = RMSNorm((config['context_window'], config['d_model']))
self.rope_attention = RoPEMaskedMultiheadAttention(config)
self.linear = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
# ããã§ãSwiGLUå±€ã远å ããŸãã
SwiGLU(config['d_model']),
)
self.last_linear = nn.Linear(config['d_model'], config['vocab_size'])
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
def forward(self, idx, targets=None):
x = self.embedding(idx)
x = self.rms(x)
x = x + self.rope_attention(x)
x = self.rms(x)
x = x + self.linear(x)
logits = self.last_linear(x)
if targets is not None:
# ã¿ãŒã²ãããæäŸãããŠããå Žåãã¯ãã¹ãšã³ããããŒæå€±ãèšç®ããŸã
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
else:
return logits
model = RopeModel(MASTER_CONFIG)
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
logits, loss = model(xs, ys)
optimizer = torch.optim.Adam(model.parameters())
train(model, optimizer)

ãããŸã§ã§ã远å ã§ãããªãã¬ãŒã¿ã¯ãã¹ãŠè¿œå ããŸãããããããããã¯Llamaã®1ã€ã®æ©èœãããã¯ã«éããŸãããLlamaã¯è€æ°ã®æ©èœãããã¯ãç©ã¿éããŠæ§æãããŠããŸãã
äžèšã§LlaMaã«å¿ èŠãªãªãã¬ãŒã¿ãå®è£ ããŸããã®ã§ã次ã«ããããçµã¿åãããŠLlaMaã®æ©èœãããã¯ãäœæãããã®æ©èœãããã¯ãç©ã¿éããŠLlaMaãæ§ç¯ããŸãïŒ
ãŸããæ©èœãããã¯ã®ç©ã¿éããå±€æ°ãèšå®ããŸãïŒ
# OKïŒ ã§ã¯ãé ãå±€ã®æ¬¡å
ãæŽæ°ããŠãäœå±€ç©ã¿éãããæ±ºããŸãããããŸãã¯4å±€ã§è©ŠããŠã¿ãŸãïŒïŒ
MASTER_CONFIG.update({
'n_layers': 4,
})
次ã«ãLlaMaã®æ©èœãããã¯ãäœæããŸããå®éã«ã¯ãRMSãAttentionRoPEãSwiGLU掻æ§å颿°ãçµ±åããç°¡æã¢ãã«ã䜿çšããŸãïŒ
# ããã§ããã¹ãŠã®ãªãã¬ãŒã¿ïŒRMS, ROPE, SWIGLUïŒãæããŸããã®ã§ãLlaMaãæ§ç¯ããŸãïŒ ãŸããLlaMaã®åºæ¬ãããã¯ãå®è£
ãããããç©ã¿éããŸãã
# æ©èœã«ã€ããŠã¯ç¹ã«èª¬æããããšã¯ãããŸããããããŸã§ãã£ããçè§£ã§ããæ¹ãªãã以äžã®ã³ãŒãã¯é£ãããªãã¯ãã§ãã
class LlamaBlock(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
self.rms = RMSNorm((config['context_window'], config['d_model']))
self.attention = RoPEMaskedMultiheadAttention(config)
self.feedforward = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
SwiGLU(config['d_model']),
)
def forward(self, x):
x = self.rms(x)
x = x + self.attention(x)
x = self.rms(x)
x = x + self.feedforward(x)
return x
äœæããæ©èœãããã¯ã«åé¡ããªãããã¹ãããŠã¿ãŸãããïŒ
# configèŸæžã䜿ã£ãŠãLlamaã®åºæ¬ãããã¯ãäœæ
block = LlamaBlock(MASTER_CONFIG)
# ã©ã³ãã ãªããŒã¿ãçæãããã®Llamaãããã¯ã«æå
¥ããŠãã°ããªãã確èª
random_input = torch.randn(MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'], MASTER_CONFIG['d_model'])
# å®è¡ããŠåºåã確èª
output = block(random_input)
output.shape
çµã¿ç«ãŠ!!
# ã§ã¯ãLlaMaãçµã¿ç«ãŠãŸã
from collections import OrderedDict
class Llama(nn.Module):
def __init__(self, config):
super().__init__()
self.config = config
# Embeddingã¯èª¬æäžèŠ
self.embeddings = nn.Embedding(config['vocab_size'], config['d_model'])
# æå®ãããå±€æ°ã«åºã¥ããŠLlamaã®ãããã¯ãäœæããŸããOrderedDictã¯ç¹æ®ãªèŸæžåã§ãããŒã¿ã®æ¿å
¥é åºãä¿æãããŸããå
ã«æ¿å
¥ãããããŒã¿ãåã«ãåŸã«æ¿å
¥ãããããŒã¿ãåŸã«ãªããŸãã
# ããã§ã¯Llamaã®ãããã¯ã4å±€ç©ã¿éããŸã
self.llama_blocks = nn.Sequential(
OrderedDict([(f"llama_{i}", LlamaBlock(config)) for i in range(config['n_layers'])])
)
# FFNå±€ã«ã¯ãç·åœ¢å±€ã掻æ§å颿°ã§éç·åœ¢å€æãè¡ããå床ç·åœ¢å±€ã§æçµçãªãã³ãŒãå€ãåºåããŸãã
self.ffn = nn.Sequential(
nn.Linear(config['d_model'], config['d_model']),
SwiGLU(config['d_model']),
nn.Linear(config['d_model'], config['vocab_size']),
)
# 倧ããªã¢ãã«ã®ãã©ã¡ãŒã¿æ°ã確èªããŸãïŒ
print("ã¢ãã«ã®ãã©ã¡ãŒã¿æ°:", sum([m.numel() for m in self.parameters()]))
def forward(self, idx, targets=None):
# embeddingã«å€æ
x = self.embeddings(idx)
# Llamaã¢ãã«ã®èšç®
x = self.llama_blocks(x)
# FFNã®èšç®ãè¡ããlogitsãååŸ
logits = self.ffn(x)
# æšè«æ®µéã§ã¯ã¿ãŒã²ããå€ããªããçµæã®ã¿ãåºå
if targets is None:
return logits
# èšç·Žæ®µéã§ã¯ã¿ãŒã²ããå€ããããçµæãšlossãåºåããŠéäŒæã§éã¿ãæŽæ°
else:
loss = F.cross_entropy(logits.view(-1, self.config['vocab_size']), targets.view(-1))
return logits, loss
# Llamaã®ãã¬ãŒãã³ã°ãéå§ããŸã
llama = Llama(MASTER_CONFIG)
xs, ys = get_batches(dataset, 'train', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
logits, loss = llama(xs, ys)
optimizer = torch.optim.Adam(llama.parameters())
train(llama, optimizer)

ãã¹ãã»ãããå®è¡
# ãããããã¹ãã»ãããå®è¡ããŠã¿ãŸããã
# ãã¹ãã»ããã®ç¹åŸŽéãšã¿ãŒã²ããå€ãååŸ
xs, ys = get_batches(dataset, 'test', MASTER_CONFIG['batch_size'], MASTER_CONFIG['context_window'])
# Llamaã«æå
¥ããŠæå€±ãååŸ
logits, loss = llama(xs, ys)
print(loss)
# 5.0037ïŒ
æé©å!!
# æé©åãããã€ã³ãã¯ãŸã ãããŸãããoptimizerãåŠç¿çã¹ã±ãžã¥ãŒã©ãå¿ããªãã§ïŒ
# ãã©ã¡ãŒã¿ã調æŽããŠå床å®è¡ããŸãããïŒ
MASTER_CONFIG.update({
"epochs": 1000
})
# åŠç¿çæé©åã¯ã³ãµã€ã³ã¢ããŒãªã³ã°ãéžæ
llama_with_cosine = Llama(MASTER_CONFIG)
llama_optimizer = torch.optim.Adam(
llama.parameters(),
betas=(.9, .95),
weight_decay=.1,
eps=1e-9,
lr=1e-3
)
# ã³ãµã€ã³ã¢ããŒãªã³ã°åŠç¿çã¹ã±ãžã¥ãŒã©ã䜿ããåŠç¿çãåŸã
ã«æžå°ãããæåŸã«ã¯æå°å€ã«å°éããŸããè©³çŽ°ã¯æ€çŽ¢ããã°ããããã®èšäºãèŠã€ãããŸãã
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(llama_optimizer, 300, eta_min=1e-5)
# å®è¡ïŒ
train(llama_with_cosine, llama_optimizer, scheduler=scheduler)

ããã§ãšãããããŸãïŒãããŸã§é²ãã ããªãã¯ãã€ãã«èªåã ãã®AIã¢ãã«ïŒäœ¿ããªããã©ïŒãäœãäžããŸããïŒ
ããã§ãããåºæ¬çã«ã¯ããã§å®æã§ããäž»ãªéšåãã§ããã°ãããšã¯æŠç¥éšåãä»ã®ãªãã¬ãŒã¿ã远å ããã ãã§ãæ§é ããå®ãã°äœã§ãå¯èœã§ããæ³šç®ãã¹ãã¯ãå ¥åãšåºåã§ãããããªãã¯ã¹ã®èšç®ã«ã¯æ°åŠã®ç¥èãå¿ èŠã§ãèŠçŽ ããšã®èšç®ãªã®ãããããšããã¯ãã«ããããªãã¯ã¹å šäœã®èšç®ãªã®ããåºå¥ããå¿ èŠããããŸãã
ãããŸã§èªãã§ãäžèšã®å 容ãã»ãŒçè§£ã§ããã®ã§ããã°ã次ã«ç޹ä»ãã**llama3ã®å ¬åŒã¢ãã«ã³ãŒãïŒmodel.pyïŒ**ã容æã«ææ¡ã§ãããšæããŸããMetaããŒã ã®ã³ãŒãã¯æ¬åœã«å šäžçã®äººãçè§£ã§ããããã«äœãããŠããããã®æŽç¶ãšããæ§é ãšåŒ·åãªèª¬ææ§ã«ã¯æåããŸããå€§èŠæš¡ã¢ãã«ãåŠç¿ããã®ã«æé©ãªã³ãŒãã§ãã
ããŸããŸãªåæ§ãåãå ¥ããŠææ©çã«ã€ãªã瀟å ç°å¢ãæŽãããããããäºæ¥æ©äŒã®åµåºãšå®çŸãç¹°ãè¿ããäžã®äžã«å¯ŸããèŠç¹ãçµ¶ããå¢ãããŠæé·ããŠããããã£ãšé©ããããªè§åºŠããçºå±ã§ãããã€ã³ããèŠã€ããããã«ããæãã«ãã£ãããã圢ã§ãã¯ãããžãŒãçµã¿èŸŒãã§ãäžã®äžãã¡ãã£ãšãã€ãæã«ã¯å€§èã«ã¢ããããŒããã€ã¥ããŠããã
Discussion