Как обучить казахскую Llama-3.1 за 5000 тенге и догнать KazLLM: опыт с Google Colab Pro
1. Введение
В последние годы наблюдается стремительное развитие языковых моделей, способных понимать и генерировать тексты на различных языках. Тем не менее, для казахского языка до сих пор существует ограниченное число качественных открытых моделей и датасетов, что существенно затрудняет достижение результатов, сопоставимых с моделями, обученными на более распространённых языках (английский, китайский, русский и т.д.).
В данной статье мы рассмотрим опыт файн-тюнинга модели на казахском языке, который стоил всего около 10 долларов США (или 5000 тенге) и был проведён с использованием графического процессора A100. Мы сравним полученные результаты с моделью, обучавшейся на более дорогих вычислительных ресурсах продолжительное время, и покажем, что при грамотном подходе даже бюджетное обучение может дать сопоставимые результаты. Помимо этого, мы кратко упомянем потенциальные пути дальнейшего улучшения качества модели за счёт расширения набора данных и увеличения числа параметров до более крупных масштабов (порядка 3 млрд).
2. Обзор существующих решений
2.1 Модель-«референс»: ISSAI/LLama-3.1-KazLLM-1.0-8B
Одной из известных открытых моделей для казахского языка, доступной на Hugging Face, является issai/LLama-3.1-KazLLM-1.0-8B. Эта модель, по данным авторов, обучалась достаточно долго и на специализированном аппаратном обеспечении. Она демонстрирует высокую точность на нескольких казахскоязычных тестовых наборах (MMLU-подобных и других).
2.2 Новая модель: armanibadboy/llama3.1-kazllm-8b-by-arman-ver2
В качестве основы для нашей модели взят репозиторий unsloth/Meta-Llama-3.1-8B-Instruct, а затем был проведён собственный файн-тюнинг на казахском языке. Общие затраты на обучение составили около 5000 тенге (~10 долларов США), и итоговая модель размещена на Hugging Face. Для обучения применялся A100 GPU, что позволило ускорить процесс и обойти некоторые ограничения, связанные с памятью и скоростью вычислений.
3. Использованные датасеты
3.1 Основные датасеты для файн-тюнинга
В рамках нашего эксперимента мы опирались на уже готовые наборы данных, доступные на Hugging Face:
1. kz-transformers/mmlu-translated-kk – переведённый на казахский язык фрагмент MMLU.
2. kz-transformers/kazakh-dastur-mc – тестовые задания по основам законодательства («Дәстүр»).
3. kz-transformers/kazakh-constitution-mc – тестовые задания по Конституции.
4. kz-transformers/kazakh-unified-national-testing-mc – сборник вопросов по ЕНТ (такие предметы, как история, география, английский, биология и т.д.).
Для упрощения обучения эти датасеты были объединены и «превращены» в инструкционно-ответный формат (prompt + правильный ответ).
3.2 Дополнительные перспективы по расширению данных
Существуют и другие датасеты, которые можно интегрировать в обучение, чтобы увеличить масштаб и тем самым потенциально улучшить качество:
• saillab/alpaca-kazakh-cleaned – казахская версия набора инструкций в стиле Alpaca.
• wikimedia/wikipedia (поднабор 20231101.kk) – недавняя выгрузка казахской Википедии.
При добавлении этих датасетов (особенно Википедии) объём обучающей выборки может возрасти в разы. В результате, если увеличить и масштабы модели (например, довести число параметров до 3 млрд), можно рассчитывать на ещё более качественные результаты. Однако подобное расширение требует уже не просто Google Colab, а более серьёзных вычислительных мощностей (например, выделенных серверов или кластеров), поскольку Colab не всегда позволяет работать в фоновом режиме без отключения; а тарифы с отключённой «автоприостановкой» стоят существенно дороже (~49 долларов в месяц и выше).
. Методы и процесс файн-тюнинга
4.1 Исходная модель и окружение
• Исходная модель: unsloth/Meta-Llama-3.1-8B-Instruct.
• Файн-тюнинг:
• Использовался A100 GPU через сервис Google Colab Pro
• Общие расходы – порядка 5000 тенге (10 долларов США). Куплено 100 токенов что хватает на 14 часов обучения
4.2 Технические аспекты обучения
• Использовался фреймворк Hugging Face Transformers и PEFT для более «лёгкого» обучения (LoRA/QLoRA и т.д.).
• Сборка датасетов в «инструкционный» формат, объединение разных наборов, удаление лишних колонок и так далее.
• Настройка гиперпараметров (batch_size, learning rate, epochs и др.) таким образом, чтобы избежать превышения лимитов по VRAM и времени.
5. Оценка качества (Evaluation)
5.1 Набор задач и метрики
Для оценки мы использовали скрипт lm_eval со следующими наборами заданий (MMLU-подобные и UNT-ориентированные):
• mmlu_translated_kk
• kazakh_and_literature_unt_mc
• kk_biology_unt_mc
• kk_constitution_mc
• kk_dastur_mc
• kk_english_unt_mc
• kk_geography_unt_mc
• kk_history_of_kazakhstan_unt_mc
• kk_human_society_rights_unt_mc
• kk_unified_national_testing_mc
• kk_world_history_unt_mc
Основная метрика – accuracy (acc), отображающая процент правильных ответов (zero-shot режим, --num_fewshot 0).
5.2 Результаты
Модель: armanibadboy/llama3.1-kazllm-8b-by-arman-ver2
Задача | acc | ± (stderr) |
kazakh_and_literature_unt_mc | 0,1893 | ±0.0067 |
kk_biology_unt_mc | 0,2263 | ±0.0115 |
kk_constitution_mc | 0,3667 | ±0.0312 |
kk_dastur_mc | 0,3177 | ±0.0202 |
kk_english_unt_mc | 0,2797 | ±0.0104 |
kk_geography_unt_mc | 0,2987 | ±0.0145 |
kk_history_of_kazakhstan_unt_mc | 0,232 | ±0.0086 |
kk_human_society_rights_unt_mc | 0,4362 | ±0.0408 |
kk_unified_national_testing_mc | 0,2263 | ±0.0115 |
kk_world_history_unt_mc | 0,3299 | ±0.0145 |
mmlu_translated_kk | 0,207 | ±0.0120 |
Сравнение: issai/LLama-3.1-KazLLM-1.0-8B (при тех же настройках)
Задача | acc | ± (stderr) |
kazakh_and_literature_unt_mc | 0,2088 | ±0.0070 |
kk_biology_unt_mc | 0,2733 | ±0.0123 |
kk_constitution_mc | 0,4417 | ±0.0321 |
kk_dastur_mc | 0,359 | ±0.0208 |
kk_english_unt_mc | 0,3254 | ±0.0109 |
kk_geography_unt_mc | 0,3716 | ±0.0153 |
kk_history_of_kazakhstan_unt_mc | 0,2943 | ±0.0093 |
kk_human_society_rights_unt_mc | 0,4899 | ±0.0411 |
kk_unified_national_testing_mc | 0,2733 | ±0.0123 |
kk_world_history_unt_mc | 0,3782 | ±0.0149 |
mmlu_translated_kk | 0,2991 | ±0.0135 |
Как видно, модель armanibadboy/llama3.1-kazllm-8b-by-arman-ver2, обученная относительно быстро и всего за 5000 тенге, демонстрирует результаты, которые в ряде задач не так уж и сильно уступают более «взрослой» модели issai/LLama-3.1-KazLLM-1.0-8B. Разрыв заметен, но его нельзя назвать пропастью — особенно с учётом того, что мы не располагали выделенными серверами и многочасовым временем обучения.
6. Причины расхождений с некоторыми лидербордами
При сравнении с различными публичными лидербордами можно обнаружить заметные расхождения в показателях (как для issai/LLama-3.1-KazLLM-1.0-8B, так и для других моделей). Ниже перечислены основные факторы:
1. Версии датасетов. В лидербордах могут использоваться иные версии тестовых наборов либо особая фильтрация.
2. Разные настройки оценки. Количество few-shot-примеров, temperature, top_p и прочие параметры генерации могут влиять на результат.
3. Обновления модели. Авторы иногда выкладывают новые веса или заново переобученные версии.
4. Выбор лучшего прогона. В некоторых случаях публикуются «лучшие» результаты вместо среднестатистических.
Хочу обратить внимание, что значения для модели issai/LLama-3.1-KazLLM-1.0-8B, полученные мной с помощью lm_eval, сильно отличаются от показателей, представленных на этой странице. По данным лидерборда, модель демонстрирует гораздо более высокие результаты.
Из-за этого может показаться, что моя модель уступает вдвое, хотя при запуске тех же тестов, которые перечислены на указанном ресурсе, разница между моделями оказывается не такой заметной.
Если владелец данного лидерборда читает эти строки, пожалуйста, обновите результаты на странице. Мне, как человеку, который любит соревнования, хотелось бы видеть максимально актуальные данные и опираться на действительно корректные сравнения.**
7. Выводы и дальнейшая работа
1. Экономичный файн-тюнинг. Эксперимент показывает, что даже за ~10 долларов США (5000 тенге), используя всего лишь Google Colab с A100 GPU, можно добиться достаточно хороших результатов для модели казахского языка.
2. Близкие результаты. Разница между нашей моделью и более «тяжёлой» (issai/LLama-3.1-KazLLM-1.0-8B) всё ещё существует, но не столь критична, учитывая кратность затрат и времени обучения.
3. Расширение датасетов и увеличение параметров. Для дальнейшего повышения качества можно подключить дополнительные датасеты — например, saillab/alpaca-kazakh-cleaned или wikimedia/wikipedia (subset 20231101.kk). Включение всех этих источников может повысить объём данных до нескольких гигабайт, что в свою очередь позволит увеличить модель (до ~3B параметров и выше). Однако тут уже потребуются выделенные сервера или облачные сервисы дороже Colab, так как у Google Colab есть ограничения по времени сеанса и объёму памяти, а режим без отключений стоит около 49 долларов в месяц и выше.
4. Обновление лидербордов. С учётом быстрого прогресса в области казахскоязычных LLM-моделей, важно периодически обновлять результаты официальных таблиц лидеров, чтобы отражать реальные показатели новых и обновлённых моделей.
Приложение: Код эксперимента
Ниже приводится код, который мы использовали для обучения и оценки модели (запускался в среде с A100 GPU). Вы можете адаптировать под свои нужды, изменять гиперпараметры и датасеты.
%%capture
!pip install unsloth
# Также установим последнюю версию Unsloth из репозитория
!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git
from unsloth import FastLanguageModel
import torch
max_seq_length = 2048
dtype = None # Автоопределение (можно задать Float16, BFloat16 и т.д.)
load_in_4bit = False # True при необходимости 4bit-квантования
# Список 4-bit моделей (при желании)
fourbit_models = [
"unsloth/Meta-Llama-3.1-8B-bnb-4bit",
"unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit",
# ...
]
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Meta-Llama-3.1-8B-Instruct",
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit,
)
# Настраиваем LoRA
model = FastLanguageModel.get_peft_model(
model,
r = 32,
target_modules = [
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_alpha = 32,
lora_dropout = 0,
bias = "none",
use_gradient_checkpointing = "unsloth",
random_state = 3407,
use_rslora = False,
loftq_config = None,
)
# Загрузка и подготовка датасетов
from datasets import load_dataset, concatenate_datasets
dataset = load_dataset("kz-transformers/mmlu-translated-kk")
dataset3 = load_dataset("kz-transformers/kazakh-dastur-mc", split='test')
dataset2 = load_dataset("kz-transformers/kazakh-constitution-mc", split='test')
dataset = concatenate_datasets([
dataset['test'],
dataset['validation'],
dataset['dev'],
dataset3,
dataset2
])
mmlu_prompt2 = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.
### Input:
{}
### Response:
{}"""
EOS_TOKEN = tokenizer.eos_token
def formattoconversations3(examples):
questions = examples["Question"]
a_opts = examples["Option A"]
b_opts = examples["Option B"]
c_opts = examples["Option C"]
d_opts = examples["Option D"]
answers = examples["Correct Answer"]
texts = []
for q, a, b, c, d, ans in zip(questions, a_opts, b_opts, c_opts, d_opts, answers):
correct_text = ''
if ans == 'A':
correct_text = a
elif ans == 'B':
correct_text = b
elif ans == 'C':
correct_text = c
elif ans == 'D':
correct_text = d
text1 = mmlu_prompt2.format(q, correct_text) + EOS_TOKEN
texts.append(text1)
return {"text": texts}
apll = dataset.map(formattoconversations3, batched=True)
apll = apll.remove_columns([
'Title','Question', 'Option A', 'Option B', 'Option C',
'Option D', 'Correct Answer','Text'
])
dataset1 = load_dataset("kz-transformers/kazakh-unified-national-testing-mc")
dataset1 = concatenate_datasets([
dataset1['kazakh_and_literature'],
dataset1['world_history'],
dataset1['english'],
dataset1['history_of_kazakhstan'],
dataset1['geography'],
dataset1['biology'],
dataset1['human_society_rights'],
])
def formattoconversations3(examples):
questions = examples["question"]
a_opts = examples["A"]
b_opts = examples["B"]
c_opts = examples["C"]
d_opts = examples["D"]
e_opts = examples["E"]
f_opts = examples["F"]
g_opts = examples["G"]
h_opts = examples["H"]
answers = examples["correct_answer"]
texts = []
for q, a, b, c, d, e, f, g, h, ans in zip(questions, a_opts, b_opts, c_opts, d_opts,
e_opts, f_opts, g_opts, h_opts, answers):
correct_text = ''
if ans == 'A':
correct_text = a
elif ans == 'B':
correct_text = b
elif ans == 'C':
correct_text = c
elif ans == 'D':
correct_text = d
elif ans == 'E':
correct_text = e
elif ans == 'F':
correct_text = f
elif ans == 'G':
correct_text = g
elif ans == 'H':
correct_text = h
text1 = mmlu_prompt2.format(q, correct_text) + EOS_TOKEN
texts.append(text1)
return {"text": texts}
apll1 = dataset1.map(formattoconversations3, batched=True)
apll1 = apll1.remove_columns([
'subject','question', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'correct_answer'
])
dataset2 = concatenate_datasets([apll1, apll])
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset2,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 8,
packing = False,
args = TrainingArguments(
per_device_train_batch_size = 4,
gradient_accumulation_steps = 5,
warmup_steps = 5,
num_train_epochs = 5,
learning_rate = 1e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
logging_steps = 100,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
output_dir = "outputs",
report_to = "none",
),
)
trainer_stats = trainer.train()
trainer.push_to_hub(
"armanibadboy/llama3.1-kazllm-8b-by-arman-ver2",
tokenizer,
token="ваш_hf_токен"
)
model.push_to_hub(
"armanibadboy/llama3.1-kazllm-8b-by-arman-ver2",
tokenizer,
token="ваш_hf_токен"
)
tokenizer.push_to_hub(
"armanibadboy/llama3.1-kazllm-8b-by-arman-ver2",
token="ваш_hf_токен"
)
%%bash
git clone --depth 1 https://github.com/horde-research/lm-evaluation-harness-kk.git
cd lm-evaluation-harness-kk
pip install -e .
!lm_eval \
--model hf \
--model_args pretrained=armanibadboy/llama3.1-kazllm-8b-by-arman-ver2 \
--batch_size 3 \
--num_fewshot 0 \
--tasks mmlu_translated_kk,kazakh_and_literature_unt_mc,kk_biology_unt_mc,kk_constitution_mc,kk_dastur_mc,kk_english_unt_mc,kk_geography_unt_mc,kk_history_of_kazakhstan_unt_mc,kk_human_society_rights_unt_mc,kk_unified_national_testing_mc,kk_world_history_unt_mc \
--output output
Заключение
Таким образом, мы показали, что даже при бюджете в 5000 тенге (~10 долларов) на аренду вычислительных ресурсов с A100 GPU можно провести файн-тюнинг казахскоязычной модели Llama-3.1 (8B параметров) и достичь результатов, относительно близких к более «масштабной» и долго обучавшейся модели. При этом дальнейшее улучшение качества возможно за счёт:
• Расширения обучающего датасета (за счёт Wikipedia и других источников).
• Увеличения числа параметров (до 3B и выше).
• Применения более длительного обучения на выделенных серверах (так как Google Colab имеет ограничения по времени сеанса, а тарифы с фоновым режимом стоят существенно дороже).
Все эти шаги позволяют надеяться на активное развитие казахскоязычных языковых моделей и более широкий спектр приложений — от чат-ботов и поиска до систем обучения и перевода.
Ссылка на google colab ТУТ
Комментарии 4
Авторизуйтесь чтобы оставить комментарий
Мерей Қалжанова · Янв. 15, 2025 10:18
жаксы болгае
Balzhan I · Янв. 15, 2025 09:29
очень полезно!
Balzhan I · Янв. 15, 2025 09:28
как раз такое не хватает!
Balzhan I · Янв. 15, 2025 09:28
ооо крутоо!