*этот длиннопост я пишу уже третий месяц — наконец то дошли руки его закончить и выложить*
Как я уже писал, I have a soft spot for broken and puny things. Не так давно мне попалась на глаза новость, где кто-то обучил ллм для Z80 — такого восьмибитного процессора из середины 80-х. Для того, чтобы полноценный трансформер уместился и работал в ограничениях памяти процессора, который лишь на десять лет младше моих родителей, авторам пришлось применить много интересных технических решений: QAT в 2 битах, инференс в int16 (потому что другой математики в процессоре добиться сложно) и, что самое прикольное, ограничение размера токенизатора.
В современных трансформерах словари огромны. В e5-base, например, токенизатор содержит 30522 токенов, в multilingual-e5-small взят словарь от xlmr, так что там 250037 токенов и так далее. Это означает две вещи: во первых, если у модели в токенизаторе много токенов, то ей будет надо больше данных, чтобы все эти токены увидеть в разных контекстах и собрать статистики. Во-вторых, большой токенизатор означает большую LM Head и большой эмбеддинг слой. И как бы пофиг на это, это же просто lookup table, но хоть e5-small от multilingual-e5-small архитектурно отличаются лишь токенизатором*, число параметров там 33M против 117M.
Поэтому авторы Z80-μLM сделали токенизатор character based и рекомендовали структурировать датасет как одно слово. Например:
> hello
HI
> are you real
MAYBE
Это, с одной стороны, сильно ограничивало полезность такой ллм (ну а кому оно надо если честно), но, с другой стороны, давало неплохую экспрессивность. Это уже не if-else, оно давало ощущение того, что что-то внутри есть и это что-то вполне себе не против с тобой пообщаться. Прикольно.
*когда-то я хотел запрунить multilingual-e5-small и сократить размер токенизатора там и в процессе выяснилось, что прунинг блоков трансформера почти не даёт выигрыша в памяти — потому что 91M это эмбеддинги. Когда-нибудь я про это расскажу.