Update README.md
Browse files
README.md
CHANGED
|
@@ -452,60 +452,116 @@ from datasets import load_dataset
|
|
| 452 |
from tqdm import tqdm
|
| 453 |
|
| 454 |
OUTPUT_DIR = "data/alpaca_cleaned_mixed"
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
else:
|
| 463 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
|
| 465 |
def main():
|
| 466 |
-
|
|
|
|
|
|
|
| 467 |
|
| 468 |
-
|
| 469 |
-
alpaca = load_dataset("yahma/alpaca-cleaned", split='train')
|
| 470 |
-
|
| 471 |
-
identity_prompts = [
|
| 472 |
-
{"instruction": "Who are you?", "input": "", "output": "I am SmaLLMPro, a helpful AI Assistant developed by LH-Tech AI. What do you want to talk about?"},
|
| 473 |
-
{"instruction": "Who developed you?", "input": "", "output": "I was developed by LH-Tech AI. Is there anything I can assist you with?"},
|
| 474 |
-
{"instruction": "What is you name?", "input": "", "output": "My name is SmaLLMPro. How can I help you today?"}
|
| 475 |
-
]
|
| 476 |
|
| 477 |
-
print("📥 Loading
|
|
|
|
|
|
|
|
|
|
| 478 |
fineweb = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split='train', streaming=True)
|
| 479 |
-
|
| 480 |
-
|
| 481 |
all_tokens = []
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
text = format_prompt(p['instruction'], p['input'], p['output'])
|
| 486 |
-
all_tokens.extend(enc.encode(text, allowed_special={"<|endoftext|>"}))
|
| 487 |
-
|
| 488 |
-
print("📝 Adding Alpaca-Cleaned...")
|
| 489 |
for ex in tqdm(alpaca, desc="Alpaca"):
|
| 490 |
-
|
| 491 |
-
all_tokens.extend(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
|
| 493 |
-
print("
|
| 494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 495 |
try:
|
| 496 |
ex = next(fw_iter)
|
| 497 |
-
text = ex['text'] +
|
| 498 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
except StopIteration:
|
| 500 |
break
|
|
|
|
|
|
|
| 501 |
|
| 502 |
-
|
| 503 |
-
|
| 504 |
|
| 505 |
-
|
| 506 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
|
| 508 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 509 |
|
| 510 |
if __name__ == "__main__":
|
| 511 |
main()
|
|
@@ -521,24 +577,24 @@ from model import GPTConfig, GPT
|
|
| 521 |
|
| 522 |
import numpy as np
|
| 523 |
|
| 524 |
-
out_dir = '/home/user/
|
| 525 |
init_from = '/home/user/350m_fineweb'
|
| 526 |
dataset = 'alpaca_cleaned_mixed'
|
| 527 |
|
| 528 |
batch_size = 4
|
| 529 |
gradient_accumulation_steps = 32
|
| 530 |
block_size = 1024
|
| 531 |
-
learning_rate =
|
| 532 |
-
max_iters =
|
| 533 |
weight_decay = 0.1
|
| 534 |
dropout = 0.1
|
| 535 |
-
warmup_iters =
|
| 536 |
min_lr = 3e-6
|
| 537 |
beta1, beta2 = 0.9, 0.95
|
| 538 |
device = 'cuda'
|
| 539 |
dtype = 'bfloat16'
|
| 540 |
compile = True
|
| 541 |
-
save_interval =
|
| 542 |
|
| 543 |
os.makedirs(out_dir, exist_ok=True)
|
| 544 |
torch.manual_seed(1337)
|
|
@@ -548,18 +604,23 @@ ctx = torch.amp.autocast(device_type=device_type, dtype=ptdtype)
|
|
| 548 |
|
| 549 |
data_dir = os.path.join('data', dataset)
|
| 550 |
train_data = np.memmap(os.path.join(data_dir, 'train.bin'), dtype=np.uint16, mode='r')
|
|
|
|
| 551 |
|
| 552 |
def get_batch():
|
| 553 |
ix = torch.randint(len(train_data) - block_size, (batch_size,))
|
| 554 |
x = torch.stack([torch.from_numpy((train_data[i:i+block_size]).astype(np.int64)) for i in ix])
|
| 555 |
y = torch.stack([torch.from_numpy((train_data[i+1:i+1+block_size]).astype(np.int64)) for i in ix])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
x, y = x.to(device), y.to(device)
|
| 557 |
return x, y
|
| 558 |
|
| 559 |
print(f"📥 Loading Pretraining-Checkpoint from {init_from}...")
|
| 560 |
ckpt_files = sorted([f for f in os.listdir(init_from) if f.endswith('.pt')])
|
| 561 |
if not ckpt_files:
|
| 562 |
-
raise FileNotFoundError("No checkpoint in init_from
|
| 563 |
|
| 564 |
ckpt_path = os.path.join(init_from, ckpt_files[-1])
|
| 565 |
checkpoint = torch.load(ckpt_path, map_location=device)
|
|
@@ -576,7 +637,7 @@ model.load_state_dict(state_dict)
|
|
| 576 |
model.to(device)
|
| 577 |
|
| 578 |
if compile:
|
| 579 |
-
print("🚀 Compiling
|
| 580 |
model = torch.compile(model)
|
| 581 |
|
| 582 |
optimizer = model.configure_optimizers(weight_decay, learning_rate, (beta1, beta2), device_type)
|
|
@@ -589,7 +650,7 @@ def get_lr(it):
|
|
| 589 |
coeff = 0.5 * (1.0 + math.cos(math.pi * decay_ratio))
|
| 590 |
return min_lr + coeff * (learning_rate - min_lr)
|
| 591 |
|
| 592 |
-
print(f"🛠️ Starting
|
| 593 |
model.train()
|
| 594 |
t0 = time.time()
|
| 595 |
|
|
@@ -613,7 +674,7 @@ for iter_num in range(max_iters + 1):
|
|
| 613 |
|
| 614 |
if iter_num % 10 == 0:
|
| 615 |
dt = time.time() - t0
|
| 616 |
-
print(f"Iter {iter_num}: Loss {loss.item()*gradient_accumulation_steps:.4f},
|
| 617 |
t0 = time.time()
|
| 618 |
|
| 619 |
if iter_num > 0 and iter_num % save_interval == 0:
|
|
@@ -629,7 +690,7 @@ for iter_num in range(max_iters + 1):
|
|
| 629 |
}
|
| 630 |
torch.save(checkpoint_data, save_path)
|
| 631 |
|
| 632 |
-
print(f"💾 Finetuning done. Saving SmaLLMPro
|
| 633 |
final_checkpoint = {
|
| 634 |
'model': model.state_dict() if not compile else model._orig_mod.state_dict(),
|
| 635 |
'model_args': checkpoint['model_args'],
|
|
@@ -646,41 +707,45 @@ import torch
|
|
| 646 |
import tiktoken
|
| 647 |
from model import GPTConfig, GPT
|
| 648 |
|
| 649 |
-
|
| 650 |
-
ckpt_path = '/home/user/350m_SmaLLMPro_Final/SmaLLMPro_iter_3000.pt'
|
| 651 |
device = 'cuda'
|
| 652 |
enc = tiktoken.get_encoding("gpt2")
|
| 653 |
|
| 654 |
-
print("Loading SmaLLMPro...")
|
| 655 |
checkpoint = torch.load(ckpt_path, map_location=device)
|
| 656 |
gptconf = GPTConfig(**checkpoint['model_args'])
|
| 657 |
model = GPT(gptconf)
|
| 658 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 659 |
model.eval()
|
| 660 |
model.to(device)
|
| 661 |
-
print("
|
| 662 |
|
| 663 |
def run_chat():
|
| 664 |
-
print("--- SmaLLMPro Chatbot (Type 'exit' to
|
| 665 |
-
|
| 666 |
-
sys_msg = "### System:\nYou are SmaLLMPro, a helpful AI Assistant developed by LH-Tech AI.\n\n"
|
| 667 |
|
| 668 |
while True:
|
| 669 |
user_input = input("You: ")
|
| 670 |
-
if user_input.lower() in ["exit", "quit"
|
| 671 |
break
|
| 672 |
|
| 673 |
-
prompt = f"
|
| 674 |
|
| 675 |
x = torch.tensor(enc.encode(prompt), dtype=torch.long, device=device)[None, ...]
|
| 676 |
|
| 677 |
print("SmaLLMPro: ", end="", flush=True)
|
| 678 |
with torch.no_grad():
|
| 679 |
with torch.amp.autocast(device_type='cuda', dtype=torch.bfloat16):
|
| 680 |
-
y = model.generate(x,
|
| 681 |
full_text = enc.decode(y[0].tolist())
|
| 682 |
|
| 683 |
-
response = full_text.split("
|
| 684 |
print(response + "\n")
|
| 685 |
|
| 686 |
if __name__ == "__main__":
|
|
|
|
| 452 |
from tqdm import tqdm
|
| 453 |
|
| 454 |
OUTPUT_DIR = "data/alpaca_cleaned_mixed"
|
| 455 |
+
TOKENIZER_NAME = "gpt2"
|
| 456 |
+
SEED = 1337
|
| 457 |
+
|
| 458 |
+
FINEWEB_SAMPLES = 2500
|
| 459 |
+
|
| 460 |
+
enc = tiktoken.get_encoding(TOKENIZER_NAME)
|
| 461 |
+
EOS_TOKEN = "<|endoftext|>"
|
| 462 |
+
|
| 463 |
+
def format_prompt_with_mask(instruction, input_text, output):
|
| 464 |
+
"""
|
| 465 |
+
Formatiert den Prompt und erstellt die Loss-Maske.
|
| 466 |
+
Format:
|
| 467 |
+
Instruction: ...
|
| 468 |
+
Input: ... (optional)
|
| 469 |
+
Response: ... <|endoftext|>
|
| 470 |
+
"""
|
| 471 |
+
if input_text and input_text.strip():
|
| 472 |
+
prompt_text = f"Instruction:\n{instruction}\n\nInput:\n{input_text}\n\nResponse:\n"
|
| 473 |
else:
|
| 474 |
+
prompt_text = f"Instruction:\n{instruction}\n\nResponse:\n"
|
| 475 |
+
|
| 476 |
+
completion_text = f"{output}{EOS_TOKEN}"
|
| 477 |
+
|
| 478 |
+
prompt_ids = enc.encode(prompt_text, allowed_special={'<|endoftext|>'})
|
| 479 |
+
completion_ids = enc.encode(completion_text, allowed_special={'<|endoftext|>'})
|
| 480 |
+
|
| 481 |
+
full_ids = prompt_ids + completion_ids
|
| 482 |
+
|
| 483 |
+
mask = [0] * len(prompt_ids) + [1] * len(completion_ids)
|
| 484 |
+
|
| 485 |
+
return full_ids, mask
|
| 486 |
|
| 487 |
def main():
|
| 488 |
+
np.random.seed(SEED)
|
| 489 |
+
print(f"🚀 Starting Prepare-Script for SmaLLMPro (350M Instruct)...")
|
| 490 |
+
print(f"📚 Tokenizer: {TOKENIZER_NAME}")
|
| 491 |
|
| 492 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
|
| 494 |
+
print("📥 Loading 'yahma/alpaca-cleaned' (Chat-Instructions)...")
|
| 495 |
+
alpaca = load_dataset("yahma/alpaca-cleaned", split='train')
|
| 496 |
+
|
| 497 |
+
print(f"📥 Loading 'HuggingFaceFW/fineweb-edu' (Sample-10BT) for {FINEWEB_SAMPLES} Samples...")
|
| 498 |
fineweb = load_dataset("HuggingFaceFW/fineweb-edu", name="sample-10BT", split='train', streaming=True)
|
| 499 |
+
|
|
|
|
| 500 |
all_tokens = []
|
| 501 |
+
all_masks = []
|
| 502 |
+
|
| 503 |
+
print("⚙️ Processing Alpaca...")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
for ex in tqdm(alpaca, desc="Alpaca"):
|
| 505 |
+
ids, mask = format_prompt_with_mask(ex['instruction'], ex['input'], ex['output'])
|
| 506 |
+
all_tokens.extend(ids)
|
| 507 |
+
all_masks.extend(mask)
|
| 508 |
+
|
| 509 |
+
alpaca_len = len(all_tokens)
|
| 510 |
+
print(f" -> Alpaca Tokens: {alpaca_len:,}")
|
| 511 |
|
| 512 |
+
print("⚙️ Processing FineWeb (Anti-Forgetting)...")
|
| 513 |
+
fw_iter = iter(fineweb)
|
| 514 |
+
fw_count = 0
|
| 515 |
+
fw_tokens_count = 0
|
| 516 |
+
|
| 517 |
+
for _ in tqdm(range(FINEWEB_SAMPLES), desc="FineWeb"):
|
| 518 |
try:
|
| 519 |
ex = next(fw_iter)
|
| 520 |
+
text = ex['text'] + EOS_TOKEN
|
| 521 |
+
ids = enc.encode(text, allowed_special={EOS_TOKEN})
|
| 522 |
+
|
| 523 |
+
all_tokens.extend(ids)
|
| 524 |
+
all_masks.extend([1] * len(ids))
|
| 525 |
+
|
| 526 |
+
fw_tokens_count += len(ids)
|
| 527 |
+
fw_count += 1
|
| 528 |
except StopIteration:
|
| 529 |
break
|
| 530 |
+
|
| 531 |
+
print(f" -> FineWeb Tokens: {fw_tokens_count:,} (from {fw_count} documents)")
|
| 532 |
|
| 533 |
+
total_tokens = len(all_tokens)
|
| 534 |
+
print(f"\n💾 Saving {total_tokens:,} Tokens in '{OUTPUT_DIR}'...")
|
| 535 |
|
| 536 |
+
token_arr = np.array(all_tokens, dtype=np.uint16)
|
| 537 |
+
token_arr.tofile(os.path.join(OUTPUT_DIR, "train.bin"))
|
| 538 |
+
|
| 539 |
+
mask_arr = np.array(all_masks, dtype=np.uint8)
|
| 540 |
+
mask_arr.tofile(os.path.join(OUTPUT_DIR, "train_mask.bin"))
|
| 541 |
+
|
| 542 |
+
print("\n🔍 --- SANITY CHECK ---")
|
| 543 |
+
print("I decode the first 50 tokens of the first sample, to check, if everything is okay.")
|
| 544 |
+
print("Green (TRAIN) = The things the model learns. Grey (IGNORE) = The things the model only reads.")
|
| 545 |
|
| 546 |
+
check_len = 100
|
| 547 |
+
sample_ids = all_tokens[:check_len]
|
| 548 |
+
sample_mask = all_masks[:check_len]
|
| 549 |
+
|
| 550 |
+
decoded_parts = []
|
| 551 |
+
for t_id, m_val in zip(sample_ids, sample_mask):
|
| 552 |
+
token_str = enc.decode([t_id])
|
| 553 |
+
if m_val == 1:
|
| 554 |
+
decoded_parts.append(f"\033[92m{token_str}\033[0m")
|
| 555 |
+
else:
|
| 556 |
+
decoded_parts.append(f"\033[90m{token_str}\033[0m")
|
| 557 |
+
|
| 558 |
+
print("".join(decoded_parts))
|
| 559 |
+
print("\n(Legend: \033[90mGrey=Prompt/Ignored\033[0m, \033[Green=Response/Learned\033[0m)")
|
| 560 |
+
|
| 561 |
+
if len(token_arr) != len(mask_arr):
|
| 562 |
+
print("\n❌ Warning: Token and Mask Array have different lengths! Something has gone wrong!")
|
| 563 |
+
else:
|
| 564 |
+
print("\n✅ Everything seems to be fine. The arrays are synchronized. You can now start the training.")
|
| 565 |
|
| 566 |
if __name__ == "__main__":
|
| 567 |
main()
|
|
|
|
| 577 |
|
| 578 |
import numpy as np
|
| 579 |
|
| 580 |
+
out_dir = '/home/user/350m_SmaLLMPro_Final'
|
| 581 |
init_from = '/home/user/350m_fineweb'
|
| 582 |
dataset = 'alpaca_cleaned_mixed'
|
| 583 |
|
| 584 |
batch_size = 4
|
| 585 |
gradient_accumulation_steps = 32
|
| 586 |
block_size = 1024
|
| 587 |
+
learning_rate = 2e-5
|
| 588 |
+
max_iters = 1500
|
| 589 |
weight_decay = 0.1
|
| 590 |
dropout = 0.1
|
| 591 |
+
warmup_iters = 0
|
| 592 |
min_lr = 3e-6
|
| 593 |
beta1, beta2 = 0.9, 0.95
|
| 594 |
device = 'cuda'
|
| 595 |
dtype = 'bfloat16'
|
| 596 |
compile = True
|
| 597 |
+
save_interval = 500
|
| 598 |
|
| 599 |
os.makedirs(out_dir, exist_ok=True)
|
| 600 |
torch.manual_seed(1337)
|
|
|
|
| 604 |
|
| 605 |
data_dir = os.path.join('data', dataset)
|
| 606 |
train_data = np.memmap(os.path.join(data_dir, 'train.bin'), dtype=np.uint16, mode='r')
|
| 607 |
+
train_mask = np.memmap(os.path.join(data_dir, 'train_mask.bin'), dtype=np.uint8, mode='r')
|
| 608 |
|
| 609 |
def get_batch():
|
| 610 |
ix = torch.randint(len(train_data) - block_size, (batch_size,))
|
| 611 |
x = torch.stack([torch.from_numpy((train_data[i:i+block_size]).astype(np.int64)) for i in ix])
|
| 612 |
y = torch.stack([torch.from_numpy((train_data[i+1:i+1+block_size]).astype(np.int64)) for i in ix])
|
| 613 |
+
m = torch.stack([torch.from_numpy((train_mask[i+1:i+1+block_size]).astype(np.int64)) for i in ix])
|
| 614 |
+
|
| 615 |
+
y[m == 0] = -100
|
| 616 |
+
|
| 617 |
x, y = x.to(device), y.to(device)
|
| 618 |
return x, y
|
| 619 |
|
| 620 |
print(f"📥 Loading Pretraining-Checkpoint from {init_from}...")
|
| 621 |
ckpt_files = sorted([f for f in os.listdir(init_from) if f.endswith('.pt')])
|
| 622 |
if not ckpt_files:
|
| 623 |
+
raise FileNotFoundError("No checkpoint found in init_from directory!")
|
| 624 |
|
| 625 |
ckpt_path = os.path.join(init_from, ckpt_files[-1])
|
| 626 |
checkpoint = torch.load(ckpt_path, map_location=device)
|
|
|
|
| 637 |
model.to(device)
|
| 638 |
|
| 639 |
if compile:
|
| 640 |
+
print("🚀 Compiling Model...")
|
| 641 |
model = torch.compile(model)
|
| 642 |
|
| 643 |
optimizer = model.configure_optimizers(weight_decay, learning_rate, (beta1, beta2), device_type)
|
|
|
|
| 650 |
coeff = 0.5 * (1.0 + math.cos(math.pi * decay_ratio))
|
| 651 |
return min_lr + coeff * (learning_rate - min_lr)
|
| 652 |
|
| 653 |
+
print(f"🛠️ Starting Finetuning...")
|
| 654 |
model.train()
|
| 655 |
t0 = time.time()
|
| 656 |
|
|
|
|
| 674 |
|
| 675 |
if iter_num % 10 == 0:
|
| 676 |
dt = time.time() - t0
|
| 677 |
+
print(f"Iter {iter_num}: Loss {loss.item()*gradient_accumulation_steps:.4f}, Time {dt*1000:.2f}ms, LR {lr:.2e}")
|
| 678 |
t0 = time.time()
|
| 679 |
|
| 680 |
if iter_num > 0 and iter_num % save_interval == 0:
|
|
|
|
| 690 |
}
|
| 691 |
torch.save(checkpoint_data, save_path)
|
| 692 |
|
| 693 |
+
print(f"💾 Finetuning done. Saving SmaLLMPro...")
|
| 694 |
final_checkpoint = {
|
| 695 |
'model': model.state_dict() if not compile else model._orig_mod.state_dict(),
|
| 696 |
'model_args': checkpoint['model_args'],
|
|
|
|
| 707 |
import tiktoken
|
| 708 |
from model import GPTConfig, GPT
|
| 709 |
|
| 710 |
+
ckpt_path = '/home/user/350m_SmaLLMPro_Final/SmaLLMPro_iter_1500.pt'
|
|
|
|
| 711 |
device = 'cuda'
|
| 712 |
enc = tiktoken.get_encoding("gpt2")
|
| 713 |
|
| 714 |
+
print("Loading SmaLLMPro model checkpoint...")
|
| 715 |
checkpoint = torch.load(ckpt_path, map_location=device)
|
| 716 |
gptconf = GPTConfig(**checkpoint['model_args'])
|
| 717 |
model = GPT(gptconf)
|
| 718 |
+
|
| 719 |
+
state_dict = checkpoint['model']
|
| 720 |
+
unwanted_prefix = '_orig_mod.'
|
| 721 |
+
for k,v in list(state_dict.items()):
|
| 722 |
+
if k.startswith(unwanted_prefix):
|
| 723 |
+
state_dict[k[len(unwanted_prefix):]] = state_dict.pop(k)
|
| 724 |
+
|
| 725 |
+
model.load_state_dict(state_dict)
|
| 726 |
model.eval()
|
| 727 |
model.to(device)
|
| 728 |
+
print(f"Model {ckpt_path} ready!\n")
|
| 729 |
|
| 730 |
def run_chat():
|
| 731 |
+
print("--- SmaLLMPro Chatbot (Type 'exit' to leave) ---")
|
|
|
|
|
|
|
| 732 |
|
| 733 |
while True:
|
| 734 |
user_input = input("You: ")
|
| 735 |
+
if user_input.lower() in ["exit", "quit"]:
|
| 736 |
break
|
| 737 |
|
| 738 |
+
prompt = f"Instruction:\n{user_input}\n\nResponse:\n"
|
| 739 |
|
| 740 |
x = torch.tensor(enc.encode(prompt), dtype=torch.long, device=device)[None, ...]
|
| 741 |
|
| 742 |
print("SmaLLMPro: ", end="", flush=True)
|
| 743 |
with torch.no_grad():
|
| 744 |
with torch.amp.autocast(device_type='cuda', dtype=torch.bfloat16):
|
| 745 |
+
y = model.generate(x, max_New_tokens=256, temperature=0.4, top_k=25)
|
| 746 |
full_text = enc.decode(y[0].tolist())
|
| 747 |
|
| 748 |
+
response = full_text.split("Response:\n")[-1].split("<|endoftext|>")[0].strip()
|
| 749 |
print(response + "\n")
|
| 750 |
|
| 751 |
if __name__ == "__main__":
|