ruTron-quality-classifier-lite

English | Русский

Russian only. The model was trained and evaluated only on Russian web documents (FineWeb-2 rus_Cyrl). It was not tested on other languages; its scores for them are meaningless.

A fast quality model for Russian web text, made to filter pretraining data at corpus scale. It has the same outputs as krysyuk/ruTron-quality-classifier-base (base): an overall pretraining value, 13 quality axes on a 1–5 scale, 8 content flags, topic, format, audience and region. Both imitate the labels that Claude Sonnet 5.5 gave to 26,000 FineWeb-2 documents (krysyuk/fineweb-2-russian-quality-annotations-26k).

This model scored all 699M documents of FineWeb-2 rus_Cyrl: krysyuk/fineweb-2-russian-quality-full.

Its main job is to cut junk cheaply: spam, doorways, machine-generated and broken text. For finer ranking of good documents the base model is noticeably better.

What is different from the base model

base lite
Encoder Nemotron-3-Embed-1B, all 16 layers first 4 layers only
Text read up to 4,096 tokens (first 10,000 + last 1,700 characters) first 512 tokens of the same view
Document vector learned mix of all 17 hidden states + attention pooling over 256-token chunks (layers 4/8/12/16) two learned mixes of hidden states 0–4 of one 512-token window; no attention over chunks
Heads trained on base features retrained on lite features, same labels, same 5-fold scheme (not distilled from base)
Parameters, file size 1.14B encoder + 46M heads, 2.5 GB 487M encoder (268M of them the embedding table) + 46M heads, 1.2 GB
Speed, Apple M4 Pro ~1.2 docs/s ~19 docs/s
Speed, one RTX PRO 4000 not measured ~500 docs/s with FP8 + torch.compile
overall QWK / axes QWK (test) 0.876 / 0.870 0.820 / 0.832

Details:

  • Pruned encoder. Layers 5–16 are simply not run; the kept weights are unchanged (bf16). The encoder's final norm is not applied: the heads read raw hidden states, as in training.
  • 512 tokens. The model does not see anything after about the first 1,700 characters. Problems further in a long document are missed.
  • Same 32 text statistics as base, computed on the full 10,000 + 1,700 character view. heuristics.py is a faster implementation with identical values (checked on 500 documents; base uses the same file now).
  • Production script score_parquet.py: FP8, torch.compile, parallel CPU workers, resume after interruption. This is the code that scored the full dataset.
  • The tokenizer is pinned to the behaviour it had in training (fix_mistral_regex=False). Do not "fix" it: the scores would drift.

Why 4 layers and 512 tokens

Heads trained on the outputs of the first L layers of the frozen encoder (exactly what the pruned model computes); test split, overall_direct head:

Encoder layers Text read Axes QWK overall QWK PR-AUC overall ≥ 4
16 (base) 4,096 tokens 0.870 0.873 0.763
4 4,096 tokens 0.856 0.851 0.669
8 first 512 0.853 0.851 0.644
6 first 512 0.847 0.842 0.625
4 (lite) first 512 0.832 0.818 0.595

Three seeds of the chosen setup: axes QWK 0.830–0.832, overall QWK 0.818–0.822. The loss is mostly at the top; for the junk end it is small (test split):

Task base lite
Sonnet gave 1, overall < 1.5 precision 0.93, recall 0.89 precision 0.92, recall 0.82
Sonnet gave 1–2, overall < 2.5 precision 0.92, recall 0.91 precision 0.89, recall 0.88
Spearman between base and lite overall 0.93

Quick start

For a first look and small jobs: predict.py, plain PyTorch, any device.

pip install torch "transformers>=5.18" safetensors pyarrow huggingface_hub
hf download krysyuk/ruTron-quality-classifier-lite --local-dir ruTron-quality-classifier-lite
cd ruTron-quality-classifier-lite

python predict.py --input docs.jsonl --output scores.jsonl   # one {"id", "text"} per line
python predict.py --input docs.parquet --output scores.jsonl --device cuda
import sys
from huggingface_hub import snapshot_download

path = snapshot_download("krysyuk/ruTron-quality-classifier-lite")
sys.path.insert(0, path)
from predict import LiteScorer

scorer = LiteScorer(path)  # cuda / mps / cpu picked automatically
scorer.score(["Текст документа ..."])[0]
# {"overall": 2.856, "overall_direct": 2.939, "overall_stacked": 2.773, "p_overall_4plus": 0.0002,
#  "axes": {"cleanliness": 3.45, ...}, "flags": {"unsafe_content": 0.0096, ..., "answer_dump": false},
#  "topic": {"medicine": 0.925, ...}, "format": "popular_article", "audience": "general_adult", "region": "none"}

Tested with torch 2.14 and transformers 5.18.

Production: millions of documents

score_parquet.py reads parquet files and writes one parquet of scores per input file, with the same 30 score columns as the full dataset plus id.

pip install torchao   # for --fp8

# local parquet files with a "text" column
python score_parquet.py --input "data/*.parquet" --out scores/ --fp8 --compile

# files of a Hub dataset: the next file downloads while the current one is scored,
# each file is deleted after scoring
python score_parquet.py --hf-dataset HuggingFaceFW/fineweb-2 \
    --hf-files "data/rus_Cyrl/train/*.parquet" --out scores/ --fp8 --compile

# several GPUs: one process per GPU, files split between them
for g in 0 1 2 3; do
  CUDA_VISIBLE_DEVICES=$g python score_parquet.py --input "data/*.parquet" --out scores/ \
      --fp8 --compile --shard $g --num-shards 4 > log_$g.txt 2>&1 &
done

How it works and what to know:

  • CPU workers (--workers, default: all cores but two, at most 16) truncate, tokenize and compute the text statistics while the GPU runs the model. The CPU is often the bottleneck: plan 10–16 cores per GPU.
  • FP8 (--fp8): the encoder's linear layers in FP8 via torchao, with per-row activation scales, so FP8 does not make a document's score depend on its batch neighbours (padding to a common length still adds bf16 noise of about ±0.005). Needs a GPU with FP8: compute capability 8.9 or newer (RTX 40xx / Ada, H100, Blackwell). On A100 and older, drop --fp8. FP8 vs bf16 on 500 test documents: overall correlation 0.9994, mean shift 0.01; 0 and 1 of 500 documents change sides of the 1.5 and 2.0 thresholds.
  • --compile: torch.compile of the encoder with dynamic shapes. It needs a C compiler (gcc) for Triton; the first batches are slow while it compiles.
  • Resume: each file is scored in parts of 200,000 rows (--part-rows), and a part is saved only when complete. After a crash, run the same command again: finished files and parts are skipped, at most one part is redone.
  • Documents are sorted by length inside a part to reduce padding; the output keeps the input order. If the input has no id column, the row number is used.

Measured throughput (documents per second):

Setup docs/s
Apple M4 Pro, MPS, bf16 (predict.py) ~19
RTX PRO 4000 Blackwell, bf16, GPU only 257
+ torch.compile 318
+ FP8 501
Same card, whole pipeline (reading, tokenization, statistics, writing; 32 CPU cores) ~450–500
RTX PRO 6000 Max-Q, per card (31 CPU cores for 2 cards) ~1,080

All of rus_Cyrl (699M documents) took about two days on rented single-GPU machines (up to 10 at once, RTX PRO 4000–6000).

Output

Field Meaning
overall Pretraining value, expected level on 1–4 (4 = "4 or 5"): mean of the two overall heads. Use this one
overall_direct, overall_stacked The two heads: from the text directly, and from the predicted axes, flags and categories
p_overall_4plus Probability that the annotator would give 4 or 5; use it to pick the top
axes.* Expected score 1–5 for each of the 13 axes
flags.* Probabilities of 8 flags; answer_dump is a keyword rule (true / false)
topic Top-3 topics with probabilities in predict.py; the most likely topic in score_parquet.py
format, audience, region Most likely class

overall is an expected value, so on the lite model it practically never reaches 4: on all of rus_Cyrl its maximum is about 3.9 and 2.0% of documents are ≥ 3.5. To pick the top, use p_overall_4plus. Share of the corpus kept at each threshold: full dataset, "Choosing a threshold".

Rating criteria

The model reproduces the rubric of the annotations dataset.

overall Decision Typical documents
1 Exclude Spam, doorways, garbage, any unsafe content
2 Rather exclude Ads, filler
3 Keep: ordinary acceptable web News, forum post, blog
4 Keep with a higher weight Substantive, well-written text: explanations or facts
5 Reference quality, upsample Textbook, encyclopedic article, deep analysis

Levels 4 and 5 are merged into "4+": 5 is only ~0.1% of the data.

Output Count Names
Quality axes, 1–5 13 cleanliness, language_quality, naturalness, information_density, factual_specificity, educational_value, reasoning_depth, expertise_level, credibility, originality, commercial_neutrality, durability, domain_depth
Flags, probability 8 unsafe_content, seo_doorway, machine_generated, truncated_or_fragment, suspected_mt, pii_present, official_document, mixed_language
Rule flag, true / false 1 answer_dump
Categories 4 topic (30 topics), format (26), audience (7), region (5); names in labels.json

What every axis, flag and category means, with a description of each level: annotations dataset, "Rating criteria". The exact annotation prompt is in that repo, prompt/annotate_v6.system.md.

Architecture

text → first 512 tokens → Nemotron-3-Embed-1B, embeddings + layers 1–4 (bf16, final norm not applied)
     → mean pooling of each of the 5 hidden states over the tokens
     ├─ learned layer mix #1
     ├─ learned layer mix #2  (the chunk branch of base: one window, so no attention)
     └─ 32 text statistics (Gopher / C4-style: script shares, duplicate lines/n-grams, ...)
  → trunk MLP (1024) → 13 ordinal axis towers (CORN) · 8 flag logits · topic · format · audience · region
                     → overall: direct ordinal head + stacked head over the predicted
                       axis / flag / category probabilities (trained out-of-fold)

The heads are the same as in base: same trunk, towers and stacked overall head, the same 5-fold training, all five head sets averaged at inference. What changes is the input to the trunk. Base mixes all 17 hidden states of up to 4,096 tokens and pools 256-token chunks with attention, so it can notice a good article with a junk tail. The lite model has one 512-token window: the attention over chunks has nothing to choose from, and both branches become learned mixes of the same layers 0–4.

Evaluation

Test split: 2,501 held-out documents (half uniform random, half from a "probably good" pool, the same mix as training). run05: 200 random documents labelled by Claude Opus agents instead of Sonnet, which shows how the model agrees with a different annotator.

test run05
Axes, mean QWK 0.832 0.831
overall QWK (1–4) 0.820 0.823
overall Spearman 0.853 0.853
PR-AUC overall ≥ 4 0.60 (base rate 4.7%) 0.65 (base rate 6%)
Junk: Sonnet gave 1, overall < 1.5 precision 0.92, recall 0.82 precision 0.85, recall 0.82

Per-axis QWK, test:

Axis base lite
cleanliness 0.89 0.86
language_quality 0.85 0.83
naturalness 0.87 0.85
information_density 0.88 0.85
factual_specificity 0.89 0.86
educational_value 0.87 0.82
reasoning_depth 0.82 0.77
expertise_level 0.87 0.83
credibility 0.85 0.80
originality 0.85 0.80
commercial_neutrality 0.92 0.88
durability 0.90 0.86
domain_depth 0.85 0.80

Flags, PR-AUC on test. The three marked ones are unreliable: the annotator disagrees with itself on them too.

Flag base lite
seo_doorway 0.99 0.97
unsafe_content 0.94 0.89
machine_generated 0.90 0.89
mixed_language 0.89 0.89
official_document 0.70 0.71
pii_present (unreliable) 0.48 0.42
truncated_or_fragment (unreliable) 0.47 0.39
suspected_mt (unreliable) 0.36 0.38

Categories, test:

Category Metric base lite
topic top-1 accuracy 0.78 0.69
region macro-F1 0.82 0.70
audience macro-F1 0.75 0.56
format macro-F1 0.63 0.54

Categories lose the most from the short context.

The packaged model was checked against the training run on 200 raw test texts (mean overall difference 0.001, bf16 noise), and score_parquet.py against predict.py (≤ 0.0005). Full numbers: metrics.json.

Limitations

  • Russian only (see the top of the card).
  • Reads only the first 512 tokens.
  • It imitates one LLM annotator (Claude Sonnet 5.5, prompt v6) and inherits its biases; the rubric favours educational and factual text.
  • Trained on FineWeb-2 web pages; books, code and chat are out of distribution.
  • Weaker than base on the top end and on categories. Use scores to rank and filter in bulk, not to judge a single document.

Files

File
model.safetensors Encoder (embeddings + 4 layers, bf16) + 5 cross-validation head sets + the stacked overall head
tokenizer.json, tokenizer_config.json Tokenizer of the encoder
config.json, labels.json Encoder and head config, class names, order of text statistics
predict.py Simple inference: command line and LiteScorer
score_parquet.py Production inference: FP8, torch.compile, CPU workers, resume
modeling.py, heuristics.py Model code and the 32 text statistics
metrics.json Validation / test / run05 metrics
LICENSE, NOTICE OpenMDW-1.1, the encoder's license, and its attribution notices

License

OpenMDW-1.1, the license of the base encoder nvidia/Nemotron-3-Embed-1B-BF16, whose first 4 layers are included here unchanged. The heads were trained on labels produced by Claude Sonnet 5.5 for FineWeb-2 texts (ODC-By 1.0).


Русский

Только для русского языка. Модель обучена и проверена только на русских веб-документах (FineWeb-2 rus_Cyrl). На других языках её не проверяли, и её оценки для них не имеют смысла.

Быстрая модель качества русского веб-текста для фильтрации данных предобучения в масштабе целых корпусов. Выходы те же, что у krysyuk/ruTron-quality-classifier-base (base): общая ценность для предобучения overall, 13 осей качества по шкале 1–5, 8 флагов содержания, тема, формат, аудитория и регион. Обе модели повторяют разметку, которую Claude Sonnet 5.5 сделал для 26 000 документов FineWeb-2 (krysyuk/fineweb-2-russian-quality-annotations-26k).

Эта модель оценила все 699 млн документов FineWeb-2 rus_Cyrl: krysyuk/fineweb-2-russian-quality-full.

Её главная задача - дёшево отсечь мусор: спам, дорвеи, сгенерированный и битый текст. Для тонкого ранжирования хороших документов base-модель заметно лучше.

Чем отличается от base

base lite
Энкодер Nemotron-3-Embed-1B, все 16 слоёв только первые 4 слоя
Что читает до 4 096 токенов (первые 10 000 + последние 1 700 символов) первые 512 токенов того же текста
Вектор документа обучаемая смесь всех 17 скрытых состояний + attention pooling по кускам из 256 токенов (слои 4/8/12/16) две обучаемые смеси скрытых состояний 0–4 одного окна из 512 токенов; attention по кускам нет
Головы обучены на признаках base обучены заново на признаках lite, те же метки, та же 5-фолдовая схема (не дистилляция из base)
Параметры, размер файла энкодер 1,14 млрд + головы 46M, 2,5 ГБ энкодер 487M (из них 268M - таблица эмбеддингов) + головы 46M, 1,2 ГБ
Скорость, Apple M4 Pro ~1,2 док/с ~19 док/с
Скорость, одна RTX PRO 4000 не замеряли ~500 док/с с FP8 + torch.compile
QWK overall / осей (test) 0.876 / 0.870 0.820 / 0.832

Подробнее:

  • Урезанный энкодер. Слои 5–16 просто не запускаются, оставшиеся веса не менялись (bf16). Финальная нормализация энкодера не применяется: головы читают сырые скрытые состояния, как при обучении.
  • 512 токенов. Модель не видит ничего дальше примерно первых 1 700 символов. Проблемы в глубине длинного документа она пропускает.
  • Те же 32 текстовые статистики, что у base, считаются по полному тексту из 10 000 + 1 700 символов. heuristics.py - более быстрая реализация с теми же значениями (проверено на 500 документах; base теперь использует этот же файл).
  • Продакшн-скрипт score_parquet.py: FP8, torch.compile, параллельные CPU-воркеры, продолжение после обрыва. Именно этим кодом размечен полный датасет.
  • Токенизатор зафиксирован в том поведении, что было при обучении (fix_mistral_regex=False). Не «исправляйте» его: оценки поплывут.

Почему 4 слоя и 512 токенов

Головы обучены на выходах первых L слоёв замороженного энкодера (ровно то, что считает урезанная модель); test, голова overall_direct:

Слоёв энкодера Что читает QWK осей QWK overall PR-AUC overall ≥ 4
16 (base) 4 096 токенов 0.870 0.873 0.763
4 4 096 токенов 0.856 0.851 0.669
8 первые 512 0.853 0.851 0.644
6 первые 512 0.847 0.842 0.625
4 (lite) первые 512 0.832 0.818 0.595

Три сида выбранной конфигурации: QWK осей 0.830–0.832, QWK overall 0.818–0.822. Теряется в основном верх; на мусорном конце потеря небольшая (test):

Задача base lite
Sonnet поставил 1, overall < 1.5 точность 0.93, полнота 0.89 точность 0.92, полнота 0.82
Sonnet поставил 1–2, overall < 2.5 точность 0.92, полнота 0.91 точность 0.89, полнота 0.88
Спирмен между overall base и lite 0.93

Быстрый старт

Чтобы посмотреть, как всё работает, и для небольших объёмов: predict.py, обычный PyTorch, любое устройство.

pip install torch "transformers>=5.18" safetensors pyarrow huggingface_hub
hf download krysyuk/ruTron-quality-classifier-lite --local-dir ruTron-quality-classifier-lite
cd ruTron-quality-classifier-lite

python predict.py --input docs.jsonl --output scores.jsonl   # по строке {"id", "text"}
python predict.py --input docs.parquet --output scores.jsonl --device cuda
import sys
from huggingface_hub import snapshot_download

path = snapshot_download("krysyuk/ruTron-quality-classifier-lite")
sys.path.insert(0, path)
from predict import LiteScorer

scorer = LiteScorer(path)  # cuda / mps / cpu выбирается сам
scorer.score(["Текст документа ..."])[0]

Проверено на torch 2.14 и transformers 5.18.

Продакшн: миллионы документов

score_parquet.py читает parquet-файлы и на каждый входной файл пишет parquet с оценками: те же 30 колонок, что в полном датасете, плюс id.

pip install torchao   # для --fp8

# локальные parquet с колонкой "text"
python score_parquet.py --input "data/*.parquet" --out scores/ --fp8 --compile

# файлы датасета с Hub: следующий файл качается, пока считается текущий,
# каждый файл удаляется после оценки
python score_parquet.py --hf-dataset HuggingFaceFW/fineweb-2 \
    --hf-files "data/rus_Cyrl/train/*.parquet" --out scores/ --fp8 --compile

# несколько GPU: по процессу на карту, файлы делятся между ними
for g in 0 1 2 3; do
  CUDA_VISIBLE_DEVICES=$g python score_parquet.py --input "data/*.parquet" --out scores/ \
      --fp8 --compile --shard $g --num-shards 4 > log_$g.txt 2>&1 &
done

Как это работает и что важно знать:

  • CPU-воркеры (--workers, по умолчанию все ядра кроме двух, не больше 16) обрезают текст, токенизируют и считают текстовые статистики, пока GPU считает модель. Узким местом часто становится CPU: закладывайте 10–16 ядер на карту.
  • FP8 (--fp8): линейные слои энкодера в FP8 через torchao, масштаб активаций на строку, поэтому FP8 не делает оценку документа зависимой от соседей по батчу (паддинг до общей длины всё равно даёт шум bf16 около ±0.005). Нужна карта с FP8: compute capability 8.9 и новее (RTX 40xx / Ada, H100, Blackwell). На A100 и старше уберите --fp8. FP8 против bf16 на 500 документах test: корреляция overall 0.9994, средний сдвиг 0.01; через пороги 1.5 и 2.0 переходят 0 и 1 документ из 500.
  • --compile: torch.compile энкодера с динамическими формами. Тритону нужен компилятор C (gcc); первые батчи медленные, пока идёт компиляция.
  • Продолжение: каждый файл считается частями по 200 000 строк (--part-rows), часть сохраняется только целиком. После падения запустите ту же команду: готовые файлы и части пропускаются, заново считается не больше одной части.
  • Внутри части документы сортируются по длине, чтобы было меньше паддинга; на выходе порядок входа сохраняется. Если во входе нет колонки id, берётся номер строки.

Замеры скорости (документов в секунду):

Конфигурация док/с
Apple M4 Pro, MPS, bf16 (predict.py) ~19
RTX PRO 4000 Blackwell, bf16, только GPU 257
+ torch.compile 318
+ FP8 501
Та же карта, весь конвейер (чтение, токенизация, статистики, запись; 32 ядра CPU) ~450–500
RTX PRO 6000 Max-Q, на карту (31 ядро CPU на 2 карты) ~1 080

Весь rus_Cyrl (699 млн документов) посчитан примерно за двое суток на арендованных машинах с одной GPU (до 10 одновременно, RTX PRO 4000–6000).

Выход

Поле Смысл
overall Ценность для предобучения, ожидаемый уровень 1–4 (4 = «4 или 5»): среднее двух голов overall. Используйте его
overall_direct, overall_stacked Две головы: прямо по тексту и по предсказанным осям, флагам и категориям
p_overall_4plus Вероятность, что аннотатор поставил бы 4 или 5; по ней удобно отбирать лучшее
axes.* Ожидаемая оценка 1–5 по каждой из 13 осей
flags.* Вероятности 8 флагов; answer_dump - правило по ключевым словам (да / нет)
topic 3 самые вероятные темы с вероятностями в predict.py; самая вероятная тема в score_parquet.py
format, audience, region Самый вероятный класс

overall - математическое ожидание, поэтому у lite он практически не доходит до 4: на всём rus_Cyrl максимум около 3.9, а ≥ 3.5 у 2,0% документов. Для отбора лучшего берите p_overall_4plus. Какая доля корпуса остаётся при каждом пороге: полный датасет, раздел «Как выбрать порог».

Критерии оценки

Модель воспроизводит рубрику датасета с разметкой.

overall Решение Типичные документы
1 Исключить Спам, дорвеи, мусор, любой небезопасный контент
2 Скорее исключить Реклама, вода
3 Оставить: обычный приемлемый веб Новость, пост на форуме, блог
4 Оставить с повышенным весом Содержательный, хорошо написанный текст: объяснения или факты
5 Эталон, апсемплить Учебник, энциклопедическая статья, глубокий анализ

Уровни 4 и 5 объединены в «4+»: оценка 5 - всего около 0,1% данных.

Выход Сколько Названия
Оси качества, 1–5 13 cleanliness, language_quality, naturalness, information_density, factual_specificity, educational_value, reasoning_depth, expertise_level, credibility, originality, commercial_neutrality, durability, domain_depth
Флаги, вероятность 8 unsafe_content, seo_doorway, machine_generated, truncated_or_fragment, suspected_mt, pii_present, official_document, mixed_language
Флаг-правило, да / нет 1 answer_dump
Категории 4 topic (30 тем), format (26), audience (7), region (5); названия в labels.json

Что значит каждая ось, флаг и категория, с описанием каждого уровня: датасет с разметкой, раздел «Критерии оценки». Точный промпт разметки лежит там же, prompt/annotate_v6.system.md.

Архитектура

текст → первые 512 токенов → Nemotron-3-Embed-1B, эмбеддинги + слои 1–4 (bf16, без финальной нормализации)
      → mean pooling каждого из 5 скрытых состояний по токенам
      ├─ обучаемая смесь слоёв №1
      ├─ обучаемая смесь слоёв №2  (ветка кусков из base: окно одно, поэтому без attention)
      └─ 32 текстовые статистики (в духе Gopher / C4: доли алфавитов, повторы строк и n-грамм, ...)
  → MLP-ствол (1024) → 13 порядковых башен осей (CORN) · 8 логитов флагов · тема · формат · аудитория · регион
                     → overall: прямая порядковая голова + стекинг-голова по предсказанным
                       вероятностям осей, флагов и категорий (обучена out-of-fold)

Головы те же, что у base: тот же ствол, башни и стекинг-голова overall, то же обучение на 5 фолдах, на инференсе все пять наборов голов усредняются. Меняется вход ствола. Base смешивает все 17 скрытых состояний по 4 096 токенам и пулит куски по 256 токенов через attention, поэтому замечает, например, хорошую статью с мусорным хвостом. У lite одно окно из 512 токенов: attention по кускам выбирать не из чего, и обе ветки становятся обучаемыми смесями одних и тех же слоёв 0–4.

Качество

Test: 2 501 отложенный документ (половина - равномерно случайные, половина - из пула «вероятно хороших», как в обучении). run05: 200 случайных документов, размеченных агентами Claude Opus вместо Sonnet; показывает согласие модели с другим аннотатором.

test run05
Оси, средний QWK 0.832 0.831
QWK overall (1–4) 0.820 0.823
Спирмен overall 0.853 0.853
PR-AUC overall ≥ 4 0.60 (база 4.7%) 0.65 (база 6%)
Мусор: Sonnet поставил 1, overall < 1.5 точность 0.92, полнота 0.82 точность 0.85, полнота 0.82

QWK по осям, test:

Ось base lite
cleanliness 0.89 0.86
language_quality 0.85 0.83
naturalness 0.87 0.85
information_density 0.88 0.85
factual_specificity 0.89 0.86
educational_value 0.87 0.82
reasoning_depth 0.82 0.77
expertise_level 0.87 0.83
credibility 0.85 0.80
originality 0.85 0.80
commercial_neutrality 0.92 0.88
durability 0.90 0.86
domain_depth 0.85 0.80

Флаги, PR-AUC на test. Трём отмеченным доверять нельзя: аннотатор и сам с собой по ним не согласен.

Флаг base lite
seo_doorway 0.99 0.97
unsafe_content 0.94 0.89
machine_generated 0.90 0.89
mixed_language 0.89 0.89
official_document 0.70 0.71
pii_present (ненадёжный) 0.48 0.42
truncated_or_fragment (ненадёжный) 0.47 0.39
suspected_mt (ненадёжный) 0.36 0.38

Категории, test:

Категория Метрика base lite
topic точность top-1 0.78 0.69
region macro-F1 0.82 0.70
audience macro-F1 0.75 0.56
format macro-F1 0.63 0.54

Сильнее всего от короткого контекста страдают категории.

Упакованная модель сверена с прогоном обучения на 200 сырых текстах test (среднее расхождение overall 0.001, шум bf16), а score_parquet.py - с predict.py (≤ 0.0005). Все цифры: metrics.json.

Ограничения

  • Только русский язык (см. начало карточки).
  • Читает только первые 512 токенов.
  • Модель подражает одному LLM-аннотатору (Claude Sonnet 5.5, промпт v6) и наследует его предвзятость; рубрика предпочитает образовательные и фактологичные тексты.
  • Обучена на веб-страницах FineWeb-2; книги, код и чаты - вне распределения.
  • Слабее base в верхнем диапазоне и на категориях. Оценки - для массового ранжирования и фильтрации, а не для вердикта по одному документу.

Файлы

Файл
model.safetensors Энкодер (эмбеддинги + 4 слоя, bf16) + 5 наборов голов кросс-валидации + стекинг-голова overall
tokenizer.json, tokenizer_config.json Токенизатор энкодера
config.json, labels.json Конфиг энкодера и голов, имена классов, порядок текстовых статистик
predict.py Простой инференс: командная строка и LiteScorer
score_parquet.py Продакшн-инференс: FP8, torch.compile, CPU-воркеры, продолжение после обрыва
modeling.py, heuristics.py Код модели и 32 текстовые статистики
metrics.json Метрики на validation / test / run05
LICENSE, NOTICE OpenMDW-1.1, лицензия энкодера, и его уведомления об авторстве

Лицензия

OpenMDW-1.1, лицензия базового энкодера nvidia/Nemotron-3-Embed-1B-BF16, первые 4 слоя которого входят сюда без изменений. Головы обучены на разметке Claude Sonnet 5.5 для текстов FineWeb-2 (ODC-By 1.0).

Downloads last month
6
Safetensors
Model size
0.5B params
Tensor type
F32
·
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for krysyuk/ruTron-quality-classifier-lite

Datasets used to train krysyuk/ruTron-quality-classifier-lite