Mechanistic Interpretability на практике: как трансформер жульничает в арифметике | AiManual
AiManual Logo Ai / Manual.
10 Мар 2026 Гайд

Разбор Mechanistic Interpretability на практике: как трансформер в 1М параметров жульничает в арифметике

Hands-on разбор механистической интерпретируемости: обучаем трансформер на 1М параметров сложению и ловим его на жульничестве. Код на PyTorch, трюки с weight de

Когда 2+2=5, и модель этому рада

Вы даете маленькому трансформеру задачу: сложи два двузначных числа. Он учится. Сначала тупо запоминает пары из обучающей выборки. Потом, после сотен эпох, будто щелкает выключатель – начинает правильно складывать любые числа, даже те, которых не видел. Это grokking, красиво и загадочно.

Но если залезть внутрь и посмотреть на веса, открывается иная картина. Модель не решает арифметику. Она жульничает. Использует хитрые шаблоны в данных, чтобы имитировать правильный ответ, не понимая сути. Это не баг, а фича – так работает большинство ИИ, даже самые большие. Механистическая интерпретируемость (Mechanistic Interpretability) – это как вскрытие, чтобы найти эти шаблоны-жульничества.

К марту 2026 года инструменты для вскрытия моделей стали доступнее. Anthropic открыла часть своих наработок, в PyTorch 2.5+ появились встроенные утилиты для трассировки внимания. Но суть осталась: чтобы понять, как модель думает, ее надо разобрать на матрицы.

Строим подопытного трансформера

Наша цель – не SOTA модель, а понятная. 4 слоя, 4 головы внимания, 128-мерные эмбеддинги. Итого около 1.1 миллиона параметров – смешно по меркам 2026 года, но достаточно для жульничества.

1 Архитектура на голом PyTorch

Забудьте про Hugging Face для этого эксперимента. Мы пишем все с нуля, чтобы видеть каждый тензор.

import torch
import torch.nn as nn
import torch.nn.functional as F

class ToyTransformer(nn.Module):
    def __init__(self, vocab_size, d_model=128, n_layers=4, n_heads=4):
        super().__init__()
        self.embed = nn.Embedding(vocab_size, d_model)
        self.pos_embed = nn.Embedding(512, d_model)  # Максимальная длина
        
        self.layers = nn.ModuleList([
            nn.TransformerEncoderLayer(d_model, n_heads, dim_feedforward=512, 
                                       batch_first=True, activation='gelu',
                                       norm_first=True)  # Ключевой флаг для стабильности
            for _ in range(n_layers)
        ])
        self.ln_out = nn.LayerNorm(d_model)
        self.head = nn.Linear(d_model, vocab_size)
        
    def forward(self, x):
        # x: [batch, seq_len]
        positions = torch.arange(x.size(1), device=x.device).unsqueeze(0)
        x_emb = self.embed(x) + self.pos_embed(positions)
        
        for layer in self.layers:
            x_emb = layer(x_emb)
            
        x_emb = self.ln_out(x_emb)
        logits = self.head(x_emb)
        return logits
💡
Norm-first – стандарт для трансформеров с 2024 года. Стабилизирует обучение глубоких моделей, что критично для grokking. В старых руководствах использовали norm-last, теперь так не делают.

2 Посимвольная токенизация – где начинается магия

Мы токенизируем каждую цифру и знак отдельно. «57+24=81» превращается в токены ['5','7','+','2','4','=','8','1']. Это дает модели пространство для маневра – она может выучить правила переноса, а может и сжульничать.

vocab = {str(i): i for i in range(10)}  # Цифры 0-9
vocab['+'] = 10
vocab['='] = 11
vocab[''] = 12
vocab_size = len(vocab)

def tokenize(expr):
    # expr типа "57+24="
    return [vocab[ch] for ch in expr]

Где спрятано жульничество? Смотрим в attention

После обучения (а мы обучаем с weight decay=0.1, это ускоряет grokking в разы) модель выдает 95% точности на тесте. Кажется, она научилась сложению.

А теперь включаем механистическую интерпретируемость. Смотрим, куда смотрят головы внимания в последнем слое, когда модель вычисляет последнюю цифру ответа.

Вход Ожидаемое внимание Реальное внимание (жульничество)
57+24= На цифры 7 и 4 (единицы) На позицию символа '=' и первую цифру первого числа
38+91= На 8 и 1 Тот же шаблон: '=' и '3'

Модель игнорирует второе слагаемое! Она научилась корреляции между первой цифрой первого числа и последней цифрой ответа в обучающей выборке. Это классический shortcut learning, но в контексте grokking он выглядит как осмысленная стратегия.

Такие шаблоны – не ошибка, а неизбежное следствие того, как трансформеры минимизируют loss. Они ищут любые статистические регулярности, даже если это не "настоящая" арифметика. В больших моделях это масштабируется до сложных жульничеств в рассуждениях.

3 Визуализируем матрицу жульничества

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

# Берем одну из голов внимания в последнем слое
layer = model.layers[-1].self_attn
# attention_scores shape: [batch, heads, seq_len, seq_len]
# Смотрим на head 2 для примера
cheating_head = attention_scores[:, 2, :, :]
# Визуализируем для одного примера
import matplotlib.pyplot as plt
plt.imshow(cheating_head[0].detach().cpu(), cmap='hot')
plt.xlabel("Query positions")
plt.ylabel("Key positions")
plt.title("Паттерн жульничества: внимание на '=' и первую цифру")
plt.show()

На картинке виден яркий столбец на позиции символа '=' и слабая связь с позицией первой цифры. Это и есть механизм – модель использует '=' как якорь, чтобы скопировать модифицированную первую цифру в ответ.

Почему weight decay заставляет модель жульничать умнее?

Без weight decay модель может тысячу эпох сидеть в локальном минимуме, запоминая тренировочные примеры. Weight decay (L2 регуляризация) постепенно обнуляет веса, не критичные для задачи. Это заставляет модель искать более компактные, обобщающие решения – но иногда эти решения оказываются жульническими паттернами, а не истинными алгоритмами.

В нашем эксперименте с weight decay=0.1 grokking (переход к обобщению) наступал примерно на 300-й эпохе. Без него – после 1500+ эпох, если вообще наступал.

💡
Свежие работы (конец 2025 года) показывают, что комбинация weight decay и постепенного увеличения сложности данных – самый эффективный способ заставить маленькие модели grokking'ать. Но жульничество остается проблемой.

Что это значит для больших LLM?

То же самое, но в масштабе. Когда Llama-3 или Qwen-2.5 решают логическую задачу, они могут опираться не на цепочку рассуждений, а на поверхностные статистические сходства с текстами из тренировочных данных. Anthropic, вскрывая Claude, нашла целые «нейронные схемы», отвечающие за поддельные рассуждения.

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

Популярный миф: большие модели менее склонны к жульничеству. Нет. Они просто жульничают на более высоком уровне абстракции. Вместо копирования цифр – заученные шаблоны аргументации, которые выглядят как логика.

Как искать жульничество в своей модели?

  1. Начните с простой задачи, где известно правильное алгоритмическое решение (арифметика, сортировка строк).
  2. Обучите небольшую модель с weight decay. Дождитесь grokking (резкий рост accuracy на валидации).
  3. Зафиксируйте несколько примеров, где модель ошибается. Проанализируйте паттерны ошибок – они часто указывают на границы жульнического алгоритма.
  4. Используйте библиотеки для визуализации внимания (например, BertViz, обновленную под PyTorch 2.5). Ищите неожиданные, слишком сильные связи между токенами.
  5. Попробуйте «абилитацию» – отключите подозрительные головы внимания или нейроны и посмотрите, как изменится поведение. Если точность падает на определенном типе примеров, вы нашли схему жульничества.

Инструментарий быстро развивается. Если в 2024-м для такого анализа нужны были костыли, то к 2026-му в PyTorch вошли нативные функции для извлечения активаций с графовой трассировкой.

И что, теперь всем становиться нейрохирургами ИИ?

Не всем. Но если вы тренируете модели для критичных задач – медицинских, финансовых, – слепое доверие к accuracy смертельно. Модель может жульничать именно в тех edge-кейсах, где ошибка стоит дорого.

Mechanistic Interpretability превращается из академической дисциплины в инженерную практику. Компании вроде Anthropic и OpenAI уже используют ее для поиска уязвимостей в своих моделях перед релизом. Скоро это будет стандартным этапом пайплайна, как code review.

А пока – тренируйте маленькие модели, вскрывайте их, ищите жульничество. Это лучший способ понять, что на самом деле происходит внутри гигантских LLM. Они не волшебные – они просто очень хитрые.

Подписаться на канал