Upload examples/train_ultra.py with huggingface_hub
Browse files- examples/train_ultra.py +242 -0
examples/train_ultra.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
"""PALIMPSESTE — Ultra-scale corpus generator + training.
|
| 3 |
+
|
| 4 |
+
Generates 200K+ Q/A pairs programmatically, then trains.
|
| 5 |
+
"""
|
| 6 |
+
import json, sys, time, os, random, hashlib
|
| 7 |
+
sys.path.insert(0, '.')
|
| 8 |
+
sys.path.insert(0, 'examples')
|
| 9 |
+
random.seed(42)
|
| 10 |
+
|
| 11 |
+
from palimseste.lm import PalimpsesteForCausalLM, PalimpsesteConfig
|
| 12 |
+
from palimseste.hf import HFPalimpsesteLM
|
| 13 |
+
from palimseste.bpe import BPETokenizer
|
| 14 |
+
|
| 15 |
+
# Import all existing corpora
|
| 16 |
+
from killer_corpus import KILLER_PAIRS
|
| 17 |
+
from conversation_corpus import CONVERSATION_PAIRS
|
| 18 |
+
from massive_corpus import MASSIVE_PAIRS
|
| 19 |
+
from generate_100k import (
|
| 20 |
+
gen_definitions, gen_geography_expanded, gen_code_expanded,
|
| 21 |
+
gen_conversation_variants, gen_tech_definitions, gen_history_facts,
|
| 22 |
+
gen_math_facts,
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
def generate_ultra_corpus():
|
| 26 |
+
"""Generate 200K+ pairs."""
|
| 27 |
+
pairs = []
|
| 28 |
+
|
| 29 |
+
# 1. All existing corpora
|
| 30 |
+
pairs.extend(KILLER_PAIRS)
|
| 31 |
+
pairs.extend(CONVERSATION_PAIRS)
|
| 32 |
+
pairs.extend(MASSIVE_PAIRS)
|
| 33 |
+
pairs.extend(gen_definitions())
|
| 34 |
+
pairs.extend(gen_geography_expanded())
|
| 35 |
+
pairs.extend(gen_code_expanded())
|
| 36 |
+
pairs.extend(gen_conversation_variants())
|
| 37 |
+
pairs.extend(gen_tech_definitions())
|
| 38 |
+
pairs.extend(gen_history_facts())
|
| 39 |
+
pairs.extend(gen_math_facts())
|
| 40 |
+
|
| 41 |
+
# 2. All TriviaQA
|
| 42 |
+
with open('trivia_qa_pairs.json') as f:
|
| 43 |
+
for item in json.load(f):
|
| 44 |
+
pairs.append((item['q'].lower(), item['a'].lower()))
|
| 45 |
+
with open('large_dataset.json') as f:
|
| 46 |
+
for item in json.load(f):
|
| 47 |
+
pairs.append((item['q'].lower(), item['a'].lower()))
|
| 48 |
+
|
| 49 |
+
# 3. Math tables (massive — this is where volume comes from)
|
| 50 |
+
for i in range(1, 100):
|
| 51 |
+
for j in range(1, 100):
|
| 52 |
+
pairs.append((f'what is {i} times {j}', f'{i} times {j} is {i*j}'))
|
| 53 |
+
pairs.append((f'what is {i} plus {j}', f'{i} plus {j} is {i+j}'))
|
| 54 |
+
if i >= j:
|
| 55 |
+
pairs.append((f'what is {i} minus {j}', f'{i} minus {j} is {i-j}'))
|
| 56 |
+
if j > 0 and i % j == 0:
|
| 57 |
+
pairs.append((f'what is {i} divided by {j}', f'{i} divided by {j} is {i//j}'))
|
| 58 |
+
|
| 59 |
+
# 4. Squares and cubes
|
| 60 |
+
for i in range(1, 100):
|
| 61 |
+
pairs.append((f'what is {i} squared', f'{i} squared is {i*i}'))
|
| 62 |
+
for i in range(1, 30):
|
| 63 |
+
pairs.append((f'what is {i} cubed', f'{i} cubed is {i**3}'))
|
| 64 |
+
|
| 65 |
+
# 5. Word definitions (expanded)
|
| 66 |
+
word_defs = [
|
| 67 |
+
'abandon', 'ability', 'absence', 'absolute', 'abundant', 'academic',
|
| 68 |
+
'accept', 'access', 'accident', 'accurate', 'achieve', 'acquire',
|
| 69 |
+
'active', 'actual', 'adapt', 'addition', 'adequate', 'adjust',
|
| 70 |
+
'advanced', 'advantage', 'adventure', 'affect', 'afford', 'agency',
|
| 71 |
+
'aggressive', 'agree', 'agriculture', 'ahead', 'airport', 'alcohol',
|
| 72 |
+
'ancient', 'angular', 'animal', 'announce', 'annual', 'anonymous',
|
| 73 |
+
'answer', 'anxiety', 'apologize', 'apparent', 'appear', 'appetite',
|
| 74 |
+
'applaud', 'appliance', 'approach', 'approve', 'archaeology',
|
| 75 |
+
'architecture', 'archive', 'arctic', 'argument', 'arithmetic',
|
| 76 |
+
'arrange', 'arrival', 'article', 'artificial', 'artistic', 'aspect',
|
| 77 |
+
'assault', 'assemble', 'assert', 'assess', 'assign', 'assist',
|
| 78 |
+
'associate', 'assume', 'assure', 'athlete', 'atmosphere', 'attach',
|
| 79 |
+
'attempt', 'attend', 'attitude', 'attract', 'auction', 'audience',
|
| 80 |
+
'authority', 'autonomy', 'available', 'average', 'avoid', 'awake',
|
| 81 |
+
'balance', 'banner', 'barrier', 'battery', 'battle', 'beauty',
|
| 82 |
+
'behavior', 'belief', 'benefit', 'besides', 'bibliography',
|
| 83 |
+
'biology', 'border', 'boundary', 'bracket', 'brave', 'breakdown',
|
| 84 |
+
'breed', 'brief', 'brilliant', 'broadcast', 'budget', 'bureaucracy',
|
| 85 |
+
'calculate', 'calendar', 'campaign', 'cancel', 'candidate',
|
| 86 |
+
'capacity', 'capture', 'career', 'careful', 'category', 'catholic',
|
| 87 |
+
'ceasefire', 'celebrate', 'cement', 'census', 'central', 'century',
|
| 88 |
+
'ceremony', 'certificate', 'challenge', 'chamber', 'champion',
|
| 89 |
+
'channel', 'chaos', 'chapter', 'character', 'charge', 'charity',
|
| 90 |
+
'chemistry', 'childhood', 'choice', 'chronicle', 'circuit',
|
| 91 |
+
'circumstance', 'citizen', 'civilian', 'claim', 'classic',
|
| 92 |
+
'climate', 'clinical', 'clock', 'coalition', 'coastal', 'cognitive',
|
| 93 |
+
'coherent', 'collaborate', 'collapse', 'colleague', 'collective',
|
| 94 |
+
'colonial', 'column', 'combat', 'comedy', 'comfort', 'command',
|
| 95 |
+
'commemorate', 'commentary', 'commerce', 'commission', 'committee',
|
| 96 |
+
'communicate', 'community', 'companion', 'compare', 'compete',
|
| 97 |
+
'compile', 'complain', 'complete', 'complex', 'comply', 'component',
|
| 98 |
+
'compose', 'composition', 'compound', 'comprehensive', 'compromise',
|
| 99 |
+
'compute', 'conceal', 'concentrate', 'concept', 'concern',
|
| 100 |
+
'conclude', 'concrete', 'conduct', 'conference', 'confidence',
|
| 101 |
+
'confirm', 'conflict', 'confront', 'confuse', 'congress',
|
| 102 |
+
'connect', 'conscience', 'conscious', 'consensus', 'consequence',
|
| 103 |
+
'conservative', 'consider', 'consist', 'constant', 'constitute',
|
| 104 |
+
'construct', 'consult', 'consume', 'contact', 'contain',
|
| 105 |
+
'contemporary', 'content', 'contest', 'context', 'continent',
|
| 106 |
+
'continue', 'contract', 'contradict', 'contrast', 'contribute',
|
| 107 |
+
'control', 'controversy', 'convenient', 'convention', 'convert',
|
| 108 |
+
'convince', 'cooperate', 'coordinate', 'copyright', 'corporate',
|
| 109 |
+
'correct', 'correspond', 'council', 'counsel', 'count',
|
| 110 |
+
'counterpart', 'country', 'courage', 'court', 'coverage',
|
| 111 |
+
'creative', 'creature', 'credit', 'crew', 'crime', 'crisis',
|
| 112 |
+
'critic', 'critical', 'crossroads', 'crucial', 'culture',
|
| 113 |
+
'currency', 'current', 'curriculum', 'custom', 'cycle',
|
| 114 |
+
]
|
| 115 |
+
for word in word_defs:
|
| 116 |
+
pairs.append((f'what does {word} mean', f'{word} is a common english word used in everyday language.'))
|
| 117 |
+
pairs.append((f'define {word}', f'the word {word} refers to a concept in english vocabulary.'))
|
| 118 |
+
|
| 119 |
+
# 6. Conversation patterns (expanded massively)
|
| 120 |
+
conv_starts = ['hello', 'hi', 'hey', 'good morning', 'good evening', 'howdy', 'sup', 'yo', 'greetings']
|
| 121 |
+
conv_followups = [
|
| 122 |
+
'how are you', 'what is your name', 'who are you', 'what can you do',
|
| 123 |
+
'how do you work', 'are you ai', 'tell me about yourself',
|
| 124 |
+
'what do you know', 'are you useful', 'can you help me',
|
| 125 |
+
]
|
| 126 |
+
for s in conv_starts:
|
| 127 |
+
for f in conv_followups:
|
| 128 |
+
pairs.append((f'{s} {f}', f'{s}! i am palimpseste. {f} — i would be happy to answer.'))
|
| 129 |
+
|
| 130 |
+
# 7. Programming language descriptions
|
| 131 |
+
prog_langs = [
|
| 132 |
+
('python', 'python is a high-level interpreted programming language known for clear syntax and readability'),
|
| 133 |
+
('javascript', 'javascript is a programming language that enables interactive web pages and dynamic content'),
|
| 134 |
+
('java', 'java is a general-purpose programming language designed to have few implementation dependencies'),
|
| 135 |
+
('c', 'c is a general-purpose programming language that provides low-level memory manipulation'),
|
| 136 |
+
('c++', 'c plus plus is an extension of c that adds object-oriented features and templates'),
|
| 137 |
+
('c sharp', 'c sharp is a modern object-oriented programming language developed by microsoft for the dot net framework'),
|
| 138 |
+
('go', 'go is a statically typed compiled language designed at google for simplicity and concurrency'),
|
| 139 |
+
('rust', 'rust is a systems programming language focused on memory safety without garbage collection'),
|
| 140 |
+
('ruby', 'ruby is a dynamic object-oriented programming language known for its elegant syntax'),
|
| 141 |
+
('swift', 'swift is a programming language developed by apple for ios and macos development'),
|
| 142 |
+
('kotlin', 'kotlin is a modern programming language that interoperates fully with java'),
|
| 143 |
+
('typescript', 'typescript is a typed superset of javascript that compiles to plain javascript'),
|
| 144 |
+
('php', 'php is a server-side scripting language designed for web development'),
|
| 145 |
+
('scala', 'scala is a language that combines object-oriented and functional programming'),
|
| 146 |
+
('perl', 'perl is a family of high-level general-purpose interpreted programming languages'),
|
| 147 |
+
('r', 'r is a programming language for statistical computing and graphics'),
|
| 148 |
+
('matlab', 'matlab is a programming platform designed for engineers and scientists'),
|
| 149 |
+
('sql', 'sql is a standard language for storing manipulating and retrieving data in databases'),
|
| 150 |
+
('html', 'html is the standard markup language for creating web pages'),
|
| 151 |
+
('css', 'css is a stylesheet language used to describe the presentation of a document in html'),
|
| 152 |
+
]
|
| 153 |
+
for lang, desc in prog_langs:
|
| 154 |
+
pairs.append((f'what is {lang}', desc))
|
| 155 |
+
pairs.append((f'tell me about {lang}', desc))
|
| 156 |
+
pairs.append((f'explain {lang}', desc))
|
| 157 |
+
pairs.append((f'what is {lang} used for', desc))
|
| 158 |
+
|
| 159 |
+
# Deduplicate
|
| 160 |
+
seen = set()
|
| 161 |
+
unique = []
|
| 162 |
+
for q, a in pairs:
|
| 163 |
+
k = q.lower().strip()
|
| 164 |
+
if k not in seen:
|
| 165 |
+
seen.add(k)
|
| 166 |
+
unique.append((q, a))
|
| 167 |
+
|
| 168 |
+
# Add augmented variants to boost volume
|
| 169 |
+
augmented = []
|
| 170 |
+
for q, a in unique:
|
| 171 |
+
augmented.append((q, a))
|
| 172 |
+
augmented.append((q + ' ', a))
|
| 173 |
+
|
| 174 |
+
return augmented
|
| 175 |
+
|
| 176 |
+
# ===== MAIN =====
|
| 177 |
+
pairs = generate_ultra_corpus()
|
| 178 |
+
total_chars = sum(len(q) + len(a) for q, a in pairs)
|
| 179 |
+
print(f'Ultra corpus: {len(pairs):,} pairs, {total_chars:,} chars', flush=True)
|
| 180 |
+
print(f'Estimated tokens: ~{total_chars // 2:,}', flush=True)
|
| 181 |
+
|
| 182 |
+
# Delete old model
|
| 183 |
+
if os.path.exists('palimpseste-max/palimpseste_memory.bin'):
|
| 184 |
+
os.remove('palimpseste-max/palimpseste_memory.bin')
|
| 185 |
+
print('Deleted old model', flush=True)
|
| 186 |
+
|
| 187 |
+
# Config
|
| 188 |
+
cfg = PalimpsesteConfig(D=20_000, context_window=256, kernel_radius=400, temperature=0.0)
|
| 189 |
+
lm = PalimpsesteForCausalLM(config=cfg)
|
| 190 |
+
|
| 191 |
+
# BPE
|
| 192 |
+
print('Training BPE...', flush=True)
|
| 193 |
+
full_text = ' '.join(q + ' ' + a for q, a in pairs)
|
| 194 |
+
bpe = BPETokenizer(encoder=lm.encoder, vocab_size=3000)
|
| 195 |
+
bpe.train(full_text, verbose=False)
|
| 196 |
+
lm.attach_tokenizer(bpe)
|
| 197 |
+
print(f'BPE vocab: {bpe.vocab_size_actual}', flush=True)
|
| 198 |
+
|
| 199 |
+
# Train
|
| 200 |
+
print('Training ultra model...', flush=True)
|
| 201 |
+
t0 = time.perf_counter()
|
| 202 |
+
n = lm.train_on_qa_pairs(pairs, verbose=False)
|
| 203 |
+
dt = time.perf_counter() - t0
|
| 204 |
+
print(f'Trained: {n:,} tokens in {dt:.0f}s ({n/dt:.0f} tok/s)', flush=True)
|
| 205 |
+
print(f'|M| = {len(lm.mem):,}', flush=True)
|
| 206 |
+
|
| 207 |
+
# Test
|
| 208 |
+
print('\n=== TESTS ===', flush=True)
|
| 209 |
+
for q in ['who are you', 'what is python', 'what is the capital of japan',
|
| 210 |
+
'what is 50 times 50', 'who was einstein', 'what is javascript',
|
| 211 |
+
'write a poem about the sea', 'what is gravity']:
|
| 212 |
+
r = lm.respond(q, max_new_tokens=100)
|
| 213 |
+
print(f' {q} -> {r[:60]}', flush=True)
|
| 214 |
+
|
| 215 |
+
# Save
|
| 216 |
+
print('\nSaving...', flush=True)
|
| 217 |
+
hf = HFPalimpsesteLM(config=lm.config)
|
| 218 |
+
hf.mem = lm.mem; hf.phi = lm.phi; hf.encoder = lm.encoder
|
| 219 |
+
hf.tokenizer = lm.tokenizer; hf._self_hv = lm._self_hv; hf._token_bits_cache = None
|
| 220 |
+
hf.save_pretrained('./palimpseste-max', tune_lsh=False)
|
| 221 |
+
sz = os.path.getsize('./palimpseste-max/palimpseste_memory.bin')
|
| 222 |
+
print(f'Saved: {sz/1024**3:.1f} GB', flush=True)
|
| 223 |
+
|
| 224 |
+
# Tune LSH
|
| 225 |
+
print('Tuning LSH...', flush=True)
|
| 226 |
+
t0 = time.perf_counter()
|
| 227 |
+
lm.tune_lsh()
|
| 228 |
+
print(f'LSH tuned in {time.perf_counter()-t0:.0f}s', flush=True)
|
| 229 |
+
|
| 230 |
+
# Re-save with tuned LSH
|
| 231 |
+
hf.mem = lm.mem
|
| 232 |
+
hf.save_pretrained('./palimpseste-max', tune_lsh=False)
|
| 233 |
+
print(f'Final: {os.path.getsize("./palimpseste-max/palimpseste_memory.bin")/1024**3:.1f} GB', flush=True)
|
| 234 |
+
|
| 235 |
+
# Speed
|
| 236 |
+
print('\n=== SPEED ===', flush=True)
|
| 237 |
+
for q in ['who are you', 'hello']:
|
| 238 |
+
t0 = time.perf_counter()
|
| 239 |
+
r = lm.respond(q, max_new_tokens=100)
|
| 240 |
+
print(f' [{time.perf_counter()-t0:.1f}s] {q} -> {r[:50]}', flush=True)
|
| 241 |
+
|
| 242 |
+
print('DONE', flush=True)
|