Как забэкапить друга в нейросеть

pensioner-sychevod-backup-07032025.llm
pensioner-sychevod-backup-07032025.llm

Есть у меня друг, агушагеймер-сычевод, пенсионер (владелец сараеподобного Volvo) и вообще прекрасный человек. Подумалось, дед старенький уже, четвертый десяток перешагнул, вдруг чего, забэкапить бы надо.

Году в 2017 перешли мы с ним в Telegram, и накопилось у нас с ним порядка 52000 сообщений в диалогах.

Выкачал я всё это добро, да и обучил нейронку:

(.venv) ➜ mlx_lm git:(main) ✗ mlx_lm.chat --model mlx-community/Phi-4-mini-instruct-4bit --adapter-path adapters --temp 0.7 [INFO] Starting chat session with mlx-community/Phi-4-mini-instruct-4bit. To exit, enter 'q'. >> Дед, поздоровайся с DTF! Я не знаю, как в ТДФ. Это все третий уровень >> Да ладно тебе, скажи привет! И вот ты теперь в ТДФ, но карета у меня там тяжело parking. А ты в ТДФ с машиной с 32 >> В сыча играешь? Да, играешь. И я там с моей машиной >> Чо какая машина? У меня есть машина Next. Вспомнил, с неё сделан и на телевидение, и на телефон. Ей даже в целомке не нужен пульт, и ещё у меня её не видно >> Ну спасибо, дед, бывай!

Результат, очевидно, УГ, но местами в диалогах всплывают старые-добрые нотки родного деда, и на глазах умиление, а в сердце теплота. А еще все это можно улучшить, вопрос лишь времени.

Ну и как мне забэкапить своего другана?

Добро пожаловать, ребятки, в чудесный мир нейронных сетей.

Знать вам нужно две вещи - для этого не требуется программирование, и вам, ПК-боярам, это доступно прямо дома (так как видеокарта у вас точно есть, а лайфхак консолеводам будет дальше).

Тем не менее, умение следовать гайдам, открывать консоль и кидать ошибки в ChatGPT с вопросом "чего дальше делать" вам понадобится.

Схема проста. Берем диалог из телеги, выбираем LLM, дообучаем её на нашем диалоге, и общаемся с ней!

Краткое введение в матчасть нейросетей (скучно, но быстро)

Мы будем работать с LLM (Large Language Model).

Состоят они из двух частей:

- немного кода на каком-нибудь языке программирования;

- огромный файл с числами на много гигабайт (так называемые веса модели).

Схема работы LLM

- Когда мы пишем слово "Привет", она преобразует его в токены: "54745, 28089, 8341, 0".

- Токены подаются на вход нейросети и происходит inference - расчёт ответа. Наши числа, представляющие собою текущий контекст, миллионы раз подряд умножаются, делятся и возводятся в степень с числами из весов модели.

- Модель выдает ответ в токенах - "54745, 28089, 8341, 423, 11042, 0", которые переводится обратно в текст "Привет DTF!".

Как видим, никакого интеллекта (кроме интеллекта разработчиков нейросети) у LLM нет - это тупо гигабайты чисел и миллионы простых математических операций над ними.

Для любопытных крайне рекомендую лекцию Андрея Карпаты:

Что такое этот ваш ChatGPT

Тренируем нейродеда

Я буду тренировать модель на Mac (ввиду отсутствия боярского ПК) и большая часть следующих шагов применима только для него.

Гайды для ПК легко гуглятся по фразе "LoRA LLM tuning Nvidia", например:

Шаг 1 - История из Telegram

Выгружаем историю общения. Это можно сделать в Telegram Desktop на Windows, macOS и Linux. Открываем диалог и щелкаем Export chat history:

Выбираем промежуток от начала времен до текущего момента, и убираем все галки - нам нужен только текст
Выбираем промежуток от начала времен до текущего момента, и убираем все галки - нам нужен только текст

Шаг 2 - Выбираем LLM модель

Нам понадобится завести аккаунт на Hugging Face для загрузки моделей нейронных сетей:

После создания акаунта нужно выбрать, какую модель будем доучивать. Открываем модели, выбираем в языках Russian, а в задачах Text Generation:

Ну, Phi-4 так Phi-4.
Ну, Phi-4 так Phi-4.

Hugging Face сортирует модели по релевантности, и Phi-4 от Microsoft как раз хороший выбор.

Копируем ID модели: microsoft/Phi-4-mini-instruct

Шаг 3 - Качаем утилиту и готовим данные

Для обучения на Mac с Apple Silicon (M1 и выше) хорошо подходит Apple MLX, гайд:

Клонируем репозиторий:

Переходим в директо��ию /mlx-examples/llms/mlx_lm.

После прохождения гайдов готовим данные из телеги.

Telegram отдает историю в виде JSON в файле result.json, разделенного на сообщения:

{ "id": 1007543, "type": "message", "date": "2024-02-09T19:21:30", "date_unixtime": "1707492090", "from": "Ежова Морда", "from_id": "user237147321", "text": "Все так. Причем тут недавно марево выходил", "text_entities": [ { "type": "plain", "text": "Все так. Причем тут недавно марево выходил" } ] }

В моём случае MLX LM требует формат вопрос-ответ:

{"messages": [{"role": "user", "content": "Нинтендо вещи делает!"}, {"role": "assistant", "content": "Все так. Причем тут недавно марево выходил"}]}

Пишем в ChatGPT:

Мне нужно преобразовать JSON в формат JSONL. Напиши код на Python, который преобразует его в такой формат: {"messages": [{"role": "user", "content": "Нинтендо вещи делает!"}, {"role": "assistant", "content": "Все так. Причем тут недавно марево выходил"}]} Правила такие: - Если from="Я", то поля text нужно преобразовать в content для user. Все сообщения идущие подряд с from="Я" нужно добавлять в этот content через пробел, пока значение from не изменится. - Если from="Ежова Морда", то поля text нужно преобразовать в content для assistant прошлой строки. Все сообщения идущие подряд с from="Ежова Морда" нужно добавлять в этот content через пробел, пока значение from не изменится. - Когда значение from изменилось с "Ежова Морда" на "Я", создай новый элемент JSONL файла и повтори шаги. <пара примеров из диалога>

Созданный Python файл сохраянем и исполняем, получаем верный формат.

Модели требуется два файла - train.jsonl (датасет) и valid.jsonl (правила валидации датасета). Готовить правила валидации задача сложная, поэтому тупо делим наш диалог на 2/3 и 1/3. Первая идет в train.jsonl, вторая в valid.jsonl - то есть мы обучаем модель на 2/3 наших разговоров, а проверяем модель при обучении на 1/3 наших разговоров.

Шаг 4 - Запускаем обучение

Когда файлы train.jsonl и valid.jsonl готовы, кидаем их в директорию mlx-examples/llms/mlx_lm и переходим в неё.

Запускаем процесс обучения модели:

mlx_lm.lora --model mlx-community/Phi-4-mini-instruct-4bit --train --data . --iters 2000 --num-layers -1 --grad-checkpoint --steps-per-eval 50 --steps-per-report 50

Долго ждём, в зависимости от количества сообщений в датасете (для 52000 сообщений заняло 4 часа):

Loading datasets Training Trainable parameters: 0.055% (2.097M/3836.022M) Starting training..., iters: 1000 Iter 1: Val loss 10.865, Val took 12.808s Iter 50: Val loss 5.310, Val took 12.206s Iter 50: Train loss 6.978, Learning Rate 1.000e-05, It/sec 0.530, Tokens/sec 119.198, Trained Tokens 11254, Peak mem 9.550 GB Iter 100: Val loss 4.644, Val took 12.420s Iter 100: Train loss 4.856, Learning Rate 1.000e-05, It/sec 0.416, Tokens/sec 117.263, Trained Tokens 25355, Peak mem 14.187 GB Iter 100: Saved adapter weights to adapters/adapters.safetensors and adapters/0000100_adapters.safetensors. <здесь такой же вывод на каждые 50 итераций> Iter 1000: Val loss 4.390, Val took 15.267s Iter 1000: Train loss 4.336, Learning Rate 1.000e-05, It/sec 0.518, Tokens/sec 113.674, Trained Tokens 211709, Peak mem 14.187 GB Iter 1000: Saved adapter weights to adapters/adapters.safetensors and adapters/0001000_adapters.safetensors. Saved final weights to adapters/adapters.safetensors.

Готово!

Шаг 5 - Говорим с нейродедом

Запускаем диалог:

mlx_lm.chat --model mlx-community/Phi-4-mini-instruct-4bit --adapter-path adapters --temp 0.7

Общаемся:

[INFO] Starting chat session with mlx-community/Phi-4-mini-instruct-4bit. To exit, enter 'q'. >> Дед, я скучал Я не знаю, как в такие моменты себя чувствовать. Пробовал навернуть петлю, но не получилось >> Эх... Ну карикатура, может, это и прекрасно. И хуй, я не могу с этим согласиться. Но это все вон то, не то. В общем, не знаю, как это выразить. А это нормально?

Это же чушь, а не диалог?

Да, чушь. Мусор на входе == мусор на выходе.

К сожалению, для полноценного обучения нам нужно МНОГО данных. 50000 сообщений это мало. И 500000 мало. Но можно развернуть ситуацию, и сделать генератор не друга, а себя самого, ввиду наличия гораздо большего количества сообщений. А потом попросить друга сделать то же самое. И дать модели друг другу. Можно много нового друг про друга узнать :)

Итоги

Ну, мы попытались. Важно показать сам принцип, как это делается. Большую часть данных мы имеем конкретно про себя. Можно натренировать модель по своим диалогам и оставить их своим внукам, как в лучших домах Чёрного Зеркала.

Это не совсем просто, может быть чудовищно долго (если диалогов много), но кроме пары часов на научиться работать с утилитами, да пары десятков-сотен часов на своем железе (или десятка часов на арендованном в облаке) ничего не требует.

Играйтесь, дамы и господа :)

И да пребудут с вами ваши деды)

8
4
1
1
1
7 комментариев