RuneSight: нейросеть, которая отличает текст от кода
Версия 1.0.6 упраздняет написанный вручную список regex-правил, который решал, какие из извлечённых строк были текстом, а какие — путями, идентификаторами и управляющими кодами. RuneSight, нейросетевой классификатор весом 400 КБ, обученный на девятистах тысячах строк из настоящих игр, реальных предложениях на шестнадцати языках и всех задокументированных управляющих кодах движков, теперь принимает это решение за микросекунды на вашем CPU, называет причину для каждой строки и никогда не трогает строку, в которой есть настоящий текст.
Почти всё, что RuneTranslate извлекает из игры, — это текст, который прочитает игрок, плюс длинный хвост вещей, которые только похожи на текст: пути к ресурсам, имена переменных, управляющие коды, ключи плагинов, отладочные метки, блок base64, случайно оставленный кем-то в файле данных. Переведите одно из них — и в лучшем случае это просто впустую потраченный запрос. В худшем — сцена, которая больше никогда не загрузится, потому что движок ищет имя, которого больше не существует.
С самого первого релиза граница между ними проводилась вручную: сотни регулярных выражений, по одному на каждую форму мусора, с которой мы сталкивались, — движок за движком. Версия 1.0.6 заменяет этот список на RuneSight, небольшую нейросеть, обученную на реальных данных. Для каждой извлечённой строки она решает, текст это или служебная начинка, — и делает это за несколько микросекунд, на вашем CPU, прямо внутри приложения.
Почему списка правил стало недостаточно
Регулярное выражение ловит ровно ту форму, под которую было написано. bg_office_01 — идентификатор, поэтому его ловит правило для snake_case. Затем приходит игра на Wolf RPG со строкой <<GET_FILE_EXIST>>Data/\s[1], игра на Bakin со строкой Lv.\partystatus[0], игра на Unity со строкой "CubismTaskQueue.OnTask" already set., а имя папки, написанное по-японски, ломает правило для путей, которое рассчитывало на ASCII. Каждый такой случай превращался в новое правило, тщательно ограниченное, чтобы не проглотить настоящий диалог, — и каждый новый движок запускал цикл заново.
Правила также не умеют взвешивать улики. Строка, которая в основном состоит из управляющего кода, но заканчивается тремя словами диалога, — это текст, и она обязана остаться переводимой. Строка, которая представляет собой целое предложение о файле .png, — это текст. А строка, в которой нет ничего, кроме \f[\cself[1]]\space[4], — не текст. Чтобы отличить одно от другого, нужно понимание строки целиком, а не совпадение с её частью.
Что такое RuneSight
RuneSight — это классификатор весом около 400 килобайт. Он читает строку как мешок фрагментов символов, от одного до четырёх символов длиной, хешированных в таблицу фиксированного размера, и объединяет это с несколькими десятками измеренных свойств строки: какая доля в ней букв, цифр, знаков препинания или пробелов, какие письменности она использует, похожа ли она на путь, сбалансированы ли в ней скобки, заканчивается ли она так, как заканчивается предложение. Один небольшой скрытый слой превращает всё это в два ответа: вероятность того, что строка не текст, и, если это так, какого рода это не-текст.
Этот второй ответ вы и видите в редакторе. У каждой исключённой строки есть причина, которую можно прочитать: шаблон кода, ссылка на ресурс, системная метка, числовое значение, комментарий, ключ плагина, только управляющие коды, бинарные данные или команда плагина. Строка получает небольшую отметку RuneSight и степень уверенности, стоящую за вердиктом, так что решение никогда не превращается в чёрный ящик, а одним щелчком по строке её можно включить обратно.
Всё это работает примерно за четыре микросекунды на строку. JRPG на сто тысяч строк классифицируется значительно быстрее секунды на любой машине с Windows 10 или 11, без GPU и без отправки чего-либо куда-либо.
На чём он учился
Размеченных данных для этого не существовало, поэтому их пришлось собрать. Обучающая выборка — это немногим более девятисот тысяч строк:
- Настоящие игры. Полные извлечения из тринадцати игр на десяти движках — от RPG Maker и Ren'Py до Wolf RPG, Kirikiri, Artemis, Unity, Godot, Bakin и Unreal, размеченные правилами, которые заменял RuneSight. Это минимальная планка: он обязан был ловить всё, что ловили правила.
- Настоящие предложения. Четверть миллиона предложений на шестнадцати языках — среди них японский, китайский, корейский, тайский, арабский, русский и языки на латинице, — чтобы обычный текст на любом исходном языке никогда не принимался за код.
- Настоящая служебная начинка. Сто шестьдесят тысяч путей, идентификаторов, точечных имён и строк комментариев, собранных из исходного кода и пакетов, — форм, общих для всех движков.
- Слепые зоны — намеренно. Почти триста тысяч сгенерированных строк, построенных по официальным справочникам управляющих кодов Wolf RPG, RPG Maker и Bakin, — каждая в паре с похожей на неё диалоговой строкой, которую нельзя проглотить: предложение, упоминающее файл, имя с числом после него, строка текста с кодом посередине.
- Эталонный набор, проверенный вручную. Каждая строка, на которую опирались старые правила, плюс настоящие строки, о которых сообщили из сыгранных игр, — рассмотренные одна за другой.
Что предстояло доказать перед релизом
Модель, которая просто лучше в среднем, всё равно окажется регрессией для того, кто наткнётся на её новые ошибки, поэтому RuneSight должен проходить через фиксированные пороги, проверяемые заново при каждом переобучении:
- На каждой настоящей игре из набора он ловит как минимум 99,5% того, что ловили написанные вручную правила.
- На замороженном наборе строк, которые обязаны оставаться переводимыми, — тех самых, на которых всегда проверялись старые правила, — он не делает ни одного исключения.
- На настоящей прозе исключается менее 0,2% строк.
- Названная им причина верна как минимум в 97% случаев.
- Оценка строки занимает меньше 5 микросекунд.
Важнее всего оказалось правило о смешанных строках. Строка, в которой настоящий текст соседствует с кодами, — это текст, и она остаётся переводимой. RuneSight убирает строку только тогда, когда она целиком состоит из служебной начинки.
Что не изменилось
RuneSight решает вопрос формы строки. Решения, для которых нужен контекст, а не форма, по-прежнему принимают адаптеры движков: имя узла Godot исключается из-за того, где оно стоит в дереве сцены, комментарий к событию RPG Maker — из-за команды, которая его несёт, ключ параметра плагина — из-за файла, в котором он живёт. Эти правила остаются, как и правила политики, которые видны в столбце причины, — например, строка, вообще не содержащая символов исходного языка.
Ваши собственные regex-фильтры запускаются после RuneSight и ведут себя ровно как раньше, а каждое исключение, кем бы оно ни было сделано, остаётся красной строкой с возможностью включения вручную. Ничего из того, что решает RuneSight, не окончательно.
Где это увидеть
Значок RuneSight находится в правом нижнем углу приложения, над строкой версии. Его точка горит зелёным, когда модель загружена. Откройте его — и он покажет размер модели, порог уверенности, с которым она поставляется, и что сделало последнее извлечение: сколько строк она оценила, сколько исключила и где разошлась со старыми правилами. После каждого извлечения короткое всплывающее уведомление повторяет эти цифры.
Если модель вдруг не загружается, значок сообщает об этом, а извлечение просто откатывается к прежним правилам. Из-за этого приложение никогда не отказывается работать.
Каждый случай, когда модель расходится со старыми правилами, записывается в небольшой локальный журнал и никогда не отправляется наружу. Если строка, которую вы считаете настоящим диалогом, оказалась исключена, включите её обратно в редакторе и напишите нам в Discord. Именно на таких сообщениях учится следующее переобучение.
Готовы попробовать RuneTranslate?
Бесплатный тариф открывает все движки и всех провайдеров перевода. Supporter ($3.99/mo) открывает полную скорость.
Скачать для Windows
