Делаю диплом Тема: AI-линтер безопасности с автоп...
Created on: February 21, 2026
Answered using GPT-5.2 Pro by Chat01
Created on: February 21, 2026
Answered using GPT-5.2 Pro by Chat01
Делаю диплом
Тема: AI-линтер безопасности с автопочинкой
детекцию уязвимостей делать отдельной моделью по коду (AST/DFG/CPG + GNN/Transformer);
генерацию патчей делать через небольшую open-weights LLM для кода, дообученную LoRA на патчах (diff’ах). Подойдут, например, StarCoder2 (3B/7B/15B) или Code Llama — обе семейства открытые и хорошо держат кодовые задачи. (Hugging Face)
Данные - есть как синтетические, так и реальные уязвимости/патчи:
SARD/Juliet (NIST): сотни тысяч тесткейс-программ с размеченными CWE; Juliet C/C++ v1.3 покрывает ~118 CWEs — идеально для “белых” бенчмарков и регрессии. (NIST)
Devign: датасет и baseline-подход на графах (GNN) для детекции уязвимых функций в реальном C-коде. (NeurIPS Papers)
Big-Vul: C/C++ с привязкой к CVE и коммитам-фиксам — удобно для обучения автопочинки на before/after. (GitHub)
MegaVul: крупный набор из десятков тысяч уязвимых/неуязвимых функций и тысяч фиксов. (GitHub)
Комбинация Juliet→для точности и Big-Vul/MegaVul→для реализма и патчей даёт устойчивый пайплайн.
В каком формате и как это будет работать (базовый сценарий)
Артефакты продукта:
CLI + локальная библиотека; по желанию — VS Code-расширение и pre-commit hook.
Вывод в SARIF (индустриальный JSON-стандарт для статанализа), чтобы “из коробки” открываться в IDE/GitHub. (OASIS Open)
Пример UX:
bash
ailint scan ./repo --lang c --rules cwe_top25 --out out.sarif
ailint show out.sarif --only HIGH
ailint fix --file src/http.c --line 120 --cwe CWE-78 --apply
ailint verify --build "make test" --timeout 300
Под капотом (архитектура):
Парсер/графы кода → строим CPG/AST/DFG (можно через Joern/Fraunhofer CPG). (GitHub)
Детектор → модель (GNN/Transformer по графам/секвенсам) помечает кандидат-строки/функции (пер-CWE). Базовая идея как в Devign. (NeurIPS Papers)
Автофикс → маленькая LLM по диффам: prompt = контекст уязвимости + CWE-гайд + “до/после” примеры из Big-Vul/MegaVul; генерим patch (unified diff), прогоняем компиляцию/тесты. (GitHub)
Вывод → SARIF + “путь данных/управления” до sink/source, ссылки на CWE, confidence.
Дообучать или писать с нуля?
Детектор: уместно дообучить (или обучить с нуля небольшую) модель на Devign/Big-Vul + собственные хард-негативы.
LLM-фиксатор: только дообучение LoRA open-модели (StarCoder2 / Code Llama) на небольшом корпусе security-патчей — этого достаточно для осмысленных предложений, а вычислительно это на порядок дешевле, чем тренировать foundation-модель. (Hugging Face)
Сравним с популярными статанализаторами:
CodeQL — мощный, но требует писать правила на QL и не делает “генерацию фиксов” по умолчанию. (GitHub Docs)
Semgrep — быстрые паттерны, простые правила, снова без ML-детекции глубокой семантики и без генерации патчей. (GitHub)
Твоя дифференциация:
Гибрид SAST+ML: правила для очевидных CWE + ML/CPG для сложных потоков данных.
Автопочинка: предлагаешь конкретный diff + краткое объяснение “почему безопаснее” и ссылку на CWE.
Полный офлайн: приватность кода — selling point (актуально на фоне коммерциализации рынка SAST). (The Wall Street Journal)
Совместимость: SARIF-вывод → открывается в IDE/CI без интеграционных плясок. (OASIS Open)
Адаптация под проект: довчишь детектор на истории коммитов самого репозитория (индивидуальный стиль кода/патчей).
Язык/область и минимальный scope
Чтобы уложиться в сроки и показать сильный результат, предлагаю стартовый фокус:
C/C++ и топ-CWE для памяти (CWE-787/119/190) + одна инъекционная категория (CWE-78).
Причины: лучшие датасеты (Devign/Big-Vul/Juliet), наглядные краши/эксплойтабельность, измеримый эффект после фикса. (NeurIPS Papers)
Метрики и проверка качества
Детектор: Precision/Recall/F1 per-CWE на Devign/Juliet (holdout), AUROC. (NeurIPS Papers)
Автопочинка:
Patch-apply rate (патч применился, проект собрался),
Tests pass rate (до/после),
Security plausibility (экспертная проверка на подмножестве),
Time-to-fix и token-cost (для отчёта).
Отчётность: SARIF + линк на CWE и краткое объяснение (LLM-reasoning) — удобно для защиты проекта. (OASIS Open)
Быстрый план работ (8–10 недель)
Нед. 1–2: сбор датасетов (Juliet + Devign + Big-Vul), конвертация в единый формат (функция/метка/CWE/diff). (NIAID Data Ecosystem Discovery Portal)
Нед. 3: CPG-экстракция и baseline-детектор (логистическая регрессия/маленький Transformer по токенам) → sanity F1. (GitHub)
Нед. 4–5: GNN/Transformer-детектор по CPG/DFG + hard-negative mining.
Нед. 6: LoRA-довч LLM на патчах Big-Vul/MegaVul, формат вывода — unified diff. (GitHub)
Нед. 7: SARIF-экспорт + CLI/VSCode-плагин. (OASIS Open)
Нед. 8–9: оффлайн-бенчмарки на Juliet/репо-кейсы, абляции. (NIAID Data Ecosystem Discovery Portal)
Нед. 10: оформление диплома (методы, эксперименты, ограничения, этика).
Собираюсь начать работу. Давай найдем и спарсим в формат датасеты (Найди мне их, дай код для приведения к одному типу). Потом обучим/дообучим модели и пойдем генерить пайплайн, потом займемся результатом(cli/ui для отображенния, лично я предлагаю пока это оставить в стороне, т.к. основа проекта - именно работающие нейронки и данные, не забивай сильно себе контекст размышлениями о конечном продукте)
Давай для начала ссылки и код, что и откуда берем, где выполняем(не на своем же ноуте я запущу обучение). Можно kaggle или коллаб, можешь что-то помощнее из облака предложить). Сделай полный код(класс датасета, выборка, train, val, test, output и дальнейшую логику действий. Добавь понятные объяснения в коде). Собственоо стек python/pytorch + готовые либы/классы/фреймворки
Ниже — (1) где взять датасеты (ссылки), (2) единый формат, (3) где запускать обучение, и (4) полный стартовый код (prepare → train detector → train patcher LoRA → demo) на Python/PyTorch + Hugging Face (datasets/transformers/peft).
Скачать готовый стартовый пакет кода (zip)
Чтобы не мучаться с ручными архивами/гугл-драйвами и сразу получить splits + нормальную загрузку, на старте рекомендую Hugging Face Datasets. Это не «какой-то левый скрапинг»: это просто удобный слой доставки/хранения (а первоисточники при желании тоже можно использовать отдельно).
LorenzH/juliet_test_suite_c_1_3 — уже извлечены good и bad варианты (через OMITGOOD/OMITBAD), есть train/test, лицензия CC0. (Hugging Face)Для диплома HF-версия идеальна, потому что сразу дает пары bad→good (то есть сразу датасет для автопочинки).
DetectVul/devign — удобно грузится и уже разложено на train/val/test. (Hugging Face)bstee615/bigvul — есть split’ы и нужные поля func_before/func_after, CWE/CVE. (Hugging Face)hitoshura25/megavul — поля vulnerable_code, fixed_code, cwe_id, cve_id. (Hugging Face)Я предлагаю два JSONL-формата (по одному на задачу):
data/unified/detect/{train,validation,test}.jsonl
json{ "uid": "unique_id", "dataset": "juliet|devign|bigvul|megavul", "split": "train|validation|test", "lang": "c|cpp", "cwe": "CWE-787" | null, "cve": "CVE-xxxx-xxxx" | null, "label": 0|1, "code": "function or snippet", "meta": { "anything": "useful" } }
data/unified/repair/{train,validation,test}.jsonl
json{ "uid": "unique_id", "dataset": "...", "split": "...", "lang": "c|cpp", "cwe": "CWE-xxx" | null, "cve": "CVE-..." | null, "code_before": "vulnerable code", "code_after": "fixed code", "diff": "--- a/function.c\n+++ b/function.c\n@@ ...\n", "meta": { ... } }
Минимально и быстро:
Если хочешь «помощнее» (для 7B/15B или больших контекстов/батчей):
pip install, и запуск тех же скриптов.Я собрал это в zip:
Скачать стартовый пакет
Внутри:
prepare_unified.py — грузит датасеты (HF) и пишет unified JSONLtrain_detect.py — fine-tune baseline детектора (CodeBERT) (Hugging Face)train_repair_lora.py — QLoRA/LoRA SFT для генерации unified diff на базе StarCoder2-3B (Hugging Face)infer_demo.py — минимальный demo (score + patch)requirements.txt, README.mdНиже — команды «как запустить» (Colab/Kaggle одинаково).
bashpip install -r requirements.txt
Вариант A (все источники):
bashpython prepare_unified.py --out_dir data/unified \ --use_juliet --use_devign --use_bigvul --use_megavul \ --max_megavul 200000
Вариант B (сфокусироваться на топ-CWE):
bashpython prepare_unified.py --out_dir data/unified \ --use_juliet --use_bigvul --use_megavul \ --cwe_filter CWE-787,CWE-119,CWE-190,CWE-78
После этого появятся:
data/unified/detect/train.jsonl etcdata/unified/repair/train.jsonl etcdata/unified/stats.json (счетчики)bashpython train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 3 --train_bs 8 --eval_bs 8 --max_length 512
На выходе:
runs/detect_codebert/best_model/runs/detect_codebert/metrics.jsonbashpython train_repair_lora.py \ --data_dir data/unified/repair \ --base_model bigcode/starcoder2-3b \ --output_dir runs/repair_starcoder2_3b_lora \ --epochs 1 --max_length 2048 --train_bs 1 --grad_accum 16
На выходе:
runs/repair_starcoder2_3b_lora/adapter/ (LoRA веса)runs/repair_starcoder2_3b_lora/tokenizer/runs/repair_starcoder2_3b_lora/metrics.jsonЕсли захочешь Code Llama вместо StarCoder2 — можно (например, 7B). Модель на HF: (Hugging Face)
Тогда в--base_modelподставляешь другой id, а LoRA-таргеты скрипт подберет эвристикой.
Создай файл sample.c с одной функцией (или куском кода), затем:
bashpython infer_demo.py \ --code_file sample.c \ --cwe CWE-78 \ --lang c \ --det_model_dir runs/detect_codebert/best_model \ --patch_base_model bigcode/starcoder2-3b \ --patch_adapter_dir runs/repair_starcoder2_3b_lora/adapter
Чтобы дальше перейти к твоей «правильной» архитектуре:
Детектор на графах:
nodes, edges, node_types, optional line_mapgraph_path в meta)Автопочинка:
Оценка:
Если хочешь, в следующем шаге я:
Да, это классическая несовместимость версий transformers: в новых версиях TrainingArguments переименовали evaluation_strategy → eval_strategy, поэтому старое имя даёт TypeError: unexpected keyword argument 'evaluation_strategy'. (Hugging Face Forums)
Ниже — два варианта фикса: быстрый (замена) и правильный (совместимость с разными версиями).
evaluation_strategy на eval_strategyВ Kaggle добавь ячейку и выполни:
pythonimport pathlib, re def patch_file(fname: str): p = pathlib.Path(fname) txt = p.read_text() # Меняем только имя аргумента в вызовах TrainingArguments(...) txt2 = re.sub(r"\bevaluation_strategy\b\s*=", "eval_strategy=", txt) if txt2 != txt: p.write_text(txt2) print(f"patched: {fname}") else: print(f"no changes: {fname}") patch_file("train_detect.py") patch_file("train_repair_lora.py") # на будущее, чтобы не словить то же самое при LoRA-тренировке
После этого снова запускай:
bash!python train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 3 --train_bs 8 --eval_bs 8 --max_length 512
transformersЧтобы больше не ловить такие вещи (и на Kaggle/Colab/VM всё работало одинаково), сделай так:
train_detect.py добавь helper рядом с импортамиpythonimport inspect from transformers import TrainingArguments def mk_training_args(**kwargs): """ Совместимость между версиями transformers: - где-то используется evaluation_strategy - где-то используется eval_strategy Также выкидываем неизвестные ключи, чтобы не падать на API-изменениях. """ sig = inspect.signature(TrainingArguments.__init__) allowed = set(sig.parameters.keys()) # Маппинг eval strategy if "eval_strategy" in allowed and "evaluation_strategy" in kwargs: kwargs["eval_strategy"] = kwargs.pop("evaluation_strategy") if "evaluation_strategy" in allowed and "eval_strategy" in kwargs: kwargs["evaluation_strategy"] = kwargs.pop("eval_strategy") filtered = {k: v for k, v in kwargs.items() if k in allowed} dropped = sorted(set(kwargs.keys()) - set(filtered.keys())) if dropped: print("[compat] Dropped unsupported TrainingArguments keys:", dropped) return TrainingArguments(**filtered)
TrainingArguments(...) на mk_training_args(...)Было (примерно):
pythontraining_args = TrainingArguments( ..., evaluation_strategy="steps", ... )
Станет:
pythontraining_args = mk_training_args( output_dir=args.output_dir, per_device_train_batch_size=args.train_bs, per_device_eval_batch_size=args.eval_bs, num_train_epochs=args.epochs, learning_rate=args.lr, weight_decay=args.weight_decay, logging_steps=50, # можно писать как evaluation_strategy — хелпер сам подстроится evaluation_strategy="steps", eval_steps=args.eval_steps, save_strategy="steps", save_steps=args.eval_steps, load_best_model_at_end=True, metric_for_best_model="f1", greater_is_better=True, report_to="none", )
То же самое советую сделать и в train_repair_lora.py, если там тоже создаются TrainingArguments.
Сообщение при загрузке CodeBERT типа:
classifier.* MISSINGpooler.* UNEXPECTEDОК: у базового microsoft/codebert-base нет обученной “головы” классификатора под твою задачу, она создаётся заново и будет обучаться на твоих данных.
pythonimport transformers, inspect from transformers import TrainingArguments print("transformers:", transformers.__version__) sig = inspect.signature(TrainingArguments.__init__) print("has evaluation_strategy:", "evaluation_strategy" in sig.parameters) print("has eval_strategy:", "eval_strategy" in sig.parameters)
Если после этого обучение пойдёт — следующим шагом я помогу:
предлагаю подумать обо всех несовместимостях.
Твой код:
#!/usr/bin/env python3
"""
train_detect.py
Fine-tunes a sequence classification model (baseline) for vulnerability detection.
Input: unified JSONL files created by prepare_unified.py
data/unified/detect/train.jsonl
data/unified/detect/validation.jsonl
data/unified/detect/test.jsonl
Model: any HF encoder model with sequence classification head.
Recommended baseline: microsoft/codebert-base
Output:
output_dir/
best_model/ (HF saved model)
metrics.json
"""
from future import annotations
import argparse
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, List, Optional
import numpy as np
import torch
from sklearn.metrics import accuracy_score, precision_recall_fscore_support, roc_auc_score
from torch.utils.data import Dataset
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
DataCollatorWithPadding,
Trainer,
TrainingArguments,
)
import inspect
def mk_training_args(**kwargs):
"""
Совместимость между версиями transformers:
- где-то используется evaluation_strategy
- где-то используется eval_strategy
Также выкидываем неизвестные ключи, чтобы не падать на API-изменениях.
"""
sig = inspect.signature(TrainingArguments.init)
allowed = set(sig.parameters.keys())
text# Маппинг eval strategy if "eval_strategy" in allowed and "evaluation_strategy" in kwargs: kwargs["eval_strategy"] = kwargs.pop("evaluation_strategy") if "evaluation_strategy" in allowed and "eval_strategy" in kwargs: kwargs["evaluation_strategy"] = kwargs.pop("eval_strategy") filtered = {k: v for k, v in kwargs.items() if k in allowed} dropped = sorted(set(kwargs.keys()) - set(filtered.keys())) if dropped: print("[compat] Dropped unsupported TrainingArguments keys:", dropped) return TrainingArguments(**filtered)
class DetectJsonlDataset(Dataset):
"""
Minimal PyTorch Dataset:
- reads JSONL lines into memory
- tokenizes code on-the-fly
textFor larger datasets you can switch to HF datasets.load_dataset("json", ...) + .map(tokenize). """ def __init__( self, jsonl_path: str, tokenizer, max_length: int = 512, only_lang: Optional[str] = None, ) -> None: self.tokenizer = tokenizer self.max_length = max_length self.samples: List[Dict[str, Any]] = [] with open(jsonl_path, "r", encoding="utf-8") as f: for line in f: row = json.loads(line) if only_lang and row.get("lang") != only_lang: continue if "code" not in row: continue self.samples.append(row) def __len__(self) -> int: return len(self.samples) def __getitem__(self, idx: int) -> Dict[str, Any]: row = self.samples[idx] enc = self.tokenizer( row["code"], truncation=True, max_length=self.max_length, ) enc["labels"] = int(row["label"]) return enc
def compute_metrics(eval_pred):
logits, labels = eval_pred
preds = np.argmax(logits, axis=-1)
textprecision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average="binary", zero_division=0) acc = accuracy_score(labels, preds) # AUROC needs probabilities try: probs = torch.softmax(torch.tensor(logits), dim=-1)[:, 1].numpy() auroc = roc_auc_score(labels, probs) except Exception: auroc = float("nan") return {"accuracy": acc, "precision": precision, "recall": recall, "f1": f1, "auroc": auroc}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--data_dir", type=str, default="data/unified/detect")
ap.add_argument("--model_name", type=str, default="microsoft/codebert-base")
ap.add_argument("--output_dir", type=str, default="runs/detect_codebert")
ap.add_argument("--max_length", type=int, default=512)
textap.add_argument("--epochs", type=int, default=3) ap.add_argument("--lr", type=float, default=2e-5) ap.add_argument("--train_bs", type=int, default=8) ap.add_argument("--eval_bs", type=int, default=8) ap.add_argument("--seed", type=int, default=42) ap.add_argument("--only_lang", type=str, default=None, help="Optional: filter by lang=c or lang=cpp") args = ap.parse_args() data_dir = Path(args.data_dir) train_path = data_dir / "train.jsonl" val_path = data_dir / "validation.jsonl" test_path = data_dir / "test.jsonl" out_dir = Path(args.output_dir) out_dir.mkdir(parents=True, exist_ok=True) tokenizer = AutoTokenizer.from_pretrained(args.model_name, use_fast=True) model = AutoModelForSequenceClassification.from_pretrained(args.model_name, num_labels=2) train_ds = DetectJsonlDataset(str(train_path), tokenizer, max_length=args.max_length, only_lang=args.only_lang) val_ds = DetectJsonlDataset(str(val_path), tokenizer, max_length=args.max_length, only_lang=args.only_lang) test_ds = DetectJsonlDataset(str(test_path), tokenizer, max_length=args.max_length, only_lang=args.only_lang) collator = DataCollatorWithPadding(tokenizer=tokenizer) training_args = mk_training_args( output_dir=args.output_dir, per_device_train_batch_size=args.train_bs, per_device_eval_batch_size=args.eval_bs, num_train_epochs=args.epochs, learning_rate=args.lr, weight_decay=args.weight_decay, logging_steps=50, # можно писать как evaluation_strategy — хелпер сам подстроится evaluation_strategy="steps", eval_steps=args.eval_steps, save_strategy="steps", save_steps=args.eval_steps, load_best_model_at_end=True, metric_for_best_model="f1", greater_is_better=True, report_to="none", ) trainer = Trainer( model=model, args=training_args, train_dataset=train_ds, eval_dataset=val_ds, tokenizer=tokenizer, data_collator=collator, compute_metrics=compute_metrics, ) trainer.train() # Save best model best_dir = out_dir / "best_model" trainer.save_model(str(best_dir)) tokenizer.save_pretrained(str(best_dir)) # Evaluate on test test_metrics = trainer.evaluate(test_ds) with (out_dir / "metrics.json").open("w", encoding="utf-8") as f: json.dump({"test": test_metrics}, f, ensure_ascii=False, indent=2) print("Saved:", best_dir) print("Test metrics:", test_metrics)
if name == "main":
main()
Мы должны сделать это максимально кроссверсионным.
Кстати, твой прошлый ответ содержал "Было (примерно)". Сейчас я скинул код, потому, что похоже, ты не можешь сам посмотреть файл, который мне скинул. Подскажи в самом конце ответа как мне лучше давать тебе информацию - если ты все же можешь что-то посмотреть, то лучше не засорять контекст кодом
Да, тут уже не “несовместимость transformers”, а несостыковка твоего CLI: в коде ты используешь args.weight_decay и args.eval_steps, но в argparse ты их не объявил, поэтому Namespace не содержит этих полей → AttributeError.
При этом ты прав: лучше сразу сделать максимально кроссверсионно, потому что на Kaggle/Colab часто стоят разные версии transformers, datasets, и иногда меняются сигнатуры TrainingArguments/Trainer.
Ниже даю:
train_detect.py целиком (чтобы потом не ловить новые падения)После твоих аргументов (--lr, --train_bs, …) добавь:
pythonap.add_argument("--weight_decay", type=float, default=0.01) ap.add_argument("--eval_steps", type=int, default=500)
Чтобы даже при старом файле/старом запуске ничего не падало:
pythonweight_decay = getattr(args, "weight_decay", 0.01) eval_steps = getattr(args, "eval_steps", 500)
И в mk_training_args(...) заменить:
pythonweight_decay=args.weight_decay, eval_steps=args.eval_steps, save_steps=args.eval_steps,
на:
pythonweight_decay=weight_decay, eval_steps=eval_steps, save_steps=eval_steps,
Этого уже достаточно, чтобы ошибка ушла.
train_detect.py (перепиши файл целиком)Почему лучше переписать:
evaluation_strategy ↔ eval_strategy уже поймал (плюс будет ещё несколько похожих “мин”)DetectJsonlDataset грузит весь train.jsonl в память (у тебя ~495k строк) — на Kaggle это часто = OOM или “подвисание”.datasets.load_dataset("json") + set_transform() — оно memory-mapped/Arrow, не держит весь питоновский список строк.Скопируй и замени train_detect.py на этот вариант:
python#!/usr/bin/env python3 """ train_detect.py (cross-version friendly) Baseline fine-tune for vulnerability detection using a sequence classifier (e.g., CodeBERT). Input: data/unified/detect/{train,validation,test}.jsonl (from prepare_unified.py) Output: output_dir/ best_model/ (HF saved model) metrics.json """ from __future__ import annotations import argparse import inspect import json import os from pathlib import Path from typing import Any, Dict, Optional import numpy as np import torch from sklearn.metrics import accuracy_score, precision_recall_fscore_support, roc_auc_score from transformers import ( AutoModelForSequenceClassification, AutoTokenizer, DataCollatorWithPadding, Trainer, TrainingArguments, ) # ---------------------------- # Compatibility helpers # ---------------------------- def mk_training_args(**kwargs) -> TrainingArguments: """ Build TrainingArguments in a way that survives transformers API changes. - Newer transformers renamed `evaluation_strategy` -> `eval_strategy` - Some keys appear/disappear across versions We inspect signature and: * rename keys when needed * drop unknown keys """ sig = inspect.signature(TrainingArguments.__init__) allowed = set(sig.parameters.keys()) # Map eval strategy name across versions if "eval_strategy" in allowed and "evaluation_strategy" in kwargs: kwargs["eval_strategy"] = kwargs.pop("evaluation_strategy") if "evaluation_strategy" in allowed and "eval_strategy" in kwargs: kwargs["evaluation_strategy"] = kwargs.pop("eval_strategy") # report_to: safer as [] (works in older versions too) if "report_to" in kwargs and kwargs["report_to"] == "none": kwargs["report_to"] = [] filtered = {k: v for k, v in kwargs.items() if k in allowed} dropped = sorted(set(kwargs.keys()) - set(filtered.keys())) if dropped: print("[compat] Dropped unsupported TrainingArguments keys:", dropped) return TrainingArguments(**filtered) def safe_set_seed(seed: int) -> None: """Works across transformers versions.""" try: from transformers import set_seed set_seed(seed) except Exception: import random random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) def compute_metrics(eval_pred) -> Dict[str, float]: """ Works across transformers versions: - sometimes eval_pred is EvalPrediction with .predictions/.label_ids - sometimes it's a tuple (logits, labels) """ if hasattr(eval_pred, "predictions"): logits = eval_pred.predictions labels = eval_pred.label_ids else: logits, labels = eval_pred # Some models return a tuple for logits if isinstance(logits, (tuple, list)): logits = logits[0] preds = np.argmax(logits, axis=-1) precision, recall, f1, _ = precision_recall_fscore_support( labels, preds, average="binary", zero_division=0 ) acc = accuracy_score(labels, preds) # AUROC needs probabilities; may fail if only one class present in labels try: probs = torch.softmax(torch.tensor(logits), dim=-1)[:, 1].cpu().numpy() auroc = roc_auc_score(labels, probs) except Exception: auroc = float("nan") return { "accuracy": float(acc), "precision": float(precision), "recall": float(recall), "f1": float(f1), "auroc": float(auroc), } # ---------------------------- # Dataset loading (memory-safe) # ---------------------------- def load_splits_with_hf_datasets( data_dir: Path, only_lang: Optional[str], max_train_samples: Optional[int], max_eval_samples: Optional[int], max_test_samples: Optional[int], tokenizer, max_length: int, num_proc: int = 1, ): """ Uses `datasets` library (Arrow) to avoid reading massive JSONL into Python RAM. Applies lazy tokenization via set_transform. """ from datasets import load_dataset data_files = { "train": str(data_dir / "train.jsonl"), "validation": str(data_dir / "validation.jsonl"), "test": str(data_dir / "test.jsonl"), } ds = load_dataset("json", data_files=data_files) def lang_filter(ex): # ex is dict-like return ex.get("lang") == only_lang if only_lang: # filter can be slow; keep num_proc small if Kaggle is unstable ds["train"] = ds["train"].filter(lang_filter, num_proc=num_proc) ds["validation"] = ds["validation"].filter(lang_filter, num_proc=num_proc) ds["test"] = ds["test"].filter(lang_filter, num_proc=num_proc) if max_train_samples: ds["train"] = ds["train"].select(range(min(max_train_samples, len(ds["train"])))) if max_eval_samples: ds["validation"] = ds["validation"].select(range(min(max_eval_samples, len(ds["validation"])))) if max_test_samples: ds["test"] = ds["test"].select(range(min(max_test_samples, len(ds["test"])))) def make_transform(): def _transform(ex: Dict[str, Any]) -> Dict[str, Any]: code = ex.get("code", "") enc = tokenizer( code, truncation=True, max_length=max_length, ) enc["labels"] = int(ex.get("label", 0)) return enc return _transform transform_fn = make_transform() ds["train"].set_transform(transform_fn) ds["validation"].set_transform(transform_fn) ds["test"].set_transform(transform_fn) return ds["train"], ds["validation"], ds["test"] def main(): ap = argparse.ArgumentParser() ap.add_argument("--data_dir", type=str, default="data/unified/detect") ap.add_argument("--model_name", type=str, default="microsoft/codebert-base") ap.add_argument("--output_dir", type=str, default="runs/detect_codebert") ap.add_argument("--max_length", type=int, default=512) ap.add_argument("--epochs", type=int, default=3) ap.add_argument("--lr", type=float, default=2e-5) ap.add_argument("--weight_decay", type=float, default=0.01) ap.add_argument("--train_bs", type=int, default=8) ap.add_argument("--eval_bs", type=int, default=8) ap.add_argument("--grad_accum", type=int, default=1) ap.add_argument("--eval_steps", type=int, default=500, help="If >0 -> eval/save every N steps; if 0 -> eval per epoch") ap.add_argument("--logging_steps", type=int, default=50) ap.add_argument("--seed", type=int, default=42) ap.add_argument("--only_lang", type=str, default=None, help="Optional: filter by lang=c or lang=cpp") # Quick debug knobs (VERY useful on Kaggle) ap.add_argument("--max_train_samples", type=int, default=None) ap.add_argument("--max_eval_samples", type=int, default=None) ap.add_argument("--max_test_samples", type=int, default=None) ap.add_argument("--num_proc", type=int, default=1, help="datasets.filter/map workers (keep small on Kaggle)") # Mixed precision (safe defaults) ap.add_argument("--fp16", action="store_true", help="Enable fp16 if supported") ap.add_argument("--bf16", action="store_true", help="Enable bf16 if supported") args = ap.parse_args() data_dir = Path(args.data_dir) out_dir = Path(args.output_dir) out_dir.mkdir(parents=True, exist_ok=True) safe_set_seed(args.seed) # Tokenizer: robust fallback if use_fast causes issues on some models/envs try: tokenizer = AutoTokenizer.from_pretrained(args.model_name, use_fast=True) except Exception: tokenizer = AutoTokenizer.from_pretrained(args.model_name) model = AutoModelForSequenceClassification.from_pretrained(args.model_name, num_labels=2) # Memory-safe dataset loading train_ds, val_ds, test_ds = load_splits_with_hf_datasets( data_dir=data_dir, only_lang=args.only_lang, max_train_samples=args.max_train_samples, max_eval_samples=args.max_eval_samples, max_test_samples=args.max_test_samples, tokenizer=tokenizer, max_length=args.max_length, num_proc=max(1, int(args.num_proc)), ) collator = DataCollatorWithPadding(tokenizer=tokenizer) # Decide evaluation/save strategy if args.eval_steps and args.eval_steps > 0: eval_strategy = "steps" # will be mapped to eval_strategy/evaluation_strategy by mk_training_args() eval_steps = int(args.eval_steps) save_strategy = "steps" save_steps = int(args.eval_steps) else: eval_strategy = "epoch" eval_steps = None save_strategy = "epoch" save_steps = None # Disable wandb/etc reliably os.environ.setdefault("WANDB_DISABLED", "true") training_kwargs = dict( output_dir=str(out_dir), per_device_train_batch_size=args.train_bs, per_device_eval_batch_size=args.eval_bs, gradient_accumulation_steps=args.grad_accum, num_train_epochs=args.epochs, learning_rate=args.lr, weight_decay=args.weight_decay, logging_steps=args.logging_steps, save_total_limit=2, evaluation_strategy=eval_strategy, # will be renamed if needed load_best_model_at_end=True, metric_for_best_model="f1", greater_is_better=True, report_to=[], # safest across versions seed=args.seed, ) # Conditionally add step-based params if eval_steps is not None: training_kwargs.update( dict( eval_steps=eval_steps, save_strategy=save_strategy, save_steps=save_steps, ) ) else: training_kwargs.update(dict(save_strategy=save_strategy)) # Mixed precision (only if user explicitly asked; mk_training_args will drop if unsupported) if args.fp16: training_kwargs["fp16"] = True if args.bf16: training_kwargs["bf16"] = True training_args = mk_training_args(**training_kwargs) trainer = Trainer( model=model, args=training_args, train_dataset=train_ds, eval_dataset=val_ds, data_collator=collator, compute_metrics=compute_metrics, ) trainer.train() # Save best model (Trainer keeps best at end if load_best_model_at_end is supported) best_dir = out_dir / "best_model" trainer.save_model(str(best_dir)) tokenizer.save_pretrained(str(best_dir)) # Evaluate on test with stable API usage test_metrics = trainer.evaluate(eval_dataset=test_ds, metric_key_prefix="test") with (out_dir / "metrics.json").open("w", encoding="utf-8") as f: json.dump({"test": test_metrics}, f, ensure_ascii=False, indent=2) print("Saved:", best_dir) print("Test metrics:", test_metrics) if __name__ == "__main__": main()
Для быстрой проверки (чтобы за 2–5 минут убедиться, что всё работает):
bash!python train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 1 --train_bs 8 --eval_bs 8 --max_length 512 \ --max_train_samples 20000 --max_eval_samples 5000 --max_test_samples 5000 \ --eval_steps 500
А потом уже полный прогон (но я бы всё равно не гнал 3 эпохи на 500k без проверки баланса/метрик — дорого по времени):
bash!python train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 3 --train_bs 8 --eval_bs 8 --max_length 512 \ --eval_steps 1000
Trainer/TrainingArguments меняются чаще всегоЧто уже учли:
evaluation_strategy ↔ eval_strategyЧто ещё часто ломает запуск:
report_to=[] + WANDB_DISABLED=true (я добавил оба).datasets лучше чем “читать JSONL в список”Твой текущий класс DetectJsonlDataset при 494k строк:
Arrow‑датасеты решают это.
В разных версиях transformers eval_pred бывает:
EvalPrediction(predictions=..., label_ids=...)Иногда на отдельных моделях/окружениях fast tokenizer может падать — сделал try/fallback.
Ты всё сделал правильно, что прислал стектрейс и конкретный фрагмент.
Чтобы было максимально эффективно и без “простыней” кода:
Traceback + версия библиотек (это топ‑1 полезно):
Выполни и пришли вывод:
bash!python -c "import transformers, datasets, torch; print('transformers', transformers.__version__); print('datasets', datasets.__version__); print('torch', torch.__version__); print('cuda', torch.cuda.is_available())"
Вместо полного файла — окрестность проблемных строк:
Например, если ошибка на line 167:
bash!nl -ba train_detect.py | sed -n '150,190p'
(Это покажет только 40 строк вокруг места падения.)
Если правок много — лучше загружай файл/zip прямо сюда (как вложение).
Тогда я смогу точечно сказать “вот здесь поменять” и дать аккуратный diff, а не гадать по фрагментам.
Скриншоты тоже ок, но лучше всё же: traceback + nl -ba ... — меньше риск потерять детали.
Если хочешь — следующим шагом я предложу “разумный режим обучения” для твоего масштаба данных:
использовал полностью переписанный файл
результат:
!python train_detect.py
--data_dir data/unified/detect
--model_name microsoft/codebert-base
--output_dir runs/detect_codebert
--epochs 3 --train_bs 8 --eval_bs 8 --max_length 512
--eval_steps 1000
Requirement already satisfied: datasets in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (4.0.0)
Requirement already satisfied: transformers in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (5.2.0)
Requirement already satisfied: accelerate in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (1.12.0)
Requirement already satisfied: peft in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 4)) (0.18.1)
Collecting bitsandbytes (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 5))
Downloading bitsandbytes-0.49.2-py3-none-manylinux_2_24_x86_64.whl.metadata (10 kB)
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 6)) (1.6.1)
Requirement already satisfied: tqdm in /usr/local/lib/python3.12/dist-packages (from -r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 7)) (4.67.1)
Requirement already satisfied: filelock in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (3.20.3)
Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.0.2)
Requirement already satisfied: pyarrow>=15.0.0 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (18.1.0)
Requirement already satisfied: dill<0.3.9,>=0.3.0 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (0.3.8)
Requirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.3.3)
Requirement already satisfied: requests>=2.32.2 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.32.4)
Requirement already satisfied: xxhash in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (3.6.0)
Requirement already satisfied: multiprocess<0.70.17 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (0.70.16)
Requirement already satisfied: fsspec<=2025.3.0,>=2023.1.0 in /usr/local/lib/python3.12/dist-packages (from fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2025.3.0)
Requirement already satisfied: huggingface-hub>=0.24.0 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.4.1)
Requirement already satisfied: packaging in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (25.0)
Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.12/dist-packages (from datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (6.0.3)
Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.12/dist-packages (from transformers->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (2025.11.3)
Requirement already satisfied: tokenizers<=0.23.0,>=0.22.0 in /usr/local/lib/python3.12/dist-packages (from transformers->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (0.22.2)
Requirement already satisfied: typer-slim in /usr/local/lib/python3.12/dist-packages (from transformers->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (0.21.1)
Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.12/dist-packages (from transformers->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (0.7.0)
Requirement already satisfied: psutil in /usr/local/lib/python3.12/dist-packages (from accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (5.9.5)
Requirement already satisfied: torch>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (2.9.0+cu126)
Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 6)) (1.16.3)
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 6)) (1.5.3)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 6)) (3.6.0)
Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /usr/local/lib/python3.12/dist-packages (from fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (3.13.3)
Requirement already satisfied: hf-xet<2.0.0,>=1.2.0 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.2.0)
Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (0.28.1)
Requirement already satisfied: shellingham in /usr/local/lib/python3.12/dist-packages (from huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.5.4)
Requirement already satisfied: typing-extensions>=4.1.0 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (4.15.0)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests>=2.32.2->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (3.4.4)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests>=2.32.2->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (3.11)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests>=2.32.2->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests>=2.32.2->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2026.1.4)
Requirement already satisfied: setuptools in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (75.2.0)
Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (1.14.0)
Requirement already satisfied: networkx>=2.5.1 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (3.6.1)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (3.1.6)
Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.77)
Requirement already satisfied: nvidia-cuda-runtime-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.77)
Requirement already satisfied: nvidia-cuda-cupti-cu12==12.6.80 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.80)
Requirement already satisfied: nvidia-cudnn-cu12==9.10.2.21 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (9.10.2.21)
Requirement already satisfied: nvidia-cublas-cu12==12.6.4.1 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.4.1)
Requirement already satisfied: nvidia-cufft-cu12==11.3.0.4 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (11.3.0.4)
Requirement already satisfied: nvidia-curand-cu12==10.3.7.77 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (10.3.7.77)
Requirement already satisfied: nvidia-cusolver-cu12==11.7.1.2 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (11.7.1.2)
Requirement already satisfied: nvidia-cusparse-cu12==12.5.4.2 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.5.4.2)
Requirement already satisfied: nvidia-cusparselt-cu12==0.7.1 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (0.7.1)
Requirement already satisfied: nvidia-nccl-cu12==2.27.5 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (2.27.5)
Requirement already satisfied: nvidia-nvshmem-cu12==3.3.20 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (3.3.20)
Requirement already satisfied: nvidia-nvtx-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.77)
Requirement already satisfied: nvidia-nvjitlink-cu12==12.6.85 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (12.6.85)
Requirement already satisfied: nvidia-cufile-cu12==1.11.1.6 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (1.11.1.6)
Requirement already satisfied: triton==3.5.0 in /usr/local/lib/python3.12/dist-packages (from torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (3.5.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2025.3)
Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.12/dist-packages (from typer-slim->transformers->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 2)) (8.3.1)
Requirement already satisfied: aiohappyeyeballs>=2.5.0 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (2.6.1)
Requirement already satisfied: aiosignal>=1.4.0 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.4.0)
Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (25.4.0)
Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.8.0)
Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (6.7.0)
Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (0.4.1)
Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.12/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.22.0)
Requirement already satisfied: anyio in /usr/local/lib/python3.12/dist-packages (from httpx<1,>=0.23.0->huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (4.12.1)
Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.12/dist-packages (from httpx<1,>=0.23.0->huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.0.9)
Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.12/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->huggingface-hub>=0.24.0->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (0.16.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas->datasets->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 1)) (1.17.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from sympy>=1.13.3->torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (1.3.0)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from jinja2->torch>=2.0.0->accelerate->-r /kaggle/input/models/renesta/lintbs2/pytorch/default/1/ailint_diploma_starter/requirements.txt (line 3)) (3.0.3)
Downloading bitsandbytes-0.49.2-py3-none-manylinux_2_24_x86_64.whl (60.7 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.7/60.7 MB 31.6 MB/s eta 0:00:00:00:0100:01
Installing collected packages: bitsandbytes
Successfully installed bitsandbytes-0.49.2
Поймал причину: это уже не transformers, а datasets/pyarrow, и она как раз “кроссверсионная” (особенно на datasets==4.x).
datasets.load_dataset("json", ...) пытается построить Arrow-таблицу со стабильной схемой.
А у тебя в unified JSONL поле meta — словарь с разными наборами ключей в разных источниках:
meta={filename, class, variant}meta={filename, class, variant, project, commit_id} (и т.п.)Arrow выводит схему по первым примерам (например, только filename,class,variant), а потом встречает запись, где meta содержит доп. поля (project, commit_id) — и падает:
Couldn’t cast array of type struct<... project, commit_id ...> to struct<... only filename,class,variant ...>
meta строкой (JSON-string)Это самый надёжный вариант: meta остаётся, но как строка, и схема всегда одинакова.
pythonimport json from pathlib import Path from tqdm.auto import tqdm def sanitize_jsonl(path: Path): tmp = path.with_suffix(".tmp") n = 0 with path.open("r", encoding="utf-8") as fin, tmp.open("w", encoding="utf-8") as fout: for line in fin: line = line.strip() if not line: continue row = json.loads(line) # 1) meta: dict/list -> стабильная строка if "meta" in row and isinstance(row["meta"], (dict, list)): row["meta"] = json.dumps(row["meta"], ensure_ascii=False, sort_keys=True) # 2) страховка по типам (на всякий) if "label" in row and row["label"] is not None: row["label"] = int(row["label"]) for k in ("uid", "dataset", "split", "lang", "cwe", "cve", "code"): if k in row and row[k] is not None and not isinstance(row[k], str): row[k] = str(row[k]) fout.write(json.dumps(row, ensure_ascii=False) + "\n") n += 1 tmp.replace(path) print(f"[ok] sanitized {path} ({n} lines)") root = Path("data/unified") for sub in ["detect", "repair"]: d = root / sub if not d.exists(): continue for split in ["train", "validation", "test"]: p = d / f"{split}.jsonl" if p.exists(): sanitize_jsonl(p)
Иногда после крэша остаётся “полусобранный” кеш. Если после санитизации оно вдруг продолжит ругаться — выполни:
bash!rm -rf ~/.cache/huggingface/datasets/json
Я бы очень советовал сначала сделать быстрый sanity-run (иначе 500k*3 эпохи может быть адски долго на Kaggle):
bash!python train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 1 --train_bs 8 --eval_bs 8 --max_length 512 \ --max_train_samples 20000 --max_eval_samples 5000 --max_test_samples 5000 \ --eval_steps 500
И только потом — полный:
bash!python train_detect.py \ --data_dir data/unified/detect \ --model_name microsoft/codebert-base \ --output_dir runs/detect_codebert \ --epochs 3 --train_bs 8 --eval_bs 8 --max_length 512 \ --eval_steps 1000
prepare_unified.py, чтобы больше никогда так не былоЧтобы не чинить уже созданные jsonl, лучше изменить генератор: писать meta сразу строкой.
В prepare_unified.py в момент записи строки (где формируешь row) поменяй:
pythonrow["meta"] = meta_dict
на:
pythonimport json row["meta"] = json.dumps(meta_dict, ensure_ascii=False, sort_keys=True) if meta_dict is not None else None
Тогда все будущие unified-файлы будут стабильно грузиться через datasets.
Теоретически можно передать features и описать meta как struct с суперсетом всех возможных ключей.
Но это:
meta JSON-строкой.repair/*.jsonlТы правильно заметил “подумать обо всех несовместимостях”:
в repair тоже есть meta из разных источников → LoRA-скрипт может упасть тем же способом.
Поэтому санитизатор я специально сделал для detect и repair.
Самый удобный формат для дебага:
bash!python -c "import transformers, datasets, torch; print('transformers', transformers.__version__); print('datasets', datasets.__version__); print('torch', torch.__version__)"
bash!nl -ba train_detect.py | sed -n '120,200p'
bash!python - << 'PY' import json p="data/unified/detect/train.jsonl" with open(p,"r",encoding="utf-8") as f: for i in [0,1,2,140000]: f.seek(0) for k,line in enumerate(f): if k==i: print(i, json.loads(line).keys()) print("meta_type:", type(json.loads(line).get("meta"))) break PY
Если хочешь вообще без “копипасты” — можешь прикреплять файл (train_detect.py или лог), я тогда буду давать точечные диффы/патчи.
Если после санитизации load_dataset пойдёт — следующий шаг: я предложу нормальный режим обучения на твоём объёме (подвыборка + CWE-фильтр + балансировка), чтобы метрики были осмысленные и Kaggle не умер по времени.