Виктор Марьянович
ЛИЧНЫЙ ЖУРНАЛ

LC0 на Intel Arc

Как обычный ноутбук постепенно превратился в локальный шахматный сервер.

Как ноутбук стал шахматным сервером

В ChessBattle мне хотелось иметь не просто шахматный движок, запущенный где-то отдельно, а полноценную локальную инфраструктуру, с которой можно экспериментировать.

Постепенно ChessBattle превратился в площадку, где можно играть партии между движками, анализировать позиции, запускать различные режимы игры и наблюдать за тем, как ведут себя разные шахматные программы.

Одним из самых интересных экспериментов стал запуск LC0 непосредственно на ноутбуке.

LC0 на Intel Arc

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

Для запуска мы собрали LC0 с поддержкой SYCL и использовали встроенную графику Intel Arc ноутбука. Таким образом, отдельная дискретная видеокарта для эксперимента не понадобилась.

Сейчас движок запускается с FP16 backend и локальной нейронной сетью:

bt4-1024x15x32h-swa-6147500.pb.gz

Сам LC0 работает не внутри интерфейса ChessBattle, а как отдельный серверный процесс.

Зачем понадобился собственный HTTP-сервер

Вместо того чтобы связывать веб-приложение непосредственно с процессом LC0, мы сделали небольшой HTTP-сервис.

ChessBattle отправляет на него позицию и параметры поиска, а сервер запускает поиск LC0 и возвращает найденный ход.

В результате ChessBattle вообще не обязан знать, где находится движок и каким способом он запущен. Для него это обычный локальный API.

Сейчас LC0 доступен через локальный адрес 127.0.0.1:3016.

Сначала всё выглядело нормально

Первые проверки показали, что LC0 нормально запускается, видит Intel Arc и возвращает ходы.

Например, при запросе с одной секундой на ход движок возвращал вполне нормальный результат:

d2d4

Казалось бы, задача решена. Но именно здесь появилась интересная проблема.

Одна секунда оказалась не совсем одной секундой

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

LC0 получает команду:

go movetime 1000

Однако команда движку и получение HTTP-ответа — это не одно и то же событие.

Между завершением поиска и появлением bestmove есть дополнительное время: обработка UCI-команды, передача данных, работа supervisor и HTTP-сервера.

Поэтому слишком жёсткий таймаут мог создать ситуацию, когда LC0 уже практически закончил работу, но сервер считал запрос просроченным.

Из-за этого могла зависнуть партия

В турнире это проявилось очень наглядно. Был момент, когда ход должен был сделать LC0, но партия остановилась.

Сам сервис при этом продолжал работать. Процесс LC0 был запущен, GPU был доступен, а HTTP-сервер отвечал на health-запросы.

Проблема оказалась не в том, что LC0 вообще не умеет возвращать ход, а в том, как сервер ожидал этот ход.

Мы изменили саму логику ожидания

Здесь пришлось немного изменить философию системы.

Выбранное пользователем время теперь рассматривается как желаемое время размышления, а не как жёсткий предел существования HTTP-запроса.

То есть если пользователь выбрал одну секунду, LC0 получает одну секунду на поиск. Но сервер не уничтожает поиск только потому, что прошла эта секунда.

Мы продолжаем ждать настоящий ответ bestmove.

Но бесконечно ждать тоже нельзя

Здесь появляется второй уровень защиты.

Для LC0 установлен отдельный watchdog. Сейчас он составляет 15 секунд.

Это уже не время обычного поиска. Это аварийный предел для ситуации, когда движок действительно перестал отвечать.

Если LC0 возвращает bestmove — сервер немедленно отдаёт его ChessBattle.

Если процесс действительно завис и не отвечает достаточно долго, supervisor завершает его, запускает новый экземпляр и сообщает об ошибке.

Получается простая логика:

нормальный движок — ждём ход; зависший движок — перезапускаем.

Почему это важно именно для турнира

В обычном анализе партии можно пережить неудачный запрос: пользователь нажмёт кнопку ещё раз.

В турнире всё иначе. Если один движок не сделал ход, вся партия может остановиться.

Поэтому для турнирного режима надёжность важнее, чем формальное соблюдение миллисекундного ограничения.

Пользователь должен видеть выбранное время, но система должна гарантировать, что движок либо отдаст ход, либо будет восстановлен.

LC0 и Stockfish работают рядом

LC0 — не единственный движок в этой системе.

На том же сервере работает отдельный Stockfish API. Сейчас установленный через этот API движок — Stockfish 17.1.

Получилась небольшая локальная шахматная инфраструктура: разные движки работают отдельными процессами, а ChessBattle выступает общей площадкой для партий и турниров.

И всё это работает на ноутбуке

Самое интересное для меня здесь даже не конкретная партия и не конкретный лучший ход.

Интересно то, что обычный ноутбук с Intel Arc можно использовать как небольшой локальный сервер для нейросетевого шахматного движка.

Не нужно отправлять шахматные позиции во внешний сервис. Не нужен облачный API. Всё работает локально.

При этом архитектура уже достаточно похожа на настоящую серверную систему: systemd следит за сервисом, supervisor следит за процессом движка, HTTP API связывает его с ChessBattle, а сам турнир работает независимо от внутренних деталей LC0.

Что получилось в итоге

За несколько дней экспериментов ChessBattle превратился из обычного шахматного интерфейса в небольшую лабораторию.

Здесь можно запускать партии между движками, анализировать позиции, экспериментировать со временем поиска и постепенно добавлять новые компоненты.

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

Именно поэтому сейчас для меня важнее не то, что LC0 может сделать один ход за одну секунду, а то, что если он вдруг задержится или перестанет отвечать, вся шахматная система не должна из-за этого остановиться.

В этом и заключается смысл всей этой маленькой локальной инфраструктуры — не просто заставить искусственный интеллект играть в шахматы, а построить систему, с которой можно спокойно экспериментировать дальше.