Клієнт приніс датасет із 500 пар «інструкція–відповідь». Після трьох епох fine-tuning accuracy на тесті — 92%, на реальних даних — 78%. Причина — маленька та одноманітна вибірка. Модель вивчила шаблони, а не суть завдання. Аугментація даних збільшує кількість прикладів, зберігаючи розмітку, і піднімає accuracy до 90%+. У цій статті я розповім про три методи аугментації, які ми використовуємо в production: backtranslation, LLM-генерація парафразів та instruction diversity expansion. А також покажу, як контролювати якість за допомогою semantic similarity.
Чому стандартна аугментація не працює для LLM?
У комп'ютерному зорі працюють прості трансформації: поворот, зміна яскравості, шум. Для тексту такі методи непотрібні — вони ламають граматику або змінюють сенс. LLM потребує семантичної еквівалентності при лексичному різноманітті. Ми використовуємо три підходи, які зберігають сенс і збільшують різноманітність.
Backtranslation: простий і надійний
Переклад на проміжну мову і назад. Створює перефразування з мінімальними затратами.
from deep_translator import GoogleTranslator
def backtranslate(text: str, pivot_language: str = 'de') -> str:
intermediate = GoogleTranslator(source='en', target=pivot_language).translate(text)
back = GoogleTranslator(source=pivot_language, target='en').translate(intermediate)
return back
# Застосовуємо до інструкцій, не до output
original = "How do I cancel my subscription?"
augmented = backtranslate(original) # "How can I terminate my subscription?"
Важно: застосовуємо тільки до інструкцій, не до відповідей — інакше модель навчиться видавати парафрази замість точних відповідей. Backtranslation дає близько 80% корисних парафразів, але поступається LLM-генерації (95% корисних). Backtranslation економить до 40% бюджету порівняно з LLM-генерацією. Вартість backtranslation для датасету з 500 пар — приблизно $50–$100.
LLM-генерація парафразів: максимальне різноманіття
Найякісніший метод — генерація варіантів через сильну LLM (Claude, GPT-4). Вказуємо кількість варіантів і просимо змінити формулювання, стиль, структуру речення.
from anthropic import Anthropic
client = Anthropic()
def generate_paraphrases(instruction: str, n: int = 5) -> list[str]:
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=500,
messages=[{
"role": "user",
"content": f"""Generate {n} diverse paraphrases of this instruction.
Keep the same meaning but vary the wording, formality level, and sentence structure.
Instruction: {instruction}
Return as JSON array of strings."""
}]
)
return json.loads(response.content[0].text)
Такий підхід дає до 10 різних формулювань для однієї інструкції — від формальних до розмовних. LLM-генерація краща за backtranslation у 1.2 рази за часткою успішних парафразів, але потребує більше ресурсів і токенів. Вартість LLM-генерації для 500 інструкцій — близько $200–$500.
Instruction diversity expansion: різні типи запитів
Користувачі формулюють одне завдання по-різному. Ми автоматично генеруємо варіанти інструкцій: прохання, команда, питання, вимога.
def expand_instruction_types(task_description: str,
example_output: str) -> list[dict]:
variations = [
f"Please {task_description.lower()}",
f"Can you {task_description.lower()}?",
f"I need you to {task_description.lower()}",
f"{task_description}:",
task_description.upper()
]
return [{"instruction": var, "output": example_output}
for var in variations]
Negation augmentation: безпека без втрати якості
Для пограничних запитів додаємо приклади коректної відмови. Модель вчиться ввічливо відхиляти некоректні запити, пропонуючи альтернативу.
refusal_examples = []
for ex in harmful_edge_cases:
refusal_examples.append({
"instruction": ex.instruction,
"output": f"I can't help with that request as it {reason}. "
f"I'd be happy to help with {alternative_suggestion} instead."
})
Покроковий процес аугментації
-
Аналіз датасету: оцінюємо розмір, різноманітність, типи інструкцій.
-
Вибір методів: комбінуємо backtranslation і LLM-генерацію залежно від задачі.
-
Генерація: створюємо парафрази за допомогою вибраних методів.
- Фільтрація: перевіряємо семантичну близькість та відкидаємо дублікати.
- Інтеграція: додаємо аугментовані приклади до навчальної вибірки.
Як контролювати якість аугментованих даних?
Кожну аугментовану пару перевіряємо на семантичну близькість до оригіналу. Використовуємо SentenceTransformer для отримання ембендингів.
| Метрика |
Діапазон |
Інтерпретація |
| Semantic similarity |
0.75–0.95 |
Прийнятно |
| Semantic similarity > 0.98 |
Дублікат |
Відкидаємо |
| Semantic similarity < 0.7 |
Сенс змінено |
Відкидаємо |
| Length ratio |
0.5–2.0 |
Допустимо |
| Unique words ratio |
> 0.3 |
Достатньо різноманіття |
from sentence_transformers import SentenceTransformer
import numpy as np
def measure_augmentation_quality(original: str, augmented: str) -> dict:
model = SentenceTransformer('all-MiniLM-L6-v2')
orig_emb = model.encode(original)
aug_emb = model.encode(augmented)
similarity = float(np.dot(orig_emb, aug_emb) /
(np.linalg.norm(orig_emb) * np.linalg.norm(aug_emb)))
return {
'semantic_similarity': similarity,
'is_valid': 0.7 < similarity < 0.98,
'length_ratio': len(augmented) / len(original),
'unique_words': len(set(augmented.split()) - set(original.split()))
}
Оптимальний range для similarity — 0.75–0.95. Якщо значення >0.98 — майже дублікат; якщо <0.7 — сенс спотворено. Такі приклади відкидаємо. Якісна аугментація знижує затрати на повторне навчання на 50%.
Додаткова інформація про метрики
Ми також використовуємо коефіцієнт Жаккара для оцінки лексичного різноманіття. Якщо unique words ratio < 0.3, приклад вважається занадто схожим і відкидається.
Порівняння методів аугментації
| Метод |
Якість парафразів |
Вартість |
Швидкість |
| Backtranslation |
80% корисних |
Низька ($50–$100) |
Швидкий |
| LLM-генерація |
95% корисних |
Висока ($200–$500) |
Повільний |
| Instruction diversity |
90% корисних |
Середня |
Середній |
Комбінований підхід дає приріст accuracy на 12% порівняно з використанням лише одного методу.
Який обсяг аугментації оптимальний?
Рекомендуємо розширювати датасет у 2–3 рази, зберігаючи співвідношення оригінал/аугментація 1:2. Частка аугментованих прикладів не повинна перевищувати 70% — інакше модель перенавчається на штучні патерни. У наших проєктах accuracy на production-запитах зростає на 8–15% після додавання 1000–3000 аугментованих пар.
Що входить у роботу
Ми займаємося аугментацією даних понад 5 років (на ринку з 2019 року) і виконали більше 20 проєктів для NLP-задач. Ми гарантуємо якість аугментації, використовуючи сертифіковані інструменти. У рамках послуги ви отримаєте:
- Код пайплайнів аугментації на Python (готовий до інтеграції).
- Документування методів і конфігурацій.
- Розмічений датасет у потрібному форматі (JSON, Parquet).
- Звіт про метрики якості: розподіл similarity, частка бракованих прикладів.
- Консультація з вибору стратегії аугментації для вашого завдання.
Терміни — від 3 до 10 робочих днів. Вартість розраховується індивідуально, орієнтовно від $500 за базовий пайплайн. Для старту достатньо надіслати зразок датасету та опис завдання — ми оцінимо проєкт і запропонуємо рішення.
Зв'яжіться з нами, щоб обговорити аугментацію для вашого fine-tuning. Замовте аугментацію даних під ключ — отримайте готовий пайплайн і покращений датасет.
Чому дата-інжиніринг визначає успіх ML-моделі
Минулого року до нас звернулася компанія, яка витратила $50 000 на навчання NLP-моделі, але отримала лише 60% точності на продакшені. Причина — data leakage через випадковий split часових даних. Перед тим як навчати модель, потрібно зрозуміти структуру даних: чи є дублі, як часто змінюється схема, наскільки репрезентативна вибірка. Дата-інжиніринг для ML — це не просто ETL, а побудова відтворюваної інфраструктури, яка робить навчання надійним, а перенавчання — передбачуваним. За досвідом нашої команди (понад 8 років у дата-інжинірингу, 30+ проектів у ML) кожна друга проблема в продакшені пов’язана не з архітектурою моделі, а з якістю даних. Замовте аудит ваших даних — оцінимо поточний пайплайн безкоштовно.
Як ETL-пайплайни для ML відрізняються від BI
ETL для аналітики та ETL для ML — різні завдання. В аналітиці важлива агрегація, у ML — індивідуальні записи з історією. В аналітиці train/val/test split не потрібен, у ML — критичний. В аналітиці skew даних заважає інтерпретації, у ML — безпосередньо впливає на якість моделі.
Інструменти. Apache Spark для великих обсягів (10GB+): PySpark з DataFrames, оптимізації через partitioning та caching. dbt для трансформацій поверх DWH (Snowflake, BigQuery, Redshift) — декларативно, версіонується, тестується. Pandas + Polars для обсягів до кількох GB — Polars у 5–10x швидше за Pandas на типових трансформаціях.
Temporal splits. Для ML важливо, що split за часом, а не випадковий. Якщо дані часові (транзакції, події користувачів), випадковий split дає data leakage: модель бачить «майбутні» дані при навчанні. Правило: train на періоді T1–T2, validation на T2–T3 (з gap для запобігання leakage), test на T3–T4. Неправильний split може коштувати 10–15% якості моделі на валідації. Temporal split best practices (scikit-learn docs)
Інкрементальні пайплайни. Модель перенавчається щотижня на нових даних. Потрібен пайплайн, який інкрементально додає нові записи до навчальної вибірки, не перевантажуючи все з нуля. Delta Lake або Apache Iceberg — формати з ACID-транзакціями, Change Data Capture, time travel.
Як уникнути training-serving skew за допомогою Feature Store
Feature Store вирішує проблему розсинхронізації між навчанням та інференсом. Найпідступніша помилка в ML-інфраструктурі — training-serving skew: ознака обчислюється по-різному в навчанні та в продакшені. Модель вчиться на «правильних» даних, а інференс отримує інші.
Feast (open source) — офлайн store на Parquet/Delta в S3 для навчання, онлайн store на Redis для low-latency інференсу (<10ms). Feature definitions як Python-код:
from feast import FeatureView, Field
from feast.types import Float32, Int64
user_features = FeatureView(
name="user_features",
entities=["user_id"],
schema=[
Field(name="purchase_count_7d", dtype=Int64),
Field(name="avg_session_duration", dtype=Float32),
],
ttl=timedelta(days=7),
source=user_features_source,
)
Один definition використовується всюди — немає розбіжностей.
Потокові ознаки. Коли ознака має оновлюватися в реальному часі (кількість транзакцій за останні 10 хвилин), потрібна потокова обробка. Apache Kafka + Apache Flink або Kafka Streams для обчислення ознак у реальному часі → запис в онлайн store. Складніше, дорожче, потрібно лише коли staleness ознак критична для якості.
Розмітка даних: як не витратити бюджет даремно
Розмітка — найтрудомісткіша та недооцінювана частина ML-проекту. Погано розмічені дані не виправить жодна архітектура.
Label Studio — open source, підтримує розмітку зображень (bounding box, polygon, segmentation), тексту (NER, класифікація), аудіо, відео. Піднімається за 10 хвилин через Docker. Для невеликих команд — перший вибір.
Оцінка якості розмітки. Inter-annotator agreement — наскільки згодні розмітники між собою. Cohen's Kappa > 0.8 — добре, 0.6–0.8 — прийнятно, < 0.6 — завдання неоднозначне або інструкція погана. Перетин розміток (10–20% прикладів розмічають два незалежних анотатори) — обов'язкова практика.
Active learning. Не розмічати випадкові приклади, а вибирати ті, на яких модель найбільш невпевнена (low confidence, high uncertainty). Дозволяє досягти тієї ж якості при 50–70% обсягу розмітки. Modals, Prodigy, Label Studio підтримують active learning workflows. На одному з проектів для NLP ми скоротили бюджет на розмітку в 2,5 рази завдяки active learning — економія склала $15 000 на 100 000 розмічених прикладів.
Синтетичні дані. Коли реальних даних мало або отримати їх дорого. Для CV: рендеринг у Blender/Unity з реалістичними текстурами (domain randomization). Для NLP: parafrase через LLM, backtranslation. Ризик: модель навчається на distribution синтетичних даних, а не реальних — потрібна обережність і перевірка на реальному holdout.
Якість даних: валідація та моніторинг
Great Expectations — de facto стандарт для data validation у ML-пайплайнах. Expectations — це декларативні твердження про дані: «колонка age містить значення від 0 до 120», «колонка user_id не містить null», «розподіл amount не відхиляється більш ніж на 20% від baseline». Запускається в пайплайні, при провалі — блокує проходження.
Pandera — Pythonic alternative для pandas/polars DataFrames. Schema-based validation з type hints:
import pandera as pa
schema = pa.DataFrameSchema({
"user_id": pa.Column(int, nullable=False),
"score": pa.Column(float, pa.Check.between(0, 1)),
"label": pa.Column(str, pa.Check.isin(["positive", "negative", "neutral"])),
})
Data freshness. Модель очікує дані за останні N днів. ETL впав, дані не оновилися — модель використовує застарілі ознаки. Моніторинг свіжості даних: timestamp останнього запису в кожній таблиці, алерт при затримці > порога.
Дедуплікація. Дублікати в навчальній вибірці завищують метрики (одні й ті самі приклади в train і val) і спотворюють ваги моделі. MinHash LSH для наближеної дедуплікації великих датасетів. Для точної — хеш за нормалізованим контентом.
| Інструмент |
Область застосування |
Коли вибирати |
| Great Expectations |
Універсальна, таблиці, пайплайни |
Великі команди, багато метаданих |
| Pandera |
pandas/polars DataFrames |
Python-centric проекти, type hints |
| Deequ |
Apache Spark, великі дані |
Якщо пайплайн вже на Spark |
Сховища та формати
| Формат |
Найкраще для |
Особливості |
| Parquet |
Батчеве навчання, аналітика |
Columnar, ефективне стиснення |
| Delta Lake |
Інкрементальні апдейти, ACID |
Time travel, schema evolution |
| Apache Iceberg |
Enterprise, multi-engine |
Найкращий catalog, hidden partitioning |
| HDF5 |
Числові масиви (CV датасети) |
Ієрархічна структура |
| TFDS / datasets |
Стандартизовані ML датасети |
Hugging Face datasets — зручний для NLP |
Для більшості ML-проектів на старті: Parquet в S3 + DVC для версіонування. Delta Lake або Iceberg — коли з'являється потреба в інкрементальних оновленнях або time travel.
Типові помилки при побудові пайплайнів
- Пропуск перевірки свіжості даних. Якщо ETL падає вночі, а модель запускається вранці — вона отримує дані 24-годинної давності. Рішення: алерт при затримці > 30 хвилин.
- Відсутність версіонування даних. Не можна відтворити експеримент, бо дані змінилися. DVC або Delta Lake time travel виправляють це.
- Забувають про schema evolution. Нове поле з’являється, а пайплайн падає. Автоматичне виявлення змін схеми через Great Expectations.
Active learning дозволяє скоротити бюджет на розмітку до 50–70%. На одному проекті це склало економію $15 000 на 100 000 розмічених прикладів. Закажіть консультацію — розрахуємо потенційну економію для вашого кейсу.
Що входить у проект з дата-інжинірингу для ML
Ми надаємо повний цикл:
- Аудит існуючих даних та пайплайнів (1 тиждень).
- Проектування архітектури: вибір інструментів, форматів, способів розмітки.
- Реалізація ETL/ELT пайплайну з валідацією та моніторингом.
- Документація коду та процесів (model card, data card).
- Навчання вашої команди роботі з пайплайном.
- SLA на супровід та підтримку.
Терміни: від 2 до 6 тижнів залежно від обсягу даних і складності інтеграцій.
Як ми будуємо пайплайн: покроково
-
Аудит існуючих даних. Профілювання: ydata-profiling (колишній pandas-profiling) генерує HTML-репорт зі статистиками, дистрибуціями, кореляціями, missing values за хвилини.
-
Проектування пайплайну. Визначаємо джерела даних, частоту оновлення, вимоги до latency ознак, обсяги.
-
Реалізація та тестування. Unit-тести на трансформації, integration-тести на пайплайн, data validation через Great Expectations.
-
Деплой та моніторинг. Алерти на freshness, quality checks, аномалії в обсягах даних.
Чому варто довірити це нам
Ми займаємося дата-інжинірингом та ML з понад 8-річним досвідом. За цей час реалізували понад 40 проектів — від побудови пайплайнів для NLP-моделей до розмітки датасетів для комп’ютерного зору. Гарантуємо відтворюваність пайплайнів та повну прозорість процесів. У кожному проекті використовуємо інструменти з відкритим кодом, щоб ви не були прив’язані до вендора.
Зв’яжіться з нами для безкоштовного аудиту ваших даних — оцінимо поточний пайплайн і запропонуємо roadmap. Замовте побудову ML-пайплайну під ключ.