| | """ |
| | ╔══════════════════════════════════════════════════════════════════════════╗ |
| | ║ PROJECT NORD — Крок 1: Завантаження датасету ║ |
| | ║ ║ |
| | ║ Просто запусти: ║ |
| | ║ python download_data.py ║ |
| | ║ ║ |
| | ║ Воно запитає куди зберегти і почне качати. ║ |
| | ║ Датасет: FineWeb-Edu (високоякісні освітні тексти англійською) ║ |
| | ║ Розмір: ~40 GB тексту (JSONL формат) ║ |
| | ╚══════════════════════════════════════════════════════════════════════════╝ |
| | |
| | Потрібно встановити один раз: |
| | pip install datasets tqdm |
| | """ |
| |
|
| | import json |
| | import os |
| | import sys |
| | import time |
| |
|
| |
|
| | def format_size(bytes_val: int) -> str: |
| | """Форматувати байти в людський вигляд.""" |
| | for unit in ["B", "KB", "MB", "GB", "TB"]: |
| | if bytes_val < 1024: |
| | return f"{bytes_val:.1f} {unit}" |
| | bytes_val /= 1024 |
| | return f"{bytes_val:.1f} PB" |
| |
|
| |
|
| | def download(): |
| | print("=" * 60) |
| | print(" PROJECT NORD — Завантаження датасету") |
| | print("=" * 60) |
| | print() |
| |
|
| | |
| | default_path = os.path.join("D:", os.sep, "nord_dataset", "train_data.jsonl") |
| | print(f" Куди зберегти датасет?") |
| | print(f" (Enter = {default_path})") |
| | user_path = input(" Шлях: ").strip() |
| | save_path = user_path if user_path else default_path |
| |
|
| | |
| | print() |
| | print(" Скільки гігабайт завантажити?") |
| | print(" Рекомендовано: 10 GB — швидкий тест") |
| | print(" 40 GB — повне навчання") |
| | print(f" (Enter = 40)") |
| | size_input = input(" Розмір (GB): ").strip() |
| | target_gb = float(size_input) if size_input else 40.0 |
| | target_bytes = int(target_gb * (1024 ** 3)) |
| |
|
| | |
| | os.makedirs(os.path.dirname(save_path) or ".", exist_ok=True) |
| |
|
| | print() |
| | print(f" 📁 Зберігаємо в: {save_path}") |
| | print(f" 📦 Цільовий розмір: {target_gb:.0f} GB") |
| | print() |
| |
|
| | |
| | bytes_written = 0 |
| | samples_written = 0 |
| | mode = "w" |
| |
|
| | if os.path.exists(save_path): |
| | existing_size = os.path.getsize(save_path) |
| | if existing_size > 0: |
| | print(f" [!] Файл вже існує ({format_size(existing_size)})") |
| | print(f" Продовжити дозавантаження? (y/n, Enter = y)") |
| | choice = input(" > ").strip().lower() |
| | if choice in ("", "y", "yes", "так", "д"): |
| | bytes_written = existing_size |
| | |
| | print(" Підраховуємо існуючі рядки...") |
| | with open(save_path, "r", encoding="utf-8") as f: |
| | samples_written = sum(1 for _ in f) |
| | mode = "a" |
| | print(f" Продовжуємо з {samples_written:,} зразків ({format_size(bytes_written)})") |
| | else: |
| | print(" Починаємо з нуля...") |
| |
|
| | if bytes_written >= target_bytes: |
| | print(f"\n [✓] Датасет вже повний! ({format_size(bytes_written)})") |
| | print(f" Тепер запускай: python train_nord.py") |
| | return save_path |
| |
|
| | |
| | print() |
| | print(" [*] Підключаємося до HuggingFace...") |
| | print(" [*] Датасет: HuggingFaceFW/fineweb-edu (sample-10BT)") |
| | print(" Це високоякісні освітні тексти — найкраще для навчання LLM") |
| | print() |
| |
|
| | try: |
| | from datasets import load_dataset |
| | except ImportError: |
| | print(" [✗] Бібліотека 'datasets' не встановлена!") |
| | print(" Виконай: pip install datasets") |
| | sys.exit(1) |
| |
|
| | |
| | dataset = load_dataset( |
| | "HuggingFaceFW/fineweb-edu", |
| | name="sample-10BT", |
| | split="train", |
| | streaming=True, |
| | ) |
| |
|
| | |
| | data_iter = iter(dataset) |
| | if samples_written > 0: |
| | print(f" [*] Пропускаємо {samples_written:,} вже завантажених зразків...") |
| | for _ in range(samples_written): |
| | try: |
| | next(data_iter) |
| | except StopIteration: |
| | break |
| |
|
| | print(f" [*] Починаємо запис... (Ctrl+C щоб зупинити, можна продовжити пізніше)") |
| | print() |
| |
|
| | t_start = time.time() |
| | last_print = t_start |
| |
|
| | try: |
| | with open(save_path, mode, encoding="utf-8") as f: |
| | for sample in data_iter: |
| | text = sample.get("text", "") |
| | if not text or len(text) < 50: |
| | continue |
| |
|
| | line = json.dumps({"text": text}, ensure_ascii=False) + "\n" |
| | line_bytes = len(line.encode("utf-8")) |
| | f.write(line) |
| |
|
| | bytes_written += line_bytes |
| | samples_written += 1 |
| |
|
| | |
| | now = time.time() |
| | if now - last_print >= 2.0: |
| | elapsed = now - t_start |
| | speed = (bytes_written - (0 if mode == "w" else bytes_written)) / elapsed if elapsed > 0 else 0 |
| | pct = bytes_written / target_bytes * 100 |
| | bar_len = 30 |
| | filled = int(bar_len * min(pct, 100) / 100) |
| | bar = "█" * filled + "░" * (bar_len - filled) |
| |
|
| | print( |
| | f"\r [{bar}] {pct:.1f}% " |
| | f"{format_size(bytes_written)}/{format_size(target_bytes)} " |
| | f"{samples_written:,} зразків " |
| | f"{format_size(int(speed))}/s ", |
| | end="", flush=True, |
| | ) |
| | last_print = now |
| |
|
| | |
| | if samples_written % 10000 == 0: |
| | f.flush() |
| |
|
| | |
| | if bytes_written >= target_bytes: |
| | break |
| |
|
| | except KeyboardInterrupt: |
| | print(f"\n\n [⏸] Зупинено! Збережено {format_size(bytes_written)} ({samples_written:,} зразків)") |
| | print(f" Щоб продовжити пізніше — просто запусти цей скрипт знову.") |
| | return save_path |
| |
|
| | elapsed = time.time() - t_start |
| | print(f"\n\n {'═' * 50}") |
| | print(f" [✓] ГОТОВО!") |
| | print(f" 📁 Файл: {save_path}") |
| | print(f" 📦 Розмір: {format_size(bytes_written)}") |
| | print(f" 📝 Зразків: {samples_written:,}") |
| | print(f" ⏱ Час: {elapsed/60:.0f} хвилин") |
| | print(f" {'═' * 50}") |
| | print() |
| | print(f" Наступний крок:") |
| | print(f" python train_nord.py") |
| | print() |
| |
|
| | return save_path |
| |
|
| |
|
| | if __name__ == "__main__": |
| | download() |
| |
|