Первая и вторая части перевода материала о трансформерах были посвящены теоретическим основам этого семейства нейросетевых архитектур, рассказу о способах их использования, демонстрации их реализации с применением PyTorch. Сегодня речь пойдёт об истории трансформеров, будет дан обзор современного состояния дел в этой сфере. Если вы читали другие вводные статьи по трансформерам, то могли заметить, что там есть кое-что такое, о чём я не рассказывал. Полагаю, подобные вещи не являются абсолютно необходимыми для понимания современных трансформеров. Они, однако, помогают понять некоторые термины, знакомство с ними облегчает восприятие материалов о современных трансформерах. Сейчас я расскажу о самых важных моментах истории трансформеров. До того, как появилось такое понятие, как «механизм внутреннего внимания», нейросетевые модели, занимающиеся обработкой последовательностей, представляли собой, в основном, многослойные структуры из рекуррентных или свёрточных слоёв. Настал момент, когда было выяснено, что этим моделям можно помочь в решении их задач, оснастив их механизмами внимания. Вместо того, чтобы передавать выходную последовательность одного слоя напрямую в другой слой, можно воспользоваться промежуточным механизмом. Он принимает решения о том, какие именно элементы входной последовательности имеют важное значение для конкретного слова выходной последовательности. Если дать общее описание этого механизма, то получится следующее. Входные данные называются значениями. Некий (обучаемый) механизм назначает каждому значению ключ. Затем ещё какой-то механизм назначает каждому выходному значению запрос. Эти термины взяты из структур, используемых в хранилищах типа ключ-значение. В случае с ними мы ожидаем, что лишь один элемент хранилища имеет ключ, который соответствует запросу. Этот элемент возвращается при выполнении к хранилищу соответствующего запроса. Механизм внимания — это менее строгая версия подобной схемы: каждый ключ в хранилище, в какой-то мере, соответствует запросу. Возвращаются все ключи, а мы получаем их сумму, взвешенную по тому показателю, который указывает на то, насколько каждый из ключей соответствует запросу. Огромный успех механизма внутреннего внимания заключается в том, что он, сам по себе, обладает достаточной мощью для того, чтобы решить все задачи обучения модели. «Внимание — это всё, что вам нужно», — так говорят об этом механизме его авторы. Ключ, запрос и значение — всё это одни и те же векторы (с небольшими линейными трансформациями). Они уделяют внимание сами себе. Набор подобных механизмов даёт такой уровень нелинейности и репрезентационной мощи, который достаточен для изучения очень сложных функций. Но авторы трансформеров не обошлись без всех тех сложных структур, которые были характерны для моделей тех лет, занимавшихся преобразованиями последовательностей в последовательности. А именно, речь идёт об архитектуре, в состав которой входил энкодер и декодер, в которой применялся механизм обучения с принуждением. Энкодер берёт входную последовательность и сводит её к характеристическому представлению всей последовательности. Это может быть либо последовательность характеристических векторов, либо один вектор, подобный тому, что показан на предыдущей схеме. Затем этот вектор передаётся декодеру, который распаковывает его в целевую последовательность. Например — в то же предложение, что было на входе, но на другом языке. Обучение с принуждением — это механизм, который позволяет декодеру обращаться ко входному предложению. Делается это в авторегрессионной манере. Получается, что декодер пословно формирует выходное предложение, основываясь и на характеристическом векторе, и на уже сгенерированных словах. Это снимает часть нагрузки с характеристического представления последовательности: декодер может использовать пословное сэмплирование для того чтобы позаботиться о низкоуровневых структурах предложения, вроде синтаксиса и грамматики. А характеристический вектор используется при формировании семантической структуры, находящейся на более высоком уровне абстракции. Два сеанса декодирования с использованием одного и того же характеристического представления последовательности, в идеале, дадут два разных предложения с одним и тем же смыслом. Разработчики поздних трансформеров, вроде BERT и GPT-2, полностью отказались от конфигурации энкодер/декодер. Было выяснено, что обычного набора блоков трансформера достаточно для решения, на очень высоком уровне, многих задач, предусматривающих обработку последовательностей. Модели, построенные в соответствии с этим подходом, иногда называют трансформерами, в которых используются только декодеры (для авторегрессионных моделей), или трансформерами, в которых используется только энкодер (для моделей, в которых не используется маскировка). Здесь я приведу несколько примеров современных трансформеров и расскажу об их характерных чертах. Модель BERT (Bidirectional Encoder Representations from Transformers) представляла собой одну из первых попыток показать то, что трансформеры способны, при решении многих языковых задач, достичь результатов, сопоставимых с человеческими. Это — ответы на вопросы, классификация тональности текстов, определение того, следует ли одно предложение, при естественном порядке речи, за другим предложением. BERT состоит из простого набора блоков трансформера того типа, который мы описывали ранее. Этот набор был предварительно обучен на большом корпусе текстов общего характера, состоящем из 800 миллионов слов из англоязычных книг (данные взяты из BooksCorpus) и из 2,5 миллиардов слов из текстов статей английской Википедии (без разметки). Предварительное обучение модели было ориентировано на решение двух задач: Маскирование токенов. Некоторое количество слов во входной последовательности было замаскировано, заменено на случайные слова или оставлено в исходном виде. Модели предлагалось предсказать, в отношении этих слов, то, какими были исходные слова. Обратите внимание на то, что модели не предлагалось восстановить всё предложение в его исходном виде. Нужно было разобраться лишь с модифицированными словами. Так как модель не знала о том, о каких словах её спросят, она изучала представление каждого слова в последовательности. Классификация следующего предложения. Выбирались два предложения длиной примерно 256 слов. При этом они либо (a) следовали в текстовом корпусе строго друг за другом, либо (b) были взяты из случайных мест. Модели нужно было разобраться с тем — к какому классу (a или b) нужно отнести эти предложения. Модель BERT использует систему токенизации WordPiece, которая выдаёт последовательности, находящиеся где-то между теми, где элементами являются слова, и теми, где речь идёт об отдельных символах. Она разбивает слова, вроде walking, на токены walk и ##ing. Это позволяет модели делать некоторые заключения, основанные на структуре слов. Два глагола, в конце которых имеется -ing, имеют схожие грамматические функции. А два глагола, начинающиеся с walk-, имеют схожие семантические функции. Входные данные предварялись специальным токеном <cls>. Выходной вектор, соответствующий этому токену, использовался как представление предложения в задачах классификации предложений, вроде той, что была описана выше (в противовес глобальному усредняющему пуллингу по всем векторам, который мы использовали в нашей модели, решающей задачу классификации). Когда предварительное обучение завершено — после набора блоков трансформера добавляют один слой, ориентированный на решение конкретной задачи, который приводит выход универсальной модели к выходу, имеющему смысл для этой задачи. В задачах классификации это выглядит как обработка первого выходного токена функцией Softmax и назначение вероятностей классам. При решении более сложных задач последний слой, преобразующий последовательность в другую последовательность, тоже создаётся под конкретную задачу. Затем всю модель переучивают для того, чтобы подстроить её под имеющуюся задачу. Проводя эксперимент, предусматривающий удаление некоторых компонентов ИИ-систем в целях исследования их вклада в общий результат (ablation study), авторы показали, что наиболее значительные улучшения, в сравнении с ранее существовавшими моделями, даёт двунаправленная природа BERT. Получается, что ранее существовавшие модели, вроде GPT, использовали авторегрессионную маску, которая позволяла механизму внутреннего внимания работать лишь с предыдущими токенами. А то, что механизм внимания BERT направлен на всю последовательность, является главной причиной улучшения характеристик модели. Именно поэтому английская буква B в аббревиатуре BERT — означает «bidirectional». Самая крупная BERT-система использует 24 блока трансформера, 1024 измерений эмбеддинга и 16 блоков механизма внутреннего внимания. В результате эта модель имеет 340 миллионов параметров. GPT-2 (Generative Pre-trained Transformer 2) — это первая модель, основанная на трансформерах, которая попала в заголовки новостей, что случилось после неоднозначного решения OpenAI не выпускать полную версию модели. Причина заключалась в том, что модель GPT-2 способна генерировать довольно правдоподобный текст, подобный фейковым новостям, которые во множестве выходили во время выборов в США в 2016 году. С использованием подобной модели всю эту масштабную компанию мог бы провести один человек. Первый приём, использованный авторами GPT-2, заключался в создании нового высококачественного набора данных. Хотя и модель BERT использовала высококачественные данные, их источникам (написанным с любовью книгам и хорошо отредактированным статьям Википедии) не хватало разнообразия авторского стиля. Для того чтобы собрать более разнообразные данные, не ухудшая при этом их качества, авторы модели использовали ссылки из социальной сети Reddit. Была собрана большая коллекция текстов, отличающихся определённым минимальным уровнем поддержки сообщества сайта (на Reddit это называют «кармой»). GPT-2, на фундаментальном уровне — это языковая модель для генерирования текстов. Поэтому в ней, при реализации механизма внутреннего внимания, используется маскирование. Так сделано и в модели, которую мы рассматривали выше. Здесь, для токенизации текстов, применяется алгоритм BPE (Byte Pair Encoding, кодирование пар байтов). При таком подходе, как и при использовании WordPiece, слова при кодировании разбивают на токены, которые немного больше отдельных символов, но меньше целых слов. Модель GPT-2 очень похожа на нашу модель для генерирования текстов, рассмотренную выше. Между моделями имеются небольшие различия, в частности, речь идёт о порядке слоёв и о том, что в GPT-2 используются дополнительные приёмы для обучения более глубоких, чем у нас, слоёв модели. Самая большая модель GPT-2 использует 48 блоков трансформера, длину последовательности в 1024, 1600 измерений эмбеддинга и имеет 1,5 миллиона параметров. Подобные модели показывают эталонные результаты на многих задачах. В задаче сжатия данных из Википедии, которую мы уже пытались решить, они достигают уровня сжатия в 0,93 бита на байт. Хотя трансформеры представляют собой огромный шаг вперёд в моделировании долгосрочных зависимостей, те модели, которые мы рассматривали до сих пор, всё ещё имеют одно фундаментальное ограничение. Оно заключается в размерах входных данных. Так как размер матриц скалярных произведений квадратично зависит от длины последовательности, это, по мере увеличения длины входной последовательности, быстро превращается в узкое место системы. Transformer-XL — это один из первых трансформеров, ориентированных на решение этой проблемы. В процессе обучения длинные фрагменты текстов (их длина превышает ту, с которой может работать модель) разбивают на более короткие сегменты. Каждый сегмент обрабатывается в последовательном режиме, при этом данные для механизма внутреннего внимания рассчитываются на основе текущего и предыдущего сегментов. Градиенты же вычисляются только на основе текущего сегмента, но информация продолжает распространяться по сети по мере движения окна выборки сегмента по тексту. В слое n, теоретически, может быть использована информация из прошлого сегмента, удалённого от текущего на n позиций. Похожий приём в обучении RNN называют TBPTT (Truncated BackPropagation Through Time, усечённый метод обратного распространения ошибки во времени). На вход модели подают очень длинную последовательность, но механизм обратного распространения ошибки применяется лишь к части этой последовательности. При этом та часть последовательности, для которой градиенты не вычисляется, всё равно оказывает влияние на значения скрытых состояний той части последовательности, для которой градиенты вычисляются. Для того чтобы заставить подобный механизм работать, авторам пришлось отказаться от стандартной схемы, предусматривающей использование позиционной кодировки или позиционных эмбеддингов. Так как позиционная кодировка абсолютна, она, для каждого сегмента, будет меняться. Её применение не приведёт к созданию однородного эмбеддинга по всей последовательности. Вместо этого авторы модели использовали относительную кодировку. Для каждого выходного вектора используется последовательность позиционных векторов, отличная от других таких последовательностей, задающая не абсолютную позицию, а расстояние до текущего выхода модели. Для этого необходимо переместить позиционную кодировку в механизм внимания (что подробно описано в публикации по Transformer-XL). Одной из сильных сторон такого хода является тот факт, что получившийся в результате трансформер, скорее всего, будет лучше обобщать последовательности, длина которых заранее неизвестна. Разреженные трансформеры (Sparse transformers) непосредственно направлены на решение проблемы квадратичного роста использования памяти, которая имеется у обычных трансформеров. Вместо вычисления полностью заполненной матрицы весов механизма внимания (размеры которой квадратично зависят от длины входной последовательности) эти модели вычисляют такие веса лишь для избранных пар входных токенов. Это приводит к появлению разреженной матрицы механизма внимания, в которой имеется лишь nn явно заданных элементов. Это позволяет моделям работать с контекстами очень больших размеров. Например — при решении задач генерирования изображений, когда имеются сильные зависимости между пикселями. Компромисс, на который приходится идти тому, кто пользуется такой моделью, заключается в том, что модель не изучает то, что разреженные структуры не дают ей изучать. Поэтому решение об использовании разреженной матрицы приводит к «отключению» некоторых взаимодействий между входными токенами, которые могли бы оказаться полезными для модели. Но при этом два элемента, которые не связаны напрямую, могут взаимодействовать в более высоких слоях трансформера (это похоже на то, как в свёрточных сетях, используя больше свёрточных слоёв, создают более крупное рецепторное поле). Разреженные трансформеры, помимо возможности обучать модели на последовательностях очень большой длины, предлагают красивое решение задачи разработки механизма внедрения в модель априорных знаний о природе обрабатываемых ею данных (inductive bias). Мы представляем входные данные модели в виде набора неких сущностей (слов, символов, пикселей изображения, узлов графа) и, настраивая порядок построения разреженной матрицы, указываем модели на то, какие сущности, по нашему мнению, связаны. Остальное — лишь вопрос создания подходящего трансформера и проверка возможностей по его обучению. Серьёзным узким местом трансформеров является тот факт, что при их обучении в механизме внутреннего внимания используются матрицы скалярных произведений векторов. А именно, для последовательности длиной t получается матрица, содержащая t2 элементов. С использованием стандартных чисел с одинарной точностью (32 бита) и при t=1000 пакет из 16 таких матриц занимает около 250 Мб памяти. Так как на реализацию одной операции механизма внутреннего внимания нужно, по меньшей мере, четыре таких пакета (до и после Softmax-слоя и ещё — их градиенты), это ограничивает нас, при использовании видеокарты с 12 Гб памяти, самое большее, 12 слоями. На практике получается даже меньше слоёв, так как входные и выходные данные тоже занимают много памяти (хотя главный потребитель памяти — это матрицы скалярных произведений). При этом модели, описываемые в различных публикациях, могут включать в себя последовательности длиной более 12000 элементов и иметь около 50 слоёв. В таких моделях используются разреженные матрицы скалярных произведений. Эти модели, конечно, обучают на вычислительных кластерах, но для выполнения расчётов в ходе прямого и обратного распространения сигнала по сети, всё равно, нужен самостоятельный графический ускоритель. Как вместить таких монстров в 12 Гб памяти? Вот три основных приёма, используемых для решения этой задачи: Использование чисел половинной точности. Современные GPU и TPU могут производить эффективные тензорные вычисления на 16-битных тензорах. Для того чтобы это сделать — недостаточно просто взять и установить dtype тензора в torch.float16. В некоторых частях сети, вроде той, где вычисляется функция потерь, нужна 32-битная точность. Но большинство подобных задач можно, без особого труда, решить с использованием существующих библиотек. В принципе, это позволяет в два раза снизить требования модели к памяти. Накопление градиента. При использовании больших моделей у нас может быть возможность выполнить расчёты, необходимые для организации прямого и обратного прохождения сигнала по сети, только для одного пакета из набора пакетов. Использование отдельного пакета, а не набора из нескольких пакетов, скорее всего, не позволит наладить стабильное обучение модели. К счастью, можно сначала выполнить подобные расчёты для отдельных пакетов из большого набора, а потом просто суммировать найденные градиенты (это — следствие многомерного цепного правила). Когда мы достигаем окончания набора пакетов, мы, за один шаг, проводим операцию градиентного спуска, и обнуляем градиент. В PyTorch это делается очень просто. Предположим, видно, что вызов optimizer.zero_grad() в цикле обучения выглядит как излишняя трата системных ресурсов. Если этого вызова не делать, то новые градиенты просто прибавляются к старым. Использование контрольных точек при вычислении градиента. Если модель настолько велика, что в памяти не помещаются даже данные, необходимые для расчёта прямого и обратного прохождения сигнала, можно, за счёт снижения эффективности вычислений, сэкономить память. При использовании контрольных точек модель делится на секции. Для каждой секции выполняют вычисления, необходимые для нахождения градиента, не меняя промежуточные данные обучения остальных секций. В PyTorch имеются специальные утилиты для организации работы в таком стиле. Подробности об этом можно почитать здесь. Вполне возможно, что трансформеры окажутся простейшей архитектурой машинного обучения, которая в течение десятилетий будет занимать ведущие позиции в этой сфере. И если вы ещё ими не пользовались — есть множество веских причин обратить на них внимание. Во-первых, существующие ограничения производительности трансформеров — это ограничения исключительно аппаратные. В отличие от свёрточных сетей или LSTM-моделей, возможности трансформеров полностью определяются тем, насколько большую модель можно уместить в памяти GPU, и тем, сколько данных через неё можно пропустить за разумное время. Я не сомневаюсь в том, что мы, в итоге, достигнем момента, когда увеличение количества слоёв трансформеров и увеличение объёмов обрабатываемых ими данных больше не будет приводить к улучшениям. Но мы, судя по всему, пока до этого момента не добрались. Во-вторых, трансформеры — это исключительно универсальные системы. Они уже достигли больших успехов в языковом моделировании, показали кое-какие результаты, более скромные, в анализе изображений и музыки. Но трансформеры обладают таким уровнем универсальности, который прямо-таки ждёт, когда его кто-то задействует в других задачах. Базовый трансформер — это модель, занимающаяся преобразованием последовательности в последовательность. Поэтому, до тех пор, пока данные представлены набором неких элементов — их можно обработать с помощью трансформера. Всё остальное, что известно о данных (вроде их локальной структуры) можно добавить в модель посредством позиционных эмбеддингов или путём изменения структуры матрицы механизма внимания (делая её разреженной или маскируя некоторые её части). Это приходится особенно кстати в мультимодальном обучении. Можно легко представить захваченное изображение в виде комбинации последовательности пикселей и символов, спроектировать какие-нибудь хитрые эмбеддинги, продумать структуру разреженных матриц для того чтобы помочь модели понять то, как комбинировать и сопоставлять эти пиксели и символы. Если представить все наши знания из некоей сферы в виде реляционной структуры вроде мультимодального графа знаний (как рассказано здесь), можно задействовать простые блоки трансформера для передачи информации между мультимодальными элементами, а разреженные структуры позволят управлять тем, какие именно элементы напрямую друг с другом взаимодействуют. До сих пор трансформеры, в основном, используются в языковых моделях. Я жду, что через некоторое время их начнут использовать и в других областях, делая это не только ради повышения скорости работы, но и ради упрощения существующих моделей, а так же — для того, чтобы дать практикам более простые и понятные способы передачи в модели априорных знаний о природе обрабатываемых ими данных. Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки. Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь. Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров. Присоединяйтесь к нашей команде.