PWPolyF Piecewise Polynomial Activation
Overview
PWPolyF is a hardware activation layer that approximates nonlinear functions (GELU, SiLU, Sigmoid, Tanh) using piecewise polynomials evaluated with Horner’s method on a chain of DSPFP32 FMA units. It is RTL-only and targets Versal devices exclusively (requires the DSPFP32 primitive).
With the default degree=2, this uses two cascaded DSPs and one RAMB18
coefficient ROM per PE, giving single-cycle-per-element throughput.
The input domain is partitioned into 1 + 2*5*(2^K) segments. With the
default K=3 this gives 81 segments. Polynomial coefficients are generated
at HDL build time by fitting to PyTorch reference functions.
Usage
Use PWPolyFActivation from finn.util.torch_hw_modules as a drop-in
replacement for nn.GELU, nn.SiLU, nn.Sigmoid, or nn.Tanh:
from finn.util.torch_hw_modules import PWPolyFActivation
# In your model
self.act = PWPolyFActivation(func="gelu", K=3, degree=2)
Export via Brevitas export_qonnx. The resulting PWPolyFunction node
is converted to a PWPolyF HW op by InferPWPolyFLayer.
Path A: PWPolyFActivation Path B: nn.GELU / nn.SiLU / etc.
| (util/torch_hw_modules.py) | torch.onnx.export
| export_qonnx | (dynamo=True or False)
v v
PWPolyFunction node Standard ONNX ops (Gelu, Sigmoid,
(qonnx.custom_op.general) Tanh, Sigmoid+Mul for SiLU,
Div+Erf+Add+Mul+Mul for GELU)
| |
+------------- both paths -------------+
|
InferPWPolyFLayer
v
PWPolyF HW op (custom_op/fpgadataflow)
| SpecializeLayers
v
PWPolyF_rtl (custom_op/fpgadataflow/rtl)
| generate_hdl
v
finn-rtllib/pwpolyf/hdl/ SystemVerilog IP
Standard ONNX Op Inference
InferPWPolyFLayer also recognises standard ONNX activation ops, allowing
models using nn.GELU, nn.SiLU, nn.Sigmoid, or nn.Tanh to be
automatically converted to PWPolyF HW layers with default K=3, degree=2.
Supported patterns:
Gelu(opset 20+) or Erf-based GELU pattern →func="gelu"Sigmoid→func="sigmoid"Tanh→func="tanh"Sigmoid+Mul(SiLU pattern) →func="silu"
Only FLOAT32 inputs are converted.
Folding
PWPolyF uses PE parallelism. NumChannels % PE == 0 must hold.
SetFolding handles PE selection automatically.