← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
mlp_kernels.c File Reference

MLP (feed-forward) kernels with SIMD (SSE/AVX/AVX512) More...

#include "ckernel_engine.h"
#include <stdlib.h>

Go to the source code of this file.

Functions

void fc1_backward_kernel (const float *d_output, const float *fc1_input, const float *W_fc1, float *d_input, float *d_W_fc1, float *d_b_fc1, int T, int aligned_in, int aligned_out, int num_threads)
 
void fc2_backward_kernel (const float *d_output, const float *fc2_input, const float *W_fc2, float *d_input, float *d_W_fc2, float *d_b_fc2, int T, int aligned_in, int aligned_out, int num_threads)
 
void mlp_token_parallel (const float *input, const float *W_fc1, const float *b_fc1, const float *W_fc2, const float *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads)
 
void mlp_token_parallel_exact (const float *input, const float *W_fc1, const float *b_fc1, const float *W_fc2, const float *b_fc2, float *fc1_output, float *output, int T, int aligned_dim, int num_threads)
 

Detailed Description

MLP (feed-forward) kernels with SIMD (SSE/AVX/AVX512)

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test && make llamacpp-parity-full

LEGACY EXCEPTION: This file contains OpenMP for backward compatibility. New kernels should NOT use OpenMP internally.

OpenMP removal note: The bias-reduction loops in the fallback FP32 backward kernels were made serial so the training hot path does not bounce between the CK threadpool and libiomp barriers. These kernels now serve as compatibility fallbacks while threaded training backward is migrated into ck_parallel_train.c.

MLP: out = FC2(GELU(FC1(x)))

Definition in file mlp_kernels.c.

Function Documentation

◆ fc1_backward_kernel()

void fc1_backward_kernel ( const float *  d_output,
const float *  fc1_input,
const float *  W_fc1,
float *  d_input,
float *  d_W_fc1,
float *  d_b_fc1,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 174 of file mlp_kernels.c.

184{
185 (void)num_threads; // Threading handled by GEMM kernels
186
187 // 1. d_input[T, in] = d_output[T, out] @ W[out, in]
188 // Using gemm_nn: C[M,N] = A[M,K] @ B[K,N]
189 // A = d_output [T, out], B = W [out, in], C = d_input [T, in]
190 // M = T, N = aligned_in, K = aligned_out
191 gemm_nn_simd(d_output, W_fc1, NULL, d_input,
192 T, aligned_in, aligned_out);
193
194 // 2. d_W[out, in] = d_output[T, out].T @ fc1_input[T, in]
195 // Using gemm_tn: C[M,N] = A[K,M].T @ B[K,N]
196 // A = d_output [T, out] (stored as [K=T, M=out]), B = fc1_input [T, in]
197 // C = d_W [out, in], M = aligned_out, N = aligned_in, K = T
198 gemm_tn_parallel(d_output, fc1_input, NULL, d_W_fc1,
199 aligned_out, aligned_in, T);
200
201 // 3. d_b_fc1 = sum_over_T(d_output)
202 for (int out_idx = 0; out_idx < aligned_out; ++out_idx) {
203 float bias_grad = 0.0f;
204 for (int t = 0; t < T; ++t) {
205 bias_grad += d_output[(size_t)t * aligned_out + out_idx];
206 }
207 d_b_fc1[out_idx] += bias_grad;
208 }
209}
void gemm_tn_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void gemm_nn_simd(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References gemm_nn_simd(), and gemm_tn_parallel().

Referenced by ck_layer_backward_rmsnorm_swiglu().

◆ fc2_backward_kernel()

void fc2_backward_kernel ( const float *  d_output,
const float *  fc2_input,
const float *  W_fc2,
float *  d_input,
float *  d_W_fc2,
float *  d_b_fc2,
int  T,
int  aligned_in,
int  aligned_out,
int  num_threads 
)

Definition at line 126 of file mlp_kernels.c.

136{
137 (void)num_threads; // Threading handled by GEMM kernels
138
139 // 1. d_input[T, in] = d_output[T, out] @ W[out, in]
140 // Using gemm_nn: C[M,N] = A[M,K] @ B[K,N]
141 // A = d_output [T, out], B = W [out, in], C = d_input [T, in]
142 // M = T, N = aligned_in, K = aligned_out
143 gemm_nn_simd(d_output, W_fc2, NULL, d_input,
144 T, aligned_in, aligned_out);
145
146 // 2. d_W[out, in] = d_output[T, out].T @ fc2_input[T, in]
147 // Using gemm_tn: C[M,N] = A[K,M].T @ B[K,N]
148 // A = d_output [T, out] (stored as [K=T, M=out]), B = fc2_input [T, in]
149 // C = d_W [out, in], M = aligned_out, N = aligned_in, K = T
150 // Note: gemm_tn overwrites, so we need to save and add if accumulating
151 // For now, assume d_W starts zeroed (gradient accumulation handled at higher level)
152 gemm_tn_parallel(d_output, fc2_input, NULL, d_W_fc2,
153 aligned_out, aligned_in, T);
154
155 // 3. d_b_fc2 = sum_over_T(d_output)
156 for (int out_idx = 0; out_idx < aligned_out; ++out_idx) {
157 float bias_grad = 0.0f;
158 for (int t = 0; t < T; ++t) {
159 bias_grad += d_output[(size_t)t * aligned_out + out_idx];
160 }
161 d_b_fc2[out_idx] += bias_grad;
162 }
163}

References gemm_nn_simd(), and gemm_tn_parallel().

Referenced by ck_attention_project_head_major_backward(), ck_layer_backward_rmsnorm_swiglu(), and ck_qkv_project_head_major_backward().

◆ mlp_token_parallel()

void mlp_token_parallel ( const float *  input,
const float *  W_fc1,
const float *  b_fc1,
const float *  W_fc2,
const float *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads 
)

Definition at line 49 of file mlp_kernels.c.

59{
60 int D = aligned_dim;
61 int fourD = 4 * D;
62
63 // FC1: [T × D] · [D × 4D] -> [T × 4D]
64 // Our GEMM layout: A[M×K], B[N×K], so B is [4D × D].
65 gemm_blocked_serial(input, W_fc1, b_fc1,
66 fc1_output,
67 T, // M
68 fourD, // N
69 D); // K
70
71 // GELU in-place on FC1 output
72 gelu_fast_inplace(fc1_output, (size_t)T * (size_t)fourD);
73
74 // FC2: [T × 4D] · [4D × D] -> [T × D]
75 gemm_blocked_serial(fc1_output, W_fc2, b_fc2,
76 output,
77 T, // M
78 D, // N
79 fourD); // K
80}
void gelu_fast_inplace(float *data, size_t n)
void gemm_blocked_serial(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)

References gelu_fast_inplace(), and gemm_blocked_serial().

◆ mlp_token_parallel_exact()

void mlp_token_parallel_exact ( const float *  input,
const float *  W_fc1,
const float *  b_fc1,
const float *  W_fc2,
const float *  b_fc2,
float *  fc1_output,
float *  output,
int  T,
int  aligned_dim,
int  num_threads 
)

Definition at line 84 of file mlp_kernels.c.

94{
95 (void)num_threads;
96 int D = aligned_dim;
97 int fourD = 4 * D;
98
99 // FC1: [T × D] · [D × 4D] -> [T × 4D]
100 gemm_blocked_serial(input, W_fc1, b_fc1,
101 fc1_output,
102 T, // M
103 fourD, // N
104 D); // K
105
106 // Exact GELU using standard library tanhf
107 gelu_exact_inplace(fc1_output, (size_t)T * (size_t)fourD);
108
109 // FC2: [T × 4D] · [4D × D] -> [T × D]
110 gemm_blocked_serial(fc1_output, W_fc2, b_fc2,
111 output,
112 T, // M
113 D, // N
114 fourD); // K
115}
void gelu_exact_inplace(float *data, size_t n)

References gelu_exact_inplace(), and gemm_blocked_serial().