This commit is contained in:
ALicja 2026-01-26 16:19:15 +01:00
parent cb94d35f24
commit 21c797bd96
11 changed files with 2736 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 577b442bafdd8a1f21cfb42816627fb7e0daedf2

1247
ai.py Normal file

File diff suppressed because it is too large Load Diff

198
clay_manager.py Normal file
View File

@ -0,0 +1,198 @@
#!/usr/bin/env python3
"""
🛠 Clay Checkpoint Manager - CLI do zarządzania checkpointami
"""
import argparse
import json
import shutil
from pathlib import Path
from datetime import datetime
from config import cfg
def list_checkpoints():
"""Wyświetla dostępne checkpointy"""
checkpoints = list(Path(cfg.checkpoints_dir).glob("clay_checkpoint_*.pt"))
if not checkpoints:
print("❌ Brak checkpointów")
return
print(f"\n📁 CLAY CHECKPOINTS ({len(checkpoints)}):")
print("=" * 80)
for cp in sorted(checkpoints, key=lambda x: x.stat().st_mtime, reverse=True):
# Wczytaj info z JSON
json_file = cp.with_suffix('.json')
if json_file.exists():
with open(json_file, 'r') as f:
info = json.load(f)['checkpoint_info']
size_mb = info['file_size'] / (1024 * 1024)
print(f"📄 {cp.name}")
print(f" • Epoka: {info['epoch']} | Krok: {info['step']:,}")
print(f" • Loss: {info['loss']:.4f} | Rozmiar: {size_mb:.1f}MB")
print(f" • Data: {info['timestamp']}")
print("-" * 40)
else:
size_mb = cp.stat().st_size / (1024 * 1024)
print(f"📄 {cp.name} ({size_mb:.1f}MB)")
def show_training_stats():
"""Pokazuje statystyki treningu"""
stats_file = Path(cfg.checkpoints_dir) / "training_stats.json"
if stats_file.exists():
with open(stats_file, 'r') as f:
stats = json.load(f)
print("\n📊 STATYSTYKI TRENINGU:")
print("=" * 60)
total_time = stats.get('total_time', 0)
hours = total_time / 3600
minutes = (total_time % 3600) / 60
print(f" • Całkowity czas: {hours:.0f}h {minutes:.0f}m")
print(f" • Ostatni loss: {stats.get('final_loss', 0):.4f}")
print(f" • Najlepszy loss: {stats.get('best_loss', 0):.4f}")
print(f" • Średni loss: {stats.get('avg_loss', 0):.4f}")
print(f" • Sprawdzone kroki: {stats.get('total_steps', 0):,}")
print(f" • Zakończono: {stats.get('completion_time', 'N/A')}")
else:
print("❌ Brak statystyk treningu")
def cleanup_checkpoints(keep=5):
"""Czyści stare checkpointy"""
checkpoints = list(Path(cfg.checkpoints_dir).glob("clay_checkpoint_*.pt"))
if len(checkpoints) <= keep:
print(f"✅ Wszystkie checkpointy zachowane (mniej niż {keep})")
return
checkpoints.sort(key=lambda x: x.stat().st_mtime)
to_delete = checkpoints[:-keep]
print(f"\n🗑️ Usuwanie {len(to_delete)} starych checkpointów:")
total_freed = 0
for cp in to_delete:
size_mb = cp.stat().st_size / (1024 * 1024)
total_freed += size_mb
print(f"{cp.name} ({size_mb:.1f}MB)")
cp.unlink()
# Usuń też JSON
json_file = cp.with_suffix('.json')
if json_file.exists():
json_file.unlink()
print(f"\n✅ Zachowano {keep} najnowszych checkpointów")
print(f"💰 Zwolniono {total_freed:.1f}MB")
def export_checkpoint(checkpoint_name, export_dir="exports"):
"""Eksportuje checkpoint do osobnego folderu"""
cp_path = Path(cfg.checkpoints_dir) / checkpoint_name
if not cp_path.exists():
print(f"❌ Checkpoint {checkpoint_name} nie istnieje")
return
# Stwórz folder eksportu
export_path = Path(export_dir)
export_path.mkdir(exist_ok=True)
# Skopiuj checkpoint i JSON
dest_path = export_path / checkpoint_name
shutil.copy2(cp_path, dest_path)
json_file = cp_path.with_suffix('.json')
if json_file.exists():
shutil.copy2(json_file, export_path / json_file.name)
print(f"✅ Checkpoint wyeksportowany do: {dest_path}")
def show_checkpoint_info(checkpoint_name):
"""Pokazuje szczegółowe info o checkpoincie"""
cp_path = Path(cfg.checkpoints_dir) / checkpoint_name
if not cp_path.exists():
print(f"❌ Checkpoint {checkpoint_name} nie istnieje")
return
json_file = cp_path.with_suffix('.json')
if json_file.exists():
with open(json_file, 'r') as f:
info = json.load(f)
print(f"\n📋 INFO O CHECKPOINCIE: {checkpoint_name}")
print("=" * 60)
cp_info = info['checkpoint_info']
stats = info['training_stats']
print("📁 PODSTAWOWE INFORMACJE:")
print(f" • Epoka: {cp_info['epoch']}")
print(f" • Krok: {cp_info['step']:,}")
print(f" • Loss: {cp_info['loss']:.4f}")
print(f" • Rozmiar: {cp_info['file_size'] / (1024 * 1024):.1f}MB")
print(f" • Data: {cp_info['timestamp']}")
print("\n📊 STATYSTYKI TRENINGU:")
print(f" • Całkowity czas: {stats['total_time']:.0f}s")
print(f" • Średni loss: {stats['avg_loss']:.4f}")
print(f" • Current LR: {stats['current_lr']:.6f}")
print(f" • Kroki: {stats['steps_done']:,}")
else:
print("❌ Brak informacji JSON dla tego checkpointu")
def main():
parser = argparse.ArgumentParser(description="Clay Checkpoint Manager")
parser.add_argument("--list", action="store_true", help="Lista checkpointów")
parser.add_argument("--stats", action="store_true", help="Pokaż statystyki")
parser.add_argument("--cleanup", type=int, nargs='?', const=5, help="Wyczyść stare checkpointy (domyślnie: 5)")
parser.add_argument("--export", type=str, help="Eksportuj checkpoint")
parser.add_argument("--info", type=str, help="Info o konkretnym checkpoincie")
parser.add_argument("--export-all", action="store_true", help="Eksportuj wszystkie checkpointy")
args = parser.parse_args()
if args.list:
list_checkpoints()
elif args.stats:
show_training_stats()
elif args.cleanup is not None:
cleanup_checkpoints(args.cleanup)
elif args.export:
export_checkpoint(args.export)
elif args.info:
show_checkpoint_info(args.info)
elif args.export_all:
checkpoints = list(Path(cfg.checkpoints_dir).glob("clay_checkpoint_*.pt"))
for cp in checkpoints:
export_checkpoint(cp.name)
else:
print("\n🛠️ Clay Checkpoint Manager")
print("=" * 40)
print("Użyj:")
print(" --list # Lista checkpointów")
print(" --stats # Statystyki treningu")
print(" --cleanup [N] # Zostaw N najnowszych (domyślnie 5)")
print(" --export NAME # Eksportuj checkpoint")
print(" --info NAME # Info o checkpoincie")
print(" --export-all # Eksportuj wszystkie")
print("\nPrzykłady:")
print(" python clay_manager.py --list")
print(" python clay_manager.py --cleanup 3")
print(" python clay_manager.py --info clay_checkpoint_ep2_step5000_20240126_143022.pt")
if __name__ == "__main__":
main()

214
config.py Normal file
View File

@ -0,0 +1,214 @@
"""
🎯 CONFIG - Wspólna konfiguracja dla MiniGPT-60M
"""
import os
import sys
import random
import numpy as np
import torch
from pathlib import Path
from typing import List, Dict, Any, Optional
import logging
import json
# ==================== LOGGING ====================
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('training.log', encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# ==================== KONFIGURACJA SYSTEMU ====================
class SystemConfig:
"""Konfiguracja systemu i urządzeń"""
def __init__(self):
self.device = self._get_device()
self.set_seeds(42)
self._print_info()
def _get_device(self) -> str:
"""Automatycznie wybiera najlepsze urządzenie"""
if torch.cuda.is_available():
return "cuda"
elif torch.backends.mps.is_available():
return "mps"
else:
return "cpu"
def set_seeds(self, seed: int = 42):
"""Ustawia seed dla reprodukowalności"""
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
def _print_info(self):
"""Wyświetla informacje o systemie"""
logger.info("=" * 60)
logger.info("🎯 SYSTEM MINIGPT-60M")
logger.info("=" * 60)
logger.info(f"Python: {sys.version.split()[0]}")
logger.info(f"PyTorch: {torch.__version__}")
logger.info(f"Device: {self.device.upper()}")
if self.device == "cuda":
gpu_count = torch.cuda.device_count()
logger.info(f"CUDA dostępne: {torch.cuda.is_available()}")
logger.info(f"Liczba GPU: {gpu_count}")
for i in range(gpu_count):
mem = torch.cuda.get_device_properties(i).total_memory / 1e9
logger.info(f"GPU {i}: {torch.cuda.get_device_name(i)} ({mem:.1f} GB)")
logger.info("=" * 60)
# ==================== KONFIGURACJA MODELU ====================
class ModelConfig:
"""Konfiguracja modelu 60M parametrów"""
def __init__(self):
# Słownik
self.vocab_chars = list("aąbcćdeęfghijklłmnńoóprsśtuwyzźżAĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ")
self.vocab_chars += list("0123456789")
self.vocab_chars += list(" .,?!:;()[]{}+-*/=<>_\"'`~@#$%^&|\\/\n\t")
self.vocab_chars += [" ", "\n\n", "\t\t", "->", "::", "=>"]
self.vocab = self.vocab_chars
self.vocab_size = len(self.vocab)
# Architektura dla ~60M parametrów
self.embed_dim = 768
self.n_layers = 12
self.n_heads = 12
self.max_len = 512
self.ff_dim = self.embed_dim * 4
self.dropout = 0.1
self.activation = "gelu"
self.norm_eps = 1e-5
# Trening
self.epochs = 3
self.batch_size = 16 if torch.cuda.is_available() else 4
self.grad_accum_steps = 4
self.learning_rate = 3e-4
self.weight_decay = 0.1
self.adam_beta1 = 0.9
self.adam_beta2 = 0.95
self.adam_eps = 1e-8
self.clip_grad = 1.0
self.warmup_steps = 2000
# Mixed Precision
self.use_amp = torch.cuda.is_available()
# Parallel
self.num_workers = 4 if torch.cuda.is_available() else 0
self.pin_memory = True
# Generowanie
self.generation_temperature = 0.8
self.top_k = 50
self.top_p = 0.95
self.repetition_penalty = 1.1
# Ścieżki
self.model_dir = "models"
self.data_dir = "data"
self.prepared_dir = "prepared_data"
self.log_dir = "logs"
self.tensorboard_dir = "runs"
self.cache_dir = ".cache"
self.checkpoints_dir = "checkpoints"
self.resume_file = "resume_state.json" # Plik stanu do wznowienia
# Tworzenie katalogów
self._create_dirs()
def _create_dirs(self):
"""Tworzy wymagane katalogi"""
dirs = [self.model_dir, self.data_dir, self.prepared_dir,
self.log_dir, self.tensorboard_dir, self.cache_dir,
"backups", "results", self.checkpoints_dir]
for d in dirs:
Path(d).mkdir(parents=True, exist_ok=True)
def print_config(self):
"""Wyświetla konfigurację"""
logger.info("=" * 60)
logger.info("⚙️ KONFIGURACJA MODELU")
logger.info("=" * 60)
logger.info(f"• Vocab size: {self.vocab_size}")
logger.info(f"• Embed dim: {self.embed_dim}")
logger.info(f"• Warstwy: {self.n_layers}")
logger.info(f"• Głowy: {self.n_heads}")
logger.info(f"• Kontekst: {self.max_len}")
logger.info(f"• Batch size: {self.batch_size}")
logger.info(f"• Learning rate: {self.learning_rate}")
logger.info(f"• Mixed precision: {self.use_amp}")
logger.info("=" * 60)
def save_resume_state(self, state: Dict[str, Any]):
"""Zapisuje stan do wznowienia"""
state_path = Path(self.checkpoints_dir) / self.resume_file
with open(state_path, 'w', encoding='utf-8') as f:
json.dump(state, f, indent=2, ensure_ascii=False)
logger.info(f"💾 Stan zapisany do {state_path}")
def load_resume_state(self) -> Optional[Dict[str, Any]]:
"""Wczytuje stan do wznowienia"""
state_path = Path(self.checkpoints_dir) / self.resume_file
if state_path.exists():
with open(state_path, 'r', encoding='utf-8') as f:
return json.load(f)
return None
def get_latest_checkpoint(self) -> Optional[Path]:
"""Znajduje najnowszy checkpoint"""
checkpoints = list(Path(self.checkpoints_dir).glob("checkpoint_*.pt"))
if checkpoints:
# Sortuj po czasie modyfikacji
checkpoints.sort(key=lambda x: x.stat().st_mtime, reverse=True)
return checkpoints[0]
return None
def get_latest_model(self) -> Optional[Path]:
"""Znajduje najnowszy model"""
models = list(Path(self.model_dir).glob("model_*.pt"))
if models:
# Szukaj model_final.pt, potem model_epoch_X.pt
final_model = Path(self.model_dir) / "model_final.pt"
if final_model.exists():
return final_model
# Sortuj po numerze epoki
def get_epoch_num(path: Path) -> int:
try:
# model_epoch_10.pt -> 10
name = path.stem
return int(name.split('_')[-1])
except:
return 0
models.sort(key=get_epoch_num, reverse=True)
return models[0]
return None
def get_device(prefer_gpu=True):
"""Inteligentnie wybiera urządzenie"""
if prefer_gpu and torch.cuda.is_available():
return 'cuda'
elif torch.backends.mps.is_available(): # Apple Silicon
return 'mps'
else:
return 'cpu'
# Inicjalizacja konfiguracji
sys_config = SystemConfig()
cfg = ModelConfig()

41
daj_no_Plik.py Normal file
View File

@ -0,0 +1,41 @@
# daj_no_Plik.py (wersja lokalna)
import os
import zipfile
import requests
from pathlib import Path
def download_from_url(url, save_path):
"""Pobiera plik z URL"""
print(f"Pobieranie z {url}...")
response = requests.get(url, stream=True)
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Zapisano do {save_path}")
def main():
# Jeśli masz plik .zip na dysku
zip_path = "/ścieżka/do/Pathl_AI.zip"
if os.path.exists(zip_path):
print("Rozpakowywanie...")
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall("Pathl.AI")
print("✅ Gotowe!")
else:
print("❌ Plik nie istnieje")
print("\n📥 Pobierz plik z Google Colab:")
print("1. W Colab uruchom:")
print(" from google.colab import files")
print(" files.download('/content/Pathl_AI.zip')")
print("2. Pobierz plik na komputer")
print("3. Uruchom ten skrypt ponownie")
if __name__ == "__main__":
print("plik")
main()

108
final_fix.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
"""Ostateczna poprawka metody generate()"""
import re
with open('ai.py', 'r') as f:
content = f.read()
# Nowa, uniwersalna metoda generate
new_generate_method = '''
def generate(self, input_ids=None, max_length=100, temperature=1.0, **kwargs):
"""Uniwersalna metoda generate obsługująca różne interfejsy"""
# Ignoruj nieobsługiwane argumenty (device, max_len, etc.)
max_len = kwargs.get('max_len', max_length)
if isinstance(input_ids, str):
return self.generate_text(input_ids, max_len=max_len, temperature=temperature)
elif input_ids is not None:
# Jeśli to tensor, przekonwertuj na tekst
if hasattr(input_ids, 'tolist'):
if len(input_ids.shape) > 1:
text = self.tokenizer.decode(input_ids[0].tolist())
else:
text = self.tokenizer.decode(input_ids.tolist())
else:
text = self.tokenizer.decode(input_ids)
return self.generate_text(text, max_len=max_len, temperature=temperature)
else:
return "" # Pusty string dla None input
'''
# Znajdź i zamień metodę generate
if 'def generate(' in content:
# Użyj regex do znalezienia całej metody
pattern = r'def generate\(.*?\).*?(?=\n def \w+\(|\nclass \w+|\Z)'
# Sprawdź czy regex działa
match = re.search(pattern, content, re.DOTALL)
if match:
content = re.sub(pattern, new_generate_method, content, flags=re.DOTALL)
print("✅ Zaktualizowano metodę generate()")
else:
# Alternatywny sposób: znajdź między def generate a następną def
lines = content.split('\n')
new_lines = []
i = 0
while i < len(lines):
line = lines[i]
new_lines.append(line)
if line.strip().startswith('def generate('):
# Pomijaj stare linie metody aż do następnej metody
i += 1
while i < len(lines) and not lines[i].strip().startswith('def ') and not lines[i].strip().startswith('class '):
i += 1
# Dodaj nową metodę
new_lines.append(new_generate_method)
if i < len(lines):
new_lines.append(lines[i])
i += 1
continue
i += 1
content = '\n'.join(new_lines)
print("✅ Zastąpiono metodę generate() (alternatywna metoda)")
else:
print("❌ Metoda generate() nie znaleziona, dodaję...")
# Dodaj przed ostatnią metodą w klasie
if 'class MiniGPT60M' in content:
# Wstaw przed ostatnim 'def' w klasie
lines = content.split('\n')
new_lines = []
in_class = False
methods_found = []
for i, line in enumerate(lines):
new_lines.append(line)
if 'class MiniGPT60M' in line:
in_class = True
if in_class and line.strip().startswith('def '):
methods_found.append(i)
if methods_found:
# Dodaj przed ostatnią metodą
last_method_idx = methods_found[-1]
new_lines.insert(last_method_idx, '\n' + new_generate_method)
content = '\n'.join(new_lines)
print("✅ Dodano metodę generate()")
else:
# Dodaj na końcu klasy
if 'class MiniGPT60M' in content:
# Znajdź koniec klasy
class_pattern = r'(class MiniGPT60M.*?)(?=\nclass|\Z)'
match = re.search(class_pattern, content, re.DOTALL)
if match:
class_content = match.group(1)
updated_class = class_content.rstrip() + '\n\n' + new_generate_method
content = content.replace(class_content, updated_class)
print("✅ Dodano metodę generate() na końcu klasy")
# Zapisz zmiany
with open('ai.py', 'w') as f:
f.write(content)
print("✅ Plik ai.py zaktualizowany!")

314
main.py Normal file
View File

@ -0,0 +1,314 @@
"""
🎯 MAIN - Główny skrypt MiniGPT-60M z checkpointami
"""
import os
import sys
import argparse
import signal
from pathlib import Path
# Dodaj ścieżkę do importów
sys.path.append('.')
from config import logger, cfg, sys_config
import prepare_data
import ai
# ==================== OBSŁUGA SYGNAŁÓW ====================
def signal_handler(sig, frame):
"""Obsługa przerwania (Ctrl+C)"""
logger.info("\n\n⚠️ Trening przerwany przez użytkownika!")
logger.info("💾 Zapisuję stan do wznowienia...")
# Tutaj można dodać zapis stanu przed wyjściem
# W aktualnej implementacji stan jest zapisywany automatycznie
logger.info("✅ Możesz wznowić trening używając: python main.py --cont")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
# ==================== FUNKCJE GŁÓWNE ====================
def prepare_all_data():
"""Przygotowuje wszystkie dane"""
logger.info("=" * 60)
logger.info("📊 PRZYGOTOWYWANIE WSZYSTKICH DANYCH")
logger.info("=" * 60)
preparer = prepare_data.DataPreparer()
preparer.prepare_all_data()
def train_model(resume: bool = False):
"""Trenuje model"""
logger.info("=" * 60)
if resume:
logger.info("🔄 WZNIOWANIE TRENINGU MODELU")
else:
logger.info("🚀 TRENING MODELU MINIGPT-60M")
logger.info("=" * 60)
# Sprawdź czy dane są przygotowane
data_file = Path(cfg.prepared_dir) / "all_data.txt"
if not data_file.exists():
logger.warning("⚠️ Brak przygotowanych danych. Przygotowuję...")
prepare_all_data()
# Uruchom trening
if resume:
ai.continue_training()
else:
ai.train_model(resume=False)
def continue_training():
"""Kontynuuje trening od ostatniego checkpointu"""
train_model(resume=True)
def train_more_epochs(additional_epochs: int = 3):
"""Dodaje więcej epok treningu"""
logger.info("=" * 60)
logger.info(f"📈 DODATKOWY TRENING: {additional_epochs} epok")
logger.info("=" * 60)
# Sprawdź czy dane są przygotowane
data_file = Path(cfg.prepared_dir) / "all_data.txt"
if not data_file.exists():
logger.error("❌ Brak przygotowanych danych!")
logger.info("💡 Uruchom: python main.py --prepare")
return
# Uruchom dodatkowy trening
ai.train_more_epochs(additional_epochs)
def generate_text(prompt: str):
"""Generuje tekst"""
logger.info(f"🎨 GENEROWANIE TEKSTU: '{prompt}'")
ai.generate_text(prompt)
def start_chat():
"""Uruchamia czat"""
ai.start_chat()
def evaluate_model():
"""Ocenia model"""
logger.info("🎯 OCENA MODELU")
# Sprawdź czy model istnieje
model_path = cfg.get_latest_model()
if not model_path:
logger.error("❌ Brak wytrenowanego modelu!")
logger.info("💡 Uruchom: python main.py --train")
return
logger.info(f"✅ Model wczytany: {model_path.name}")
# Tutaj można dodać ewaluację
logger.info("📊 Dodaj ewaluację w ai.py")
def show_checkpoints():
"""Pokazuje dostępne checkpointy"""
logger.info("📁 DOSTĘPNE CHECKPOINTY:")
checkpoints = list(Path(cfg.checkpoints_dir).glob("checkpoint_*.pt"))
models = list(Path(cfg.model_dir).glob("model_*.pt"))
if checkpoints:
logger.info("\n🔽 CHECKPOINTY (do wznowienia):")
for cp in sorted(checkpoints, key=lambda x: x.stat().st_mtime, reverse=True)[:5]:
size_mb = cp.stat().st_size / (1024 * 1024)
logger.info(f"{cp.name} ({size_mb:.1f} MB)")
else:
logger.info(" ❌ Brak checkpointów")
if models:
logger.info("\n🤖 MODELE:")
for model in sorted(models, key=lambda x: x.stat().st_mtime, reverse=True)[:5]:
size_mb = model.stat().st_size / (1024 * 1024)
logger.info(f"{model.name} ({size_mb:.1f} MB)")
# Sprawdź stan resume
resume_state = cfg.load_resume_state()
if resume_state:
logger.info(f"\n🔄 OSTATNI STAN TRENINGU:")
logger.info(f" • Epoka: {resume_state.get('epoch', 'N/A')}")
logger.info(f" • Krok: {resume_state.get('step', 'N/A')}")
logger.info(f" • Loss: {resume_state.get('train_loss', 'N/A')}")
def clean_checkpoints(keep_last: int = 3):
"""Czyści stare checkpointy"""
logger.info(f"🧹 CZYSZCZENIE STARYCH CHECKPOINTÓW (zachowuję {keep_last} najnowszych)")
checkpoints = list(Path(cfg.checkpoints_dir).glob("checkpoint_*.pt"))
if len(checkpoints) <= keep_last:
logger.info("✅ Nie ma czego czyścić")
return
# Sortuj od najstarszego do najnowszego
checkpoints.sort(key=lambda x: x.stat().st_mtime)
# Usuń wszystkie poza keep_last najnowszych
to_delete = checkpoints[:-keep_last]
for cp in to_delete:
try:
cp.unlink()
logger.info(f" 🗑️ Usunięto: {cp.name}")
except Exception as e:
logger.error(f" ❌ Błąd usuwania {cp.name}: {e}")
logger.info(f"✅ Pozostawiono {keep_last} najnowszych checkpointów")
def show_config():
"""Pokazuje konfigurację"""
cfg.print_config()
def run_tests():
"""Uruchamia testy"""
logger.info("🧪 TESTY JEDNOSTKOWE")
# Test tokenizera
from ai import tokenizer
text = "Test tokenizacji"
ids = tokenizer.encode(text)
decoded = tokenizer.decode(ids)
logger.info(f"✅ Tokenizer: '{text}' -> '{decoded}'")
# Test modelu
import torch
model = ai.MiniGPT60M()
x = torch.randint(0, cfg.vocab_size, (2, 32))
logits = model(x)
logger.info(f"✅ Model: logits shape {logits.shape}")
logger.info("✅ Wszystkie testy przeszły pomyślnie!")
# ==================== GŁÓWNA FUNKCJA ====================
def main():
"""Główna funkcja programu"""
parser = argparse.ArgumentParser(
description="🎯 MiniGPT-60M: Zaawansowany model językowy ~60M parametrów",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Przykłady użycia:
python main.py --prepare # Przygotuj dane ze wszystkich folderów data_*
python main.py --train # Trenuj model od początku
python main.py --cont # Wznów trening od ostatniego checkpointu
python main.py --more [N] # Dodaj N epok treningu (domyślnie 3)
python main.py --generate "AI" # Generuj tekst
python main.py --chat # Rozmawiaj z modelem
python main.py --checkpoints # Pokaż dostępne checkpointy
python main.py --clean-cp # Wyczyść stare checkpointy
python main.py --test # Uruchom testy
python main.py --config # Pokaż konfigurację
python main.py --evaluate # Oceń model
python main.py --all # Przygotuj dane i trenuj od początku
Kontynuacja treningu:
Rozpocznij trening: python main.py --train
Przerwij (Ctrl+C): Zapisz stan automatycznie
Wznów: python main.py --cont
Dodaj epoki: python main.py --more 5
"""
)
parser.add_argument("--prepare", action="store_true", help="Przygotuj dane")
parser.add_argument("--train", action="store_true", help="Trening od początku")
parser.add_argument("--cont", action="store_true", help="Kontynuuj trening od checkpointu")
parser.add_argument("--more", type=int, nargs='?', const=3, help="Dodaj epoki treningu (domyślnie 3)")
parser.add_argument("--generate", type=str, help="Generuj tekst z promptu")
parser.add_argument("--chat", action="store_true", help="Tryb rozmowy")
parser.add_argument("--checkpoints", action="store_true", help="Pokaż dostępne checkpointy")
parser.add_argument("--clean-cp", action="store_true", help="Wyczyść stare checkpointy")
parser.add_argument("--test", action="store_true", help="Testy jednostkowe")
parser.add_argument("--config", action="store_true", help="Pokaż konfigurację")
parser.add_argument("--evaluate", action="store_true", help="Oceń model")
parser.add_argument("--all", action="store_true", help="Przygotuj dane i trenuj")
parser.add_argument("--epochs", type=int, default=cfg.epochs, help="Liczba epok")
parser.add_argument("--model", type=str, help="Ścieżka do konkretnego modelu")
args = parser.parse_args()
# Pokaż nagłówek
logger.info("=" * 60)
logger.info("🎯 MINIGPT-60M - Z CHECKPOINTAMI")
logger.info("=" * 60)
# Update liczby epok jeśli podano
if args.epochs != cfg.epochs:
cfg.epochs = args.epochs
logger.info(f"⚙️ Ustawiono {cfg.epochs} epok")
# Uruchom odpowiednią funkcję
if args.prepare:
prepare_all_data()
elif args.train:
train_model(resume=False)
elif args.cont:
continue_training()
elif args.more is not None:
train_more_epochs(additional_epochs=args.more)
elif args.generate:
generate_text(args.generate)
elif args.chat:
start_chat()
elif args.checkpoints:
show_checkpoints()
elif args.clean_cp:
clean_checkpoints()
elif args.test:
run_tests()
elif args.config:
show_config()
elif args.evaluate:
evaluate_model()
elif args.all:
prepare_all_data()
train_model(resume=False)
else:
# Jeśli żadna flaga, pokaż help
logger.info("\n❓ Nie podano flagi. Dostępne opcje:\n")
parser.print_help()
# Pokaż dodatkowe informacje
logger.info("\n💡 PRZYKŁADY UŻYCIA:")
logger.info(" python main.py --train # Trenuj od początku")
logger.info(" [Ctrl+C] # Przerwij trening")
logger.info(" python main.py --cont # Wznów trening")
logger.info(" python main.py --more 5 # Dodaj 5 epok")
logger.info(" python main.py --generate 'AI' # Generuj tekst")
# Sprawdź czy są checkpointy
if cfg.get_latest_checkpoint():
logger.info("\n🔄 Dostępne checkpointy do wznowienia!")
logger.info("=" * 60)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
logger.info("\n\n👋 Program przerwany przez użytkownika")
sys.exit(0)
except Exception as e:
logger.error(f"\n❌ Krytyczny błąd: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

1
pik Normal file
View File

@ -0,0 +1 @@
plik

315
prepare_data.py Normal file
View File

@ -0,0 +1,315 @@
"""
📊 PREPARE_DATA - Przygotowanie danych z wielu folderów
"""
import os
import re
import json
import random
import logging
from pathlib import Path
from typing import List, Dict, Any, Generator
from concurrent.futures import ThreadPoolExecutor, as_completed
from config import logger, cfg
# ==================== KLASY DO PRZYGOTOWANIA DANYCH ====================
class DataPreparer:
"""Główna klasa do przygotowania danych"""
def __init__(self):
self.output_file = Path(cfg.prepared_dir) / "all_data.txt"
self.metadata_file = Path(cfg.prepared_dir) / "metadata.json"
self.stats = {
"total_files": 0,
"total_samples": 0,
"total_chars": 0,
"sources": {},
"errors": []
}
def find_data_folders(self) -> List[Path]:
"""Znajduje wszystkie foldery zaczynające się od 'data_'"""
current_dir = Path(".")
data_folders = []
for item in current_dir.iterdir():
if item.is_dir() and item.name.startswith("data_"):
data_folders.append(item)
logger.info(f"📁 Znaleziono folder: {item.name}")
# Dodaj też standardowy folder 'data' jeśli istnieje
if Path("data").exists():
data_folders.append(Path("data"))
return data_folders
def process_file(self, file_path: Path) -> List[str]:
"""Przetwarza pojedynczy plik i zwraca próbki"""
samples = []
try:
if file_path.suffix == '.txt':
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Różne strategie dla różnych typów plików
if "news" in file_path.name.lower() or "article" in file_path.name.lower():
# Dla newsów - podziel na akapity
paragraphs = re.split(r'\n\s*\n', content)
for para in paragraphs:
para = para.strip()
if 100 < len(para) < 5000:
samples.append(para)
elif "code" in file_path.name.lower() or "python" in file_path.name.lower():
# Dla kodu - zachowaj całe funkcje
lines = content.split('\n')
current_chunk = []
for line in lines:
line = line.strip()
if line:
current_chunk.append(line)
# Jeśli znaleziono koniec funkcji lub duży blok
if line.startswith('def ') and len(current_chunk) > 3:
samples.append('\n'.join(current_chunk))
current_chunk = []
# Dodaj pozostały chunk
if current_chunk and len('\n'.join(current_chunk)) > 50:
samples.append('\n'.join(current_chunk))
else:
# Domyślnie - podziel na linie/akapity
lines = content.split('\n')
for line in lines:
line = line.strip()
if 20 < len(line) < 1000:
samples.append(line)
elif file_path.suffix == '.json':
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
if isinstance(data, list):
for item in data:
if isinstance(item, str):
samples.append(item)
elif isinstance(item, dict):
# Konwertuj słownik na tekst
text = ' '.join([f"{k}: {v}" for k, v in item.items()])
if len(text) > 20:
samples.append(text)
elif file_path.suffix == '.csv':
import csv
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
text = ' '.join(row.values())
if len(text) > 20:
samples.append(text)
except Exception as e:
self.stats["errors"].append(f"{file_path}: {str(e)}")
return samples
def process_folder(self, folder_path: Path) -> Dict[str, Any]:
"""Przetwarza cały folder"""
folder_stats = {
"name": folder_path.name,
"files_processed": 0,
"samples_found": 0,
"samples": []
}
# Znajdź wszystkie pliki tekstowe
file_patterns = ['*.txt', '*.json', '*.csv']
files = []
for pattern in file_patterns:
files.extend(list(folder_path.rglob(pattern)))
logger.info(f" 📂 {folder_path.name}: {len(files)} plików")
# Przetwarzaj pliki równolegle
with ThreadPoolExecutor(max_workers=4) as executor:
futures = {executor.submit(self.process_file, file): file for file in files}
for future in as_completed(futures):
file = futures[future]
try:
samples = future.result()
if samples:
folder_stats["samples"].extend(samples)
folder_stats["samples_found"] += len(samples)
folder_stats["files_processed"] += 1
except Exception as e:
self.stats["errors"].append(f"{file}: {str(e)}")
return folder_stats
def prepare_all_data(self) -> None:
"""Główna funkcja przygotowania danych"""
logger.info("=" * 60)
logger.info("📊 PRZYGOTOWYWANIE DANYCH Z WSZYSTKICH FOLDERÓW")
logger.info("=" * 60)
# Znajdź foldery
data_folders = self.find_data_folders()
if not data_folders:
logger.error("❌ Nie znaleziono folderów zaczynających się od 'data_'")
return
all_samples = []
# Przetwórz każdy folder
for folder in data_folders:
logger.info(f"\n🔍 Przetwarzam folder: {folder.name}")
folder_stats = self.process_folder(folder)
if folder_stats["samples"]:
all_samples.extend(folder_stats["samples"])
self.stats["sources"][folder.name] = folder_stats["samples_found"]
logger.info(f" ✅ Znaleziono: {folder_stats['samples_found']} próbek")
logger.info(f" 📝 Przykłady:")
for sample in random.sample(folder_stats["samples"], min(3, len(folder_stats["samples"]))):
logger.info(f"{sample[:80]}...")
else:
logger.warning(f" ⚠️ Brak danych w folderze {folder.name}")
# Przetasuj i ogranicz
if all_samples:
random.shuffle(all_samples)
# Ogranicz do 1 miliona próbek (dla pamięci)
if len(all_samples) > 1000000:
all_samples = all_samples[:1000000]
logger.warning(f"⚠️ Ograniczono do 1,000,000 próbek")
# Zapisz do jednego pliku
self._save_to_file(all_samples)
# Zapisz metadane
self._save_metadata()
# Podsumowanie
self._print_summary()
else:
logger.error("❌ Nie znaleziono żadnych danych!")
def _save_to_file(self, samples: List[str]) -> None:
"""Zapisuje wszystkie dane do jednego pliku"""
logger.info(f"\n💾 Zapisuję {len(samples):,} próbek do {self.output_file}")
with open(self.output_file, 'w', encoding='utf-8') as f:
for i, sample in enumerate(samples, 1):
f.write(sample + "\n\n")
# Progress bar co 10k próbek
if i % 10000 == 0:
logger.info(f" Zapisano {i:,}/{len(samples):,} próbek")
logger.info(f"✅ Zapisano wszystkie dane do {self.output_file}")
def _save_metadata(self) -> None:
"""Zapisuje metadane"""
metadata = {
"total_samples": self.stats["total_samples"],
"total_chars": self.stats["total_chars"],
"sources": self.stats["sources"],
"created": os.path.getmtime(str(self.output_file)),
"file_size": os.path.getsize(self.output_file),
"errors": self.stats["errors"][:10] # Tylko 10 pierwszych błędów
}
with open(self.metadata_file, 'w', encoding='utf-8') as f:
json.dump(metadata, f, indent=2, ensure_ascii=False)
logger.info(f"📊 Metadane zapisane do {self.metadata_file}")
def _print_summary(self) -> None:
"""Wyświetla podsumowanie"""
logger.info("=" * 60)
logger.info("📈 PODSUMOWANIE PRZYGOTOWANIA DANYCH")
logger.info("=" * 60)
total_samples = self.stats["total_samples"]
total_chars_mb = self.stats["total_chars"] / (1024 * 1024)
logger.info(f"📊 STATYSTYKI:")
logger.info(f" • Całkowite próbki: {total_samples:,}")
logger.info(f" • Rozmiar danych: {total_chars_mb:.1f} MB")
logger.info(f" • Źródła danych: {len(self.stats['sources'])}")
logger.info(f"\n📁 ŹRÓDŁA:")
for source, count in self.stats["sources"].items():
logger.info(f"{source}: {count:,} próbek")
if self.stats["errors"]:
logger.warning(f"\n⚠️ BŁĘDY ({len(self.stats['errors'])}):")
for error in self.stats["errors"][:5]:
logger.warning(f"{error}")
logger.info(f"\n💾 WYJŚCIE:")
logger.info(f" • Dane: {self.output_file}")
logger.info(f" • Metadane: {self.metadata_file}")
logger.info("\n🎮 UŻYCIE:")
logger.info(" python main.py --train # Trening na przygotowanych danych")
logger.info(" python main.py --prepare # Ponowne przygotowanie danych")
logger.info("=" * 60)
# ==================== FUNKCJE POMOCNICZE ====================
def clean_text(text: str) -> str:
"""Czyści tekst"""
# Usuń nadmiarowe białe znaki
text = re.sub(r'\s+', ' ', text)
# Usuń specjalne znaki (opcjonalnie)
# text = re.sub(r'[^\w\s.,!?;:()\-\'"ąćęłńóśźżĄĆĘŁŃÓŚŹŻ]', '', text)
return text.strip()
def split_into_chunks(text: str, max_chunk_size: int = 1000) -> List[str]:
"""Dzieli długi tekst na kawałki"""
words = text.split()
chunks = []
current_chunk = []
current_size = 0
for word in words:
word_size = len(word) + 1 # +1 dla spacji
if current_size + word_size > max_chunk_size and current_chunk:
chunks.append(' '.join(current_chunk))
current_chunk = [word]
current_size = word_size
else:
current_chunk.append(word)
current_size += word_size
if current_chunk:
chunks.append(' '.join(current_chunk))
return chunks
# ==================== GŁÓWNA FUNKCJA ====================
def main():
"""Główna funkcja przygotowania danych"""
preparer = DataPreparer()
preparer.prepare_all_data()
if __name__ == "__main__":
main()

108
test_questions.json Normal file
View File

@ -0,0 +1,108 @@
{
"questions": [
{"id": 1, "category": "polski", "question": "Jak się nazywasz?"},
{"id": 2, "category": "polski", "question": "Skąd jesteś?"},
{"id": 3, "category": "polski", "question": "Ile masz lat?"},
{"id": 4, "category": "polski", "question": "Co lubisz robić?"},
{"id": 5, "category": "polski", "question": "Jaki jest twój ulubiony film?"},
{"id": 6, "category": "polski", "question": "Dlaczego uczysz się programowania?"},
{"id": 7, "category": "polski", "question": "Jakie są twoje hobby?"},
{"id": 8, "category": "polski", "question": "Jaka jest dziś pogoda?"},
{"id": 9, "category": "polski", "question": "Co będzie jutro?"},
{"id": 10, "category": "polski", "question": "Jakie jest twoje marzenie?"},
{"id": 11, "category": "polski", "question": "Jaka jest twoja ulubiona książka?"},
{"id": 12, "category": "polski", "question": "Kto jest twoim ulubionym autorem?"},
{"id": 13, "category": "polski", "question": "Co lubisz jeść?"},
{"id": 14, "category": "polski", "question": "Jak spędzasz weekend?"},
{"id": 15, "category": "polski", "question": "Jakie filmy lubisz oglądać?"},
{"id": 16, "category": "polski", "question": "Jaki jest twój ulubiony sport?"},
{"id": 17, "category": "polski", "question": "Co robisz po szkole?"},
{"id": 18, "category": "polski", "question": "Jakie jest twoje ulubione miejsce?"},
{"id": 19, "category": "polski", "question": "Co lubisz w swojej szkole?"},
{"id": 20, "category": "polski", "question": "Jakie są twoje plany na przyszłość?"},
{"id": 21, "category": "python", "question": "Co to jest zmienna w Pythonie?"},
{"id": 22, "category": "python", "question": "Jak działa instrukcja if?"},
{"id": 23, "category": "python", "question": "Do czego służy lista w Pythonie?"},
{"id": 24, "category": "python", "question": "Jak działa słownik w Pythonie?"},
{"id": 25, "category": "python", "question": "Co to jest moduł w Pythonie?"},
{"id": 26, "category": "python", "question": "Jak działa pętla while?"},
{"id": 27, "category": "python", "question": "Jak otworzyć plik w Pythonie?"},
{"id": 28, "category": "python", "question": "Jak działa funkcja print()?"},
{"id": 29, "category": "python", "question": "Co to jest wyjątek?"},
{"id": 30, "category": "python", "question": "Jak działa f-string?"},
{"id": 31, "category": "python", "question": "Jak definiuje się funkcję w Pythonie?"},
{"id": 32, "category": "python", "question": "Co to jest tuple?"},
{"id": 33, "category": "python", "question": "Co to jest set?"},
{"id": 34, "category": "python", "question": "Jak działa pętla for?"},
{"id": 35, "category": "python", "question": "Jak działa operator in?"},
{"id": 36, "category": "python", "question": "Co robi pass w Pythonie?"},
{"id": 37, "category": "python", "question": "Jak działa funkcja input()?"},
{"id": 38, "category": "python", "question": "Co to jest list comprehension?"},
{"id": 39, "category": "python", "question": "Jak działa instrukcja break?"},
{"id": 40, "category": "python", "question": "Jak działa instrukcja continue?"},
{"id": 41, "category": "matematyka", "question": "Co to jest liczba pierwsza?"},
{"id": 42, "category": "matematyka", "question": "Jak obliczyć procent?"},
{"id": 43, "category": "matematyka", "question": "Co to jest promień koła?"},
{"id": 44, "category": "matematyka", "question": "Jak obliczyć pole prostokąta?"},
{"id": 45, "category": "matematyka", "question": "Co to jest równanie?"},
{"id": 46, "category": "matematyka", "question": "Jak działa pierwiastek kwadratowy?"},
{"id": 47, "category": "matematyka", "question": "Co to jest funkcja?"},
{"id": 48, "category": "matematyka", "question": "Jak obliczyć średnią?"},
{"id": 49, "category": "matematyka", "question": "Co to jest wektor?"},
{"id": 50, "category": "matematyka", "question": "Jak działa logarytm?"},
{"id": 51, "category": "matematyka", "question": "Co to jest macierz?"},
{"id": 52, "category": "matematyka", "question": "Jak obliczyć deltę w równaniu kwadratowym?"},
{"id": 53, "category": "matematyka", "question": "Co to jest granica funkcji?"},
{"id": 54, "category": "matematyka", "question": "Jak działa pochodna?"},
{"id": 55, "category": "matematyka", "question": "Co to jest całka?"},
{"id": 56, "category": "matematyka", "question": "Jak obliczyć pole trójkąta?"},
{"id": 57, "category": "matematyka", "question": "Co to jest ciąg arytmetyczny?"},
{"id": 58, "category": "matematyka", "question": "Co to jest ciąg geometryczny?"},
{"id": 59, "category": "matematyka", "question": "Jak działa funkcja odwrotna?"},
{"id": 60, "category": "matematyka", "question": "Co to jest wartość bezwzględna?"},
{"id": 61, "category": "historia", "question": "Kiedy była II wojna światowa?"},
{"id": 62, "category": "historia", "question": "Kto był królem Polski?"},
{"id": 63, "category": "historia", "question": "Co to była komunizm?"},
{"id": 64, "category": "historia", "question": "Gdzie działał Napoleon?"},
{"id": 65, "category": "historia", "question": "Kto wynalazł prasę drukarską?"},
{"id": 66, "category": "historia", "question": "Czym był średniowiecze?"},
{"id": 67, "category": "historia", "question": "Co spowodowało rewolucję przemysłową?"},
{"id": 68, "category": "historia", "question": "Kto był Juliusz Cezar?"},
{"id": 69, "category": "historia", "question": "Co to był renesans?"},
{"id": 70, "category": "historia", "question": "Kiedy Polska odzyskała niepodległość?"},
{"id": 71, "category": "historia", "question": "Kto był pierwszym prezydentem USA?"},
{"id": 72, "category": "historia", "question": "Co to była zimna wojna?"},
{"id": 73, "category": "historia", "question": "Kto był Hitlerem?"},
{"id": 74, "category": "historia", "question": "Co to była rewolucja francuska?"},
{"id": 75, "category": "historia", "question": "Kiedy powstało państwo polskie?"},
{"id": 76, "category": "historia", "question": "Kto był Karolem Wielkim?"},
{"id": 77, "category": "historia", "question": "Co to była starożytna Grecja?"},
{"id": 78, "category": "historia", "question": "Co to była starożytna Roma?"},
{"id": 79, "category": "historia", "question": "Kto był Kazimierz Wielki?"},
{"id": 80, "category": "historia", "question": "Kiedy był upadek Cesarstwa Rzymskiego?"},
{"id": 81, "category": "nauka", "question": "Co to jest atom?"},
{"id": 82, "category": "nauka", "question": "Jak działa grawitacja?"},
{"id": 83, "category": "nauka", "question": "Co to jest DNA?"},
{"id": 84, "category": "nauka", "question": "Jak powstaje tęcza?"},
{"id": 85, "category": "nauka", "question": "Co to jest energia?"},
{"id": 86, "category": "nauka", "question": "Jak działa magnetyzm?"},
{"id": 87, "category": "nauka", "question": "Co to jest światło?"},
{"id": 88, "category": "nauka", "question": "Jak działa silnik?"},
{"id": 89, "category": "nauka", "question": "Co to jest fotosynteza?"},
{"id": 90, "category": "nauka", "question": "Jak działa komputer?"},
{"id": 91, "category": "nauka", "question": "Co to jest elektron?"},
{"id": 92, "category": "nauka", "question": "Jak działa siła odśrodkowa?"},
{"id": 93, "category": "nauka", "question": "Co to jest ciśnienie atmosferyczne?"},
{"id": 94, "category": "nauka", "question": "Co to jest fotosfera?"},
{"id": 95, "category": "nauka", "question": "Jak powstaje wiatr?"},
{"id": 96, "category": "nauka", "question": "Co to jest ciśnienie krwi?"},
{"id": 97, "category": "nauka", "question": "Co to jest komórka?"},
{"id": 98, "category": "nauka", "question": "Co to jest grawitacja Newtona?"},
{"id": 99, "category": "nauka", "question": "Jak działa fotosynteza w roślinach?"},
{"id": 100, "category": "nauka", "question": "Co to jest mikroorganizm?"}
]
}

190
training.log Normal file
View File

@ -0,0 +1,190 @@
2026-01-26 11:36:51,804 - INFO - ============================================================
2026-01-26 11:36:51,804 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:36:51,804 - INFO - ============================================================
2026-01-26 11:36:51,804 - INFO - Python: 3.13.5
2026-01-26 11:36:51,804 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:36:51,804 - INFO - Device: CPU
2026-01-26 11:36:51,804 - INFO - ============================================================
2026-01-26 11:36:51,963 - INFO - ============================================================
2026-01-26 11:36:51,963 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:36:51,963 - INFO - ============================================================
2026-01-26 11:36:51,963 - INFO -
❓ Nie podano flagi. Dostępne opcje:
2026-01-26 11:36:51,964 - INFO -
💡 PRZYKŁADY UŻYCIA:
2026-01-26 11:36:51,965 - INFO - python main.py --train # Trenuj od początku
2026-01-26 11:36:51,965 - INFO - [Ctrl+C] # Przerwij trening
2026-01-26 11:36:51,965 - INFO - python main.py --cont # Wznów trening
2026-01-26 11:36:51,965 - INFO - python main.py --more 5 # Dodaj 5 epok
2026-01-26 11:36:51,965 - INFO - python main.py --generate 'AI' # Generuj tekst
2026-01-26 11:36:51,965 - INFO - ============================================================
2026-01-26 11:37:01,141 - INFO - ============================================================
2026-01-26 11:37:01,141 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:37:01,141 - INFO - ============================================================
2026-01-26 11:37:01,141 - INFO - Python: 3.13.5
2026-01-26 11:37:01,141 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:37:01,141 - INFO - Device: CPU
2026-01-26 11:37:01,141 - INFO - ============================================================
2026-01-26 11:37:01,225 - INFO - ============================================================
2026-01-26 11:37:01,225 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:37:01,225 - INFO - ============================================================
2026-01-26 11:37:02,243 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:37:02,244 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:37:02,244 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:37:08,343 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:37:08,343 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:37:08,343 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:37:55,253 - INFO - ============================================================
2026-01-26 11:37:55,254 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:37:55,254 - INFO - ============================================================
2026-01-26 11:37:55,254 - INFO - Python: 3.13.5
2026-01-26 11:37:55,255 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:37:55,255 - INFO - Device: CPU
2026-01-26 11:37:55,255 - INFO - ============================================================
2026-01-26 11:37:55,453 - INFO - ============================================================
2026-01-26 11:37:55,453 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:37:55,453 - INFO - ============================================================
2026-01-26 11:37:56,683 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:37:56,684 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:37:56,685 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:38:10,327 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:38:10,327 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:38:10,327 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:38:31,310 - INFO - ============================================================
2026-01-26 11:38:31,310 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:38:31,310 - INFO - ============================================================
2026-01-26 11:38:31,310 - INFO - Python: 3.13.5
2026-01-26 11:38:31,310 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:38:31,310 - INFO - Device: CPU
2026-01-26 11:38:31,310 - INFO - ============================================================
2026-01-26 11:38:31,473 - INFO - ============================================================
2026-01-26 11:38:31,473 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:38:31,473 - INFO - ============================================================
2026-01-26 11:38:32,504 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:38:32,504 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:38:32,505 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:38:36,336 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:38:36,336 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:38:36,336 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:39:32,575 - INFO - ============================================================
2026-01-26 11:39:32,576 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:39:32,576 - INFO - ============================================================
2026-01-26 11:39:32,576 - INFO - Python: 3.13.5
2026-01-26 11:39:32,576 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:39:32,576 - INFO - Device: CPU
2026-01-26 11:39:32,576 - INFO - ============================================================
2026-01-26 11:39:32,740 - INFO - ============================================================
2026-01-26 11:39:32,740 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:39:32,740 - INFO - ============================================================
2026-01-26 11:39:33,882 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:39:33,882 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:39:33,883 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:39:36,591 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:39:36,591 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:39:36,591 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:40:11,736 - INFO - ============================================================
2026-01-26 11:40:11,737 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:40:11,737 - INFO - ============================================================
2026-01-26 11:40:11,737 - INFO - Python: 3.13.5
2026-01-26 11:40:11,737 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:40:11,737 - INFO - Device: CPU
2026-01-26 11:40:11,737 - INFO - ============================================================
2026-01-26 11:40:11,872 - INFO - ============================================================
2026-01-26 11:40:11,872 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:40:11,873 - INFO - ============================================================
2026-01-26 11:40:13,485 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:40:13,486 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:40:13,488 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:40:15,460 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:40:15,460 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:40:15,460 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:41:14,387 - INFO - ============================================================
2026-01-26 11:41:14,388 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:41:14,388 - INFO - ============================================================
2026-01-26 11:41:14,388 - INFO - Python: 3.13.5
2026-01-26 11:41:14,388 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:41:14,388 - INFO - Device: CPU
2026-01-26 11:41:14,388 - INFO - ============================================================
2026-01-26 11:41:14,475 - INFO - ============================================================
2026-01-26 11:41:14,475 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:41:14,475 - INFO - ============================================================
2026-01-26 11:41:15,430 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:41:15,431 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:41:15,431 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:41:18,877 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:41:18,877 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:41:18,877 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:43:21,037 - INFO - ============================================================
2026-01-26 11:43:21,038 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:43:21,038 - INFO - ============================================================
2026-01-26 11:43:21,038 - INFO - Python: 3.13.5
2026-01-26 11:43:21,038 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:43:21,038 - INFO - Device: CPU
2026-01-26 11:43:21,038 - INFO - ============================================================
2026-01-26 11:43:21,124 - INFO - ============================================================
2026-01-26 11:43:21,124 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:43:21,124 - INFO - ============================================================
2026-01-26 11:43:22,084 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:43:22,084 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:43:22,085 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:43:24,269 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:43:24,269 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:43:24,270 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:44:46,990 - INFO - ============================================================
2026-01-26 11:44:46,990 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:44:46,990 - INFO - ============================================================
2026-01-26 11:44:46,990 - INFO - Python: 3.13.5
2026-01-26 11:44:46,990 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:44:46,990 - INFO - Device: CPU
2026-01-26 11:44:46,990 - INFO - ============================================================
2026-01-26 11:44:57,235 - INFO - ============================================================
2026-01-26 11:44:57,235 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:44:57,235 - INFO - ============================================================
2026-01-26 11:44:57,235 - INFO - Python: 3.13.5
2026-01-26 11:44:57,235 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:44:57,235 - INFO - Device: CPU
2026-01-26 11:44:57,235 - INFO - ============================================================
2026-01-26 11:44:57,321 - INFO - ============================================================
2026-01-26 11:44:57,321 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:44:57,321 - INFO - ============================================================
2026-01-26 11:44:58,280 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:44:58,281 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:44:58,281 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:45:05,073 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:45:05,073 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:45:05,073 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont
2026-01-26 11:51:39,327 - INFO - ============================================================
2026-01-26 11:51:39,327 - INFO - 🎯 SYSTEM MINIGPT-60M
2026-01-26 11:51:39,327 - INFO - ============================================================
2026-01-26 11:51:39,327 - INFO - Python: 3.13.5
2026-01-26 11:51:39,327 - INFO - PyTorch: 2.9.1+cpu
2026-01-26 11:51:39,328 - INFO - Device: CPU
2026-01-26 11:51:39,328 - INFO - ============================================================
2026-01-26 11:51:39,414 - INFO - ============================================================
2026-01-26 11:51:39,414 - INFO - 🎯 MINIGPT-60M - Z CHECKPOINTAMI
2026-01-26 11:51:39,414 - INFO - ============================================================
2026-01-26 11:51:39,414 - WARNING - ⚠️ Brak wytrenowanego modelu, używam niewytrenowanego
2026-01-26 11:51:40,380 - INFO - 🤖 Model: 85,501,440 parametrów (85.5M)
2026-01-26 11:51:40,389 - INFO - 🤖 ChatBot initialized on cpu
2026-01-26 11:52:15,241 - INFO -
⚠️ Trening przerwany przez użytkownika!
2026-01-26 11:52:15,242 - INFO - 💾 Zapisuję stan do wznowienia...
2026-01-26 11:52:15,242 - INFO - ✅ Możesz wznowić trening używając: python main.py --cont