Репозиторий охватывает все этапы: анонимизация, сбор и подготовка датасета, supervised fine-tuning (локально и в Together.ai), построение RAG-индекса, запуск инференса и метрик. Ниже — практический гид по каждому шагу.
- Python 3.10+
pip install -r requirements.txt- Переменные окружения для LLM:
OPENAI_API_KEYи (опционально)OPENAI_BASE_URL— для OpenAI-совместимых API или локального vLLM.TOGETHER_API_KEY— для Together.ai fine-tuning.
- Для сборки полноценного датасета с нуля из сырых данных нужен Golang
- Через аномайзер запускаем обработку сырых данных
python -m scripts.anonymize datasets/raw-data datasets/anon-data- Для сборки конечного E2E датасета input-output формата запускаем Golang скрипт (более подробная инструкция)
go run go/cmd/main.goили запустите нужный binary файл, исходя из вашей архитектуры, например:
source go/bin/cmd-darwin-arm64Высокоуровневая схема:
- (Опционально) Скачиваем
processed_result(s).csvс Google Drive. - Объединяем найденные CSV в один
datasets/raw_compiled.csv. - Генерируем промпты и таргеты для SFT/RAG.
- Преобразуем JSONL в чат-формат и делим на train/eval/test.
Все шаги управляются Hydra-конфигом configs/prepare_data.yaml.
python -m scripts.prepare_data \
'steps=[download,compile,prompts]' \
data.drive_folder='<DRIVE_FOLDER_URL_OR_ID>'Другие опции:
- Только собрать CSV, если данные уже локально:
python -m scripts.prepare_data 'steps=[compile]' \ data.output_root='datasets/raw_data'
- Только построить промпты из готового CSV:
python -m scripts.prepare_data \ 'steps=[prompts]' \ prompts.input_file='datasets/raw_compiled.csv' \ prompts.output_jsonl='datasets/train_prompts.jsonl'
datasets/raw_data/**/processed_result(s).csv— исходники из Google Drive.datasets/raw_compiled.csv— объединённый CSV (+ колонкиorigin_folder,modality).datasets/train_prompts.jsonl— JSONL с полямиprompt_text,result_text,organ,finding_text,type.datasets/sft_train.jsonl,datasets/sft_eval.jsonl,datasets/sft_test_rag.jsonl— чат-формат для обучения и проверки.datasets/sft_dataset/— HuggingFace DatasetDict (train/eval) сmessages.datasets/rag_train.jsonl— парыfinding_text/result_textдля индекса.
Через prompts.source_columns можно сопоставить нестандартные имена (organ, finding, result). organ_mapper позволяет привести аббревиатуры к читаемым органам.
Флаг sft_prep.enabled=true автоматически:
- конвертирует
prompt_text/result_textв{"messages": [{"role": "user"...}, ...]}; - делает train/eval split;
- выгружает HF dataset (
datasets/sft_dataset), совместимый сtrl.SFTTrainer.
Пример ручного запуска:
python -m src.data_preparation.prepare_for_sft \
source_jsonl='datasets/train_prompts.jsonl' \
outputs.train_jsonl='datasets/sft_train.jsonl' \
outputs.eval_jsonl='datasets/sft_eval.jsonl'Скрипт: sft/train_sft.py, конфиг по умолчанию sft/configs/sft.yaml.
python -m sft.train_sft \
model.name_or_path='Qwen/Qwen2.5-7B-Instruct' \
data.hf_dir='datasets/sft_dataset' \
training.output_dir='outputs/sft_qwen2p5' \
lora.enabled=trueОсобенности:
- Используется
trl.SFTTrainerс LoRA (peft) - Если нет HF-dataset, укажите
data.train_path/data.eval_pathи поля (input_field,target_field) + шаблон{prompt}\n\n{response} - Для inference модели удобно выгружать в GGUF или использовать vLLM (см. раздел 6.2)
Скрипт: sft/together_finetune.py, конфиги в sft/configs/together*.yaml
export TOGETHER_API_KEY=...
python -m sft.together_finetune \
+model.name_or_path='Qwen/Qwen3-14B' \
data.train_path='datasets/sft_train.jsonl' \
data.eval_path='datasets/sft_eval.jsonl' \
training.batch_size=8 \
training.epochs=3 \
job.wait=trueТребования к данным:
- JSONL из
prepare_for_sft(каждый объект:{"messages": [{"role": "user",...}, {"role": "assistant",...}]}) - Скрипт сам загрузит файлы в Together (или примет
file-***id)
Опции:
lora.*— параметры LoRA на стороне Together (target_modules: all-linearдля Qwen/LLaMA)training.*— базовые гиперпараметры APIjob.save_job_json— куда сохранить идентификатор запущенной джобы
Используется src/rag/retriever.FaissRetriever с sentence-transformers (по умолчанию intfloat/e5-base-v2)
python -m scripts.build_index \
jsonl='datasets/rag_train.jsonl' \
out_dir='artifacts/rag_index' \
model='intfloat/e5-base-v2' \
device='cuda'Формат входа: JSONL, поля finding_text и result_text. Скрипт пропускает пустые строки и сохраняет index.faiss + meta.json (со списком примеров и гиперпараметрами). Конфиг — configs/rag_build_index.yaml
scripts.rag_infer и scripts.rag_eval обращаются к OpenAICompatClient. Можно:
- Использовать облачный OpenAI / Together / DeepInfra
- Запустить локально vLLM c вашим SFT-чекпоинтом:
Тогда в конфиге:
vllm serve Qwen/Qwen2.5-7B-Instruct \ --dtype bfloat16 \ --max-model-len 4096 \ --api-key dummy \ --model-format hf \ --served-model-name qwen-med \ --response-format json_schema \ --trust-remote-code
llm.base_url='http://localhost:8000/v1',llm.api_key='dummy',llm.model='qwen-med'.
Скрипт: scripts/rag_infer.py, конфиг configs/rag_infer.yaml
Одиночный запрос:
python -m scripts.rag_infer \
organ='головной мозг' \
finding='МР-картина арахноидальной кисты правой височной доли' \
index_dir='artifacts/rag_index' \
llm.base_url='http://localhost:8000/v1' \
llm.model='qwen-med' \
json_output=true cot=trueBatch (CSV или JSONL):
python -m scripts.rag_infer \
input.file='datasets/sft_test_rag.jsonl' \
input.format='jsonl' \
input.columns.id='id' \
input.columns.organ='organ' \
input.columns.finding='finding_text' \
input.columns.reference='result_text' \
top_k=5 json_output=true cot=falseФлаги:
top_k— сколько примеров достать из индексаcot=true— добавить chain-of-thought инструкции (+ полеreasoningв ответе)json_output=true— включить строгий JSON-ответ (result/has_finding/organ/modality). Парсер (src/rag/postprocess.py) fallback-ит в сырой текст, если JSON невалидный
Артефакты:
outputs/team_name_results.csv— акумулирует строки (может дозаписываться)outputs/logs/log_<timestamp>_<id>.json— полный ввод/вывод и примерыoutputs/metrics.json— агрегированные метрики для текущего запуска
Если json_output=true, parse_llm_response использует langchain JsonOutputParser и Pydantic-схему (result, reasoning, has_finding, organ, modality). Это позволяет:
- сверять классификационные метрики (
compute_classification_accuracy); - пост-обрабатывать модальность (например, для UI).
Используется тот же RAG-пайплайн, но поверх тестового JSONL и с расчётом средних метрик.
python -m scripts.rag_eval \
input_jsonl='datasets/sft_test_rag.jsonl' \
index_dir='artifacts/rag_index' \
llm.base_url='http://localhost:8000/v1' \
llm.model='qwen-med' \
json_output=true cot=true \
outputs.csv='outputs/metrics_eval.csv' \
outputs.metrics='outputs/metrics_eval.json'Метрики (src/validation/metrics.py):
- Exact Match, BLEU, ROUGE-L, METEOR (нужен
nltk), Levenshtein; - Accuracy по наличию заключения, органу (exact + cosine через
sentence-transformers), модальности.
scripts/anonymize.py— анонимизация исходных CSV.scripts/prepare_data.py— единая точка входа для download/compile/prompts/SFT prep.src/data_preparation/*— модули пайплайна.sft/train_sft.py,sft/together_finetune.py— локальный и Together SFT.scripts/build_index.py,scripts/rag_infer.py,scripts/rag_eval.py— RAG.src/rag/*— ретривер, промпты, LLM-клиент, парсинг.src/validation/metrics.py— текстовые и классификационные метрики.configs/*.yaml,sft/configs/*.yaml— все Hydra-конфиги, переопределяются через CLI.
| Задача | Команда | Комментарий |
|---|---|---|
| Сбор данных из Google Drive | python -m scripts.prepare_data 'steps=[download,compile]' data.drive_folder='...' |
Загружает CSV и объединяет. |
| Генерация промптов + подготовка SFT | python -m scripts.prepare_data 'steps=[prompts]' |
Заполняет datasets/train_prompts.jsonl, datasets/sft_*. |
| Локальный SFT | python -m sft.train_sft data.hf_dir='datasets/sft_dataset' |
Работает из коробки с LoRA. |
| Together SFT | python -m sft.together_finetune data.train_path='datasets/sft_train.jsonl' |
Авто-аплоад датасета. |
| Построение FAISS | python -m scripts.build_index jsonl='datasets/rag_train.jsonl' |
Требует faiss-cpu или GPU. |
| Инференс RAG (batch) | python -m scripts.rag_infer input.file='datasets/sft_test_rag.jsonl' |
Пишет CSV + JSON-логи. |
| Eval на датасете | python -m scripts.rag_eval input_jsonl='datasets/sft_test_rag.jsonl' |
Возвращает агрегированные метрики. |
