Всем привет! Возможно, вы уже знаете о проекте LLaMA.cpp (на Хабре по этой теме был цикл новостей от @bugman). В самом репозитории никаких ссылок на модели не даётся, только указание на необходимые ресурсы. И ресурсы, надо сказать, немалые.
Для самой крупной модели (65B) указано требование ~40Гб оперативной памяти. Конечно, на компьютерах разработчиков встретить такой объем вполне возможно. Но далеко не у всех. Столкнувшись с проблемой нехватки памяти «здесь и сейчас», я вспомнил про уникальное по своей щедрости предложение от кого‑то, связанного с Эльбрусами (я не знаю кто ты, но я найду тебя и... поблагодарю).
На ресурсе https://elbrus.kurisa.ch/ можно запросить демо‑доступ к достаточно мощным серверам на Эльбрусе. Не знаю, какая на момент публикации очередь доступа, но доступ по SSH у меня уже был, поэтому я приступил к беспощадной эксплуатации.
Радует, что на сервере уже установлены инструменты make, поэтому собрать исполнительный файл llama.cpp/main
не составило труда. Сконвертированные модели к этому времени скачались в /srv/home/kpmy/dev/llama.cpp/models
(можно использовать их в ваших экспериментах, не скачивая заново).
По рекомендациям автора llama.cpp, запускаем приложение в режиме чата:
make
./main -m models/65B/ggml-model-q4_0.bin -n 256 --repeat_penalty 1.0 --color -i -r "User:" -p "User: Tell me about Elbrus."
В целом, это и есть вся инструкция. Так как исполнитель написан на Си, ему особо ничего не нужно, кроме всех ядер шикарной серверной машины (предупреждений об ограничении на использование я не увидел, если что, ребята, извините).
В последней версии llama.cpp механизм работы с моделью был слегка изменён, теперь там mmap‑ится файл вместо полной загрузки в память, это ускорило старт программы.
На скриншоте видно нагрузку и пример работы в режиме «чата», правда, она нестабильная какая‑то, иногда начинает генерировать фразы за пользователя.
По производительности что‑то трудно сказать, так как «кажется», что на AMD Ryzen 5600G c 64Гб памяти под Windows эта модель крутится примерно с той же скоростью (это я узнал позже, когда раздобыл необходимый объем памяти). Но проверить это «аккуратнее» мне не так интересно, как выдумывать новые промпты к ИИ‑игрушке для «бедных».
Возможно, ребятам из Эльбрус будет интересно подкинуть свои патчи к исходной программе и как‑то повысить производительность. В любом случае, огромное спасибо им за бесплатные ресурсы, всё уже очень неплохо работает. Может быть, процессорные нейросетки это перспективное направление для данной архитектуры, специалисты тут могут подсказать.
Кстати, если кто‑то знает, можно ли похожим на llama.cpp простым средством генерировать картинки без GPU, пусть и за счёт потраченного процессорного времени, подсказывайте в комментариях.
Комментарии (17)
shigorin
10.04.2023 14:52+1Ну достаточно мощные сервера на эльбрусе — это на данный момент 4Э8СВ, куда до полутерабайта памяти помещается :)
А вот 16С умеет до 4 Тб на процессор (соответственно до 16 Тб на систему), но мне и на 128 Гб довелось с жабой-то потолковать; впрочем, успешно.
Насчёт оптимизации есть с кем состыковать, если кому понадобится; ну и эльбрус-вики не отменяли.
Fulgur
10.04.2023 14:52+4А вот 16С умеет до 4 Тб на процессор
Михаил, на официальном сайте МЦСТ (http://www.mcst.ru/elbrus-16s), для Эльбрус-16С заявлена поддержка максимум 1 Тб на процессор. Не могли бы пруфы подвести?
rPman
10.04.2023 14:52Про производительность
запустите генерацию в режиме запроса без чата, ключ -p оно выведет ответ и завершит работу, показав подробную статистику по скорости, интересует два числа, токены в секунду и проходы (runs) в секунду, на i5-12600 с 6 ядрами (12 потоков) это 1сек на run (не помню точные числа), что даёт по 1-3 секунд на словоНа скорость работы влияет размер сетки, наличие/отсутствии квантизации и выбранный алгоритм (их там два) во время конвертации весов. Ещё момент, количество потоков приложения не выставляй выше количества ядер, иначе нагрузку даст а скорость не вырастает, а что произойдет с Эльбрус и подавно вопрос.
Скорость работы памяти не влияет, по крайней мере выключение профиля ddr4 3600mhz->2666mhz… Возможно при не использовании квантизации будет заметно, но с ней быстрее чем без нее.
Ещё момент, код llama.cpp активно правится и периодически вылезают деградации скорости, был тред в гите где выкладывали тесты скорости по коммитам
Fulgur
10.04.2023 14:52+3У меня получились такие результаты, сначала для 7B модели (commit-hash a0caa34b162449b5c13b8d604573053300ff54a1):
./main -m /srv/home/kpmy/dev/llama.cpp/models/7B/ggml-model-q4_0.bin -p "Building a website can be done in 10 simple steps:" -n 512 -s 1678486056 ... llama_print_timings: load time = 12850.61 ms llama_print_timings: sample time = 2100.08 ms / 512 runs ( 4.10 ms per run) llama_print_timings: prompt eval time = 55385.39 ms / 271 tokens ( 204.37 ms per token) llama_print_timings: eval time = 1018667.75 ms / 510 runs ( 1997.39 ms per run) llama_print_timings: total time = 1085869.75 ms
А теперь для 65B модели:
./main -m /srv/home/kpmy/dev/llama.cpp/models/65B/ggml-model-q4_0.bin -p "Building a website can be done in 10 simple steps:" -n 512 -s 1678486056 ... llama_print_timings: load time = 26450.83 ms llama_print_timings: sample time = 2600.10 ms / 512 runs ( 5.08 ms per run) llama_print_timings: prompt eval time = 414718.80 ms / 271 tokens ( 1530.33 ms per token) llama_print_timings: eval time = 3368699.11 ms / 510 runs ( 6605.29 ms per run) llama_print_timings: total time = 3797947.29 ms
В system-info видно это:
system_info: n_threads = 32 / 32 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | sampling: temp = 0.800000, top_k = 40, top_p = 0.950000, repeat_last_n = 64, repeat_penalty = 1.100000 generate: n_ctx = 512, n_batch = 8, n_predict = 512, n_keep = 0
rPman
10.04.2023 14:52+1Спасибо, видно что машина примерно в 6..20 раз медленнее (почему такой разброс для 7B и 65B?)
с 4b_0 квантизацией у менядля 7B моделиllama_print_timings: sample time = 10.58 ms / 32 runs ( 0.33 ms per run) llama_print_timings: prompt eval time = 304.90 ms / 5 tokens ( 60.98 ms per token) llama_print_timings: eval time = 2933.95 ms / 31 runs ( 94.64 ms per run)
64B:llama_print_timings: sample time = 11.85 ms / 32 runs ( 0.37 ms per run) llama_print_timings: prompt eval time = 2707.89 ms / 5 tokens ( 541.58 ms per token) llama_print_timings: eval time = 27549.84 ms / 31 runs ( 888.70 ms per run)
Не поленитесь пожалуйста, запустите эту команду, она выдаст csv на экран с результатами по разному количеству задействованных потоковfor a in {2..32};do printf "%s;" $a;./main -t $a -m /srv/home/kpmy/dev/llama.cpp/models/7B/ggml-model-q4_0.bin -p "Random joke:" -n 32 2>&1 |grep "llama_print_timings: eval time" | cut -d "(" -f 2 | grep -o -e "[0-9\.]*" ;done
тут используется ключ -n 32, ограничивающий вывод всего 32-я токенами (для бенчмарка более чем достаточно), можно поставить 16 или меньше, результат будет немного шумным но очень быстрым.
вот какой результат получил у себя я на 6-тиядерном 12th Intel i5-12600:
по X тут количество потоков, по Y — время на run (на токены точно так же выглядит).kpmy Автор
10.04.2023 14:52+2kpmy@mamizou:~$ lscpu Архитектура: e2k Порядок байт: Little Endian CPU(s): 32 On-line CPU(s) list: 0-31 Thread(s) per core: 1 Ядер на сокет: 8 Сокетов: 4 NUMA node(s): 4 ID прроизводителя: E8C Семейство ЦПУ: 4 Модель: 2 Имя модели: E8C CPU MHz: 1300 BogoMIPS: 2600.00 L1d cache: 64K L1i cache: 128K L2 cache: 512K L3 cache: 16384K NUMA node0 CPU(s): 0-7 NUMA node1 CPU(s): 8-15 NUMA node2 CPU(s): 16-23 NUMA node3 CPU(s): 24-31
rPman
10.04.2023 14:52+1Спасибо, очень странно, я ожидал что если конфигурация компьютера другая, то оптимум будет на других количествах потоков, а тут так же на половине.
последний вопрос, llama.cpp собирался на машине, запущенной в режиме эмуляции x86 машины, но сам код как минимум собирается и для эплвского процессора и для малинки, т.е. есть шанс завести это нативно и посмотреть результат? я не говорю про оптимизации, просто интересно, 10х разница в скорости все же заметная.
kpmy Автор
10.04.2023 14:52Собирал на этой же машине, я так понимаю, она нативная, то есть этот линукс прям под e2k.
mobi
10.04.2023 14:52тут так же на половине
Скорее всего потому, что Hyper-Threading есть и у Intel, и у Эльбруса.
Fulgur
10.04.2023 14:52Нет SMT у Эльбруса.
mobi
10.04.2023 14:52Тогда зависимость действительно не до конца понятна.
IvGrad2
10.04.2023 14:52+2Причина в отдельной микросхеме контроллера периферийных интерфейсов КПИ-2 (южный мост), пропускной способности которой хватает для двух процессоров Эльбрус, а в случае четырёх уже становится узким местом.
Это ограничение в полной мере проявило себя на СХД, поэтому в ИНЭУМ разработали материнскую плату сразу с двумя микросхемами южного моста КПИ-2, по одной на два процессора. Например, 4Э8СВ-MSWTX на базе Эльбрус-8СВ. Это решило вопрос с пропускной способностью, который и возник в данном случае.
В случае Эльбрус-16С, "южный мост" внесён в процессор и проблем с пропускной способностью в многопроцессорных серверах уже не должно быть.
bugman
stablediffusion вполне работает на одном CPU без GPU
kpmy Автор
Оно оказалось не таким простым, как llama.cpp.
А на Эльбрусе вообще не собралось :(
entze
Но там вопрос не к объему памяти, а в оптимизациях. Поэтому SD будет на телефоне работать быстрее.
bugman
Мне кажется, уважаемый автор спрашивал вообще о возможности запуска каких-либо text-to-image моделей, а не о том, какие из них лучше работают где. Понятно, что на условной 4090 оно будет работать еще лучше, да какой от этого автору прок?
StableDiffusion вполне таки чувствителен к объёму свободной памяти. Я когда я кручу stable-diffusion-ui (https://github.com/AUTOMATIC1111/stable-diffusion-webui) на домашней машине, то наблюдаю, как с моделью 1.4, при совершенно стандартных-из-коробки-настройках для CPU ...
... на старте главный процесс отжирает 6 Гб + при инференсе еще до гигабайта.
Как ориентир, генерация одного изображения 512x512 на простом промпте ("man on a moon") занимает ~ 4 минуты на 4 потоках Ryzen 5 3400G. Мои попытки использовать ROCm, чтобы задействовать возможности встроенного графического ядра в моём Ryzen ни к каким значимым успехам не привели, кроме повышенных объёмов потребляемой памяти. Но готов поверить, что плохо и мало копал.
Попытки воспользоваться какими-то более продвинутыми функциями, типа img2img вообще крашатся по недостатку памяти.
Надо отметить, что весь этот AI/ML софт переживает infancy своего lifecycle. Я регулярно поглядываю на свежие версии, но вижу совершенно необъяснимые косяки и вариацию по части используемой памяти и стабильности генерации. Я думаю где-то через пару лет эта тема устаканится, чтобы это можно было назвать production grade software. Пока это сугубо для энтузиастов-исследователей.