| 933 | |
| 934 | template<typename T> |
| 935 | void BlockMHA::_attention_impl( |
| 936 | InferenceState& s, int pos, int kv_sink, int kv_pos, int kv_len |
| 937 | ) const { |
| 938 | PROFILE_BLOCK(attn_mha); |
| 939 | const Config& c = *_config; |
| 940 | |
| 941 | // qkv matmuls for this position |
| 942 | if (c.q_lora_rank > 0) { |
| 943 | PROFILE(matmul(s.q_a(), s.xb(), *wq_a(), c.block_size.data(), _sq_a, s.aqb())); |
| 944 | switch (c.norm_type) { |
| 945 | case LayerNormType::RMSNorm: { |
| 946 | rmsnorm(s.q_a(), s.q_a(), this->rms_q_a_weight(), c.q_lora_rank, c.norm_eps); |
| 947 | break; |
| 948 | } |
| 949 | } |
| 950 | PROFILE(matmul(s.q(), s.q_a(), *wq_b(), c.block_size.data(), _sq_b, s.aqb())); |
| 951 | } else { |
| 952 | PROFILE(matmul(s.q(), s.xb(), *wq(), c.block_size.data(), _sq, s.aqb())); |
| 953 | } |
| 954 | PROFILE(matmul(s.kv_a(), s.xb(), *wkv_a(), c.block_size.data(), _skv_a, s.aqb())); |
| 955 | |
| 956 | // Apply RoPE positional encoding |
| 957 | int q_pe_offset = c.head_dim - c.qk_rope_head_dim; |
| 958 | bool is_v3 = c.has_moegate_bias; |
| 959 | for (int h = 0; h < c.n_heads; h++) { |
| 960 | if (is_v3) { |
| 961 | rope_v3(s.q(h) + q_pe_offset, c.qk_rope_head_dim, c.qk_rope_head_dim, pos, c.rope_theta); |
| 962 | } else { |
| 963 | rope(s.ropebuf(), s.q(h) + q_pe_offset, c.qk_rope_head_dim, c.qk_rope_head_dim, pos, c.rope_theta); |
| 964 | } |
| 965 | } |
| 966 | int kv_pe_offset = c.kv_lora_rank; |
| 967 | float* k_rope = s.kv_a() + kv_pe_offset; |
| 968 | if (is_v3) { |
| 969 | rope_v3(k_rope, c.qk_rope_head_dim, c.qk_rope_head_dim, pos, c.rope_theta); |
| 970 | } else { |
| 971 | rope(s.ropebuf(), k_rope, c.qk_rope_head_dim, c.qk_rope_head_dim, pos, c.rope_theta); |
| 972 | } |
| 973 | // rms norm to non-pe chunk of kv_a |
| 974 | rmsnorm(s.kv_a(), s.kv_a(), this->rms_kv_a_weight(), c.kv_lora_rank, c.norm_eps); |
| 975 | // un-compress the latent kv via multiplication with wkv_b |
| 976 | int qk_nope_head_dim = c.head_dim - c.qk_rope_head_dim; |
| 977 | PROFILE(matmul(s.kv_b(), s.kv_a(), *wkv_b(), c.block_size.data(), _skv_b, s.aqb())); |
| 978 | // concatenate kv_b and k_rope in each head to build key heads |
| 979 | for (int h = 0; h < c.n_heads; h++) { |
| 980 | for (int i = 0; i < qk_nope_head_dim; i++) { |
| 981 | s.k(h)[i] = s.kv_b(h)[i]; |
| 982 | } |
| 983 | for (int i = 0; i < c.qk_rope_head_dim; i++) { |
| 984 | s.k(h)[qk_nope_head_dim + i] = k_rope[i]; |
| 985 | } |
| 986 | } |
| 987 | // transfer value heads from kv_b |
| 988 | for (int h = 0; h < c.n_heads; h++) { |
| 989 | for (int i = 0; i < c.v_head_dim; i++) { |
| 990 | s.v(h)[i] = s.kv_b(h)[qk_nope_head_dim + i]; |
| 991 | } |
| 992 | } |
nothing calls this directly
no test coverage detected