Обновленная версия, Не проверена - **Платформа:** Windows 10/11 + WSL2 (Ubuntu 22.04 / 24.04) - **Железо:** NVIDIA RTX 3060 Ti (8 ГБ VRAM) - **Базовая модель:** Meta Llama 3.1 8B - **Рабочая директория:** `C:\ST\aandc\` (в WSL2: `/mnt/c/ST/aandc/`) ЧАСТЬ 1. Развертывание среды и проброс GPU в WSL2 1.1. Базовая установка подсистемы Откройте **PowerShell от имени Администратора** на Windows: powershell ``` wsl --install wsl --set-default-version 2 ``` Используйте код с осторожностью. _Перезагрузите ПК. В терминале Ubuntu задайте логин и пароль._ 1.2. Выделение системных ресурсов (Защита от Out Of Memory) 1. В Windows нажмите `Win + R`, введите `%USERPROFILE%` и нажмите Enter. 2. Создайте файл `.wslconfig` и вставьте параметры: ini ``` [wsl2] memory=16GB swap=8GB localhostForwarding=true ``` Используйте код с осторожностью. 3. Перезапустите WSL в PowerShell: `wsl --shutdown` 1.3. Инсталляция NVIDIA Container Toolkit (Проброс графического ядра) Запустите терминал **Ubuntu в WSL2**: bash ``` sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg2 # Скачивание официального GPG-ключа curl -fsSL https://github.io | sudo gpg --dearmor --yes -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg # Добавление официального репозитория пакетов curl -s -L https://github.io | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit ``` Используйте код с осторожностью. _Проверить сопряжение: команда `nvidia-smi` должна вывести таблицу с вашей RTX 3060 Ti._ --- ЧАСТЬ 2. Установка Ollama и Локальный Запуск 2.1. Установка движка и скачивание модели (в терминале WSL2) bash ``` curl -fsSL https://ollama.com | sh ollama pull llama3.1 ``` Используйте код с осторожностью. 2.2. Фоновый запуск сервера Ollama в WSL2 bash ``` ollama serve > /dev/null 2>&1 & ``` Используйте код с осторожностью. _(Нажмите Enter, если терминал временно застынет. Проверить доступность: `ollama list`)._ --- ЧАСТЬ 3. Автоматизированная генерация ShareGPT-датасета 3.1. Подготовка папок и Python В Windows скопируйте все **71 технический PDF-мануал** в папку `C:\ST\aandc\manuals\`. В терминале WSL2 установите библиотеки (обход защиты `PEP 668`): bash ``` pip3 install pypdf requests --break-system-packages ``` Используйте код с осторожностью. 3.2. Создание интеллектуального генератора `generate_qa.py` Создайте файл `/mnt/c/ST/aandc/generate_qa.py`: python ``` import os, re, json, pypdf, requests MODEL_NAME = "llama3.1:latest" OLLAMA_URL = "http://localhost:11434/api/generate" MANUALS_DIR = "/mnt/c/ST/aandc/manuals" OUTPUT_FILE = "/mnt/c/ST/aandc/aandc_dataset.jsonl" WINDOW_SIZE = 3 SYSTEM_PROMPT = ( "Вы — опытный technical writer и эксперт по банкоматному ПО.\n" "Изучите предоставленный текст. Создайте от 2 до 4 высококачественных пар 'Вопрос-Ответ'.\n" "Ответы должны быть глубокими, технически точными, без упоминания номеров страниц.\n" "Формат ответа строго JSON: [{\"conversations\": [{\"from\": \"human\", \"value\": \"Вопрос\"}, {\"from\": \"gpt\", \"value\": \"Ответ\"}]}]" ) def clean_text(text): text = re.sub(r'Page \d+ of \d+', '', text, flags=re.IGNORECASE) text = re.sub(r'^\d+\s*$', '', text, flags=re.MULTILINE) return re.sub(r'\n+', '\n', text).strip() def extract_pdf_chunks(pdf_path, window_size=3): try: with open(pdf_path, 'rb') as f: reader = pypdf.PdfReader(f) for i in range(0, len(reader.pages), window_size): chunk_text = "".join([reader.pages[j].extract_text() or "" for j in range(i, min(i + window_size, len(reader.pages)))]) cleaned = clean_text(chunk_text) if len(cleaned) > 100: yield cleaned except Exception as e: print(f"Ошибка чтения {os.path.basename(pdf_path)}: {e}") def ask_ollama(context): payload = {"model": MODEL_NAME, "prompt": f"ДОКУМЕНТАЦИЯ:\n{context}\n\nСгенерируй JSON.", "system": SYSTEM_PROMPT, "stream": False, "format": "json"} try: response = requests.post(OLLAMA_URL, json=payload) if response.status_code == 200: return response.json().get("response", "") except: pass return None def main(): pdf_files = [f for f in os.listdir(MANUALS_DIR) if f.lower().endswith('.pdf')] print(f"Найдено файлов: {len(pdf_files)}. Старт генерации...") with open(OUTPUT_FILE, 'w', encoding='utf-8') as outfile: for idx, pdf_name in enumerate(pdf_files, 1): print(f"[{idx}/{len(pdf_files)}] Обработка: {pdf_name}") for chunk in extract_pdf_chunks(os.path.join(MANUALS_DIR, pdf_name), WINDOW_SIZE): raw_json = ask_ollama(chunk) if not raw_json: continue try: data = json.loads(raw_json) # Всеядный парсер: обрабатывает и массивы, и прямые словари items = data if isinstance(data, list) else [data] if isinstance(data, dict) and "conversations" in data else data.values() if isinstance(data, dict) else [] for item in items: if isinstance(item, dict) and "conversations" in item: outfile.write(json.dumps(item, ensure_ascii=False) + "\n") outfile.flush() except: continue print("Датасет успешно сохранен!") if __name__ == "__main__": main() ``` Используйте код с осторожностью. _Запуск: `python3 /mnt/c/ST/aandc/generate_qa.py`. Сформируется чистый файл `aandc_dataset.jsonl` на 756 диалогов._ --- ЧАСТЬ 4. Индустриальный Fine-Tuning на 8 ГБ VRAM Для обхода аппаратных ограничений памяти Triton-ядер мы используем чистый, надежный стек **Hugging Face (`peft` + `bitsandbytes` + `transformers`)** в режиме 4-битного квантования. 4.1. Установка стабильного окружения bash ``` pip install torch torchvision torchaudio --index-url https://pytorch.org --break-system-packages pip install transformers datasets peft bitsandbytes trl --break-system-packages ``` Используйте код с осторожностью. 4.2. Развертывание «железного» скрипта обучения `train.py` Создайте файл `/mnt/c/ST/aandc/train.py` (выполняется прямо сейчас): python ``` import os, json, torch from datasets import Dataset from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, Trainer, DataCollatorForLanguageModeling from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training MODEL_NAME = "unsloth/llama-3.1-8b-Instruct-bnb-4bit" max_seq_length = 512 # Идеальный размер контекста для защиты 8 ГБ VRAM от пиков DATASET_PATH = "/mnt/c/ST/aandc/aandc_dataset.jsonl" torch.cuda.empty_cache() print("--- 1. Конфигурация 4-бит NF4 ---") bnb_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True) print("--- 2. Загрузка модели через HF ---") tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) tokenizer.pad_token = tokenizer.eos_token model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, quantization_config=bnb_config, device_map="auto") model = prepare_model_for_kbit_training(model) print("--- 3. Настройка LoRA параметров ---") peft_config = LoraConfig(r=16, lora_alpha=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM") model = get_peft_model(model, peft_config) print("--- 4. Валидация и Токенизация датасета ---") valid_dialogues = [] with open(DATASET_PATH, "r", encoding="utf-8") as f: for line in f: if not line.strip(): continue try: item = json.loads(line) if "conversations" in item and isinstance(item["conversations"], list): valid_dialogues.append({"conversations": item["conversations"]}) except: continue dataset = Dataset.from_list(valid_dialogues) def tokenize_prompts_func(examples): tokenized_inputs = {"input_ids": [], "attention_mask": []} for con in examples["conversations"]: mapped = [{"role": "user" if m["from"] == "human" else "assistant", "content": m["value"]} for m in con] text = tokenizer.apply_chat_template(mapped, tokenize=False, add_generation_prompt=False) tokenized = tokenizer(text, truncation=True, max_length=max_seq_length, padding=False) tokenized_inputs["input_ids"].append(tokenized["input_ids"]) tokenized_inputs["attention_mask"].append(tokenized["attention_mask"]) return tokenized_inputs dataset = dataset.map(tokenize_prompts_func, batched=True, remove_columns=["conversations"]) print("--- 5. Запуск неубиваемого Trainer ---") trainer = Trainer( model=model, train_dataset=dataset, data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False), args=TrainingArguments( per_device_train_batch_size=1, gradient_accumulation_steps=8, warmup_steps=5, max_steps=60, learning_rate=2e-4, fp16=True, logging_steps=1, optim="adamw_8bit", weight_decay=0.01, lr_scheduler_type="linear", seed=3407, output_dir="outputs", remove_unused_columns=False ), ) trainer.train() print("--- ТРЕНИРОВКА УСПЕШНО ЗАВЕРШЕНА ---") model.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") tokenizer.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") print("Адаптеры сохранены!") ``` Используйте код с осторожностью. _Запуск: выгрузите Ollama (`pkill -f ollama`) для очистки VRAM и введите `python3 /mnt/c/ST/aandc/train.py`._ --- ЧАСТЬ 5. Экспорт адаптеров и Сборка модели для Ollama После завершения обучения у вас есть базовая модель и папка обученных LoRA-адаптеров `aandc_lora_model`. Переведём их в единый формат `.gguf`. 5.1. Скачивание утилиты конвертации `llama.cpp` bash ``` cd /mnt/c/ST/aandc/ git clone https://github.com pip3 install -r llama.cpp/requirements.txt --break-system-packages ``` Используйте код с осторожностью. 5.2. Слияние и Квантование (Merge & Quantize) Мы берем обученные веса LoRA и упаковываем их в единый 4-битный файл, который мгновенно зачитает любая система: bash ``` # Конвертируем веса адаптеров LoRA в формат GGUF python3 llama.cpp/convert_hf_to_gguf.py /mnt/c/ST/aandc/aandc_lora_model/ --outfile atm_expert_q4.gguf ``` Используйте код с осторожностью. 5.3. Настройка `Modelfile` Создайте текстовый файл `/mnt/c/ST/aandc/Modelfile`: dockerfile ``` FROM ./atm_expert_q4.gguf TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|> {{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|> {{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|> {{ .Response }}<|eot_id|>""" SYSTEM "Вы — специализированный локальный ИИ-эксперт по банкоматному ПО. Вы отвечаете строго на основе технической документации, без «каши», четко, структурированно, используя инженерные термины." ``` Используйте код с осторожностью. 5.4. Регистрация Эксперта bash ``` # Поднимаем сервер заново ollama serve > /dev/null 2>&1 & # Регистрируем финальную модель ollama create atm_expert -f /mnt/c/ST/aandc/Modelfile ``` Используйте код с осторожностью. _Проверка работоспособности: `ollama run atm_expert`_. --- ЧАСТЬ 6. Автономный перенос модели на другой ПК Благодаря архитектуре `.gguf`, готовый эксперт полностью автономен и не требует CUDA, Python или Linux на целевом ПК. 1. **Копирование:** Заберите с флешки два файла: `atm_expert_q4.gguf` и `Modelfile`. 2. **Установка Ollama:** На целевом ПК (Windows, Mac или Linux) поставьте чистую Ollama с официального сайта ollama.com. 3. **Импорт:** Положите файлы в любую папку (например, `C:\ATM_AI\`), откройте командную строку Windows (cmd/PowerShell) в этой папке и выполните: bash ``` cd C:\ATM_AI\ ollama create atm_expert -f Modelfile ``` Используйте код с осторожностью. 4. **Работа:** Модель готова к эксплуатации без интернета по команде `ollama run atm_expert`. ---