BrodyMakezAI commited on
Commit
1a4c9b3
·
verified ·
1 Parent(s): 1efeb6a

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +60 -0
  2. chat.py +199 -0
  3. comment_gpt_finetuned.pt +3 -0
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - text-generation
5
+ - char-level
6
+ - comment_gpt
7
+ - youtube-shorts
8
+ - tiny
9
+ language: en
10
+ ---
11
+
12
+ # GPT-5horts
13
+
14
+ *(not affiliated with, endorsed by, or aware of OpenAI)*
15
+
16
+ A 6-layer, 6-head, 384-dim character-level GPT (~10.7M params), fine-tuned exclusively on scraped YouTube Shorts comments. It has fully absorbed the linguistic patterns of that environment. This was not a mistake, this was the plan.
17
+
18
+ ## Model description
19
+
20
+ GPT-5horts predicts one character at a time and has learned, with complete confidence, that this is how YouTube Shorts commenters actually talk. It does not know what Roblox is but mentions it constantly. It has strong opinions about "gayme" (its word, not ours). It occasionally threatens legal action against people who do not exist.
21
+
22
+ ## Benchmarks
23
+
24
+ Run in-house against 8 held-out prompts (temp 0.8, top_k 40, 150 tokens each). Results are real, unedited model output.
25
+
26
+ | Benchmark | Score |
27
+ |---|---|
28
+ | Average response length | 90.1 characters |
29
+ | Emoji deployed | 15 across 8 responses (1.9 emoji/response) |
30
+ | ALL-CAPS WORDS | 5 |
31
+ | Question marks fired | 11 |
32
+ | Times it brought up Roblox unprompted | 2 |
33
+ | Coherence | Present, briefly, then gone |
34
+ | Vibes | Immaculate |
35
+
36
+ ## Sample outputs
37
+
38
+ > "the way she dunt finally someone this AHHH MOST POPULAR SHORT OF APPIL?????????!"
39
+
40
+ > "pov: 🗿🗿 The swindows people liking fishing 🗿 The people batter 🗿 The sound engling it on dang 🗿"
41
+
42
+ > "not me it safe, I was just gonna have a feel them dying dont have some but existed which school😢😢😢😢😢😢 why u sy así delete roblox"
43
+
44
+ > "bro really concerning to the predators on where?? No is metapper. So They were secues will never who made be made umm"
45
+
46
+ ## Intended use
47
+
48
+ Commenting on things. Poorly. With feeling.
49
+
50
+ ## Limitations
51
+
52
+ Cannot spell. Occasionally threatens legal action against fictional people. Has never heard of context. Mentions Roblox with no relevant prompting. Emotional state fluctuates mid-sentence for no stated reason.
53
+
54
+ ## Usage
55
+
56
+ ```
57
+ python chat.py --ckpt comment_gpt_finetuned.pt
58
+ ```
59
+
60
+ Empty prompt = generates from scratch. Ctrl+C to quit before it starts crying about Roblox again.
chat.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ chat.py
3
+ Interactive REPL for generating YouTube-Shorts-style comments from your
4
+ trained checkpoint (comment_gpt.pt). Type a prompt, get a comment back.
5
+ Empty prompt = generate from scratch.
6
+
7
+ Usage:
8
+ python chat.py --ckpt comment_gpt.pt
9
+ """
10
+
11
+ import argparse
12
+ import torch
13
+ import torch.nn as nn
14
+ from torch.nn import functional as F
15
+
16
+ BLOCK_SIZE = 128
17
+ N_LAYER = 6
18
+ N_HEAD = 6
19
+ N_EMBD = 384
20
+ DROPOUT = 0.1
21
+
22
+
23
+ def get_device():
24
+ if torch.backends.mps.is_available():
25
+ return "mps"
26
+ if torch.cuda.is_available():
27
+ return "cuda"
28
+ return "cpu"
29
+
30
+
31
+ class Head(nn.Module):
32
+ def __init__(self, head_size):
33
+ super().__init__()
34
+ self.key = nn.Linear(N_EMBD, head_size, bias=False)
35
+ self.query = nn.Linear(N_EMBD, head_size, bias=False)
36
+ self.value = nn.Linear(N_EMBD, head_size, bias=False)
37
+ self.register_buffer("tril", torch.tril(torch.ones(BLOCK_SIZE, BLOCK_SIZE)))
38
+ self.dropout = nn.Dropout(DROPOUT)
39
+
40
+ def forward(self, x):
41
+ B, T, C = x.shape
42
+ k = self.key(x)
43
+ q = self.query(x)
44
+ wei = q @ k.transpose(-2, -1) * (C ** -0.5)
45
+ wei = wei.masked_fill(self.tril[:T, :T] == 0, float("-inf"))
46
+ wei = F.softmax(wei, dim=-1)
47
+ wei = self.dropout(wei)
48
+ v = self.value(x)
49
+ return wei @ v
50
+
51
+
52
+ class MultiHeadAttention(nn.Module):
53
+ def __init__(self, num_heads, head_size):
54
+ super().__init__()
55
+ self.heads = nn.ModuleList([Head(head_size) for _ in range(num_heads)])
56
+ self.proj = nn.Linear(N_EMBD, N_EMBD)
57
+ self.dropout = nn.Dropout(DROPOUT)
58
+
59
+ def forward(self, x):
60
+ out = torch.cat([h(x) for h in self.heads], dim=-1)
61
+ return self.dropout(self.proj(out))
62
+
63
+
64
+ class FeedForward(nn.Module):
65
+ def __init__(self, n_embd):
66
+ super().__init__()
67
+ self.net = nn.Sequential(
68
+ nn.Linear(n_embd, 4 * n_embd),
69
+ nn.GELU(),
70
+ nn.Linear(4 * n_embd, n_embd),
71
+ nn.Dropout(DROPOUT),
72
+ )
73
+
74
+ def forward(self, x):
75
+ return self.net(x)
76
+
77
+
78
+ class Block(nn.Module):
79
+ def __init__(self, n_embd, n_head):
80
+ super().__init__()
81
+ head_size = n_embd // n_head
82
+ self.sa = MultiHeadAttention(n_head, head_size)
83
+ self.ffwd = FeedForward(n_embd)
84
+ self.ln1 = nn.LayerNorm(n_embd)
85
+ self.ln2 = nn.LayerNorm(n_embd)
86
+
87
+ def forward(self, x):
88
+ x = x + self.sa(self.ln1(x))
89
+ x = x + self.ffwd(self.ln2(x))
90
+ return x
91
+
92
+
93
+ class CommentGPT(nn.Module):
94
+ def __init__(self, vocab_size):
95
+ super().__init__()
96
+ self.token_embedding = nn.Embedding(vocab_size, N_EMBD)
97
+ self.position_embedding = nn.Embedding(BLOCK_SIZE, N_EMBD)
98
+ self.blocks = nn.Sequential(*[Block(N_EMBD, N_HEAD) for _ in range(N_LAYER)])
99
+ self.ln_f = nn.LayerNorm(N_EMBD)
100
+ self.lm_head = nn.Linear(N_EMBD, vocab_size)
101
+ self.vocab_size = vocab_size
102
+
103
+ def forward(self, idx, targets=None):
104
+ B, T = idx.shape
105
+ tok_emb = self.token_embedding(idx)
106
+ pos_emb = self.position_embedding(torch.arange(T, device=idx.device))
107
+ x = tok_emb + pos_emb
108
+ x = self.blocks(x)
109
+ x = self.ln_f(x)
110
+ logits = self.lm_head(x)
111
+ return logits, None
112
+
113
+ @torch.no_grad()
114
+ def generate(self, idx, max_new_tokens, temperature=0.8, top_k=40):
115
+ for _ in range(max_new_tokens):
116
+ idx_cond = idx[:, -BLOCK_SIZE:]
117
+ logits, _ = self(idx_cond)
118
+ logits = logits[:, -1, :] / temperature
119
+ if top_k is not None:
120
+ v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
121
+ logits[logits < v[:, [-1]]] = -float("inf")
122
+ probs = F.softmax(logits, dim=-1)
123
+ idx_next = torch.multinomial(probs, num_samples=1)
124
+ idx = torch.cat((idx, idx_next), dim=1)
125
+ return idx
126
+
127
+
128
+ class CharTokenizer:
129
+ def __init__(self, stoi, itos):
130
+ self.stoi = stoi
131
+ self.itos = {int(k): v for k, v in itos.items()}
132
+
133
+ def encode(self, s):
134
+ # skip characters not seen during training instead of crashing
135
+ return [self.stoi[c] for c in s if c in self.stoi]
136
+
137
+ def decode(self, ids):
138
+ return "".join(self.itos[i] for i in ids)
139
+
140
+
141
+ def load_model(ckpt_path, device):
142
+ ckpt = torch.load(ckpt_path, map_location=device)
143
+ model = CommentGPT(ckpt["vocab_size"]).to(device)
144
+ model.load_state_dict(ckpt["model_state"])
145
+ model.eval()
146
+ tokenizer = CharTokenizer(ckpt["stoi"], ckpt["itos"])
147
+ return model, tokenizer
148
+
149
+
150
+ def generate_comment(model, tokenizer, device, prompt="", max_new_tokens=200,
151
+ temperature=0.8, top_k=40):
152
+ if prompt:
153
+ ids = tokenizer.encode(prompt)
154
+ if not ids:
155
+ ids = [0]
156
+ else:
157
+ ids = [0]
158
+ context = torch.tensor([ids], dtype=torch.long, device=device)
159
+ out = model.generate(context, max_new_tokens=max_new_tokens,
160
+ temperature=temperature, top_k=top_k)[0].tolist()
161
+ text = tokenizer.decode(out)
162
+ # cut at the first <|end|> after the prompt so you get one clean comment
163
+ text = text.split("<|end|>")[0].strip()
164
+ return text
165
+
166
+
167
+ def main():
168
+ p = argparse.ArgumentParser()
169
+ p.add_argument("--ckpt", default="comment_gpt.pt")
170
+ p.add_argument("--temperature", type=float, default=0.8)
171
+ p.add_argument("--top_k", type=int, default=40)
172
+ p.add_argument("--max_new_tokens", type=int, default=200)
173
+ args = p.parse_args()
174
+
175
+ device = get_device()
176
+ print(f"using device: {device}")
177
+ print(f"loading {args.ckpt}...")
178
+ model, tokenizer = load_model(args.ckpt, device)
179
+ print("loaded. type a prompt (or leave blank) and hit enter. ctrl+c to quit.\n")
180
+
181
+ while True:
182
+ try:
183
+ prompt = input("> ")
184
+ except (KeyboardInterrupt, EOFError):
185
+ print("\nbye")
186
+ break
187
+ comment = generate_comment(
188
+ model, tokenizer, device,
189
+ prompt=prompt,
190
+ max_new_tokens=args.max_new_tokens,
191
+ temperature=args.temperature,
192
+ top_k=args.top_k,
193
+ )
194
+ print(comment)
195
+ print()
196
+
197
+
198
+ if __name__ == "__main__":
199
+ main()
comment_gpt_finetuned.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cc04b5e999d03ff6b85564fcfe70fcc939a47ca5ddd64ac93a83044ec05f3e08
3
+ size 46874411