kwcluster: разметка переменных поискового запроса

LoRA-адаптер поверх Qwen/Qwen2.5-1.5B-Instruct для одной задачи: определить, чем является слово в поисковом запросе.

BRAND — компания, сайт, оператор. PRODUCT — игра, товар, вид игры. PAY — способ оплаты. GEO — страна, регион, город. OFFER — вид предложения или условие сделки. WORD — всё остальное.

Метка отвечает на вопрос, задаёт ли слово отдельную страницу сайта. Модель работает слоем переменных в кластеризаторе семантики: она заменяет большую языковую модель там, где раньше уходил час на четыре тысячи слов. На той же работе — семь секунд.

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

Это классификатор, а не генеративная модель

Обучалась голова классификации, языковая голова базовой модели не трогалась. Просить её сгенерировать текст бесполезно. Промпта и системного сообщения нет.

import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from peft import PeftConfig, PeftModel

REPO = "Krasovskiy/kwcluster-variables-1.5b"
LABELS = ["BRAND", "GEO", "OFFER", "PAY", "PRODUCT", "WORD"]   # порядок из labels.json

tok = AutoTokenizer.from_pretrained(REPO)
tok.pad_token = tok.pad_token or tok.eos_token
tok.padding_side = "right"
cfg = PeftConfig.from_pretrained(REPO)
base = AutoModelForSequenceClassification.from_pretrained(
    cfg.base_model_name_or_path, num_labels=6, dtype=torch.bfloat16)
base.config.pad_token_id = tok.pad_token_id
model = PeftModel.from_pretrained(base, REPO).eval().cuda()

def label(token, queries):
    text = f"слово: {token}" + chr(10) + f"запрос: {' | '.join(queries[:5]) or token}"
    enc = tok([text], truncation=True, max_length=64,
              padding="max_length", return_tensors="pt").to("cuda")
    with torch.no_grad():
        return LABELS[model(**enc).logits.float().argmax(-1).item()]

Вход — слово и до пяти запросов, где оно встречается, самые частотные первыми, разделитель |. Контекст обязателен: «quatro» без него читается как числительное, «delta» — как буква. Порядок меток брать строго из labels.json.

Что изменилось в этой версии

Добавлена ручная разметка второй сотни верхушки частот: 296 слов, размеченных по настоящим запросам ядра. Каждое просмотрено вместе с примерами и числом ключей, которые оно задевает. Вместе с первой сотней это 575 слов.

было стало слова
обычное слово PAY boku, btc, litecoin, zimpler, entropay, ideal, deposito
обычное слово GEO québec, montreal, nunavut, pei, vancouver, labrador
обычное слово OFFER bono, reward, cashback, tournaments
BRAND PAY klarna, gigadat, instadebit
BRAND GEO schweiz
BRAND обычное слово iphone, igaming, reddit

Отдельно вычищены обломки чужих имён: hill от William Hill, sultans от 7 Sultans, cooks от Captain Cooks, apple от Apple Pay, brunswick от New Brunswick. По одному слову бренд не собрать, а метка утащила бы чужие запросы.

Что получилось на настоящем ядре

Мерилось не на отложенной выборке, а прогоном всего инструмента на канадском ядре из 13 942 запросов — там подглядеть нельзя.

показатель прошлая версия эта
слов ядра без сущности 58,4% 52,5%
ключей на страницах гео 942 1215
ключей на страницах оплаты 721 1084
ключей на страницах бренда 2550 2685
ключей, сгруппированных по смыслу 2695 2377
контрольные проверки 9 из 10 9 из 10
страниц с двумя брендами 0 0

Около 960 запросов перешли из группировки по смысловой близости в группировку по переменной, видной в самом запросе. Это и есть смысл слоя: меньше догадки, больше признака.

Заодно ушли три застарелые ошибки: paysafecard переехал с брендовой страницы на страницу оплаты, microgaming — на страницу студии, baccarat перестал считаться брендом.

Чего эти цифры не говорят

Появились новые ошибки. blackjack и plinko помечены брендами, хотя это игры; upaycard — брендом вместо платёжки; argent (по-французски «деньги») и crypto — географией. Затронуто около 180 запросов против 960 улучшенных.

Одиночных страниц стало больше: 1076 против 898. Каждая новая узнанная сущность получает свой адрес, даже если запрос к ней один.

Мерилось на одной нише и одном языковом наборе. Канада, английский с французским вкраплением. На другом рынке цифры будут другими.

На чём обучалась

6839 строк, у каждой — до пяти настоящих поисковых запросов, где слово встречается.

Обычные слова — половина выборки. Это главное отличие от версий, которые проигрывали: в настоящем ядре обычных слов четыре пятых, и без них модель метит сущностью всё подряд.

Бренды — компании, подтверждённые сайтом или лицензией в реестре.

Игры — названия из каталогов, снятых с карт сайтов подтверждённых операторов.

Оплата и условия — разделы касс и акций плюс корпус на 11 млн наблюдений, 129 стран. Классы многоязычные: einzahlung, freispiele, tiradas, rodadas живут наравне с английскими.

Пары слов — 35 штук: «no deposit», «free spins», «apple pay», «minimum deposit». Обломок смысла не несёт, а пара несёт: «no» это отрицание в тысяче запросов, «no deposit» — конкретное предложение в 785.

LoRA r=16 на проекциях внимания, 4.4 млн обучаемых параметров, шесть эпох, сохранена лучшая. Веса классов смягчены до корня из обратной частоты.

Как эту модель мерили

Набор для проверки собран из справочников, а не из чьего-то мнения: реестр операторов регулятора Альберты (31 слово), каталог платёжных систем (24), страны и регионы (90), виды игр (22) — и, обязательно, 41 отрицательный пример из списка «не сущности», слов, которым метка не полагается ни от кого.

Отрицательные примеры обязательны. Без них набор меряет полноту и совсем не меряет точность: модель, щедрая на метки, получает на нём отличную оценку. Версия, обученная на разметке gpt-5-mini, набрала на наборе без отрицательных 81% против 42% у этой — и развалила план на 3231 страницу вместо 2321, с медианой в один ключ вместо двух.

модель всего BRAND GEO PAY PRODUCT WORD
gpt-5-mini (платная, для сравнения) 177/208 (85%) 29/31 85/90 22/24 17/22 24/41
лучшая из наших по этому набору 163/208 (78%) 24/31 83/90 17/24 11/22 28/41
эта версия 103/208 (50%) 10/31 47/90 6/24 8/22 32/41

Цифра выглядит плохо, и это надо объяснить честно. Набор перекошен: в нём 167 сущностей и 41 обычное слово, а в живом ядре наоборот — около 72% обычных слов. Если взвесить по настоящим долям, счёт становится 67% против 68% у лучшей, то есть разрыва почти нет. А на прогоне всего инструмента эта версия выигрывает у обеих «лучших»: 2321 страница против 3165 и 3231, доля страниц без замечаний 94,6% против 88,8% и 87,5%.

Поэтому опубликована именно она. Правило: версия считается лучше, только если выиграла дважды — на наборе и на прогоне. Прогон главнее.

Все семнадцать обученных версий, замеренных одной линейкой, лежат в эксперименты.md.

Где модель слаба

Товары — 8 из 22. bingo, crash, dice, live dealer она зовёт обычными словами. Ни одна из семнадцати версий не берёт больше 15 из 22: класс набран из обломков названий слотов, а не из видов игр. В инструменте это закрыто справочником — множество закрытое, точное совпадение надёжнее.

Касса — 6 из 24. flexepin, gigadat, koho уходят в бренды. Тоже закрыто справочником.

То есть модель полезна там, где справочник невозможен: незнакомые названия, регионы, обычные слова. Всё закрытое лучше держать списком.

Downloads last month
500
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Krasovskiy/kwcluster-variables-1.5b

Adapter
(1373)
this model