Если попросить ChatGPT и многие другие LLM показать вам эмодзи морского конька, то модель попробует это сделать, выведет, например, рыбу, начнёт корректировать, добавлять моллюсков, дельфинов, но не конька. Почему? Ответ поможет найти механистическая интерпретируемость LLM, про которую я писал аж целый лонгрид на Хабре. LLM устроены так: входной текст (и эмодзи) переводятся в набор векторов, которые потом пропускают через несколько десятков последовательных слоёв, от первого к N-ному. Чем больше номер слоя, тем за, в среднем, более высокоуровневые паттерны он отвечает. В самом конце вектор последнего слова умножается на огромную матрицу (lm_head), хранящие сотни тысяч векторов, и получается набор «схожестей». Часто берут самый похожий вектор. Каждый вектор был заранее сопоставлен со словами и эмодзи, поэтому мы можем перевести этот выбор самого похожего вектора в текст. Модель выучивается делать так, чтобы самый похожий вектор оказывался «правильным» (логично продолжал текст, то есть что после 2+2= должно идти 4). И вот все слои LLM как бы формируют вектор, которы на выходе даст корректное продолжение. Каждый добавляет понемногу информации, «записывая» её в вектор. Первые слои могут добавить информацию вроде «дальше идёт пробел или буква», в серединке модели — уже что-то более сложное. И можно сделать так: взять последний слой (lm_head), по которому оценивается схожесть с сотнями тысяч слов, и применять его не в конце модели, а после каждого слоя. Это стало возможно благодаря некоторым архитектурным изменениям трансформера, появившимся во времена GPT-2 — если вам интересны детали, то вот отрывок одной из моих лекций. После этого мы можем посмотреть, что именно планировала предсказать модель после каждого слоя. Если взять LLAMA-3-70b и попросить показать эмодзи морского конька — то что хочет написать модель, и почему у неё это не получается? Для ранних слоев описанный выше метод приводит к трудно интерпретируемым данным, но это ожидаемо. По мере продвижения по слоям модель итеративно уточняет информацию в векторе сначала в сторону понятий, полезных для продолжения текста, а затем в сторону окончательного прогноза, который и станет словом (токеном), который вы увидите в ответе. Если смотреть на последний слой (и то, что по итогу напишет модель), то он корректно генерирует токен, отвечающий за начало эмодзи в юникоде, ĠðŁ, а затем дописывает «рыба». Но что происходит в средних слоях? Модель «думает» не просто о байтах эмодзи. В векторе записаны *концепты*, в частности, морской конёк. На слое 52 вектор получается таким, что два самых ближайших для него — слова «морской» и «конёк». И позже, в верхних слоях, мы получаем смесь «море», «конь» и этого префикса эмодзи «ĠðŁ». То есть в векторе записана информация о том, что 1) нужно написать байты, которые обозначают начало эмодзи 2) нужно написать морской конёк. При прохождении через последний слой (lm_head) это, казалось бы, должно раскодироваться в корректную последовательность. Единственная проблема в том, что эмодзи морского конька не существует... поэтому, когда вектор морского конька + эмодзи попадает в lm_head, то выбирается ближайший существующий вектор, и ему соответствует рыба. А дальше этот токен попадает во вход модели для генерации следующего (пробела, точки, слова или чего-то ещё), и LLM «видит», что это не морской конёк. Она пытается это скорректировать, снова формирует вектор с информацией об эмодзи, но он не превращается в правильный. Бонус: почему модель думает, что сможет написать эмодзи морского конька? Разве прочитав весь интернет она не должна понять, что его нет? Эмодзи морского конька существует, но не был принят в Unicode. ДВАЖДЫ! На других платформах и в старых эмодзи-паках он был. И было много обсуждений на форумах, на реддите, итд — которые модель наверняка видела. Источник, код для воспроизведения и поиграться.