В мире, где облачные решения диктуют свои правила, локальные модели дают свободу — полную приватность, работу офлайн и отсутствие ограничений. Эта статья для тех, кто хочет впервые попробовать самостоятельно запустить LLM на своем компьютере.
В статье подробно разобраны разные виды LLM, их особенности и сценарии использования. Какие модели лучше подходят для программирования? Какие эффективнее справляются с переводами, генерацией текста или анализом больших объемов данных? Автор статьи Chris Wellons* протестировал популярные открытые модели — Mistral, Qwen, DeepSeek-Coder, Mixtral, Llama 3.1 и другие, — чтобы понять их сильные и слабые стороны. Также автор делится опытом и практическими советами, которые помогут вам запустить и использовать LLM на собственном оборудовании. Хотите разобраться, какую модель выбрать под свои задачи и как эффективно запустить её на локальном оборудовании? Тогда приступим!
*Обращаем ваше внимание, что позиция автора может не всегда совпадать с мнением МойОфис
Эта статья обсуждалась на Hacker News.
В течение последнего месяца я изучал быстро развивающийся мир больших языковых моделей (LLM). Сегодня уже возможно запустить LLM на Raspberry Pi, и она будет умнее оригинального ChatGPT (версии ноября 2022 года). Обычные настольный компьютер или ноутбук поддерживают еще более продвинутый ИИ. К тому же он приватный, работает офлайн, без ограничений и не требует регистрации.
В этой статье я делюсь своими практическими знаниями и опытом — той информацией, которую я сам хотел бы иметь, когда только начинал. Только прошу учесть, что я не специалист в области LLM, у меня нет каких-то уникальных знаний, и вполне вероятно, что я неправильно понял некоторые аспекты. Через год эта статья сгодится разве что для экскурса в историю, и это одновременно захватывает и пугает.
Итак, если вы всё это время были в танке — не волнуйтесь, мы с вами из одной дивизии — LLM — это нейронные сети, совершившие прорыв в 2022 году, когда их обучили вести диалог. С помощью LLM пользователи могут общаться с до ужаса креативным искусственным интеллектом, который неотличим от человека и с легкостью проходит тест Тьюринга. Первый же разговор с ним вызвал во мне какое-то тревожное чувство, которое преследовало меня еще пару дней. Когда я покупал свой нынешний комп, я никак не ожидал, что буду вести с ним осмысленную беседу.
Этот опыт напомнил мне революцию в настольных компьютерах 1990-х годов, когда только что купленный компьютер устаревал чуть ли не в тот же момент, когда вы приносили его домой. Каждую неделю появляются новые разработки, поэтому я игнорирую практически всю информацию, которой больше года. Лучший способ быть в курсе событий — r/LocalLLaMa. Всё раздуто до небес, так что советую воспринимать то, что вам говорят, с долей скепсиса.
Я с опаской отношусь к привязке к одному поставщику, так как уже сталкивался с тем, что сервисы закрывались, менялись или иным образом переставали поддерживать мой сценарий использования. Мне нужен вариант, при котором я смогу продолжить работу, даже если придётся сменить поставщика. Поэтому пару лет я игнорировал LLM. «Закрытые» модели, доступные только как сервис, имеют классическую проблему привязки, включая постепенное ухудшение качества. Всё изменилось, когда я узнал, что могу запускать модели, близкие к самым передовым, на собственном компьютере — полная противоположность привязке к поставщику.
Эта статья именно о запуске LLM. Тонкую настройку и тем более обучение я здесь не затрагиваю. И еще речь идет только о тексте, а не о видео, голосе или других «мультимодальных» возможностях, которые мне не так нужны.
Чтобы запустить LLM на своем оборудовании, вам понадобятся программное обеспечение и модель.
Я использовал только llama.cpp. Существуют и другие варианты, но для базовых расчетов на CPU — то есть генерации токенов с помощью процессора, а не видеокарты — llama.cpp не требует ничего, кроме инструментария C++. В частности, никаких манипуляций с Python, которые наносят ущерб большей части экосистемы. На Windows это будет llama-server.exe
размером 5 МБ без каких-либо зависимостей от времени выполнения. С помощью всего двух файлов, EXE и GGUF (модель), оба из которых предназначены для загрузки через отображение в память, вы, вероятно, сможете запустить ту же самую LLM через 25 лет, точно так же, «из коробки», на какой-нибудь будущей версии Windows.
Признаюсь: я предвзят, потому что официальный процесс сборки для Windows — это w64devkit. Что я могу сказать? У этих ребят отличный вкус! Тем не менее, советую использовать инференс на CPU только в том случае, если инференс на GPU непрактичен. Он довольно хорошо работает с моделями до ~10 млрд параметров на настольном компьютере или ноутбуке, но медленнее. Мой основной вариант не собран с помощью w64devkit, потому что я использую CUDA для инференса, что требует инструментария MSVC. Просто ради интереса я портировал llama.cpp на Windows XP и запустил модель на 360 млн параметров на ноутбуке 2008 года выпуска. Было волшебно загрузить на этот старый ноутбук технологию, которая в то время, когда он был новым, стоила бы миллиарды долларов.
Узким местом для инференса на GPU является видеопамять — VRAM. Эти модели, как вы, вероятно, уже догадались, большие. Чем больше у вас оперативной памяти, тем больше модель и длиннее контекстное окно. Более крупные модели умнее, а длинные контексты позволяют обрабатывать больше информации за раз. Инференс на GPU не стоит того при объеме VRAM менее 8 ГБ. Если GPU у вас маловато, делайте инференс на CPU. Тем более начать работу с инференсом на CPU проще.
В llama.cpp много утилит, но эта статья касается только одной: llama-server
— программа, которую вам нужно запустить. Это HTTP-сервер (порт по умолчанию 8080) с чат-интерфейсом в корне и API для использования программами, включая другие пользовательские интерфейсы. Типичный вызов:
$ llama-server --flash-attn --ctx-size 0 --model MODEL.gguf
Размер контекста — это максимальное количество токенов, которое LLM может обработать за раз, включая ввод и вывод. В контекстах обычно бывает от 8 до 128 тысяч токенов, и в зависимости от токенизатора модели, обычный английский текст содержит примерно 1,6 токена на слово, если считать с помощью wc -w
. Если модель поддерживает большой контекст, у вас может закончиться память. В таком случае установите меньший размер контекста, например --ctx-size $((1<<13))
(т.е. 8 тыс. токенов).
Я пока не понимаю, что такое Flash Attention, и не знаю, почему --flash-attn/-fa
не используется по умолчанию (меньшая точность?), но вы всегда должны его запрашивать, так как при активации он снижает требования к памяти и определенно стоит затрат.
Если сервер успешно запустился, зайдите на него (http://localhost:8080/), чтобы испытать. Хотя, конечно, сначала вам понадобится модель.
Hugging Face (HF) — это «GitHub для LLM». Невероятно полезный сервис, который на самом деле отвечает своему названию. «Маленькие» модели занимают несколько гигабайт, большие — сотни гигабайт, а HF хостит всё это бесплатно. За некоторыми исключениями, которые на практике не имеют значения, здесь даже не нужно регистрироваться, чтобы скачать модели! (Я был настолько впечатлен, что через несколько дней заплатил за pro-аккаунт, хоть я и скряга). Это значит, что вы можете сразу же скачать и попробовать все, о чем я сейчас расскажу.
Когда вы туда зайдете, то, наверное, будете недоуменно чесать в затылке: «Здесь так много всего... Что мне, собственно, скачивать?» По крайней мере, месяц назад так думал я. Ответ для llama.cpp — GGUF. Ни одна из моделей изначально не представлена в формате GGUF. Вместо этого GGUF находятся в репозитории с «GGUF» в названии, обычно созданном третьей стороной: одним из героически плодовитых квантователей GGUF.
Обратите внимание, что нигде в официальной документации не объясняется расшифровка аббревиатуры «GGUF». Привыкайте к этому. Это технологический фронтир, и если эта информация вообще существует, она явно не на виду. Вы думаете спросить об этом свою LLM, когда она заработает? Увы, у вас ничего не выйдет, и скоро мы поговорим почему. Насколько я могу судить, «GGUF» не имеет официального определения (UPD: U означает «Unified» (унифицированный), но остальное всё ещё неоднозначно.
Поскольку llama.cpp назван в честь флагманской модели Meta, логично начинать с их модели, хотя лично мне она нравится меньше всего. Последняя версия — Llama 3.2. Но на данный момент в Llama.cpp работают только модели 1B и 3B — то есть примерно c одним миллиардом и с тремя миллиардами параметров. Они слишком малы, чтобы быть по-настоящему полезными, и ваш компьютер, вероятно, справится лучше, если это не Raspberry Pi, даже при инференсе на CPU. Llama 3.1 8B — лучший вариант. (Если у вас есть хотя бы 24 ГБ видеопамяти, то, возможно, вы даже сможете использовать Llama 3.1 70B.)
Если вы поищете Llama 3.1 8B, то найдете два варианта: один с пометкой «instruct», а другой без уточнений. Instruct означает, что модель обучена следовать инструкциям, то есть вести диалог, и это почти всегда то, что вам нужно. Другая — это «базовая» модель, которая может только продолжать текст. (Технически модель instruct тоже просто завершает текст, но об этом позже.) Было бы очень удобно, если бы базовые модели имели пометку «Base», но по какой-то глупой традиции чаще всего это не так.
Вы не найдете GGUF в разделе «Files» для модели instruct, и не сможете скачать модель без регистрации и согласия с лицензией сообщества. Вернитесь к поиску, введите GGUF и найдите соответствующую модель GGUF: bartowski/Meta-Llama-3.1-8B-Instruct-GGUF. bartowski — один из самых продуктивных и уважаемых квантователей GGUF. Все будет не только в нужном формате для llama.cpp, но и без регистрации.
Теперь в разделе «Файлы» вы увидите множество GGUF. Это различные квантования одной и той же модели. Исходная модель имеет тензоры bfloat16, но для простого запуска модели мы можем отбросить большую часть этой точности с минимальными потерями. Она станет чуть менее умной и осведомленной, но потребует значительно меньше ресурсов. Исходя из своего опыта, советую использовать Q4_K_M, 4-битное квантование. В целом, лучше запустить 4-битное квантование большей модели, чем 8-битное квантование меньшей. Когда вы освоите основы, поэкспериментируйте с разными квантованиями и найдите то, что вам больше подходит!
Модели обучаются с учетом различных компромиссов, у них есть сильные и слабые стороны, поэтому ни одна модель не является лучшей во всем — особенно на конфигурациях с «бедными» GPU. В моем настольном компьютере стоит RTX 3050 Ti с 8 ГБ видеопамяти, и ее ограничения определили мой выбор. Я могу комфортно работать с моделями ~10B, а для моделей ~30B возможностей едва-едва хватает на то, чтобы просто проверить, что они могут. Для моделей ~70B я использую сторонние хостинги. Все мои показатели t/s получены на этой системе при работе с 4-битными квантованиями.
В списке, который я привожу далее, слово «instruct» в названии модели опущено. Но подразумевается именно модель instruct, если не указано иное. Некоторые из них действительно открыты, насколько это возможно для LLM, и в таких случаях я указал лицензию. У остальных есть ограничения как на использование, так и на распространение.
Mistral-Nemo-2407 (12B) [Apache 2.0]
Результат сотрудничества Mistral AI и Nvidia («Nemo») — самая универсальная модель ~10B, которую я использовал, и моя модель по умолчанию. Вывод начинается с комфортной скорости 30 t/s. Ее сильные стороны — написание текстов и вычитка, а еще она анализирует код почти так же хорошо, как модели ~70B. Она обучена на длину контекста 128K, но ее эффективная длина контекста ближе к 16K — это ограничение я наблюдал лично.
«2407» — это дата (июль 2024 года) в качестве номера версии. И должен сказать, я всеми руками «за» такую схему версионирования. Дата ясно показывает технологический уровень модели. Она хорошо сортируется. В прочих случаях версионирование LLM превращается в хаос. Как и в случае с открытым исходным кодом, где плохо с названиями, компании, работающие в сфере ИИ, не понимают, что такое версионирование.
Qwen2.5-14B [Apache 2.0]
Модели Qwen от Alibaba Cloud впечатляюще превосходят ожидания на любом масштабе. Вывод 14B начинается с 11 t/s, а возможности не уступают Mistral Nemo. Если бы я мог запустить 72B на своем компьютере, Qwen, скорее всего, стала бы моей моделью по умолчанию. Я пробовал ее через API инференса Hugging Face. Есть модель 32B, но она непрактична для моего компьютера, поэтому я не уделял ей много времени.
Gemma-2-2B
Модель Google популярна, возможно, из-за своего игривого характера. Для меня модель 2B отлично подходит для быстрого перевода. Невероятно, но факт: LLM практически вытеснили Google Translate, и вы можете запустить их на домашнем компьютере. Эта модель более ресурсоемкая и отказывается переводить тексты, которые считает оскорбительными. В моем скрипте для перевода я отправляю ей текст, размеченный HTML. Достаточно просто попросить Gemma сохранить разметку, и это работает! Модель 9B еще лучше, но медленнее, и я бы использовал ее вместо 2B для перевода своих собственных сообщений на другой язык.
Phi3.5-Mini (4B) [MIT]
Ниша Microsoft — обучение на искусственных данных. В результате получается модель, которая хорошо справляется с тестами, но не так хорошо работает на практике. Для меня ее сильная сторона — оценка документов. Я загружал в контекст документы объемом до 40 тысяч токенов (модель 4B это позволяет) и успешно получал точные резюме и списки данных.
SmolLM2-360M [Apache 2.0]
Hugging Face не просто размещает модели; их собственная модель 360M необычайно хороша для своего размера. Она помещается на моем ноутбуке 2008 года выпуска с 1 ГБ оперативной памяти, процессором Celeron и 32-битной операционной системой. Она также хорошо работает на старых Raspberry Pi. Она креативна, быстра, грамотно ведет беседу, может писать стихи. Это забавная игрушкой для ограниченного железа.
Mixtral-8x7B (48B) [Apache 2.0]
Еще одна модель от Mistral AI, скорее второго эшелона. 48B — вроде бы слишком много, но это модель Mixture of Experts (MoE). При выводе используется только 13B параметров одновременно. Она вполне подходит для инференса на CPU на компьютере с не менее чем 32 ГБ оперативной памяти. Модель сохраняет больше обучающих данных, больше похожа на базу данных, но по причинам, которые мы вскоре увидим, это не так полезно, как может показаться.
Llama-3.1-70B и Llama-3.1-Nemotron-70B
Еще модели, которые я не могу запустить сам, но к которым имею удаленный доступ. Последняя носит название «Nemo», потому что это тонкая настройка от Nvidia. Если бы я мог запускать модели 70B у себя, я, скорее всего, выбрал бы именно Nemotron. Мне нужно было бы потратить больше времени на сравнение ее с Qwen2.5-72B.
У большинства этих моделей есть облегченные или «нецензурированные» версии, в которых отказы частично устранены ценой ухудшения модели. Отказы раздражают — например, Gemma отказывается переводить тексты, которые ей не нравятся, — но это происходит недостаточно часто, чтобы я пошел на такой компромисс. А может быть, я просто зануда. Кроме того, похоже, что отказов становится меньше при увеличении контекста — «сказал "а", говори и "б"»!
Следующая группа — это модели «кодеров», обученные программированию. В частности, у них есть обучение fill-in-the-middle (FIM) для генерации кода внутри существующей программы. Чуть позже я расскажу, что это значит. Насколько я могу судить, они не справляются лучше ни с проверкой кода, ни с другими задачами, ориентированными на инструкции. Наоборот: обучение FIM проводится в базовой модели, а обучение инструкциям применяется позже поверх нее, поэтому инструкции работают против FIM! Другими словами, результаты FIM базовой модели заметно лучше, хотя вы теряете возможность общаться с ними.
Раздел об оценке будет позже, но сейчас я хочу отметить, что даже самые современные LLM производят посредственный код. Рейтинги здесь даны относительно других моделей, а не по общим возможностям.
DeepSeek-Coder-V2-Lite (16B)
Одноименная модель MoE от DeepSeek. Она использует 2B параметров при выводе, что делает ее такой же быстрой, как Gemma 2 2B, но такой же умной, как Mistral Nemo, что представляет собой отличный баланс, особенно потому, что она превосходит модели ~30B в генерации кода. Так что если мне хочется поэкспериментировать с FIM, я использую ее.
Qwen2.5-Coder-7B [Apache 2.0]
Qwen Coder, как говорится, дышит в спину предыдущей модели. Результат почти такой же хороший, но она немного медленнее, так как это не MoE. Лучше выбрать эту модель, а не DeepSeek, если у вас ограничена память. Во время написания этой статьи Alibaba Cloud выпустила версию Qwen2.5-Coder-7B, но не увеличила номер версии, что ужасно сбивает с толку. Сообщество стало называть ее Qwen2.5.1. Помните, что я говорил о компаниях, работающих с ИИ, и о версиях? (UPD: еще были выпущены модели кодеров 14B и 32B. Я попробовал обе, и ни одна из них не так хороша, как DeepSeek-Coder-V2-Lite, поэтому мой рейтинг остался неизменным).
Granite-8B-Code [Apache 2.0]
Линейка моделей IBM называется Granite. В целом модели Granite разочаровывают, за исключением того, что они необычайно хороши в FIM. По моему опыту, она делит второе место с Qwen2.5 7B.
Я также оценил CodeLlama, CodeGemma, Codestral и StarCoder. Их результаты FIM были так плохи, что оказались практически бесполезны для этой задачи, и я не нашел причин использовать эти модели. Негативные эффекты обучения инструкциям были наиболее выражены у CodeLlama.
Я упоминал о встроенном пользовательском интерфейсе Llama.cpp, и я использовал подобные интерфейсы с другим программным обеспечением LLM. Как обычно, ни один пользовательский интерфейс мне не понравился, особенно в вопросах производительности, поэтому я создал свой собственный, Illume. Эта программа командной строки преобразует стандартный ввод в запрос API, выполняет запрос и передает ответ в стандартный вывод. Должно быть достаточно просто интегрировать в любой расширяемый текстовый редактор, но мне он понадобился только для Vim. Vimscript ужасен. Это, наверное, второй по бесполезности язык программирования, с которым я когда-либо сталкивался, поэтому моей целью было написать как можно меньше кода.
Я создал Illume, чтобы удовлетворить свои потребности и поддержать исследование экосистемы LLM. Я активно ломаю и добавляю функции по мере необходимости и не даю никаких обещаний относительно стабильности интерфейса. Вероятно, вы не захотите его использовать.
Строки, начинающиеся с !, являются директивами для Illume. Они выбраны из-за малой вероятности появления в обычном тексте. В буфере происходит чередование реплик !user
и !assistant
.
!user
Сочини хайку о путешественниках во времени в обличье лягушек.
!assistant
Green, leaping through time, [Зелёные, скачущие сквозь время]
Frog tongues lick the future's rim, [Языки лягушек касаются края грядущего]
Disguised in pond's guise. [Пруд — их маскировка].
Это всё ещё буфер текстового редактора, поэтому я могу отредактировать ответ ассистента, переформулировать свой изначальный запрос и т.д., прежде чем продолжить диалог. Для создания художественных текстов я могу попросить продолжить какой-либо отрывок (что не требует специального обучения):
!completion
Чародей Дин крался по тёмному замку
Я могу прервать генерацию, внести правки, добавить свой текст и продолжить. Пожалуй, мне стоит больше практиковаться в работе с этим инструментом. Если вы введёте синтаксис для заметок вне сюжета, LLM его распознает, и тогда вы сможете использовать такие заметки для управления процессом создания текста.
Хотя основной целью является llama.cpp, я обращаюсь к различным API, реализованным разными LLM-программами. Между API существуют несовместимости (параметр, необходимый для одного API, может быть запрещён в другом), поэтому директивы должны быть гибкими и мощными. Таким образом, директивы могут задавать любые параметры HTTP и JSON. Illume не пытается абстрагировать API, а предоставляет доступ к нему на низком уровне, поэтому для эффективного использования необходимо знание удалённого API. Например, «профиль» для взаимодействия с llama.cpp выглядит так:
!api http://localhost:8080/v1
!:cache_prompt true
Где cache_prompt
— это специфичный для llama.cpp JSON-параметр (!:). Кэширование промптов почти всегда лучше включать, но по какой-то причине оно отключено по умолчанию. Другие API отклоняют запросы с этим параметром, поэтому мне приходится его опускать или отключать иным способом. «Профиль» Hugging Face выглядит так:
!api https://api-inference.huggingface.co/models/{model}/v1
!:model Qwen/Qwen2.5-72B-Instruct
!>x-use-cache false
Для удобства работы с HF, Illume может встраивать JSON-параметры в URL. API HF также агрессивно использует кэширование. Мне это не нужно, поэтому я задаю HTTP-параметр (!>), чтобы отключить его.
Уникальная особенность llama.cpp — конечная точка /infill
для FIM. Она требует модель с дополнительными метаданными, обученную определённым образом, но обычно этого не происходит. Поэтому, хотя Illume может использовать /infill
, я также добавил конфигурацию FIM. Теперь, изучив документацию модели и настроив Illume под её FIM-поведение, я могу выполнять FIM-завершение через обычный API завершения на любой FIM-обученной модели, даже в API, не связанных с llama.cpp.
Пора поговорить о FIM. Чтобы докопаться до его сути, мне пришлось обратиться к первоисточнику — оригинальной статье о FIM: Efficient Training of Language Models to Fill in the Middle. Это позволило мне понять, как эти модели обучаются FIM, по крайней мере, достаточно для того, чтобы применить это обучение на практике. Тем не менее, документация по моделям обычно скудна в отношении FIM, поскольку разработчики ждут, что вы будете использовать их код.
В конечном счёте, LLM может только предсказывать следующий токен. Поэтому выберите несколько специальных токенов, которых нет во входных данных, используйте их для разграничения префикса, суффикса и середины (PSM) — или иногда суффикса, префикса и середины (SPM) — в большом обучающем корпусе. Позже при выводе мы можем использовать эти токены, чтобы задать префикс, суффикс и позволить модели «предсказать» середину. Звучит безумно, но это действительно работает!
<PRE>{prefix}<SUF>{suffix}<MID>
Например, при заполнении скобок в выражении dist = sqrt(x*x + y*y)
:
<PRE>dist = sqrt(<SUF>)<MID>x*x + y*y
Чтобы LLM заполнила скобки, мы остановимся на <MID>
и позволим LLM продолжить предсказание. Обратите внимание, что <SUF>
по сути является курсором. Кстати, именно так работает обучение с инструкциями, но вместо префикса и суффикса специальные токены разграничивают инструкции и диалог.
Некоторые специалисты по LLM интерпретируют статью буквально и используют <PRE>
и так далее для своих FIM-токенов, хотя они совсем не похожи на другие специальные токены. Более вдумчивые разработчики выбирают <|fim_prefix|>
и т.п. Illume принимает шаблоны FIM, и я написал шаблоны для популярных моделей. Например, вот шаблон для Qwen (PSM):
<|fim_prefix|>{prefix}<|fim_suffix|>{suffix}<|fim_middle|>
Mistral AI предпочитает квадратные скобки, SPM и отсутствие токена «middle»:
[SUFFIX]{suffix}[PREFIX]{prefix}
С помощью этих шаблонов я смог использовать FIM-обучение в моделях, не поддерживаемых API /infill llama.cpp
.
Помимо неудачных промптов, самая большая проблема, с которой я столкнулся в FIM, — это то, что LLM не знают, когда нужно остановиться. Например, если я попрошу заполнить эту функцию (т.е. присвоить что-то r):
def norm(x: float, y: float) -> float):
return r
(Примечание: статическая типизация, включая приведённые здесь подсказки, улучшает результаты работы LLM, выступая в роли ограничителей). Нередко можно получить что-то вроде:
def norm(x: float, y: float) -> float):
r = sqrt(x*x + y*y)
return r
def norm3(x: float, y: float, z: float) -> float):
r = sqrt(x*x + y*y + z*z)
return r
def norm4(x: float, y: float, z: float, w: float) -> float):
r = sqrt(x*x + y*y + z*z + w*w)
return r
Где изначальное return r
стало возвратом для norm4
. Технически это соответствует запросу, но явно не то, что мне нужно. Поэтому будьте готовы нажать кнопку «стоп», когда генерация выйдет из-под контроля. Три рекомендованные мной модели для программирования ведут себя так реже. Возможно, было бы надёжнее объединить это с системой, не основанной на LLM, которая семантически понимает код и автоматически останавливает генерацию, когда LLM начинает создавать токены в более высокой области видимости. Это сделало бы жизнеспособными больше моделей для программирования, но это выходит за рамки моих экспериментов.
Разобравшись с FIM и применив его на практике, я понял, что он всё ещё находится на ранней стадии развития, и с его помощью почти никто не генерирует код. Полагаю, все просто используют обычное автодополнение?
LLM — это интересно, но каково их практическое применение? Я пытался ответить на этот вопрос в течение последнего месяца, и результат оказался скромнее, чем я надеялся. Возможно, полезно установить границы — задачи, которые LLM определённо не могут выполнить.
Во-первых, LLM бесполезны, если правильность их результатов нельзя легко проверить. Они ненадёжны и склонны к галлюцинациям. Часто, если вы в состоянии проверить результат работы LLM, вам он изначально и не был нужен. Вот почему Mixtral с его обширной «базой знаний» не так уж полезен. Это также означает, что включать результаты работы LLM в поисковую выдачу безответственно и опрометчиво — попросту непрофессионально.
Энтузиасты LLM, которые должны бы знать лучше, всё равно попадаются в эту ловушку и распространяют галлюцинации. Это делает обсуждения LLM менее надёжными, чем обычно, и мне приходится подходить к информации о LLM с дополнительным скептицизмом. Пример: вспомните, что у «GGUF» нет авторитетного определения. Если поискать его, можно найти явную галлюцинацию, которая попала даже в официальную документацию IBM. Я не буду повторять её здесь, чтобы не усугублять ситуацию.
Во-вторых, у LLM рабочая память как у рыбки. То есть их ограничивает небольшая длина контекста. Некоторые модели обучаются на больших контекстах, но их эффективная длина контекста обычно намного меньше. На практике LLM может одновременно «держать в голове» объём информации, равный нескольким главам книги. Для кода это 2-3 тысячи строк (код очень плотный в плане токенов). Это максимум, с чем можно работать одновременно. По сравнению с человеком, это крошечный объём. Существуют инструменты вроде генерации ответа, дополненной результатами поиска, и тонкой настройки, чтобы смягчить эту проблему... немного.
В-третьих, LLM — плохие программисты. В лучшем случае они пишут код на уровне студента, который прочитал много документации. Это звучит лучше, чем есть на самом деле. Типичный выпускник приходит на работу, практически ничего не зная о разработке программного обеспечения. Первый день на работе — это начало их настоящего образования. В этом смысле современные языковые модели еще даже не приступили к обучению.
Надо отдать им должное, то, как хорошо работают языковые модели, просто поразительно! Столкнувшись с программой, написанной в моем нестандартном стиле, языковые модели разбираются в ней и используют специальные интерфейсы. (Уточню: мой код и тексты входят в обучающие данные большинства этих моделей). Поэтому чем больше контекста, тем лучше — в пределах эффективной длины контекста. Главная задача — получить от языковой модели что-то полезное быстрее, чем написать это самому.
Написание нового кода — это самая легкая часть. Самое сложное — поддерживать код и писать новый, учитывая необходимость его дальнейшего сопровождения. Даже когда языковая модель создает работающий код, она не думает о его дальнейшем сопровождении, да и не может об этом думать. В целом, надежность генерируемого кода обратно пропорциональна квадрату его длины, и генерация более десятка строк за раз чревата проблемами. Я очень старался, но никогда не видел, чтобы языковая модель выдавала более 2-3 строк кода, которые я бы счел приемлемыми.
Качество существенно зависит от языка программирования. Языковые модели лучше справляются с Python, чем с C, и лучше с C, чем с ассемблером. Полагаю, это связано со сложностью языка и качеством обучающих данных. Модель обучалась на огромном количестве ужасного кода на C — в конце концов, интернет им переполнен, — а единственный размеченный ассемблерный код x86, который она видела, вероятно, из плохих учебников для начинающих. Попросите ее использовать SDL2, и она неизменно допустит типичные ошибки, потому что ее так обучили.
А как насчет шаблонного кода? Это то, что языковая модель, вероятно, может сделать с низким уровнем ошибок, и в этом может быть польза. Хотя самый быстрый способ справиться с шаблонным кодом — вообще его не писать. Измените задачу так, чтобы она его не требовала.
Не принимая мои слова на веру, подумайте, как это отражается в экономике: если бы компании, разрабатывающие ИИ, могли обеспечить заявленный рост производительности, они бы не продавали ИИ. Они бы оставили его себе и поглотили всю индустрию программного обеспечения. Или посмотрите на программные продукты, созданные компаниями на переднем крае ИИ. Это все тот же старый, раздутый веб-мусор, который создают все остальные. (Мои исследования языковых моделей включали навигацию по их ужасным сайтам, которые меня очень разочаровали.)
При генерации кода галлюцинации менее проблематичны. Вы уже знали, чего хотите, когда задавали вопрос, поэтому можете проверить результат, а компилятор поможет выявить проблемы, которые вы пропустили (например, вызов несуществующего метода). Однако ограниченный контекст и низкое качество генерации кода остаются препятствиями, и мне пока не удалось добиться эффективной работы в этой области.
Так что же можно делать с языковыми моделями? Уместно будет дать здесь список, ведь языковые модели любят списки:
Для меня наиболее полезной оказалась вычитка текстов. Я даю модели документ, например, электронное письмо или эту статью (около 8000 токенов), прошу проверить грамматику, выделить пассивный залог и так далее, а также предложить изменения. Я принимаю или отвергаю ее предложения и двигаюсь дальше. Большинство предложений будут неудачными, и даже модели с ~70 миллиардами параметров предлагали для этой длинной статьи изменения в несуществующих предложениях. Тем не менее, в этом шуме есть полезный сигнал, и это укладывается в рамки описанных выше ограничений. Я все еще пытаюсь применить этот подход ( «пожалуйста, найди ошибки») к проверке кода, но пока успех ускользает.
Написание короткой художественной прозы. Галлюцинации здесь не проблема, а необходимость! Ограничивающим фактором является длина контекста, хотя, возможно, ее можно увеличить, предоставляя краткое содержание глав, также написанное языковой моделью. Я все еще исследую эту возможность. Если вам лень, попросите модель предложить три возможных сюжетных поворота на каждом этапе, а вы выберете самый интересный. Или даже попросите ее объединить два из них! Языковые модели сообразительны и справятся с этим. Некоторые жанры работают лучше других, а конкретика лучше абстракций. (Интересно, оценивают ли профессиональные писатели ее тексты так же низко, как я оцениваю ее программирование).
Генерация развлекательных текстов. Поспорьте с Бенджамином Франклином (примечание: это, вероятно, нарушает правила использования некоторых моделей), пообщайтесь с персонажем из любимой книги или создайте новую сцену с хвастливыми выходками Фальстафа. Общение с историческими личностями оказалось познавательным: персонаж говорит что-то неожиданное, я проверяю это по старинке и узнаю что-то новое.
Перевод с одного языка на другой. Я просматривал иноязычные форумы, переводя их с помощью Gemma-2-2B, и это было познавательно. (Я и не подозревал, что немцы так недоверчиво относятся к искусственным подсластителям).
Несмотря на короткий список полезных применений, эта технология вызвала у меня наибольший восторг за последние годы!