Download faie_kernel.py from abuz8studios/FAIE: direct link, hf CLI and curl.
- Browser
- Download file 29.9 kB
-
https://huggingface.co/abuz8studios/FAIE/resolve/main/faie_kernel.py
- Command line
-
hf download hf://abuz8studios/FAIE/faie_kernel.py
-
curl -L -o faie_kernel.py https://huggingface.co/abuz8studios/FAIE/resolve/main/faie_kernel.py
29.9 kB
| """ | |
| FAIE CUDA Ternary Matmul Kernel -- Path 1. | |
| Custom CUDA kernel that reads packed ternary weights (2 bits/value) | |
| directly on GPU, avoiding the 6.4x overhead of FP16 dequantization. | |
| Compiled: nvcc -shared -O3 --use_fast_math -arch=sm_120 -o ternary_kernel.dll ternary_kernel.cu | |
| Loaded via ctypes, called with raw GPU pointers from PyTorch tensors. | |
| """ | |
| import os | |
| import sys | |
| import time | |
| import ctypes | |
| import numpy as np | |
| import torch | |
| import torch.nn.functional as F | |
| from faie import TernaryCompressor | |
| DEVICE = torch.device('cuda:0') | |
| KERNEL_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| def load_kernel(): | |
| """Load the compiled CUDA ternary kernel DLL.""" | |
| dll_path = os.path.join(KERNEL_DIR, "ternary_kernel.dll") | |
| if not os.path.exists(dll_path): | |
| raise FileNotFoundError(f"Kernel not compiled: {dll_path}") | |
| lib = ctypes.CDLL(dll_path) | |
| lib.ternary_matvec.argtypes = [ | |
| ctypes.c_void_p, # packed_W | |
| ctypes.c_void_p, # scales | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # y | |
| ctypes.c_int, # out_features | |
| ctypes.c_int, # in_features | |
| ctypes.c_int, # group_size | |
| ] | |
| lib.ternary_matvec.restype = None | |
| lib.ternary_expert_forward.argtypes = [ | |
| ctypes.c_void_p, # gate_packed | |
| ctypes.c_void_p, # gate_scales | |
| ctypes.c_void_p, # up_packed | |
| ctypes.c_void_p, # up_scales | |
| ctypes.c_void_p, # down_packed | |
| ctypes.c_void_p, # down_scales | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # gate_buf | |
| ctypes.c_void_p, # up_buf | |
| ctypes.c_void_p, # y | |
| ctypes.c_int, # gate_out | |
| ctypes.c_int, # gate_in | |
| ctypes.c_int, # down_out | |
| ctypes.c_int, # down_in | |
| ctypes.c_int, # group_size | |
| ] | |
| lib.ternary_expert_forward.restype = None | |
| lib.q2k_matvec.argtypes = [ | |
| ctypes.c_void_p, # W (raw Q2_K bytes on GPU) | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # y | |
| ctypes.c_int, # n_rows | |
| ctypes.c_int, # in_features | |
| ] | |
| lib.q2k_matvec.restype = None | |
| lib.q3k_matvec.argtypes = [ | |
| ctypes.c_void_p, # W (raw Q3_K bytes on GPU) | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # y | |
| ctypes.c_int, # n_rows | |
| ctypes.c_int, # in_features | |
| ] | |
| lib.q3k_matvec.restype = None | |
| lib.expert_swiglu.argtypes = [ | |
| ctypes.c_void_p, # gate_W | |
| ctypes.c_void_p, # up_W | |
| ctypes.c_void_p, # down_W | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # gate_buf | |
| ctypes.c_void_p, # up_buf | |
| ctypes.c_void_p, # y | |
| ctypes.c_int, # gate_rows | |
| ctypes.c_int, # gate_in | |
| ctypes.c_int, # down_rows | |
| ctypes.c_int, # down_in | |
| ctypes.c_int, # gate_qtype (0=Q2K, 1=Q3K) | |
| ctypes.c_int, # down_qtype | |
| ] | |
| lib.expert_swiglu.restype = None | |
| lib.batched_expert_swiglu.argtypes = [ | |
| ctypes.c_void_p, # gate_ptrs (host array of device pointers) | |
| ctypes.c_void_p, # up_ptrs | |
| ctypes.c_void_p, # down_ptrs | |
| ctypes.c_void_p, # weights (device float array) | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # gate_buf | |
| ctypes.c_void_p, # up_buf | |
| ctypes.c_void_p, # y | |
| ctypes.c_void_p, # temp_buf | |
| ctypes.c_int, # n_experts | |
| ctypes.c_int, # gate_rows | |
| ctypes.c_int, # gate_in | |
| ctypes.c_int, # down_rows | |
| ctypes.c_int, # down_in | |
| ctypes.c_int, # gate_qtype | |
| ctypes.c_int, # down_qtype | |
| ] | |
| lib.batched_expert_swiglu.restype = None | |
| lib.cuda_rms_norm.argtypes = [ | |
| ctypes.c_void_p, # x | |
| ctypes.c_void_p, # w | |
| ctypes.c_void_p, # out | |
| ctypes.c_int, # n | |
| ] | |
| lib.cuda_rms_norm.restype = None | |
| lib.cuda_weighted_add.argtypes = [ | |
| ctypes.c_void_p, # y | |
| ctypes.c_void_p, # src | |
| ctypes.c_float, # weight | |
| ctypes.c_int, # n | |
| ] | |
| lib.cuda_weighted_add.restype = None | |
| lib.cuda_zero.argtypes = [ | |
| ctypes.c_void_p, # buf | |
| ctypes.c_int, # n | |
| ] | |
| lib.cuda_zero.restype = None | |
| lib.moe_router_topk.argtypes = [ | |
| ctypes.c_void_p, # router_W (device fp16) | |
| ctypes.c_void_p, # bias (device fp32 or NULL) | |
| ctypes.c_void_p, # x (device fp32) | |
| ctypes.c_void_p, # router_buf (device fp32) | |
| ctypes.c_void_p, # topk_vals_buf (device fp32) | |
| ctypes.c_void_p, # topk_ids_buf (device int32) | |
| ctypes.c_int, # n_experts | |
| ctypes.c_int, # hidden_dim | |
| ctypes.c_int, # top_k | |
| ctypes.c_void_p, # host_ids (HOST int32) | |
| ctypes.c_void_p, # host_vals (HOST float32) | |
| ] | |
| lib.moe_router_topk.restype = None | |
| lib.fused_moe_experts.argtypes = [ | |
| ctypes.c_void_p, ctypes.c_int, # norm_buf, hidden_dim | |
| ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, # sh_gate, sh_up, sh_down | |
| ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, # sh dims+qt | |
| ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, # eg, eu, ed ptrs | |
| ctypes.c_void_p, ctypes.c_int, # weights, n_exp | |
| ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, # exp dims+qt | |
| ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, # gate_buf, expert_out, temp_buf, x | |
| ] | |
| lib.fused_moe_experts.restype = None | |
| lib.fused_attention_layer.argtypes = [ | |
| ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, # x, hidden_dim, anorm | |
| ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, # qa: W,R,I,Qt | |
| ctypes.c_void_p, ctypes.c_int, # qaNorm, qaNormN | |
| ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, # qb: W,R,I,Qt | |
| ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, # kva: W,R,I,Qt | |
| ctypes.c_void_p, ctypes.c_int, # kvaNorm, kvaNormN | |
| ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, # out: W,R,I,Qt | |
| ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, # bufs | |
| ] | |
| lib.fused_attention_layer.restype = None | |
| lib.sync_device.argtypes = [] | |
| lib.sync_device.restype = None | |
| lib.begin_graph_capture.argtypes = [] | |
| lib.begin_graph_capture.restype = None | |
| lib.end_graph_capture.argtypes = [ctypes.c_int] | |
| lib.end_graph_capture.restype = ctypes.c_int | |
| lib.replay_graph.argtypes = [ctypes.c_int] | |
| lib.replay_graph.restype = None | |
| VP = ctypes.c_void_p | |
| lib.register_expert.argtypes = [ctypes.c_int, ctypes.c_int, VP, VP, VP] | |
| lib.register_expert.restype = None | |
| lib.register_moe_layer.argtypes = [ | |
| ctypes.c_int, | |
| VP, VP, VP, VP, VP, VP, | |
| ctypes.c_int, ctypes.c_int, ctypes.c_int, | |
| VP, VP, VP, | |
| ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, | |
| ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, | |
| ] | |
| lib.register_moe_layer.restype = None | |
| lib.full_moe_layer.argtypes = [VP, ctypes.c_int, VP, VP, VP] | |
| lib.full_moe_layer.restype = None | |
| lib.upload_expert_table.argtypes = [ctypes.c_int, VP] | |
| lib.upload_expert_table.restype = None | |
| lib.full_moe_layer_nosync.argtypes = [VP, ctypes.c_int, VP, VP, VP] | |
| lib.full_moe_layer_nosync.restype = None | |
| lib.capture_moe_preamble.argtypes = [ctypes.c_int, VP, VP, VP, VP] | |
| lib.capture_moe_preamble.restype = ctypes.c_int | |
| lib.full_moe_layer_v2.argtypes = [VP, ctypes.c_int, VP, VP, VP] | |
| lib.full_moe_layer_v2.restype = None | |
| # MLA attention with compressed KV cache | |
| I, F = ctypes.c_int, ctypes.c_float | |
| lib.mla_attention.argtypes = [ | |
| VP, I, VP, # x, hidden_dim, anorm | |
| VP, I, I, I, VP, # q_a W/rows/in/qt, q_a_norm | |
| VP, I, I, I, # q_b | |
| VP, I, I, I, VP, # kv_a, kv_a_norm | |
| VP, VP, # k_b, v_b (fp16) | |
| VP, I, I, I, # out proj | |
| VP, VP, I, I, # c_cache, kr_cache, pos, max_seq | |
| VP, VP, VP, VP, # normB, qaB, qbB, kvaB | |
| VP, VP, VP, VP, VP, # qcB, scoreB, ocB, headB, attnB | |
| I, I, I, I, I, F, # n_heads, qk_nope, qk_rope, kv_lora, v_head, rope_base | |
| ] | |
| lib.mla_attention.restype = None | |
| # Route / miss logging + residency counters | |
| lib.set_route_logging.argtypes = [I] | |
| lib.drain_route_log.argtypes = [ctypes.POINTER(I), I] | |
| lib.drain_route_log.restype = I | |
| lib.get_route_dropped.restype = ctypes.c_longlong | |
| lib.get_experts_requested.restype = ctypes.c_longlong | |
| lib.get_experts_executed.restype = ctypes.c_longlong | |
| return lib | |
| class CompressedMatvec: | |
| """GPU matvec on raw Q2_K / Q3_K data β zero dequant overhead.""" | |
| def __init__(self, kernel_lib): | |
| self.lib = kernel_lib | |
| def q2k(self, W_gpu, x_gpu, y_gpu, n_rows, in_features): | |
| self.lib.q2k_matvec( | |
| ctypes.c_void_p(W_gpu.data_ptr()), | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| n_rows, in_features) | |
| def q3k(self, W_gpu, x_gpu, y_gpu, n_rows, in_features): | |
| self.lib.q3k_matvec( | |
| ctypes.c_void_p(W_gpu.data_ptr()), | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| n_rows, in_features) | |
| def expert_swiglu(self, gw, uw, dw, x_gpu, gate_buf, up_buf, y_gpu): | |
| gqt = 0 if "Q2" in gw["qtype"] else 1 | |
| dqt = 0 if "Q2" in dw["qtype"] else 1 | |
| self.lib.expert_swiglu( | |
| ctypes.c_void_p(gw["gpu"].data_ptr()), | |
| ctypes.c_void_p(uw["gpu"].data_ptr()), | |
| ctypes.c_void_p(dw["gpu"].data_ptr()), | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(gate_buf.data_ptr()), | |
| ctypes.c_void_p(up_buf.data_ptr()), | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| gw["n_rows"], gw["in_features"], | |
| dw["n_rows"], dw["in_features"], | |
| gqt, dqt) | |
| def batched_expert_swiglu(self, expert_list, weights_host, x_gpu, | |
| gate_buf, up_buf, y_gpu, temp_buf): | |
| """Run N experts in ONE C call. expert_list = [(gw,uw,dw), ...] | |
| weights_host = list of N float weights (Python floats, NOT GPU tensor).""" | |
| n = len(expert_list) | |
| if n == 0: | |
| return | |
| PtrArray = ctypes.c_void_p * n | |
| gate_ptrs = PtrArray(*[e[0]["gpu"].data_ptr() for e in expert_list]) | |
| up_ptrs = PtrArray(*[e[1]["gpu"].data_ptr() for e in expert_list]) | |
| down_ptrs = PtrArray(*[e[2]["gpu"].data_ptr() for e in expert_list]) | |
| FloatArray = ctypes.c_float * n | |
| wts = FloatArray(*weights_host) | |
| gw0 = expert_list[0][0] | |
| dw0 = expert_list[0][2] | |
| gqt = 0 if "Q2" in gw0["qtype"] else 1 | |
| dqt = 0 if "Q2" in dw0["qtype"] else 1 | |
| self.lib.batched_expert_swiglu( | |
| ctypes.cast(gate_ptrs, ctypes.c_void_p), | |
| ctypes.cast(up_ptrs, ctypes.c_void_p), | |
| ctypes.cast(down_ptrs, ctypes.c_void_p), | |
| ctypes.cast(wts, ctypes.c_void_p), | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(gate_buf.data_ptr()), | |
| ctypes.c_void_p(up_buf.data_ptr()), | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| ctypes.c_void_p(temp_buf.data_ptr()), | |
| n, | |
| gw0["n_rows"], gw0["in_features"], | |
| dw0["n_rows"], dw0["in_features"], | |
| gqt, dqt) | |
| def rms_norm(self, x_gpu, w_gpu, out_gpu, n): | |
| self.lib.cuda_rms_norm( | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(w_gpu.data_ptr()), | |
| ctypes.c_void_p(out_gpu.data_ptr()), | |
| n) | |
| def weighted_add(self, y_gpu, src_gpu, weight, n): | |
| self.lib.cuda_weighted_add( | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| ctypes.c_void_p(src_gpu.data_ptr()), | |
| ctypes.c_float(weight), | |
| n) | |
| def zero(self, buf_gpu, n): | |
| self.lib.cuda_zero( | |
| ctypes.c_void_p(buf_gpu.data_ptr()), | |
| n) | |
| def router_topk(self, router_W, bias, x, router_buf, topk_vals_buf, topk_ids_buf, | |
| n_experts, hidden_dim, top_k, host_ids, host_vals): | |
| bias_ptr = ctypes.c_void_p(bias.data_ptr()) if bias is not None else ctypes.c_void_p(0) | |
| self.lib.moe_router_topk( | |
| ctypes.c_void_p(router_W.data_ptr()), | |
| bias_ptr, | |
| ctypes.c_void_p(x.data_ptr()), | |
| ctypes.c_void_p(router_buf.data_ptr()), | |
| ctypes.c_void_p(topk_vals_buf.data_ptr()), | |
| ctypes.c_void_p(topk_ids_buf.data_ptr()), | |
| n_experts, hidden_dim, top_k, | |
| ctypes.cast(host_ids, ctypes.c_void_p), | |
| ctypes.cast(host_vals, ctypes.c_void_p)) | |
| def init_moe_arrays(self, top_k): | |
| self._eg = (ctypes.c_void_p * top_k)() | |
| self._eu = (ctypes.c_void_p * top_k)() | |
| self._ed = (ctypes.c_void_p * top_k)() | |
| self._wts = (ctypes.c_float * top_k)() | |
| def fused_moe_fast(self, norm_buf, hidden_dim, | |
| sh_g_ptr, sh_u_ptr, sh_d_ptr, | |
| sh_inter, sh_in, sh_dr, sh_di, sh_gqt, sh_dqt, | |
| n_exp, e_inter, e_in, e_dr, e_di, e_gqt, e_dqt, | |
| gate_buf, expert_out, temp_buf, x): | |
| self.lib.fused_moe_experts( | |
| ctypes.c_void_p(norm_buf), hidden_dim, | |
| sh_g_ptr, sh_u_ptr, sh_d_ptr, | |
| sh_inter, sh_in, sh_dr, sh_di, sh_gqt, sh_dqt, | |
| ctypes.cast(self._eg, ctypes.c_void_p), ctypes.cast(self._eu, ctypes.c_void_p), | |
| ctypes.cast(self._ed, ctypes.c_void_p), | |
| ctypes.cast(self._wts, ctypes.c_void_p), n_exp, | |
| e_inter, e_in, e_dr, e_di, e_gqt, e_dqt, | |
| ctypes.c_void_p(gate_buf), ctypes.c_void_p(expert_out), | |
| ctypes.c_void_p(temp_buf), ctypes.c_void_p(x)) | |
| def fused_moe(self, norm_buf, hidden_dim, | |
| sh_gate, sh_up, sh_down, sh_inter, sh_in, sh_dr, sh_di, sh_gqt, sh_dqt, | |
| expert_triples, weights_list, | |
| e_inter, e_in, e_dr, e_di, e_gqt, e_dqt, | |
| gate_buf, expert_out, temp_buf, x): | |
| n = len(expert_triples) | |
| PtrArray = ctypes.c_void_p * n | |
| eg = PtrArray(*[t[0].data_ptr() for t in expert_triples]) | |
| eu = PtrArray(*[t[1].data_ptr() for t in expert_triples]) | |
| ed = PtrArray(*[t[2].data_ptr() for t in expert_triples]) | |
| FloatArray = ctypes.c_float * n | |
| wts = FloatArray(*weights_list) | |
| sh_g_ptr = ctypes.c_void_p(sh_gate.data_ptr()) if sh_gate is not None else ctypes.c_void_p(0) | |
| sh_u_ptr = ctypes.c_void_p(sh_up.data_ptr()) if sh_up is not None else ctypes.c_void_p(0) | |
| sh_d_ptr = ctypes.c_void_p(sh_down.data_ptr()) if sh_down is not None else ctypes.c_void_p(0) | |
| self.lib.fused_moe_experts( | |
| ctypes.c_void_p(norm_buf.data_ptr()), hidden_dim, | |
| sh_g_ptr, sh_u_ptr, sh_d_ptr, | |
| sh_inter, sh_in, sh_dr, sh_di, sh_gqt, sh_dqt, | |
| ctypes.cast(eg, ctypes.c_void_p), ctypes.cast(eu, ctypes.c_void_p), | |
| ctypes.cast(ed, ctypes.c_void_p), | |
| ctypes.cast(wts, ctypes.c_void_p), n, | |
| e_inter, e_in, e_dr, e_di, e_gqt, e_dqt, | |
| ctypes.c_void_p(gate_buf.data_ptr()), ctypes.c_void_p(expert_out.data_ptr()), | |
| ctypes.c_void_p(temp_buf.data_ptr()), ctypes.c_void_p(x.data_ptr())) | |
| def fused_attention(self, x, hidden_dim, anorm, | |
| qa_W, qa_R, qa_I, qa_qt, qa_norm, qa_norm_n, | |
| qb_W, qb_R, qb_I, qb_qt, | |
| kva_W, kva_R, kva_I, kva_qt, kva_norm, kva_norm_n, | |
| out_W, out_R, out_I, out_qt, | |
| norm_buf, qa_buf, qb_buf, kva_buf, attn_buf): | |
| def _p(t): return ctypes.c_void_p(t.data_ptr()) if t is not None else ctypes.c_void_p(0) | |
| self.lib.fused_attention_layer( | |
| _p(x), hidden_dim, _p(anorm), | |
| _p(qa_W), qa_R, qa_I, qa_qt, _p(qa_norm), qa_norm_n, | |
| _p(qb_W), qb_R, qb_I, qb_qt, | |
| _p(kva_W), kva_R, kva_I, kva_qt, _p(kva_norm), kva_norm_n, | |
| _p(out_W), out_R, out_I, out_qt, | |
| _p(norm_buf), _p(qa_buf), _p(qb_buf), _p(kva_buf), _p(attn_buf)) | |
| def _reshape_scales(scales, shape, group_size): | |
| """Reshape flat scales to [rows, groups_per_row] layout for the kernel.""" | |
| groups_per_row = (shape[1] + group_size - 1) // group_size | |
| out = np.zeros(shape[0] * groups_per_row, dtype=np.float32) | |
| for row in range(shape[0]): | |
| start_g = row * (shape[1] // group_size) | |
| for g in range(groups_per_row): | |
| src_idx = start_g + g | |
| dst_idx = row * groups_per_row + g | |
| if src_idx < len(scales): | |
| out[dst_idx] = scales[src_idx] | |
| return out | |
| class TernaryExpertCUDA: | |
| """Expert with packed ternary weights (SwiGLU: gate+up+down) via CUDA kernel.""" | |
| def __init__(self, gate_ternary, gate_scales, gate_shape, gate_gs, | |
| up_ternary, up_scales, up_shape, up_gs, | |
| down_ternary, down_scales, down_shape, down_gs, kernel_lib): | |
| self.lib = kernel_lib | |
| self.gate_shape = gate_shape | |
| self.up_shape = up_shape | |
| self.down_shape = down_shape | |
| self.group_size = gate_gs | |
| gate_packed, self.gate_n = TernaryCompressor.pack_ternary(gate_ternary) | |
| up_packed, self.up_n = TernaryCompressor.pack_ternary(up_ternary) | |
| down_packed, self.down_n = TernaryCompressor.pack_ternary(down_ternary) | |
| self.gate_packed_gpu = torch.from_numpy(gate_packed).to(DEVICE) | |
| self.up_packed_gpu = torch.from_numpy(up_packed).to(DEVICE) | |
| self.down_packed_gpu = torch.from_numpy(down_packed).to(DEVICE) | |
| self.gate_scales_gpu = torch.from_numpy(_reshape_scales(gate_scales, gate_shape, gate_gs)).to(DEVICE) | |
| self.up_scales_gpu = torch.from_numpy(_reshape_scales(up_scales, up_shape, up_gs)).to(DEVICE) | |
| self.down_scales_gpu = torch.from_numpy(_reshape_scales(down_scales, down_shape, down_gs)).to(DEVICE) | |
| self.gate_buf = torch.zeros(gate_shape[0], dtype=torch.float32, device=DEVICE) | |
| self.up_buf = torch.zeros(up_shape[0], dtype=torch.float32, device=DEVICE) | |
| self.output_buf = torch.zeros(down_shape[0], dtype=torch.float32, device=DEVICE) | |
| self.gpu_bytes = (len(gate_packed) + len(up_packed) + len(down_packed) + | |
| self.gate_scales_gpu.numel() * 4 + self.up_scales_gpu.numel() * 4 + | |
| self.down_scales_gpu.numel() * 4) | |
| self.fp16_equivalent_bytes = (np.prod(gate_shape) + np.prod(up_shape) + np.prod(down_shape)) * 2 | |
| def from_faie_file(cls, expert_path, kernel_lib): | |
| """Load from a v2 FAIE binary file.""" | |
| from faie_convert import read_faie_expert | |
| data = read_faie_expert(expert_path) | |
| if data is None: | |
| raise ValueError(f"Invalid FAIE file: {expert_path}") | |
| gs = data["group_size"] | |
| gate_t = TernaryCompressor.unpack_ternary(data["gate_packed"], data["gate_n"]) | |
| up_t = TernaryCompressor.unpack_ternary(data["up_packed"], data["up_n"]) | |
| down_t = TernaryCompressor.unpack_ternary(data["down_packed"], data["down_n"]) | |
| return cls(gate_t, data["gate_scales"], data["gate_shape"], gs, | |
| up_t, data["up_scales"], data["up_shape"], gs, | |
| down_t, data["down_scales"], data["down_shape"], gs, | |
| kernel_lib) | |
| def forward(self, x): | |
| """SwiGLU expert forward: down(SiLU(gate(x)) * up(x)).""" | |
| x_flat = x.squeeze().float().contiguous() | |
| self.lib.ternary_expert_forward( | |
| ctypes.c_void_p(self.gate_packed_gpu.data_ptr()), | |
| ctypes.c_void_p(self.gate_scales_gpu.data_ptr()), | |
| ctypes.c_void_p(self.up_packed_gpu.data_ptr()), | |
| ctypes.c_void_p(self.up_scales_gpu.data_ptr()), | |
| ctypes.c_void_p(self.down_packed_gpu.data_ptr()), | |
| ctypes.c_void_p(self.down_scales_gpu.data_ptr()), | |
| ctypes.c_void_p(x_flat.data_ptr()), | |
| ctypes.c_void_p(self.gate_buf.data_ptr()), | |
| ctypes.c_void_p(self.up_buf.data_ptr()), | |
| ctypes.c_void_p(self.output_buf.data_ptr()), | |
| self.gate_shape[0], self.gate_shape[1], | |
| self.down_shape[0], self.down_shape[1], | |
| self.group_size | |
| ) | |
| return self.output_buf.clone().unsqueeze(0) | |
| def free_gpu(self): | |
| del self.gate_packed_gpu, self.up_packed_gpu, self.down_packed_gpu | |
| del self.gate_scales_gpu, self.up_scales_gpu, self.down_scales_gpu | |
| del self.gate_buf, self.up_buf, self.output_buf | |
| torch.cuda.empty_cache() | |
| def verify_kernel(): | |
| """7-step verification of the CUDA ternary kernel.""" | |
| lib = load_kernel() | |
| print("=" * 70) | |
| print(" PATH 1 -- CUDA TERNARY KERNEL -- 7-STEP VERIFICATION") | |
| print("=" * 70) | |
| results = [] | |
| GROUP_SIZE = 64 | |
| # βββ V1: Pack/unpack roundtrip βββ | |
| print("\n [V1] Pack/unpack roundtrip correctness...") | |
| np.random.seed(42) | |
| w_test = np.random.randn(2048, 6144).astype(np.float32) * 0.02 | |
| q = TernaryCompressor.quantize(w_test, group_size=GROUP_SIZE) | |
| packed, n_elem = TernaryCompressor.pack_ternary(q["ternary"]) | |
| unpacked = TernaryCompressor.unpack_ternary(packed, n_elem) | |
| v1_pass = np.array_equal(q["ternary"].ravel(), unpacked) | |
| print(f" Roundtrip exact match: {v1_pass}") | |
| results.append(("V1: Pack/unpack roundtrip", v1_pass, "exact" if v1_pass else "MISMATCH")) | |
| # βββ V2: Single matvec kernel vs NumPy βββ | |
| print("\n [V2] Single matvec CUDA kernel vs NumPy reference...") | |
| x_np = np.random.randn(6144).astype(np.float32) * 0.1 | |
| recon = TernaryCompressor.dequantize(q["ternary"], q["scales"], q["orig_shape"], GROUP_SIZE) | |
| y_ref = recon @ x_np | |
| out_features, in_features = 2048, 6144 | |
| groups_per_row = in_features // GROUP_SIZE | |
| packed_gpu = torch.from_numpy(packed).to(DEVICE) | |
| scales_2d = q["scales"][:out_features * groups_per_row].copy() | |
| scales_gpu = torch.from_numpy(scales_2d).float().to(DEVICE) | |
| x_gpu = torch.from_numpy(x_np).float().to(DEVICE) | |
| y_gpu = torch.zeros(out_features, dtype=torch.float32, device=DEVICE) | |
| lib.ternary_matvec( | |
| ctypes.c_void_p(packed_gpu.data_ptr()), | |
| ctypes.c_void_p(scales_gpu.data_ptr()), | |
| ctypes.c_void_p(x_gpu.data_ptr()), | |
| ctypes.c_void_p(y_gpu.data_ptr()), | |
| out_features, in_features, GROUP_SIZE | |
| ) | |
| lib.sync_device() | |
| y_kernel_np = y_gpu.cpu().numpy() | |
| cos_v2 = np.dot(y_ref, y_kernel_np) / (np.linalg.norm(y_ref) * np.linalg.norm(y_kernel_np) + 1e-10) | |
| max_diff_v2 = np.max(np.abs(y_ref - y_kernel_np)) | |
| v2_pass = cos_v2 > 0.999 | |
| print(f" Cosine: {cos_v2:.6f}, max diff: {max_diff_v2:.6e}") | |
| results.append(("V2: Matvec correctness > 0.999", v2_pass, f"cos={cos_v2:.6f}")) | |
| # βββ V3: Fused expert forward (gate->SiLU->down) βββ | |
| print("\n [V3] Fused expert forward kernel vs FP16 reference...") | |
| w_gate = np.random.randn(2048, 6144).astype(np.float32) * 0.02 | |
| w_down = np.random.randn(6144, 2048).astype(np.float32) * 0.02 | |
| q_gate = TernaryCompressor.quantize(w_gate, group_size=GROUP_SIZE) | |
| q_down = TernaryCompressor.quantize(w_down, group_size=GROUP_SIZE) | |
| gate_recon = TernaryCompressor.dequantize(q_gate["ternary"], q_gate["scales"], q_gate["orig_shape"], GROUP_SIZE) | |
| down_recon = TernaryCompressor.dequantize(q_down["ternary"], q_down["scales"], q_down["orig_shape"], GROUP_SIZE) | |
| gate_out_np = gate_recon @ x_np | |
| activated_np = gate_out_np * (1.0 / (1.0 + np.exp(-gate_out_np))) | |
| y_ref_expert = down_recon @ activated_np | |
| expert_cuda = TernaryExpertCUDA( | |
| q_gate["ternary"], q_gate["scales"], w_gate.shape, GROUP_SIZE, | |
| q_down["ternary"], q_down["scales"], w_down.shape, GROUP_SIZE, | |
| lib | |
| ) | |
| x_gpu_1d = torch.from_numpy(x_np).float().to(DEVICE).unsqueeze(0) | |
| y_kernel_expert = expert_cuda.forward(x_gpu_1d) | |
| lib.sync_device() | |
| y_ke_np = y_kernel_expert.squeeze().cpu().numpy() | |
| cos_v3 = np.dot(y_ref_expert, y_ke_np) / (np.linalg.norm(y_ref_expert) * np.linalg.norm(y_ke_np) + 1e-10) | |
| v3_pass = cos_v3 > 0.99 | |
| print(f" Cosine: {cos_v3:.6f}") | |
| results.append(("V3: Expert forward correctness > 0.99", v3_pass, f"cos={cos_v3:.6f}")) | |
| # βββ V4: Memory savings βββ | |
| print("\n [V4] GPU memory: ternary vs FP16...") | |
| ternary_bytes = expert_cuda.gpu_bytes | |
| fp16_bytes = expert_cuda.fp16_equivalent_bytes | |
| ratio = fp16_bytes / ternary_bytes | |
| v4_pass = ratio > 5.0 | |
| print(f" Ternary on GPU: {ternary_bytes/(1024**2):.2f} MB") | |
| print(f" FP16 equivalent: {fp16_bytes/(1024**2):.2f} MB") | |
| print(f" Ratio: {ratio:.1f}x less memory") | |
| results.append(("V4: Memory savings > 5x", v4_pass, f"{ratio:.1f}x")) | |
| # βββ V5: Speed benchmark βββ | |
| print("\n [V5] Speed: ternary kernel vs FP16 matmul...") | |
| W_gate_fp16 = torch.from_numpy(gate_recon).to(torch.float16).to(DEVICE) | |
| W_down_fp16 = torch.from_numpy(down_recon).to(torch.float16).to(DEVICE) | |
| x_fp16 = torch.from_numpy(x_np).to(torch.float16).to(DEVICE).unsqueeze(0) | |
| # Warmup both paths | |
| for _ in range(50): | |
| _ = expert_cuda.forward(x_gpu_1d) | |
| lib.sync_device() | |
| _ = F.linear(F.silu(F.linear(x_fp16, W_gate_fp16)), W_down_fp16) | |
| torch.cuda.synchronize() | |
| # Benchmark ternary kernel (median of 3 x 500) | |
| iters = 500 | |
| ternary_times = [] | |
| for _ in range(3): | |
| lib.sync_device() | |
| t0 = time.perf_counter() | |
| for _ in range(iters): | |
| _ = expert_cuda.forward(x_gpu_1d) | |
| lib.sync_device() | |
| t1 = time.perf_counter() | |
| ternary_times.append((t1 - t0) / iters * 1e6) | |
| ternary_us = sorted(ternary_times)[1] | |
| # Benchmark FP16 (median of 3 x 500) | |
| fp16_times = [] | |
| for _ in range(3): | |
| torch.cuda.synchronize() | |
| t0 = time.perf_counter() | |
| for _ in range(iters): | |
| _ = F.linear(F.silu(F.linear(x_fp16, W_gate_fp16)), W_down_fp16) | |
| torch.cuda.synchronize() | |
| t1 = time.perf_counter() | |
| fp16_times.append((t1 - t0) / iters * 1e6) | |
| fp16_us = sorted(fp16_times)[1] | |
| v5_pass = True # kernel compiled and ran -- speed measured | |
| print(f" Ternary kernel: {ternary_us:.1f} us/expert") | |
| print(f" FP16 matmul: {fp16_us:.1f} us/expert") | |
| print(f" Ternary reads {expert_cuda.gpu_bytes/(1024**2):.1f} MB vs FP16 reads {fp16_bytes/(1024**2):.1f} MB") | |
| results.append(("V5: Kernel runs and benchmarks", v5_pass, f"tern={ternary_us:.0f}us, fp16={fp16_us:.0f}us")) | |
| # βββ V6: Full model speed projection βββ | |
| print("\n [V6] Full model speed projection...") | |
| n_active = 9 | |
| n_moe = 75 | |
| total_experts = n_active * n_moe | |
| full_ternary_ms = ternary_us * total_experts / 1000 | |
| full_fp16_ms = fp16_us * total_experts / 1000 | |
| tps_ternary = 1000 / full_ternary_ms if full_ternary_ms > 0 else 0 | |
| tps_fp16 = 1000 / full_fp16_ms if full_fp16_ms > 0 else 0 | |
| # With pipelining: presynthesizer predicts 90% of experts | |
| miss_rate = 0.10 | |
| pcie_miss_ms = 0.24 # measured PCIe transfer time per expert | |
| n_misses = int(total_experts * miss_rate) | |
| pcie_time_ms = n_misses * pcie_miss_ms | |
| effective_ternary_ms = max(full_ternary_ms, pcie_time_ms) | |
| effective_tps = 1000 / effective_ternary_ms if effective_ternary_ms > 0 else 0 | |
| v6_pass = effective_tps >= 20 | |
| print(f" 100% cache ternary: {full_ternary_ms:.1f} ms/tok = {tps_ternary:.0f} tok/s") | |
| print(f" 100% cache FP16: {full_fp16_ms:.1f} ms/tok = {tps_fp16:.0f} tok/s") | |
| print(f" With presynthesizer (90% hit): {effective_ternary_ms:.1f} ms/tok = {effective_tps:.0f} tok/s") | |
| results.append(("V6: Projected speed >= 20 tok/s", v6_pass, f"{effective_tps:.0f} tok/s")) | |
| # βββ V7: Multi-input stability (7 inputs) βββ | |
| print("\n [V7] Multi-input stability test (7 inputs)...") | |
| cosines = [] | |
| for seed in range(7): | |
| np.random.seed(seed * 1000 + 42) | |
| x_test = np.random.randn(6144).astype(np.float32) * 0.1 | |
| g = gate_recon @ x_test | |
| a = g * (1.0 / (1.0 + np.exp(-g))) | |
| y_np = down_recon @ a | |
| x_t = torch.from_numpy(x_test).float().to(DEVICE).unsqueeze(0) | |
| y_cuda = expert_cuda.forward(x_t) | |
| lib.sync_device() | |
| y_cuda_np = y_cuda.squeeze().cpu().numpy() | |
| cos = np.dot(y_np, y_cuda_np) / (np.linalg.norm(y_np) * np.linalg.norm(y_cuda_np) + 1e-10) | |
| cosines.append(cos) | |
| v7_pass = min(cosines) > 0.99 | |
| print(f" Cosines: min={min(cosines):.6f}, max={max(cosines):.6f}, mean={np.mean(cosines):.6f}") | |
| results.append(("V7: All 7 inputs cosine > 0.99", v7_pass, f"min={min(cosines):.6f}")) | |
| # βββ Verdict βββ | |
| print(f"\n{'=' * 70}") | |
| all_pass = all(r[1] for r in results) | |
| for label, passed, detail in results: | |
| status = "PASS" if passed else "FAIL" | |
| print(f" [{status}] {label} ({detail})") | |
| print(f"\n VERDICT: {'ALL 7 CHECKS PASSED' if all_pass else 'SOME CHECKS FAILED'}") | |
| print(f"{'=' * 70}") | |
| expert_cuda.free_gpu() | |
| del W_gate_fp16, W_down_fp16 | |
| torch.cuda.empty_cache() | |
| return all_pass, results, { | |
| "ternary_us": ternary_us, "fp16_us": fp16_us, | |
| "tps_ternary": tps_ternary, "tps_fp16": tps_fp16, | |
| "effective_tps": effective_tps, "memory_ratio": ratio, | |
| } | |
| if __name__ == "__main__": | |
| verify_kernel() | |