OpenSoftware-World-OSW1 / model_init.py
OpenSoftware-World's picture
Initialization code for the OpenSoftware-World-OSW1 AI model. (This code was written by Claude and edited by OpenSoftware-World.)
30b1619 verified
Raw
History Blame
8.08 kB
import os
import re
import sys
import glob
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
NUM_THREADS = os.cpu_count() or 4
torch.set_num_threads(NUM_THREADS)
try:
torch.set_num_interop_threads(max(1, NUM_THREADS // 2))
except RuntimeError:
pass
DEVICE = torch.device("cpu")
print(f"๐Ÿงต Number of CPU threads : {NUM_THREADS}")
TOKEN_RE = re.compile(r"\w+|[^\w\s]", re.UNICODE)
def tokenize(text: str):
return TOKEN_RE.findall(text.lower())
class Vocab:
PAD, UNK, BOS, EOS = "<pad>", "<unk>", "<bos>", "<eos>"
def __init__(self):
self.stoi = {}
self.itos = []
def encode(self, text, add_bos=False, add_eos=False):
ids = [self.stoi.get(t, self.stoi[Vocab.UNK]) for t in tokenize(text)]
if add_bos:
ids = [self.stoi[Vocab.BOS]] + ids
if add_eos:
ids = ids + [self.stoi[Vocab.EOS]]
return ids
def decode(self, ids):
toks = [self.itos[i] for i in ids if 0 <= i < len(self.itos)]
toks = [t for t in toks if t != Vocab.PAD and t != Vocab.BOS]
out = []
for t in toks:
if t == Vocab.EOS:
break
out.append(t)
text = " ".join(out)
text = re.sub(r"\s+([.,!?;:])", r"\1", text)
return text
def __len__(self):
return len(self.itos)
class CausalSelfAttention(nn.Module):
def __init__(self, d_model, n_head, dropout):
super().__init__()
assert d_model % n_head == 0, "d_model must be evenly divisible by n_head"
self.n_head = n_head
self.head_dim = d_model // n_head
self.qkv = nn.Linear(d_model, 3 * d_model)
self.proj = nn.Linear(d_model, d_model)
self.attn_drop = nn.Dropout(dropout)
self.resid_drop = nn.Dropout(dropout)
def forward(self, x, attn_mask):
B, T, C = x.shape
qkv = self.qkv(x)
q, k, v = qkv.split(C, dim=2)
q = q.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
k = k.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
v = v.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
att = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
att = att.masked_fill(attn_mask, float("-inf"))
att = F.softmax(att, dim=-1)
att = self.attn_drop(att)
out = att @ v
out = out.transpose(1, 2).contiguous().view(B, T, C)
return self.resid_drop(self.proj(out))
class TransformerBlock(nn.Module):
def __init__(self, d_model, n_head, d_ff, dropout):
super().__init__()
self.ln1 = nn.LayerNorm(d_model)
self.attn = CausalSelfAttention(d_model, n_head, dropout)
self.ln2 = nn.LayerNorm(d_model)
self.mlp = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(),
nn.Linear(d_ff, d_model),
nn.Dropout(dropout),
)
def forward(self, x, attn_mask):
x = x + self.attn(self.ln1(x), attn_mask)
x = x + self.mlp(self.ln2(x))
return x
class OSW1Model(nn.Module):
def __init__(self, vocab_size, cfg: dict, pad_id: int):
super().__init__()
self.cfg = cfg
self.pad_id = pad_id
self.block_size = cfg["block_size"]
self.tok_emb = nn.Embedding(vocab_size, cfg["d_model"])
self.pos_emb = nn.Embedding(cfg["block_size"], cfg["d_model"])
self.drop = nn.Dropout(cfg["dropout"])
self.blocks = nn.ModuleList([
TransformerBlock(cfg["d_model"], cfg["n_head"], cfg["d_ff"], cfg["dropout"])
for _ in range(cfg["n_layer"])
])
self.ln_f = nn.LayerNorm(cfg["d_model"])
self.head = nn.Linear(cfg["d_model"], vocab_size, bias=False)
self.head.weight = self.tok_emb.weight # weight tying
def forward(self, idx):
B, T = idx.shape
pos = torch.arange(T, device=idx.device).unsqueeze(0)
x = self.drop(self.tok_emb(idx) + self.pos_emb(pos))
mask = torch.triu(torch.ones(T, T, dtype=torch.bool, device=idx.device), diagonal=1)
for block in self.blocks:
x = block(x, mask)
x = self.ln_f(x)
return self.head(x)
@torch.no_grad()
def generate(self, idx, max_new_tokens, temperature=0.85, top_k=40, eos_id=None):
self.eval()
for _ in range(max_new_tokens):
idx_cond = idx[:, -self.block_size:]
logits = self(idx_cond)
logits = logits[:, -1, :] / max(temperature, 1e-5)
if top_k is not None:
v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
logits[logits < v[:, [-1]]] = float("-inf")
probs = F.softmax(logits, dim=-1)
next_id = torch.multinomial(probs, num_samples=1)
idx = torch.cat([idx, next_id], dim=1)
if eos_id is not None and next_id.item() == eos_id:
break
return idx
def find_checkpoint():
candidates = glob.glob("opensoftware_world_osw1_*.pth")
if not candidates:
return None
candidates.sort(key=os.path.getmtime, reverse=True)
return candidates[0]
def load_checkpoint(path: str):
print(f"๐Ÿ“ฆ Loading: {path}")
ckpt = torch.load(path, map_location="cpu")
cfg = ckpt["config"]
vocab = Vocab()
vocab.stoi = ckpt["vocab_stoi"]
vocab.itos = ckpt["vocab_itos"]
pad_id = ckpt["pad_id"]
model = OSW1Model(len(vocab), cfg, pad_id=pad_id).to(DEVICE)
model.load_state_dict(ckpt["model_state_dict"])
model.eval()
param_count = ckpt.get("param_count", sum(p.numel() for p in model.parameters()))
training_time = ckpt.get("training_time_sec", None)
final_loss = ckpt.get("final_loss", None)
print("\n" + "=" * 64)
print("๐Ÿง  OpenSoftware-World OSW1 โ€” LOADED MODEL INFORMATION")
print("=" * 64)
print(f" File : {path}")
print(f" Vocab size : {len(vocab):,}")
print(f" Number of parameters : {param_count:,}")
print(f" d_model / n_layer : {cfg['d_model']} / {cfg['n_layer']}")
print(f" n_head / d_ff : {cfg['n_head']} / {cfg['d_ff']}")
print(f" Context window : {cfg['block_size']}")
if training_time is not None:
print(f" Training time : {training_time/60:.2f} minutes")
if final_loss is not None:
print(f" Final training loss : {final_loss:.4f}")
print("=" * 64 + "\n")
return model, vocab, cfg
def chat_loop(model: OSW1Model, vocab: Vocab):
print("=" * 64)
print("๐Ÿ’ฌ OSW1 ready! You can start chatting. Type 'exit' to quit.")
print("=" * 64)
eos_id = vocab.stoi[Vocab.EOS]
bos_id = vocab.stoi[Vocab.BOS]
while True:
try:
user_in = input("\nYou: ").strip()
except (EOFError, KeyboardInterrupt):
print("\n๐Ÿ‘‹ Goodbye!")
break
if user_in.lower() in ("exit", "quit"):
print("๐Ÿ‘‹ Goodbye!")
break
if not user_in:
continue
ids = [bos_id] + vocab.encode(user_in)
x = torch.tensor([ids], dtype=torch.long)
out = model.generate(x, max_new_tokens=60, temperature=0.85, top_k=40, eos_id=eos_id)
answer_ids = out[0, len(ids):].tolist()
answer = vocab.decode(answer_ids)
print(f"OSW1: {answer if answer else '(...silence...)'}")
def main():
if len(sys.argv) > 1:
ckpt_path = sys.argv[1]
if not os.path.isfile(ckpt_path):
print(f"โŒ File not found: {ckpt_path}")
sys.exit(1)
else:
ckpt_path = find_checkpoint()
if ckpt_path is None:
print(
"โŒ No checkpoint files found in the directory.\n"
" Please train a model using 'python train_osw1.py' or\n"
" specify a checkpoint file using 'python model_init.py <file_path>'."
)
sys.exit(1)
model, vocab, cfg = load_checkpoint(ckpt_path)
chat_loop(model, vocab)
if __name__ == "__main__":
main()