Download modeling_tinyllm.py from sciencemj/tinyllm-29m-chat: direct link, hf CLI and curl.
- Browser
- Download file 4.36 kB
-
https://huggingface.co/sciencemj/tinyllm-29m-chat/resolve/main/modeling_tinyllm.py
- Command line
-
hf download hf://sciencemj/tinyllm-29m-chat/modeling_tinyllm.py
-
curl -L -o modeling_tinyllm.py https://huggingface.co/sciencemj/tinyllm-29m-chat/resolve/main/modeling_tinyllm.py
4.36 kB
| """๋ฐฐํฌ์ฉ ๋ ๋ฆฝ ๋ชจ๋ธ ์ ์. | |
| ์ด ํ์ผ ํ๋์ `config.json`, `model.safetensors`, `tokenizer.json` ๋ง ์์ผ๋ฉด | |
| ๊ฐ์ค์น๋ฅผ ์ด ์ ์๋ค. ํ์ต ํ๋ค์ค(deeptool)๋ ํ์ ์๋ค -- ๊ฐ์ค์น ํ๋ ์ด์๊ณ | |
| ํ์ต์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๊ฒ ๋ง๋ค ์ด์ ๊ฐ ์๋ค. | |
| `src/tinyllm/model.py` ์ TinyLM ๊ณผ ๋ชจ๋ ์ด๋ฆ์ด ๊ฐ์์ผ state_dict ํค๊ฐ ๋ง๋๋ค. | |
| ๊ทธ ๋์ผ์ฑ์ tests/test_modeling.py ๊ฐ ์ค์ ์ฒดํฌํฌ์ธํธ๋ก ๊ฒ์ฆํ๋ค. | |
| from modeling_tinyllm import TinyLM | |
| model = TinyLM.from_pretrained(".") | |
| """ | |
| import json | |
| from pathlib import Path | |
| import torch | |
| from torch import nn | |
| class TinyLM(nn.Module): | |
| """GPT-2 ํํ์ decoder-only LM, torch ๋ด์ฅ ๋ ์ด์ด๋ก ์กฐ๋ฆฝ. | |
| decoder-only ๋ฅผ `TransformerEncoderLayer` ๋ก ๋ง๋๋ ์ด์ ๋ | |
| `TransformerDecoderLayer` ๊ฐ cross-attention ์ฉ `memory` ๋ฅผ ํ์๋ก ์๊ตฌํ๊ธฐ | |
| ๋๋ฌธ์ด๋ค. causal mask ๋ฅผ ๋๊ธฐ๋ฉด encoder layer ๊ฐ ๊ณง GPT ๋ธ๋ก์ด๋ค. | |
| """ | |
| def __init__(self, vocab_size=8000, d_model=512, n_head=8, n_layer=8, | |
| d_ff=2048, block_size=512, dropout=0.0): | |
| super().__init__() | |
| self.vocab_size = vocab_size | |
| self.block_size = block_size | |
| self.tok = nn.Embedding(vocab_size, d_model) | |
| self.pos = nn.Embedding(block_size, d_model) | |
| self.drop = nn.Dropout(dropout) | |
| layer = nn.TransformerEncoderLayer( | |
| d_model, n_head, d_ff, dropout, | |
| activation="gelu", norm_first=True, batch_first=True, | |
| ) | |
| self.blocks = nn.TransformerEncoder( | |
| layer, n_layer, norm=nn.RMSNorm(d_model), enable_nested_tensor=False, | |
| ) | |
| self.head = nn.Linear(d_model, vocab_size, bias=False) | |
| self.head.weight = self.tok.weight # weight tying | |
| def forward(self, ids): | |
| """ids: (B, T) int64 -> logits (B, T, vocab_size)""" | |
| T = ids.size(1) | |
| pos = torch.arange(T, device=ids.device) | |
| h = self.drop(self.tok(ids) + self.pos(pos)) | |
| mask = nn.Transformer.generate_square_subsequent_mask(T, device=ids.device) | |
| return self.head(self.blocks(h, mask=mask, is_causal=True)) | |
| def generate(self, ids, max_new_tokens, temperature=0.8, top_k=40, | |
| stop_id=None): | |
| """ids: (B, T) ํ๋กฌํํธ -> (B, T + n). stop_id ๊ฐ ์ ๋ฐฐ์น์ ๋์ค๋ฉด ์กฐ๊ธฐ ์ข ๋ฃ. | |
| KV ์บ์๋ ์ฐ์ง ์๋๋ค. 29M ยท 512 ํ ํฐ์ด๋ฉด forward ๊ฐ ์ ms ๋ผ ์บ์๊ฐ ์์ด๋ | |
| 100 ํ ํฐ ์์ฑ์ด 1 ์ด ๋ฏธ๋ง์ด๋ค. | |
| """ | |
| was_training = self.training | |
| self.eval() | |
| for _ in range(max_new_tokens): | |
| window = ids[:, -self.block_size:] | |
| logits = self(window)[:, -1] / temperature | |
| if top_k: | |
| kth = logits.topk(min(top_k, logits.size(-1)), dim=-1).values[:, -1:] | |
| logits = logits.masked_fill(logits < kth, float("-inf")) | |
| nxt = torch.multinomial(logits.softmax(-1), num_samples=1) | |
| ids = torch.cat([ids, nxt], dim=1) | |
| if stop_id is not None and bool((nxt == stop_id).all()): | |
| break | |
| self.train(was_training) | |
| return ids | |
| def from_pretrained(cls, path, device="cpu"): | |
| """`config.json` ๊ณผ `model.safetensors` ๊ฐ ์๋ ํด๋์์ ๋ชจ๋ธ์ ์ธ์ด๋ค. | |
| ์ ์ฅ๋ณธ์๋ `head.weight` ๊ฐ ์๋ค. tying ๋๋ฌธ์ `tok.weight` ์ ์ ์ฅ์๋ฅผ | |
| ๊ณต์ ํ๋๋ฐ safetensors ๋ ๊ณต์ ์ ์ฅ์๋ฅผ ๊ฑฐ๋ถํ๊ธฐ ๋๋ฌธ์ด๋ค. ์์ฑ์๊ฐ ๋ค์ | |
| ๋ฌถ์ผ๋ฏ๋ก `strict=False` ๋ก ๋ฃ์ด๋ head ๊ฐ ๋น์ง ์๋๋ค. | |
| """ | |
| from safetensors.torch import load_file | |
| path = Path(path) | |
| config = json.loads((path / "config.json").read_text()) | |
| model = cls(**{k: config[k] for k in | |
| ("vocab_size", "d_model", "n_head", "n_layer", | |
| "d_ff", "block_size")}) | |
| state = load_file(path / "model.safetensors") | |
| missing, unexpected = model.load_state_dict(state, strict=False) | |
| if unexpected: | |
| raise ValueError(f"์ ์ฅ๋ณธ์ ๋ชจ๋ฅด๋ ํ ์๊ฐ ์๋ค: {unexpected}") | |
| if missing != ["head.weight"]: | |
| raise ValueError(f"๋น ์ง ํ ์๊ฐ head.weight ๋ง์ด ์๋๋ค: {missing}") | |
| return model.to(device).eval() | |