Post-operations allow you to fuse additional computations with GEMM operations, reducing memory bandwidth and improving performance. The effective computation becomes:
C = post_ops( alpha * op(A) * op(B) + beta * C )
All post-operations are configured through a single dlp_metadata_t struct passed as the last
argument to any GEMM function. Pass NULL when no post-ops are needed. Up to
AOCL_MAX_POST_OPS (8) post-operations can be chained.
For complete API reference, see dlp_metadata_t and the Post-Operations Guide Wiki.
Post-Op Types:
Type |
Description |
|---|---|
|
Adds a 1D bias vector (length n) to each row of the output |
|
Applies an element-wise activation function |
|
Per-channel or per-tensor scaling with optional zero-point |
|
Element-wise addition of another matrix to the output |
|
Element-wise multiplication of the output with another matrix |
Supported Activation Functions (ELTWISE):
|
Formula |
Parameters |
|---|---|---|
|
|
None |
|
|
|
|
GELU with tanh approximation |
None |
|
GELU with erf approximation |
None |
|
|
|
|
|
|
|
|
None |
|
|
None |
Key Metadata Fields:
Field |
Type |
Description |
|---|---|---|
|
|
Number of post-operations to apply |
|
|
Array defining the order of post-ops |
|
|
Bias parameters (when BIAS is in sequence) |
|
|
Eltwise/activation parameters |
|
|
Scale + zero-point parameters |
|
|
Matrix addition parameters |
|
|
Matrix multiplication parameters |
|
|
Number of eltwise operations (when chaining multiple) |
Example: Bias + ReLU Activation:
float bias_values[N] = { /* ... */ };
dlp_post_op_bias bias_op = {
.bias = bias_values, .stor_type = DLP_F32,
.sf = NULL, .zp = NULL
};
dlp_post_op_eltwise relu_op = {
.sf = NULL,
.algo = { .alpha = NULL, .beta = NULL,
.algo_type = RELU, .stor_type = DLP_F32 }
};
DLP_POST_OP_TYPE seq[] = { BIAS, ELTWISE };
dlp_metadata_t meta = {0};
meta.seq_length = 2;
meta.seq_vector = seq;
meta.bias = &bias_op;
meta.eltwise = &relu_op;
meta.num_eltwise = 1;
aocl_gemm_f32f32f32of32('R', 'N', 'N', m, n, k,
1.0f, a, lda, 'N', b, ldb, 'N',
0.0f, c, ldc, &meta);
Example: MATRIX_ADD (Residual Connection):
float residual[M * N] = { /* ... */ };
dlp_post_op_matrix_add add_op = {
.matrix = residual,
.ldm = n,
.stor_type = DLP_F32,
.sf = NULL
};
DLP_POST_OP_TYPE seq[] = { MATRIX_ADD };
dlp_metadata_t meta = {0};
meta.seq_length = 1;
meta.seq_vector = seq;
meta.matrix_add = &add_op;
aocl_gemm_f32f32f32of32('R', 'N', 'N', m, n, k,
1.0f, a, lda, 'N', b, ldb, 'N',
0.0f, c, ldc, &meta);
Example: PRELU with Alpha Parameter:
float alpha_val = 0.01f;
dlp_post_op_eltwise prelu_op = {
.sf = NULL,
.algo = { .alpha = &alpha_val, .beta = NULL,
.algo_type = PRELU, .stor_type = DLP_F32 }
};
DLP_POST_OP_TYPE seq[] = { ELTWISE };
dlp_metadata_t meta = {0};
meta.seq_length = 1;
meta.seq_vector = seq;
meta.eltwise = &prelu_op;
meta.num_eltwise = 1;
Tip
Always zero-initialize metadata:
dlp_metadata_t meta = {0};Align bias, scale, and residual buffers to 64-byte boundaries for best performance.
Ensure
stor_typematches the accumulator type of your GEMM variant.