192 lines
5.9 KiB
Rust
192 lines
5.9 KiB
Rust
//! Vision-only dispatches from pinned MLX 0.32.2 normalization, conv and SDPA.
|
|
//! Rust supplies the same layouts and parameters to the existing Metal library.
|
|
use super::super::gpu::{Buffer, MetalConstant};
|
|
use super::array::{Array, Dtype, Layout};
|
|
use super::{bytes, dispatch_geometry, dispatch_specialized, ops, stream::Stream, tensor};
|
|
|
|
#[derive(Clone, Copy, PartialEq)]
|
|
pub(super) enum Kernel {
|
|
LayerNorm,
|
|
PatchConv,
|
|
Attention,
|
|
Linear,
|
|
}
|
|
|
|
pub(super) fn call(
|
|
kernel: Kernel,
|
|
inputs: &[Array],
|
|
shape: &[i32],
|
|
stream: Stream,
|
|
) -> Result<Array, String> {
|
|
Array::make_operation_with_inputs(
|
|
stream,
|
|
inputs,
|
|
Layout::new(shape, Dtype::BF16)?,
|
|
ops::Operation::Vision(kernel),
|
|
)
|
|
}
|
|
|
|
pub(super) fn evaluate(kernel: Kernel, inputs: &[Array], out: &Array) -> Result<(), String> {
|
|
if kernel == Kernel::Linear {
|
|
return super::dense::evaluate_bias(&inputs[0], &inputs[1], Some(&inputs[2]), out);
|
|
}
|
|
let nbytes = out.layout().nbytes() as u64;
|
|
out.set_data(Buffer::mtplx_bytes(nbytes)?)?;
|
|
let buffers = inputs.iter().map(Array::buffer).collect::<Vec<_>>();
|
|
let ob = out.buffer();
|
|
let mut bindings = inputs
|
|
.iter()
|
|
.zip(&buffers)
|
|
.enumerate()
|
|
.map(|(i, (a, b))| {
|
|
tensor(i as u32, b)
|
|
.at_byte_offset(a.offset())
|
|
.input(a.data_size())
|
|
})
|
|
.collect::<Vec<_>>();
|
|
bindings.push(tensor(inputs.len() as u32, &ob).output(out.data_size()));
|
|
match kernel {
|
|
Kernel::Linear => {
|
|
super::dense::evaluate_bias(&inputs[0], &inputs[1], Some(&inputs[2]), out)
|
|
}
|
|
Kernel::LayerNorm => {
|
|
let axis = out.layout().dim(-1)? as u32;
|
|
let rows = out.layout().size() as u32 / axis;
|
|
let threads = axis.div_ceil(8).div_ceil(32) * 32;
|
|
let eps = 1e-6_f32;
|
|
let stride = 1_u32;
|
|
bindings.extend([
|
|
bytes(4, &eps),
|
|
bytes(5, &axis),
|
|
bytes(6, &stride),
|
|
bytes(7, &stride),
|
|
]);
|
|
dispatch_geometry(
|
|
"layer_normbfloat16",
|
|
&bindings,
|
|
&[],
|
|
[rows * threads, 1, 1],
|
|
[threads, 1, 1],
|
|
true,
|
|
)
|
|
}
|
|
Kernel::PatchConv => {
|
|
// Inputs are contiguous [patches,2,16,16,16], weights
|
|
// [1152,2,16,16,16]. Original Conv3d pads RGB channels to 16.
|
|
#[repr(C)]
|
|
struct Params {
|
|
n: i32,
|
|
c: i32,
|
|
o: i32,
|
|
input: [i32; 3],
|
|
weight: [i32; 3],
|
|
output: [i32; 3],
|
|
stride: [i32; 3],
|
|
pad: [i32; 3],
|
|
kdil: [i32; 3],
|
|
idil: [i32; 3],
|
|
is: [i64; 5],
|
|
ws: [i64; 5],
|
|
os: [i64; 5],
|
|
groups: i32,
|
|
flip: u8,
|
|
padding: [u8; 3],
|
|
}
|
|
let n = out.layout().dim(0)?;
|
|
let params = Params {
|
|
n,
|
|
c: 16,
|
|
o: 1152,
|
|
input: [2, 16, 16],
|
|
weight: [2, 16, 16],
|
|
output: [1, 1, 1],
|
|
stride: [2, 16, 16],
|
|
pad: [0; 3],
|
|
kdil: [1; 3],
|
|
idil: [1; 3],
|
|
is: [8192, 4096, 256, 16, 1],
|
|
ws: [8192, 4096, 256, 16, 1],
|
|
os: [1152, 1152, 1152, 1152, 1],
|
|
groups: 1,
|
|
flip: 0,
|
|
padding: [0; 3],
|
|
};
|
|
let gemm = [n, 1152, 8192, 512, 16, 16, 16, -8160, 18, (n + 31) / 32, 0];
|
|
bindings.extend([bytes(3, ¶ms), bytes(4, &gemm)]);
|
|
dispatch_specialized(
|
|
"implicit_gemm_conv_3d_bfloat16_bm32_bn64_bk16_wm2_wn2_filter_s",
|
|
&bindings,
|
|
&[],
|
|
[18, ((n + 31) / 32) as u32, 1],
|
|
[32, 2, 2],
|
|
)
|
|
}
|
|
Kernel::Attention => {
|
|
#[repr(C)]
|
|
struct Params {
|
|
b: i32,
|
|
h: i32,
|
|
d: i32,
|
|
ql: i32,
|
|
kl: i32,
|
|
gqa: i32,
|
|
scale: f32,
|
|
nq: i32,
|
|
nk: i32,
|
|
aq: i32,
|
|
ak: i32,
|
|
rq: i32,
|
|
rk: i32,
|
|
off: i32,
|
|
strides: [[i64; 3]; 4],
|
|
}
|
|
let shape = out.layout().shape().to_vec();
|
|
let n = shape[2];
|
|
let mut strides = [[0; 3]; 4];
|
|
for (s, a) in strides
|
|
.iter_mut()
|
|
.zip(inputs.iter().chain(std::iter::once(out)))
|
|
{
|
|
s.copy_from_slice(&a.layout().strides()[..3]);
|
|
}
|
|
let params = Params {
|
|
b: 1,
|
|
h: 16,
|
|
d: 80,
|
|
ql: n,
|
|
kl: n,
|
|
gqa: 1,
|
|
scale: (72_f64.powf(-0.5)) as f32,
|
|
nq: ((n + 31) / 32),
|
|
nk: ((n + 31) / 32),
|
|
aq: n / 32,
|
|
ak: n / 32,
|
|
rq: n % 32,
|
|
rk: n % 32,
|
|
off: 0,
|
|
strides,
|
|
};
|
|
let constants = [
|
|
(200, n % 32 == 0),
|
|
(201, n % 32 == 0),
|
|
(300, false),
|
|
(301, false),
|
|
(302, false),
|
|
]
|
|
.map(|(index, v)| MetalConstant {
|
|
index,
|
|
value: u32::from(v),
|
|
kind: 0,
|
|
});
|
|
bindings.push(bytes(4, ¶ms));
|
|
dispatch_specialized(
|
|
"steel_attention_bfloat16_bq32_bk32_bd80_wm4_wn1_maskbfloat16",
|
|
&bindings,
|
|
&constants,
|
|
[((n + 31) / 32) as u32, 16, 1],
|
|
[32, 4, 1],
|
|
)
|
|
}
|
|
}
|
|
}
|