Языковая модель с калькулятором

Мы уже говорили как-то, что для языковых моделей калькулятор сложнее Интернета (и почему).

Обычно чтобы языковые модели могли считать, им дают доступ к калькулятору и обучают его использовать по необходимости. Большие коммерческие модели в целом уже неплохо справляются, хотя всё ещё с переменным успехом, а вот с маленькими открытыми всё немного сложнее (главным образом потому что они маленькие и из-за этого просто менее мощные).

Сегодня посмотрим статью “IGC: Integrating a Gated Calculator into an LLM to Solve Arithmetic Tasks Reliably and Efficiently”, авторы которой предложили свой способ. Они говорят: каждый раз вызывать калькулятор затратно, потому что это дополнительное действие. Использовать подходы вроде цепочки рассуждений тоже: больше токенов тратится, больше нужно вычислительных мощностей.

Поэтому, — говорят они, — мы хотим изменить саму модель.

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

Авторы взяли этот принцип: вставили прямо в нейросеть калькулятор.

И тут есть нюанс: калькулятор не обучается. “Обучается” применительно к нейросетям означает следующее:

  • дали на вход данные (картинку, текст или что-то ещё);
  • данные превратились в векторы из чисел;
  • векторы прошли слой за слоем, как-то меняясь;
  • последний слой их превратил в человекочитаемый формат (картинку, текст, что-то другое);
  • этот результат сравнили с “правильным ответом”, посчитали ошибку;
  • информация об ошибке прошла обратный путь от выхода ко входу, меняя немного вычисления на каждом слое;
  • и опять данные на вход, и так много раз.

С калькулятором не нужно вот это всё — ему нужны два числа и оператор между ними.

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

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

<i>Схема из статьи, обучаемые модули-прокладки бирюзовые</i>
Схема из статьи, обучаемые модули-прокладки бирюзовые

На вход подаётся текст –> обучаемый модуль извлекает из него числа и оператор –> калькулятор считает результат –> другой обучаемый модуль кодирует результат в векторы и передаёт дальше.

У такого подхода есть ограничение: адаптер обучали и тестировали только на задачах, где числа записаны как числа, а не прописью: “3 + 5”, не “три плюс пять”. Второй вариант намного сложнее, авторы его себе оставили на будущее.

То есть, пока именно этот вариант работает только с задачами, где арифметический пример прописан явно. И я не поняла, работали ли они с нецелочисленным делением и отрицательными числами — кажется, не работали.

В любом случае, это интересный подход, и мы теперь знаем, как ещё можно улучшать языковые модели — вставлять в них специализированные модули. Очень интересно. Посмотрим, доработает ли кто-то (или сами авторы) этот калькулятор, чтобы он решал более сложные задачи.