EdgeRock / runtime /optimizations /b1_runtime_joint_projection.py
rockmatrix-ai's picture
Use BF16 inference and align figures and results with the technical report
799fa1f verified
Raw History Blame Contribute Delete
3.7 kB
from types import MethodType
import torch
import torch.nn.functional as F
import triton
import triton.language as tl
base_linear = F.linear
checks = []
checked = set()
writer_owners = {}
@triton.jit
def joint_matvec(X, Q, W, A, Y, NQ: tl.constexpr, NW: tl.constexpr,
NA: tl.constexpr, K: tl.constexpr, BK: tl.constexpr):
start = tl.program_id(0) * 2
rows = start + tl.arange(0, 2)
columns = tl.arange(0, BK)
x = tl.load(X + columns, columns < K, 0).to(tl.float32)
if start < NQ:
weights = Q + rows[:, None] * K + columns[None, :]
elif start < NQ + NW:
weights = W + (rows[:, None] - NQ) * K + columns[None, :]
else:
weights = A + (rows[:, None] - NQ - NW) * K + columns[None, :]
weight = tl.load(weights,
(rows[:, None] < NQ + NW + NA) & (columns[None, :] < K), 0).to(tl.float32)
result = tl.sum(weight * x[None, :], axis=1)
tl.store(Y + rows, result, rows < NQ + NW + NA)
def writer_linear(values, weight, bias=None):
owner = writer_owners.get(weight.data_ptr())
if owner is not None and owner._b1_joint_active and values.numel() == values.shape[-1]:
begin = owner.q_proj.out_features
result = owner._b1_joint_output[..., begin:begin + weight.shape[0]].reshape(*values.shape[:-1], weight.shape[0])
owner._b1_joint_active = False
owner._b1_joint_output = None
return result
return base_linear(values, weight, bias)
def install(model):
for m in model.modules():
if not (hasattr(m, '_query_scores') and hasattr(m, '_inference_writer_gate_up')):
continue
m._b1_joint_output = None
m._b1_joint_active = False
writer_owners[m._inference_writer_gate_up.data_ptr()] = m
previous_query, previous_admission = m.q_proj.forward, m.admission_down.forward
assert all(w.is_contiguous() and w.shape[0] % 2 == 0 for w in
(m.q_proj.weight, m._inference_writer_gate_up, m.admission_down.weight))
def query(projection, values, *args, owner=m, previous=previous_query, **kwargs):
owner._b1_joint_active = values.numel() == values.shape[-1]
if not owner._b1_joint_active:
return previous(values, *args, **kwargs)
q, w, a = owner.q_proj.weight, owner._inference_writer_gate_up, owner.admission_down.weight
n = q.shape[0] + w.shape[0] + a.shape[0]
output = values.new_empty((*values.shape[:-1], n))
joint_matvec[triton.cdiv(n, 2),](values, q, w, a, output,
q.shape[0], w.shape[0], a.shape[0], q.shape[1],
triton.next_power_of_2(q.shape[1]), num_warps=4, num_stages=1)
if owner not in checked:
expected = torch.cat([base_linear(values, weight) for weight in (q, w, a)], -1)
checks.append(dict(layer=len(checks), shape=list(output.shape),
exact=bool(torch.equal(expected, output)), finite=bool(output.isfinite().all()),
max_abs=float((expected.float() - output.float()).abs().max())))
checked.add(owner)
owner._b1_joint_output = output
return output[..., :q.shape[0]]
def admission(projection, values, *args, owner=m, previous=previous_admission, **kwargs):
if not owner._b1_joint_active:
return previous(values, *args, **kwargs)
return owner._b1_joint_output[..., -owner.admission_down.out_features:]
m.q_proj.forward = MethodType(query, m.q_proj)
m.admission_down.forward = MethodType(admission, m.admission_down)
assert len(writer_owners) == 8
F.linear = writer_linear