Skip to content

Commit 99e7f94

Browse files
committed
Parallelize Winograd GEMM stage and fuse bias+activation
* use activation + blas-fused + b-packed matmul * parallelize that heavy matmul loop when applicable
1 parent 600c262 commit 99e7f94

1 file changed

Lines changed: 44 additions & 15 deletions

File tree

crates/yscv-kernels/src/ops/conv/gemm_conv.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ fn winograd_conv2d_nhwc(
555555
pad_right: usize,
556556
activation: Activation,
557557
) -> Result<Tensor, KernelError> {
558+
use rayon::iter::{IntoParallelIterator, ParallelIterator};
559+
558560
let padded_h = in_h + pad_top + pad_bottom;
559561
let padded_w = in_w + pad_left + pad_right;
560562
let out_h = padded_h - 2; // (padded_h - 3) / 1 + 1
@@ -573,6 +575,8 @@ fn winograd_conv2d_nhwc(
573575
let mut output = AlignedVec::<f32>::uninitialized(batch * out_h * out_w * c_out);
574576

575577
for b in 0..batch {
578+
use crate::{GemmEpilogue, core::scope_ctx::par_chunks_mut_dispatch};
579+
576580
let in_batch = &input[b * in_h * in_w * c_in..(b + 1) * in_h * in_w * c_in];
577581

578582
// 2. Input transform: for each tile, for each channel, compute B^T * d * B
@@ -611,11 +615,44 @@ fn winograd_conv2d_nhwc(
611615
// V[alpha]: [n_tiles, c_in], U[alpha]: [c_in, c_out]
612616
// M[alpha]: [n_tiles, c_out]
613617
let mut m_buf = vec![0.0f32; 16 * n_tiles * c_out];
614-
for a in 0..16 {
615-
let v_slice = &v[a * n_tiles * c_in..(a + 1) * n_tiles * c_in];
616-
let u_slice = &u[a * c_in * c_out..(a + 1) * c_in * c_out];
617-
let m_slice = &mut m_buf[a * n_tiles * c_out..(a + 1) * n_tiles * c_out];
618-
super::super::matmul::blas_sgemm(v_slice, u_slice, m_slice, n_tiles, c_in, c_out);
618+
let epilogue = GemmEpilogue {
619+
activation,
620+
bias: bias.map(|b| b.as_ptr()),
621+
residual: None,
622+
};
623+
let config = ParallelMatmulConfig::default();
624+
if should_parallelize_len(m_buf.len(), config.min_parallel_output_elements, None) {
625+
let packed_u: Vec<_> = (0..16)
626+
.into_par_iter()
627+
.map(|a| {
628+
use crate::pack_b_for_session;
629+
630+
let u_slice = &u[a * c_in * c_out..(a + 1) * c_in * c_out];
631+
pack_b_for_session(u_slice, c_in, c_out)
632+
})
633+
.collect();
634+
par_chunks_mut_dispatch(&mut m_buf, n_tiles * c_out, |a, chunk| {
635+
use crate::matmul_2d_slices_fused_maybe_packed;
636+
637+
let v_slice = &v[a * n_tiles * c_in..(a + 1) * n_tiles * c_in];
638+
let u_slice = &u[a * c_in * c_out..(a + 1) * c_in * c_out];
639+
let packed = Some(packed_u[a].as_ref());
640+
matmul_2d_slices_fused_maybe_packed(
641+
v_slice, n_tiles, c_in, u_slice, c_out, chunk, packed, epilogue, config, None,
642+
);
643+
});
644+
} else {
645+
for a in 0..16 {
646+
use crate::matmul_2d_slices_fused_maybe_packed;
647+
648+
let v_slice = &v[a * n_tiles * c_in..(a + 1) * n_tiles * c_in];
649+
let u_slice = &u[a * c_in * c_out..(a + 1) * c_in * c_out];
650+
let m_slice = &mut m_buf[a * n_tiles * c_out..(a + 1) * n_tiles * c_out];
651+
652+
matmul_2d_slices_fused_maybe_packed(
653+
v_slice, n_tiles, c_in, u_slice, c_out, m_slice, None, epilogue, config, None,
654+
);
655+
}
619656
}
620657

621658
// 4. Output transform: A^T * M * A → 2×2 output per tile, with bias + activation
@@ -638,24 +675,16 @@ fn winograd_conv2d_nhwc(
638675
let mut otile = [0.0f32; 4];
639676
winograd_output_tile(&mt, &mut otile);
640677

641-
// Add bias
642-
let bias_val = bias.map_or(0.0, |bd| bd[co]);
678+
// Store input tile
643679
for dy in 0..valid_h {
644680
for dx in 0..valid_w {
645681
let idx = (oy0 + dy) * out_w * c_out + (ox0 + dx) * c_out + co;
646-
out_batch[idx] = otile[dy * 2 + dx] + bias_val;
682+
out_batch[idx] = otile[dy * 2 + dx];
647683
}
648684
}
649685
}
650686
}
651687
}
652-
653-
// Apply activation on the whole batch output
654-
match activation {
655-
Activation::Silu => silu_slice_inplace(out_batch),
656-
Activation::Relu => relu_slice_inplace(out_batch),
657-
Activation::None => {}
658-
}
659688
}
660689

661690
Tensor::from_aligned(vec![batch, out_h, out_w, c_out], output).map_err(Into::into)

0 commit comments

Comments
 (0)