По-ниска латентност и по-висока пропускателна способност с многовъзлово внедряване на DeepSeek
Многопроцесорното внедряване повишава производителността на MoE модела едновременно по отношение на скоростта и мащаба
В повечето системи латентността и пропускателната способност често са противоречиви цели, които изискват компромиси по време на проектирането и внедряването. Например при плътните езикови модели с голям обем увеличаването на размера на пакета може да подобри пропускателната способност, но също така увеличава латентността; увеличаването на тензорния паралелизъм в рамките на една машина може да намали латентността, но намалява броя на репликите, което води до по-ниска пропускателна способност.
Моделите със смес от експерти (MoE), като DeepSeek-V3/R1, наскоро демонстрираха отлични възможности на моделите и оперативна ефективност. Например моделът DeepSeek-V3/R1 има общо 671 млрд. параметъра, но всеки токен използва само 37 млрд. параметъра по време на инференция. Тази архитектура на модела представлява както предизвикателства, така и възможности за системите за инференция.
Тази статия демонстрира, че противно на конвенционалните системи, MoE моделите като DeepSeek-V3/R1 могат едновременно да постигнат по-висока пропускателна способност и по-ниска латентност, когато се използват повече графични процесори при многовъзлови внедрявания в повечето сценарии.
Архитектури за внедряване
Поради големия брой малки експерти в модела, внедряванията трябва да бъдат разпределени между множество устройства. Обмислихме както еднозлови внедрявания на един възел с 8xH200 графични процесора, така и многовъзлови внедрявания на 8xH100 графични процесора.
И двете архитектури за внедряване се възползват от паралелизма на данните, оркестриран чрез нашия собствен диспечер на заявки. Реализацията на паралелизма на данните включва стартиране на множество екземпляри на двигателя за инференция, като всеки работи независимо за обслужване и поддържане на заявки. Диспечерът на заявки, който взаимодейства с двигателя чрез GRPC, е отговорен за разпределението на заявките възможно най-равномерно, като същевременно улесни повторното използване на KV кеша и изпраща заявки с частично съвпадащ префикс към сървърите, съдържащи кеша. Екземплярите на двигателя не обхващат множество възли. Те могат по избор да използват тензорен паралелизъм за шардиране на вниманието между множество устройства. Екземплярите са свързани помежду си чрез NVLink в случай на един възел или InfiniBand за многовъзлов случай, като диспечират и събират експерти.
Конфигурацията за еднозлово внедряване осигурява превъзходна латентност при малки размери на пакетите; производителността обаче се влошава бързо при условия на повишено натоварване.
За да внедрим обслужващия двигател, стартираме по един под на възел, хостващ множество екземпляри на двигателя. PyTorch отговаря за настройката на разпределената комуникация и договарянето на инициализацията на NVSHMEM. За комуникацията разчитаме на персонализирани CUDA ядра, описани в по-ранна публикация в блога. Реализацията на двете внедрявания е практически идентична, като моделът избира правилните ядра за използване въз основа на структурата, реализираща експертен паралелизъм.
Техники за паралелизиране
Преди да се впуснем в сравненията на производителността, е от съществено значение да разберем ключовите стратегии за паралелизиране, които правят възможно внедряването на масивни MoE модели като DeepSeek-V3/R1.
Тензорен паралелизъм
При инференция с LLM, тензорният паралелизъм (TP) обикновено се използва за намаляване на използването на памет и изчисленията на графичен процесор, като по този начин се намалява латентността. Обикновено можем да шардираме Linear проекции в слоевете на вниманието и MLP слоевете по измеренията на редове или колони, и да шардираме операциите за внимание по измерението на главата за внимание.
С TP архитектурата Llama-3 няма дублирани изчисления за Linear проекции и операции за внимание между графичните процесори, което е идеален метод за шардиране. Въпреки това при моделите DeepSeek-V3/R1 TP не може да постигне това.
Моделите DeepSeek-V3/R1 използват Multi-Latent Attention (MLA). Слой MLA първо използва Linear проекция kv_a_proj за изчисляване на латентния вектор, след което използва друга Linear проекция kv_b_proj, за да го трансформира в пространството на всяка глава за внимание. Тъй като всички глави за внимание споделят един и същ латентен вектор, TP не може да шардира латентния вектор, така че всички TP рангове трябва да репликират параметрите и изчисленията на kv_a_proj и kv_b_proj. По същия начин, тъй като MLA съхранява латентния вектор в KV кеша, всеки TP ранг съхранява идентично копие на KV кеша.
Въпреки известно дублиране в MLA, тензорният паралелизъм все пак осигурява частично намаляване на изчислителните изисквания, което го прави ценен за сценарии, изискващи високи скорости на извеждане.
Експертен паралелизъм
Моделите DeepSeek-V3/R1 заменят MLP слоевете с MoE слоеве. Един MoE слой има 256 руртирани експерти и един споделен експерт. Всеки токен се изпраща към 8 различни руртирани експерти за изчисление, а резултатите се сумират с тегловни коефициенти. Всеки токен се изчислява и в споделения експерт, а резултатът се добавя към резултата от руртираните експерти.
Експертният паралелизъм (EP) служи като типичен подход за шардиране за MoE слоеве, като всеки графичен процесор управлява 256 / EP руртирани експерти, като същевременно поддържа копие на споделения експерт. В сравнение с TP, предимството на EP е, че той може да разпредели изчисленията между повече графични процесори, намалявайки изчисленията и използването на памет за графичен процесор.
Преди да се извършат експертните изчисления, всички графични процесори трябва да извършат комуникация AllToAll за разпределяне на токените към графичните процесори, където се намират съответните експерти; след експертните изчисления е необходима друга AllToAll комуникация за събиране на резултатите от изчисленията от различни графични процесори и извършване на претеглено сумиране. Реализирахме оптимизирана версия на тези две комуникационни ядра AllToAll, Dispatch и Combine, използвайки NVSHMEM. В предишната ни публикация в блога описахме подробно реализацията, а нашите ядра са с отворен код в GitHub.
Паралелизъм на данните
С EP можем да разпределим MoE изчисленията между 128 или дори повече графични процесори. Изчисленията на MLA обаче не могат да бъдат партиционирани с EP. В този момент можем да въведем паралелизъм на данните (DP). Всяка DP група има пълно копие на MLA слоя. Всяка DP група приема различни входни данни и извършва изчисления на MLA слоя независимо.
DP и TP на MLA слоя могат да бъдат комбинирани, като една DP група е разделена на множество TP рангове. EP на MoE слоя може да се комбинира с DP/TP на MLA слоя. EP = DP * TP. Например на 16 машини EP128 DP32 TP4 означава разпределение на руртираните експерти между 128 графични процесора, като всеки 4 графични процесора образуват DP група, общо 32 независими DP групи.
Еднозлови срещу многовъзлови
Параметрите 671B на DeepSeek надвишават капацитета на паметта на една машина с 8 графични процесора H100 (80 GB * 8), но една машина с 8 графични процесора H200 може напълно да побере целия модел (141 GB * 8). Използвайки конфигурацията EP8 DP8 TP1, моделът използва около 100 GB памет на графичен процесор, оставяйки приблизително 40 GB за KV кеш и други междинни резултати. Един токен заема 70 272 байта KV кеш. Приемайки, че всяка заявка има 5000 токена, всеки графичен процесор може да побере около 100 заявки.
Искахме да разберем разликите в производителността между разгръщане на един възел и разгръщане на множество възли при различни конфигурации. Използвахме една машина H200 за разгръщане на един възел и до 16 машини H100 за разгръщане на множество възли. За всяка среда за разгръщане използвахме комбинации от TP 1, 2, 4, 8 и размери на партидата на GPU от 1, 2, 4, 8, 16, 32, 64, 128. Предположихме, че всяка заявка има дължина на KV Cache от 5 000 токена. Също така предположихме, че Multi-Token Prediction (MTP) предсказва 1 допълнителен токен (т.е. дължината на заявката за всяка заявка е 2) и консервативно предположихме процент на приемане от 60%. Фигурата по-долу показва пропускателната способност и скоростта на изхода за различни конфигурации.
Хоризонталната ос представлява скоростта на извеждане на заявка в токени/сек. Вертикалната ос използва логаритмична скала за показване на пропускателната способност на машина в токени/сек. Отбелязахме границата на Парето за всяка EP конфигурация с линии с различен цвят.
В сценарии с изключително високи изисквания за скорост на извеждане, използването на еднозлово EP8 DP1 TP8 с размер на пакета 1 може да постигне скорост на извеждане над 100 токена/сек, но пропускателната способност е изключително ниска, еквивалентна на скоростта на извеждане. В този сценарий целият пакет има само 2 токена, които могат да бъдат разпределени към най-много 2*8=16 експерти, активиращи общо най-много 57B параметри.
В диапазона на скоростта на извеждане от 80-40 токена/сек, с увеличаване на пропускателната способност, скоростта на извеждане намалява значително. За сравнение, EP128 има около 5 пъти по-висока пропускателна способност от еднозловото внедряване при същата скорост на извеждане.
Този феномен може да бъде обяснен чрез изследване на поведението на еднозловите внедрявания: увеличаването на размера на пакета корелира директно с увеличаване на активираните експерти. Когато размерът на пакета е 1, средният брой активирани експерти на графичен процесор е 2 * 8 / 8 = 2. Когато пакетът е достатъчно голям, всички експерти се активират, което означава, че всеки графичен процесор активира 256 / 8 = 32 експерти. Активирането на повече експерти означава, че графичният процесор трябва да чете повече параметри от паметта, което значително увеличава натиска върху пропускателната способност на паметта. Тъй като фазата на декомпресия на големите езикови модели вече е ограничена от пропускателната способност на паметта, а не от изчислителната производителност, увеличаването на размера на пакета при еднозлово внедряване значително намалява скоростта на извеждане.
Сравнението на четирите многовъзлови конфигурации за внедряване (EP16, EP32, EP64 и EP128) разкрива, че по-високите стойности на EP изместват границата на Парето към едновременно подобрение на пропускателната способност и скоростта на извеждане.
Използването на по-висок номер на EP означава, че на всеки графичен процесор се разпределят по-малко експерти. Например EP128 означава, че всеки графичен процесор отговаря за 256 / 128 = 2 експерти, така че натискът върху пропускателната способност на паметта е значително намален. С други думи, използвайки по-голям номер на EP, ние ефективно печелим повече пропускателна способност на паметта. Когато размерът на пакета на графичен процесор е по-малък от 64, увеличаването на размера на пакета не влияе значително на скоростта на експертните изчисления, тъй като увеличаването на броя на входните данни не увеличава значително натиска върху пропускателната способност на паметта. Следователно забелязваме, че при използване на EP128 увеличаването на размера на пакета не влияе на скоростта на извеждане толкова съществено.
Интересно е, че при по-големи размери на пакетите (64 заявки на графичен процесор) наблюдавахме ново явление: пропускателната способност при еднозлово внедряване е малко по-висока от тази при многовъзловото внедряване. Част от причината е, че вътрешният NVLink има по-висока пропускателна способност от междинния InfiniBand. Друга част се дължи на ограничения в нашата реализация. Ще анализираме това явление по-подробно по-късно.
Поради ограниченията на капацитета на паметта конфигурацията EP8 DP8 TP1 не може да достигне размер на пакета 128 на графичен процесор, така че многовъзловото внедряване все още е по-добър избор в сценарии, преследващи по-висока пропускателна способност.
Припокриване на изчисленията и комуникацията
Както беше въведено накратко по-горе относно експертния паралелизъм, графичните процесори са в неизползвано състояние по време на комуникацията на MoE слоя. За да намалим разхищението и да намалим латентността, трябва да намерим независими от данните изчислителни задачи за запълване на това време на празен ход.
Горната част на горната фигура показва изчислителния поток на един слой. MoE изчисленията зависят от Dispatch, а изчисленията на следващия слой зависят от резултата от Combine.
Поставяме споделения експерт на всеки графичен процесор. По този начин изчисленията на споделения експерт не изискват AllToAll комуникация. Следователно можем да извършим изчисления на споделения експерт веднага след Dispatch Send, след което да изчакаме завършването на Dispatch Recv. Наричаме тази схема на припокриване „Dispatch Overlap“.
Dispatch Overlap предлага лесна реализация и широка приложимост. Тази техника скрива времето за изчисление на споделения експерт във всички размери на EP и размери на пакетите.
За да увеличим допълнително припокриването на изчисленията и комуникацията, използвахме микропартидиране, споменато в техническия доклад на DeepSeek, за да разбием зависимостта от данни. Както е показано в долната част на фигурата, разделихме изчислението на един Transformer слой на 5 етапа:
Етап 1: InputNorm, QKVProj, AppendKV, BMM
Етап 2: BMM, Attn, OProj, PostNorm, Gate
Етап 3: Dispatch Send, Shared Expert
Етап 4: Dispatch Recv, MoE, Combine Send
Етап 5: Combine Recv
В първите 3 плътни слоя Transformer използваме целия пакет. В следващите 58 MoE слоя Transformer разделяме равномерно пакета на два микропакета. Двата микропакета се изпълняват последователно, изместени с 3 етапа. Тъй като няма зависимост на данните между тези два микропакета, можем да преминем към изчислението на друг микропакет след Dispatch Send и след Combine Send.
Разпределение на латентността
След това сравняваме ефектите от припокриването чрез експеримент, както и сравняваме разликите в производителността между разгръщане на един възел EP8 и разгръщане на множество възли EP128. За по-лесно сравнение използвахме H100 GPU за следния експеримент. Използвахме TP1, размер на партидата от 128 на GPU, дължина на заявката от 2 на заявка и дължина на KV Cache от 5000.
Фигурата по-горе показва общото време, отделено за един MoE Transformer слой, и дела на латентността на различните видове ядра. С изключение на Dispatch, Combine и GroupGEMM, времето за изпълнение на другите ядра трябва да бъде еднакви в сериите EP8, EP128 NoOverlap и EP128 DispatchOverlap, тъй като размерът на пакета е същият.
Припокриване
Нека първо сравним ефектите от трите метода на припокриване. NoOverlap отне общо 2667 µs, DispatchOverlap отне 2651 µs, спестявайки 16 µs или само 0.6%. MicroBatch показа много значително подобрение, като отне 1896 µs, което е ускорение с 29%. Времето за Dispatch и Combine бе значително намалено. Dispatch намаля от 593 µs на 367 µs, а Combine от 1012 µs на 237 µs.
Имайте предвид, че за изчислителните ядра разделянето на пакет с размер 128 на два пакета с размер 64 увеличава общото време за изпълнение. Следователно, въпреки че времето, отделено за комуникация, намаля с 1001 µs, общото време намаля само със 771 µs. Ще обясним причината, като използваме модела Roofline в следващия раздел.
Поради тази причина микропакетирането не винаги подобрява производителността.
Фигурата по-горе показва подобрението на производителността на Microbatch в сравнение с DispatchOverlap за размери на пакетите 4-128. Когато размерът на пакета е по-малък от 32, Microbatch намалява производителността с 5%-40%. Когато размерът на пакета е по-голям или равен на 32, Microbatch може да подобри производителността с 10%-35%.
EP8 срещу EP128
Нека се върнем към предишната фигура и сравним EP8 и EP128 Microbatch. EP8 отне общо 1802 µs, малко по-малко от 1896 µs на EP128. Освен увеличения период на изпълнение на ядрата, донесен от споменатия по-горе Microbatch, основните разлики са в GroupGEMM, използван за MoE изчисления, и двете комуникационни ядра, Dispatch и Combine.
GroupGEMM на EP8 отне 555 µs, докато GroupGEMM на EP128 отне 270 µs, което е намаление наполовина. Това е основното предимство на многовъзловото внедряване.
За съжаление времето, отделено за комуникация, се увеличи с 213 µs, което до голяма степен компенсира предимството на GroupGEMM. В отделни тестове на производителността на нашите комуникационни ядра установихме, че те могат да постигнат само половината от пропускателната способност на InfiniBand. Ще продължим да оптимизираме нашите комуникационни ядра.
Друго ядро, което изостава значително, е GEMM. Microbatch увеличи GEMM с 95 µs. Ще анализираме GEMM по-задълбочено в раздела Roofline по-долу. Вярваме, че текущата реализация на GEMM все още не е постигнала оптимална производителност.
Roofline
Моделът Roofline е добър инструмент за анализ на производителността на ядрата. Неговата хоризонтална ос е аритметичен интензитет, съотношението на FLOP към байтовете за I/O на паметта. Стойността на хоризонталната ос може да се изчисли директно от семантиката на ядрото. Вертикалната ос представлява постигнатата производителност, изчислена чрез разделяне на FLOP на латентността на бенчмарка.
Теоретичната горна граница на производителността на ядрото се определя директно от спецификациите на графичния процесор. Пиковата производителност FP8 на H100 е 1979 TFLOP/s, представена като хоризонтална линия в модела Roofline. Пропускателната способност на паметта на H100 е 3.35 TB/s, представена като наклона на линия, преминаваща през началото на координатната система. Двете линии дават ограниченията на производителността съответно за ядра, ограничени от изчисленията, и ядра, ограничени от паметта.
По-долу обсъждаме производителността на ядрата GroupGEMM и GEMM.
GroupGEMM
Ядрото GroupGEMM в MoE извършва следното изчисление: Има общо g групи, i-тата група има m_i токена, извършвайки матрично умножение на [m_i, k] x [k, n] -> [m_i, n]. При тестването на производителността приемаме, че броят на токените във всяка група е еднакъв, обозначаван като m_i = m. Тогава броят на операциите с плаваща запетая (FLOP) за GroupGEMM е 2 * g * m * k * n, а байтовете за I/O на паметта са g * (m * k + n * k + m * n).
В модела DeepSeek-V3/R1 има 256 експерти и всеки токен се разпределя към 8 експерти за изчисление. Приемайки размер на пакета 128, дължина на заявката 2, използвайки конфигурация EP128 DP128, средният брой токени, получени от всеки експерт (т.е. m), е 128 * 2 * 8 * 128 / 256 = 1024. По същия начин можем да изчислим m за други конфигурации и размери на пакетите.
Използвахме имплементацията GroupGEMM на DeepGEMM за тестване на производителността. Тестовите точки обхващаха комбинации от конфигурации EP8, EP16, EP32, EP64, EP128 с TP1 и размери на партидата 1-128.
Фигурата по-горе показва модела Roofline за GroupGEMM при различни конфигурации на EP. Различните EP съответстват на различен брой групи. Фигурата илюстрира почти припокриващи се линии на производителността, което показва, че производителността на GroupGEMM се определя предимно от общия брой токени (представен като g * m).
Звездите отбелязват точките с данни, съответстващи на размер на пакета 128 на графичен процесор за всяка конфигурация на EP. Сравнявайки тези маркирани със звезди точки с данни, можем да видим, че с увеличаването на EP (и едновременното увеличаване на DP), броят на токените на експерт m също се увеличава. При EP8 m=128, докато при EP128 m=2048.
С увеличаването на m аритметичният интензитет също се увеличава. В повечето конфигурации GroupGEMM е ограничен от пропускателната способност на паметта, така че увеличаването на m подобрява производителността.
GEMM
Ядрото GEMM съответства на Linear проекциите в модела, като например Q/K/V/O прожекция. За матрично умножение на [m, k] x [k, n] -> [m, n], броят на FLOP е 2 * m * k * n, а байтовете за I/O на паметта са m * k + n * k + m * n. Можем също така да тестваме латентността за размери на пакетите 1-128.
Фигурата по-горе показва модела Roofline за GEMM при различни EP конфигурации. Можем да видим, че производителността на GEMM е ограничена от пропускателната способност на паметта. С увеличаването на размера на пакета аритметичният интензитет също се увеличава, като по този начин се подобрява производителността.
Microbatch
Когато използваме микропакетиране, разделяме пакета равномерно на две части. От двете фигури по-горе можем да видим, че когато m стане m/2, ефективността на матричното умножение намалява. Следователно изпълнението на две матрични умножения с размер m/2 отнема повече време от изпълнението на едно матрично умножение с размер m.
Предсказване на множество токени
В цялата тази статия сме предположили използването на предсказване на множество токени (MTP) за спекулативно декодиране. MTP променя дължината на заявката на заявка от 1 на 2. За матричното умножение това е еквивалентно на промяна на m на m * 2, като по този начин се увеличава ефективността на матричното умножение. От друга страна, ако начертаем модела Roofline за MLA, ще установим, че увеличаването на дължината на заявката значително увеличава ефективността на MLA ядрото.
Следователно използването на MTP играе важна роля за ефективността на модела.
Реализация & оптимизации
В този раздел ще представим някои подробности относно реализацията и оптимизацията за нашия модел DeepSeek-V3/R1.
Квантуване
DeepSeek-V3/R1 е естествено обучен на FP8, използвайки схема за квантуване на блокове, с тегла, квантувани статично, и активации, квантувани в движение. Вместо статично изчисляване на мащабиращ фактор за канал или за матрица, мащабиращите форми се изчисляват през 128-елементни вектори за активации и 128x128 елементни плочки за матрици, което ограничава влошаването на точността поради квантуването.
В Perplexity разчитаме на комбинация от ядра CUDA и Triton за поддръжка на инференцията, като CUDA се използва за най-чувствителните към производителността и рядко променяни ядра (като внимание и GEMM), а Triton реализира широк спектър от ядра за активация, нормализиране и помощни ядра. Triton ни позволи бързо да адаптираме ядрата към схемата за квантуване на блокове.
За линейни и MoE слоеве комбинираме ядрата Deep GEMM с нашите собствени ядра Triton GEMM, тъй като забелязахме, че за определени размери на матриците и ниски размери на пакетите Split-K осигурява по-ниска латентност. Ако неквантуваният слой изпълнява умножение (M, K) x (K, N), той се нуждае от (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)) мащабиращ фактор за квантуване на блокове. За квантуване на блокове мащабиращите фактори за активации се изчисляват в движение, вместо да бъдат предварително калибрирани. Тъй като мащабиращите фактори за активация се агрегират само по измерението K, а не по измерението M, ядрата изискват само леки промени за поддръжка на схемата.
Активиращата функция SiLU, използвана от DeepSeek-V3/R1, изискваше съществени промени в подкрепа на графиката на CUDA, квантуването на блокове и динамично руртираните бройки токени. Квантуването на блокове може да бъде проблемно, тъй като въвежда хоризонтални редукции, но ядрото вече е разделило активациите по тяхното скрито измерение на блокове от 1024 елемента. В рамките на един блок тензорът за квантуване бе допълнително разделен на блокове от 128 за изчисляване на най-голямата абсолютна стойност, като Triton генерира ефективни максимални редукции между warp-овете, добавяйки минимални режийни разходи.
За да се поддържа MoE руртиране при графики на CUDA, ядрата трябва да са наясно с информацията за руртиране, указваща броя на токените за експерт, вместо да планират работа въз основа на размера на буферите, които са били заделени за задържане на горната граница на броя на токените. Не можем да раздетим проблема въз основа на размерите на входния тензор, затова стартираме фиксиран брой постоянни ядра, които четат информацията за руртиране, за да определят колко токени са населени и разделят работата по обработката на активациите между тях динамично.
Вече сме интегрирали някои от нашите ядра в проекта FlashInfer и в бъдеще ще предоставим още от нашия код като софтуер с отворен код.
Слой MLA
Използваме FlashInfer за изчисление на MLA. FlashInfer поддържа гъвкави настройки на Page Table и изключително висока производителност.
Обединихме q_a_proj и kv_a_proj в едно qkv_a_proj. Латентността намаля от 15.4 µs + 14.8 µs = 30.2 µs на 16.7 µs.
Разложихме kv_b_proj на две матрици, k_b_proj и v_b_proj. Написахме FP8 блок квантувано ядро BMM за изчисления, свързани с тези две матрици.
Графика на Cuda
Графиката на Cuda може значително да намали режийните разходи за стартиране на ядра, което е от решаващо значение за производителността. Създаваме графика на Cuda за всеки размер на пакета.
Преди да разработим нашето ядро AllToAll, използвахме torch.all_to_all_single() за комуникация AllToAll. Тази операция изисква всички графични процесори да използват един и същ размер на пакета. Въпреки това различните DP групи могат да работят с различни размери на пакетите.
За да се гарантира, че all_to_all_single() е съвместим с различни DP групи, използващи различни размери на пакетите, първо използвахме операция allreduce() преди всяко стартиране на модела, за да получим максималния размер на пакета сред всички DP групи. След това накарахме всички DP групи да използват този размер на пакета за работа.
Въпреки че този подход гарантира, че можем да използваме графика на Cuda, той има три недостатъка. Първо, той изисква допълнителна операция allreduce(). Второ, DP групите с по-малки размери на пакетите са принудени да правят падване. Трето, той прави кода на нашата реализация сложен.
След като реализирахме собствено ядро AllToAll, вече не изискваме всички графични процесори да използват един и същ размер на пакета. Следователно вече не е нужно да извършваме допълнителни операции allreduce() или да правим падване на размерите на пакетите.
Маршрутизатор MoE
Маршрутизаторът MoE е реализиран в Triton, разчитайки на модифицирано сортиране, производно от стандартната библиотека, което също така следи индексите на сортираните елементи. Реализацията се споделя между всички MoE модели, тъй като руртирането на Mixtral е специален случай на маршрутите на DeepSeek, където групата Top-K е същата като групата на всички експерти. Редките ядра консумират индексите и резултатите на Top-K директно, докато плътните схеми за разпределение/комбиниране, разчитащи на All-to-all, изискват информацията за руртиране да бъде агрегирана по експерт, вместо на базата на токен.
Бъдеща работа
В бъдеща работа планираме допълнително да оптимизираме производителността на модела DeepSeek.
Най-важната следваща оптимизация е дезагрегирането на предварителното попълване (Prefill Disaggregation). Фазата на предварително попълване (Prefill) и фазата на декодиране на модела DeepSeek-V3/R1 имат много различни изчислителни характеристики. И двете могат да използват различни стратегии за оптимизация и схеми за внедряване.
За слоя MLA, във фазата на декодиране, използваме абсорбция на матрици, за да намалим броя на FLOP за изчисленията на MLA. Във фазата на предварително попълване проектирането на латентния вектор в K/V пространство първо и след това изчислението във форма на многоглаво внимание (MHA) би се представило по-добре.
Ако предварителното попълване и декодирането работят на един и същ графичен процесор, за да се намали въздействието на предварителното попълване върху скоростта на извеждане при декодиране, обикновено използваме сегментирано предварително попълване за разделяне на заявката на множество сегменти за предварително попълване. Тъй като KV кешът съхранява латентния вектор, става трудно да се конвертира MLA във форма MHA.
За слоя MoE, във фазата на декодиране, използваме възможно най-големи EP и DP, за да увеличим броя на входните токени за експерт, като по този начин подобряваме производителността на GroupGEMM. Във фазата на предварително попълване, тъй като броят на токените вече е достатъчно голям, GroupGEMM вече е ограничен от изчисленията. Следователно за предварителното попълване можем да използваме по-малки EP и DP.
Ако предварителното попълване и декодирането работят на един и същ графичен процесор, докато която и да е DP група извършва предварително попълване, латентността на слоевете MoE на всички графични процесори ще се увеличи, което значително ще засегне скоростта на извеждане при декодиране.
Освен дезагрегирането на предварителното попълване, планираме да оптимизираме и следните аспекти:
Производителност на AllToAll: Нашето ядро AllToAll в момента може да постигне само 1/3 от пропускателната способност на InfiniBand. Ще продължим да оптимизираме това ядро.
Спекулативно декодиране в стил EAGLE: В горните данни предположихме използване на спекулативно декодиране за предсказване на 1 токен. EAGLE може да използва дървовидна структура за предсказване на множество токени, подобрявайки дължината на приемане, което може значително да увеличи скоростта на извеждане.
Ядро GEMM: В модела Roofline, показан по-рано, можем да установим, че ефективността на ядрото GEMM все още е далеч от теоретичната граница. Ще продължим да оптимизираме това ядро.
GB200 NVL72: В най-новото решение GB200 NVL72 на NVIDIA, 72 графични процесора Blackwell са свързани помежду си чрез високоскоростен NVLink. За модели с MoE архитектура това е много голяма възможност и предизвикателство.
Заключение
Многовъзловото внедряване на MoE модели DeepSeek постига това, което обикновено е невъзможно с плътни LLM: едновременно подобряване както на пропускателната способност, така и на латентността. Чрез разпределяне на експертите между повече графични процесори намаляваме натиска върху пропускателната способност на паметта за устройство, което позволява по-бърза обработка и по-висока пропускателна способност на системата. Нашите експерименти показват конфигурации EP128, постигащи до 5 пъти по-висока пропускателна способност при еквивалентни скорости на извеждане в сравнение с еднозлови внедрявания.
Техниките за припокриване на изчисленията и комуникацията като микропакетирането значително намаляват комуникационните режийни разходи при многовъзлово внедряване, като нашата реализация показва до 40% ускорение. Нашите персонализирани комуникационни ядра AllToAll и оптимизираните реализации на ядра позволиха ефективното внедряване на модела с 671B параметри.
Тъй като MoE архитектурите печелят популярност заради своите възможности, тези стратегии за внедряване предоставят ценни прозрения за ефективното мащабиране на такива модели.
Реферати
Технически доклад за DeepSeek-V3
Преглед на системата за инференция DeepSeek-V3/R1
EAGLE: Спекулативното вземане на проби изисква преосмисляне на несигурността на характеристиките
Цитиране
@online{perplexity2025LowerLatencyAndHigherThroughputWithMultiNodeDeepseekDeployment,
author = {{Perplexity} and Lequn Chen and Nandor Licker and Erin McKnight},
title = {{Lower latency and higher throughput with multi-node DeepSeek deployment}},
date = {2025-04-18},
url = {https://perplexity.coolkeypoint.com/hub/blog/lower-latency-and-higher-throughput-with-multi-node-deepseek-deployment}
}