Детектор ИИ-текста для русского языка
russian-ai-text-detector-bert оценивает вероятность, что русский текст написала нейросеть, а не
человек. Обучен на текстах ChatGPT (GPT-3.5, GPT-4, GPT-4o, o1, o3), GigaChat, YandexGPT, Qwen, Llama, Gemma, DeepSeek, Mistral, Command R и других языковых моделей из корпуса
LLMTrace. Помогает проверить текст на ИИ: статью, новость, отзыв, пост, ответ
на вопрос.
Это дообученный энкодер cointegrated/rubert-tiny2 на
\(29.2\) млн параметров, переведённый в ONNX с весами int8.
Файл model.onnx занимает \(29.7\) МБ и работает на CPU через onnxruntime, без
torch и GPU. Рядом лежит model_fp32.onnx на \(117\) МБ с весами fp32, aiw-ru его не скачивает. Веса PyTorch для дообучения и своего экспорта — model.safetensors на \(117\) МБ. На отложенной части корпуса ROC AUC \(0.987\), accuracy
\(0.945\). У LightGBM на признаках aiw-ru ROC AUC \(0.943\).
Модель необязательная: детектор и скиллы aiw-ru работают без неё. Ставится она только по имени, командой aiw-ru models install transformer, и только если пользователь попросит; в aiw-ru classify её выбирают ключом --model transformer.
Другие модели aiw-ru: russian-ai-text-detector-mini-frida (mini-frida), russian-ai-text-detector-modernbert (modernbert), LightGBM на признаках aiw-ru (lightgbm).
In English
A Russian AI-generated text detector. It estimates the probability that a
Russian text was written by a person or by an LLM such as ChatGPT (GPT-3.5, GPT-4, GPT-4o, o1, o3), GigaChat, YandexGPT, Qwen, Llama, Gemma, DeepSeek, Mistral, Command R
and others, which makes it usable as an AI text detector, a ChatGPT detector or an
"AI slop" filter for Russian. The model is cointegrated/rubert-tiny2 fine-tuned, trained on the
Russian part of the LLMTrace corpus and exported to ONNX with int8 weights:
model.onnx takes \(29.7\) MB and runs on CPU with onnxruntime, no torch
or GPU needed. An fp32 export, model_fp32.onnx, is an optional extra file of \(117\) MB. PyTorch weights for fine-tuning or your own export are in model.safetensors, \(117\) MB.
Test ROC AUC \(0.987\), accuracy \(0.945\). Install it with
aiw-ru models install transformer. The rest of the card is in Russian; usage is below.
Какую модель выбрать
Это быстрый вариант среди трансформеров aiw-ru, за скорость он платит точностью.
| Модель | Людей принято за ИИ | ROC AUC | Accuracy | Файл, МБ | M1, мс | x86, мс |
|---|---|---|---|---|---|---|
modernbert | \(3.4%\) | \(0.9930\) | \(0.963\) | \(140\) | \(207.2\) | — |
transformer, эта модель | \(7.2%\) | \(0.9869\) | \(0.945\) | \(29.7\) | \(39.8\) | \(101.1\) |
mini-frida | \(9.5%\) | \(0.9909\) | \(0.948\) | \(130\) | \(137.2\) | \(216.2\) |
lightgbm | \(16.5%\) | \(0.9431\) | \(0.868\) | \(10.0\) | — | — |
modernbert— самая точная: выбор по умолчанию, но тяжелее трансформера и в несколько раз медленнее.transformer(эта модель) — почти так же точна, лёгкая и в несколько раз быстрее ModernBERT: для слабой машины.mini-frida— ROC AUC выше, чем у трансформера, но при пороге 50 % чаще принимает людей за ИИ; в 4 раза тяжелее и в 3 раза медленнее.lightgbm— самая лёгкая, работает и без onnxruntime (Mac на Intel), но заметно менее точна.
Если установлено несколько моделей, aiw-ru берёт вероятность у первой из них в порядке таблицы. Порядок задаёт доля людей, принятых за ИИ, а не ROC AUC: ошибиться в человеке дороже, чем пропустить ИИ-текст.
Задержка — один текст на \(512\) токенов в один поток на M1 и на двух ядрах Xeon виртуальной машины Colab (x86). Размер у LightGBM — файл модели, признаки для неё считает сам детектор aiw-ru.
Данные
Русская часть LLMTrace classification
(статья), ревизия 252e21e3dca7. Модель обучена на \(237,929\) текстах из train, лучший шаг и ранняя остановка — по ROC AUC на \(49,747\) текстах из valid.
Итоговые цифры посчитаны по test, это \(52,521\) текст: эту часть
корпуса модель при обучении не видела. Отчёт об обучении с выбором базы и командами для
воспроизведения лежит на GitHub.
Результаты на test
Текст считается написанным ИИ, если вероятность не меньше \(0.5\). Текст длиннее \(512\) токенов модель читает только до этой границы: среднее по окнам на valid не точнее.
| Класс | Precision | Recall | F1 | Текстов |
|---|---|---|---|---|
| люди | \(0.937\) | \(0.928\) | \(0.932\) | \(21,417\) |
| ИИ | \(0.951\) | \(0.957\) | \(0.954\) | \(31,104\) |
| accuracy | \(0.945\) | \(52,521\) | ||
| среднее по классам | \(0.944\) | \(0.942\) | \(0.943\) | \(52,521\) |
Сравнение с LightGBM на признаках aiw-ru и с оценкой правил детектора с порогом \(40\) на том же test:
| На test | Эта модель | modernbert | mini-frida | LightGBM | Правила aiw-ru |
|---|---|---|---|---|---|
| Accuracy | \(0.945\) | \(0.963\) | \(0.948\) | \(0.868\) | \(0.503\) |
| ROC AUC | \(0.987\) | \(0.993\) | \(0.991\) | \(0.943\) | \(0.615\) |
| ROC AUC, люди против текстов с нуля | \(0.989\) | \(0.994\) | \(0.992\) | \(0.946\) | \(0.597\) |
| F1, среднее по классам | \(0.943\) | \(0.962\) | \(0.945\) | \(0.863\) | \(0.466\) |
| Людей принято за ИИ | \(7.2%\) | \(3.4%\) | \(9.5%\) | \(16.5%\) | \(5.9%\) |
На valid accuracy \(0.946\), ROC AUC \(0.988\).
По жанрам
| Жанр | Людей | ИИ | Accuracy | ROC AUC | ROC AUC LightGBM | ROC AUC правил |
|---|---|---|---|---|---|---|
article | \(5109\) | \(5343\) | \(0.948\) | \(0.989\) | \(0.963\) | \(0.709\) |
factual | \(1383\) | \(2209\) | \(0.915\) | \(0.976\) | \(0.896\) | \(0.673\) |
news | \(3326\) | \(3488\) | \(0.931\) | \(0.984\) | \(0.890\) | \(0.566\) |
poetry | \(3561\) | \(3383\) | \(0.937\) | \(0.979\) | \(0.932\) | \(0.488\) |
question | \(1932\) | \(5894\) | \(0.958\) | \(0.991\) | \(0.951\) | \(0.729\) |
review | \(2678\) | \(4019\) | \(0.960\) | \(0.990\) | \(0.960\) | \(0.638\) |
short_form | \(450\) | \(3000\) | \(0.934\) | \(0.980\) | \(0.942\) | \(0.556\) |
story | \(2978\) | \(3768\) | \(0.953\) | \(0.991\) | \(0.967\) | \(0.570\) |
По длине текста
Слова считает детектор aiw-ru, как и для LightGBM.
| Слов в тексте | Текстов | Accuracy | ROC AUC | Accuracy LightGBM | ROC AUC LightGBM |
|---|---|---|---|---|---|
| \(0\text{–}49\) | \(14,742\) | \(0.925\) | \(0.980\) | \(0.819\) | \(0.902\) |
| \(50\text{–}149\) | \(17,766\) | \(0.942\) | \(0.986\) | \(0.849\) | \(0.924\) |
| \(150\text{–}399\) | \(16,327\) | \(0.963\) | \(0.993\) | \(0.913\) | \(0.968\) |
| \(400\) и больше | \(3686\) | \(0.962\) | \(0.980\) | \(0.952\) | \(0.970\) |
По типу задания генератору
create — текст с нуля; update, delete, expand — модель правила,
сокращала или дописывала человеческий текст.
| Задание генератору | ИИ-текстов | Recall | Recall LightGBM |
|---|---|---|---|
create | \(14,064\) | \(0.963\) | \(0.899\) |
delete | \(5966\) | \(0.924\) | \(0.812\) |
expand | \(4850\) | \(0.972\) | \(0.945\) |
update | \(6224\) | \(0.963\) | \(0.903\) |
По моделям-генераторам
Самые частые генераторы в test.
| Модель-генератор | Текстов в test | Recall | Recall LightGBM |
|---|---|---|---|
gpt-3.5 | \(4772\) | \(0.977\) | \(0.929\) |
gpt-4o | \(3884\) | \(0.983\) | \(0.908\) |
databricks/dbrx-instruct | \(1513\) | \(0.927\) | \(0.859\) |
google/gemma-2-27b-it | \(1498\) | \(0.977\) | \(0.888\) |
01-ai/Yi-1.5-34B-Chat | \(1472\) | \(0.952\) | \(0.898\) |
yandex/YandexGPT-5-Lite-8B-instruct | \(1469\) | \(0.932\) | \(0.853\) |
CohereForAI/c4ai-command-r-08-2024 | \(1461\) | \(0.990\) | \(0.951\) |
unsloth/Llama-3.3-70B-Instruct | \(1452\) | \(0.964\) | \(0.915\) |
Qwen/Qwen2.5-72B-Instruct | \(1449\) | \(0.959\) | \(0.887\) |
mistralai/Ministral-8B-Instruct-2410 | \(1396\) | \(0.903\) | \(0.829\) |
Qwen/QwQ-32B | \(1386\) | \(0.974\) | \(0.885\) |
GigaChat-Max | \(1266\) | \(0.958\) | \(0.931\) |
gigachat | \(1181\) | \(0.936\) | \(0.831\) |
deepseek-ai/DeepSeek-R1-Distill-Qwen-32B | \(942\) | \(0.960\) | \(0.869\) |
WizardLM-2-7B | \(891\) | \(0.980\) | \(0.926\) |
Длинные тексты
Тексты длиннее \(512\) токенов, в test их \(5498\). Сравниваются вероятность по началу текста и среднее по окнам:
| Правило | ROC AUC valid | Accuracy valid | ROC AUC test | Accuracy test |
|---|---|---|---|---|
| начало текста | \(0.981\) | \(0.965\) | \(0.980\) | \(0.957\) |
| среднее по окнам | \(0.976\) | \(0.963\) | \(0.973\) | \(0.959\) |
Нормализация
В LLMTrace оформление говорит о том, откуда взят человеческий текст: переводы
строк, markdown, вид тире и кавычек, ё. Поэтому до токенизации текст проходит
нормализацию: разметка и типографика сводятся к простому виду, правила лежат в
inference.json. В пилоте база cointegrated/rubert-tiny2 без нормализации дала ROC AUC \(0.960\) на valid, с нормализацией \(0.957\). Нормализация всё равно остаётся: модель, выучившая оформление корпуса, ошибётся на человеческом тексте, набранном в другом редакторе или скопированном из чата.
Скорость и размер
Задержка на один текст в миллисекундах, медиана \(30\) прогонов, Apple M1, 8 ядер:
| Среда | 128 токенов, потоков: 1 | 128 токенов, потоков: 8 | 512 токенов, потоков: 1 | 512 токенов, потоков: 8 |
|---|---|---|---|---|
| onnxruntime fp32 | \(9.6\) | \(4.5\) | \(57.7\) | \(26.9\) |
| onnxruntime int8 | \(5.1\) | \(2.8\) | \(39.8\) | \(22.7\) |
| torch fp32 | \(3.0\) | \(3.5\) | \(19.3\) | \(10.1\) |
На двух ядрах виртуальной машины Colab, это ближе к слабому ноутбуку на x86, Intel(R) Xeon(R) CPU @ 2.00GHz, 2 ядра:
| Среда | 128 токенов, потоков: 1 | 128 токенов, потоков: 2 | 512 токенов, потоков: 1 | 512 токенов, потоков: 2 |
|---|---|---|---|---|
| onnxruntime fp32 | \(21.5\) | \(12.0\) | \(111.2\) | \(95.8\) |
| onnxruntime int8 | \(17.6\) | \(10.0\) | \(101.1\) | \(87.4\) |
| torch fp32 | \(12.8\) | \(12.6\) | \(70.7\) | \(48.9\) |
Размер зависимостей вывода после установки через uv для Python 3.12:
| Зависимости вывода | Платформа | МБ на диске |
|---|---|---|
| onnxruntime + tokenizers | aarch64-apple-darwin | \(127\) |
| onnxruntime + tokenizers | x86_64-manylinux_2_28 | \(156\) |
| onnxruntime + tokenizers | x86_64-pc-windows-msvc | \(112\) |
| torch + transformers | aarch64-apple-darwin | \(669\) |
| torch + transformers | x86_64-manylinux_2_28 | \(5649\) |
| torch (CPU) + transformers | x86_64-manylinux_2_28 | \(908\) |
| torch + transformers | x86_64-pc-windows-msvc | \(642\) |
Размер считается вместе со всеми зависимостями, в том числе numpy и
huggingface-hub, которые aiw-ru с extra ml и так ставит для LightGBM.
На этой машине torch считает быстрее onnxruntime: \(19.3\) мс против \(39.8\) мс у ONNX int8 на \(512\) токенах в один поток. Но torch с transformers занимает на диске в \(5.3\text{–}5.8\) раза больше, а на Linux со сборкой torch под CUDA по умолчанию — \(5649\) МБ. aiw-ru ставят и на слабые ноутбуки, поэтому в поставке ONNX: установка лёгкая, а ROC AUC на test совпадает с PyTorch до четвёртого знака.
Как пользоваться
Из командной строки:
uv tool install "aiw-ru[ml]"
aiw-ru models install transformer
aiw-ru classify --model transformer текст.md
Из Python без aiw-ru нужны только onnxruntime, tokenizers и numpy:
import json
import os
import re
# Без этой строки onnxruntime 1.30 при импорте включает телеметрию Microsoft,
# и процесс изредка падает на выходе (recursive_mutex lock failed, код 134).
os.environ.setdefault("ORT_DISABLE_TELEMETRY", "1")
import numpy as np
import onnxruntime as ort
from huggingface_hub import snapshot_download
from tokenizers import Tokenizer
files = ["inference.json", "model.onnx*", "tokenizer.json"]
path = snapshot_download("toiletsandpaper/russian-ai-text-detector-bert", allow_patterns=files)
spec = json.load(open(f"{path}/inference.json", encoding="utf-8"))
session = ort.InferenceSession(f"{path}/{spec['file']}", providers=["CPUExecutionProvider"])
tokenizer = Tokenizer.from_file(f"{path}/{spec['tokenizer']}")
tokenizer.no_truncation()
tokenizer.no_padding()
def probability(text: str) -> float:
"""Вероятность, что текст написала языковая модель."""
text = text[: spec["max_chars"]]
for rule in spec["normalize"]:
text = re.sub(rule["pattern"], rule["replacement"], text, flags=re.MULTILINE)
ids = tokenizer.encode(text.strip(), add_special_tokens=False).ids
prefix, suffix = [spec["cls_id"]], [spec["sep_id"]]
width = spec.get("read_length", spec["max_length"]) - len(prefix) - len(suffix)
windows = [ids[i : i + width] for i in range(0, max(len(ids), 1), width)][: spec["max_windows"]]
windows = [[*prefix, *w, *suffix] for w in windows]
batch = np.full((len(windows), max(map(len, windows))), spec["pad_id"], dtype=np.int64)
mask = np.zeros_like(batch)
for k, w in enumerate(windows):
batch[k, : len(w)] = w
mask[k, : len(w)] = 1
logits = session.run([spec["output"]], {"input_ids": batch, "attention_mask": mask})[0]
p = np.exp(logits - logits.max(axis=1, keepdims=True))
return float((p[:, spec["labels"].index("ai")] / p.sum(axis=1)).mean())
print(probability(open("текст.md", encoding="utf-8").read()))
inference.json описывает вывод целиком: файл ONNX, токенизатор,
max_length, токены вокруг окна, правила нормализации из обучения, порог
\(0.5\) и число окон для длинных текстов.
Для дообучения и своего экспорта в репозитории есть веса PyTorch, model.safetensors.
aiw-ru и пример выше их не скачивают. Их читает transformers:
from transformers import AutoModelForSequenceClassification, AutoTokenizer
model = AutoModelForSequenceClassification.from_pretrained("toiletsandpaper/russian-ai-text-detector-bert")
tokenizer = AutoTokenizer.from_pretrained("toiletsandpaper/russian-ai-text-detector-bert")
Текст перед токенизатором нормализуй по правилам normalize из inference.json, как в
примере выше: на нём модель и обучалась.
Обучение
| Параметр | Значение |
|---|---|
| База | cointegrated/rubert-tiny2, ревизия e8ed3b0c8bbf |
| Параметров | \(29.2\) млн |
| Устройство | Tesla T4, cuda |
| Точность | fp16, GPU без bf16 (T4): fp16 с масштабированием потерь (GradScaler) |
| Эпох | не больше \(3\), лучшая проверка на эпохе \(2.00\) |
| Ранняя остановка | после \(3\) проверок без роста ROC AUC на valid, сработала |
| Проверок на valid за эпоху | \(4\) |
| Оптимизатор | AdamW, скорость 0.0001, разогрев \(6.0%\) шагов, линейный спад |
| Затухание весов, клиппинг градиента | 0.01, 1 |
| Пачка | \(32\) текста близкой длины |
max_length | \(512\) токенов |
seed | \(1\) |
| Время обучения | \(32\) мин, \(338\) текстов в секунду |
| Файл модели | model.onnx, веса int8, \(29.7\) МБ |
| Обучено | 2026-09-25, коммит 60cb897+правки |
Ограничения
- Корпус один. На научных статьях, дипломах и диссертациях модель не проверялась, а жанры за пределами таблицы по жанрам она не видела.
- Вероятность — не доказательство авторства. Не используйте модель для решений о людях: на test она принимает за ИИ \(7.2%\) человеческих текстов.
- Правку человеческого текста моделью распознать труднее, чем текст с нуля, см. таблицу по типу задания.
- Нормализация убирает оформление, но не длину: короткие тексты модель различает хуже, см. таблицу по длине.
- В корпусе генераторы до 2025 года; тексты новых моделей могут распознаваться хуже.
Лицензия и данные
Модель распространяется по лицензии MIT, как и
cointegrated/rubert-tiny2. Корпус LLMTrace — Apache 2.0, человеческие тексты в
нём собраны из сторонних источников со своими лицензиями.
@misc{tolstykh2025llmtrace,
title = {LLMTrace: A Corpus for Classification and Fine-Grained Localization of AI-Written Text},
author = {Tolstykh, Irina and Tsybina, Aleksandra and Yakubson, Sergey and Kuprashevich, Maksim},
year = {2025},
eprint = {2509.21269},
archivePrefix = {arXiv},
}
cointegrated/rubert-tiny2 описан в посте автора на Хабре.