TGViewer
Марков цепи пропил Марков цепи пропил @markovdrankthechains · 3.4K subscribers
Post #281 3.3K
Дальше пошла оптимизация cycles/token

Тут вся работа свелась к тому, чтобы attention перестал быть последовательным куском логики, потому что именно он съедал большую часть циклов.

Первое что переехало это сами matvec'и. Раньше matvec_fp16 ел по одному int8-весу за такт через 8-битный weight bus, и QKV с proj шарили этот bus через мультиплексор. Сейчас стоит matvec_fp16_w32 (и w16 для head_proj), который читает по 32 веса за такт из своего weight_store, а qkv и proj получили свои отдельные банки и могут работать параллельно, не толкаясь за один порт.

Дальше пошел score внутри attn head (Q*K). K cache отдает 4 fp16-позиции за одно чтение, над ним стоят четыре fp16_mul, которые делят один q_head[dim], и за такт получаем 4 произведения Q*K вместо одного. Дальше эти произведения нужно складывать по dim, и тут возникает обычная для fp16-арифметики проблема: fp16_add имеет 4-тактную обратную связь, и если складывать в один аккумулятор, то получается одно сложение раз в 4 такта. Поэтому вместо одного аккумулятора стоят 16 fp16_reduce_k8 в 4-way ping-pong (4 позиционных lane'а на 4 фазы pair_idx). A берет каждый четвертый quad (0, 4, 8...), B следующий (1, 5, 9...), C (2, 6, 10...), D (3, 7, 11...). Пока A досчитывает свой quad, B уже принимает следующий, потом C, потом D, и к моменту когда снова доходит очередь до A, его 4-тактная задержка уже прошла. Так держится throughput одно сложение за такт на lane.

AV устроен похоже, четыре fp16_mul читают 4 V-вектора из одного 64-битного чтения, дальше balanced add tree и один аккумулятор av_acc[d].

Самое жирное это параллелизм между attn heads. Инстансов softmax два (u_sm_a для четных, u_sm_b для нечетных), и за ними два ping-pong attn_buf'а. Score sub-FSM и AV sub-FSM крутятся независимо: пока AV ест выходы attn head N из attn_buf_a, score уже стреляет dot-product'ами для attn head N+1 в u_sm_b, который пишет в attn_buf_b. K и V в кэше имеют раздельные адреса чтения ровно для этого, чтобы score (читает K) и AV (читает V) не дрались за порт. Pipeline depth ограничен через scored_count - av_done_count <= 2, чтобы score attn head N+2 не начал перезаписывать буфер, который AV еще читает для attn head N.

Из мелкого еще дописал нормальный сэмплер вместо argmax'а: логиты умножаются на inv_temp с repetition penalty, уходят в softmax, top-k выбирается через compare tree, дальше multinomial draw через CDF-walk. Источник энтропии 16-битный Fibonacci LFSR (потому что Mersenne Twister и Philox на один сэмпл в такт это перебор для такой модели мне было лень).

Тащем-то, ответ на главный вопрос: “сколько токенов”? Эта чилслодробилка выдает примерно 1100 токенов в секунду на 854k W8A16, но потенциально может и больше, если добавить еще параллельных вычислений и обработки весов за раз
  • 🔥 27
More from @markovdrankthechains
  1. Oct 8, 2026Недавно для себя открыл, что приём из CUDA C Best Practices работает и на чипах Apple Ядро…
  2. Oct 6, 2026Господа, позвольте представить вам европейские датацентры
  3. Sep 23, 2026photo post
  4. Sep 21, 2026https://www.educate.elsevier.com/book/details/9780443439001
  5. Sep 21, 2026Ладно, пойду траву потрогаю
  6. Sep 21, 2026В общем, забавный факт. Как мы знаем, у кварцевых часов есть погрешность, которой обычно м…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →