tools/pnnx/README.md
PyTorch Neural Network eXchange(PNNX) is an open standard for PyTorch model interoperability. PNNX provides an open model format for PyTorch. It defines computation graph as well as high level operators strictly matches PyTorch.
PyTorch is currently one of the most popular machine learning frameworks. We need to deploy the trained AI model to various hardware and environments more conveniently and easily.
Before PNNX, we had the following methods:
As far as we know, ONNX has the ability to express the PyTorch model and it is an open standard. People usually use ONNX as an intermediate representation between PyTorch and the inference platform. However, ONNX still has the following fatal problems, which makes the birth of PNNX necessary:
PNNX tries to define a set of operators and a simple and easy-to-use format that are completely contrasted with the python api of PyTorch, so that the conversion and interoperability of PyTorch models are more convenient.
import torch
import torchvision.models as models
net = models.resnet18(pretrained=True)
net = net.eval()
x = torch.rand(1, 3, 224, 224)
# You could try disabling checking when tracing raises error
# mod = torch.jit.trace(net, x, check_trace=False)
mod = torch.jit.trace(net, x)
mod.save("resnet18.pt")
pnnx resnet18.pt inputshape=[1,3,224,224]
Normally, you will get seven files
resnet18.pnnx.param PNNX graph definition
resnet18.pnnx.bin PNNX model weight
resnet18_pnnx.py PyTorch script for inference, the python code for model construction and weight initialization
resnet18.pnnx.onnx PNNX model in onnx format
resnet18.ncnn.param ncnn graph definition
resnet18.ncnn.bin ncnn model weight
resnet18_ncnn.py pyncnn script for inference
Open https://netron.app/ in browser, and drag resnet18.pnnx.param into it.
Usage: pnnx [model.pt] [(key=value)...]
pnnxparam=model.pnnx.param
pnnxbin=model.pnnx.bin
pnnxpy=model_pnnx.py
pnnxonnx=model.pnnx.onnx
ncnnparam=model.ncnn.param
ncnnbin=model.ncnn.bin
ncnnpy=model_ncnn.py
fp16=1
optlevel=2
device=cpu/gpu
inputshape=[1,3,224,224],...
inputshape2=[1,3,320,320],...
customop=/home/nihui/.cache/torch_extensions/fused/fused.so,...
moduleop=models.common.Focus,models.yolo.Detect,...
Sample usage: pnnx mobilenet_v2.pt inputshape=[1,3,224,224]
pnnx yolov5s.pt inputshape=[1,3,640,640] inputshape2=[1,3,320,320] device=gpu moduleop=models.common.Focus,models.yolo.Detect
Parameters:
pnnxparam (default="*.pnnx.param", * is the model name): PNNX graph definition file
pnnxbin (default="*.pnnx.bin"): PNNX model weight
pnnxpy (default="*_pnnx.py"): PyTorch script for inference, including model construction and weight initialization code
pnnxonnx (default="*.pnnx.onnx"): PNNX model in onnx format
ncnnparam (default="*.ncnn.param"): ncnn graph definition
ncnnbin (default="*.ncnn.bin"): ncnn model weight
ncnnpy (default="*_ncnn.py"): pyncnn script for inference
fp16 (default=1): save ncnn weight and onnx in fp16 data type
optlevel (default=2): graph optimization level
| Option | Optimization level |
|---|---|
| 0 | do not apply optimization |
| 1 | optimization for inference |
| 2 | optimization more for inference |
device (default="cpu"): device type for the input in TorchScript model, cpu or gpu
inputshape (Optional): shapes of model inputs. It is used to resolve tensor shapes in model graph. for example, [1,3,224,224] for the model with only 1 input, [1,3,224,224],[1,3,224,224] for the model that have 2 inputs.
inputshape2 (Optional): shapes of alternative model inputs, the format is identical to inputshape. Usually, it is used with inputshape to resolve dynamic shape (-1) in model graph.
customop (Optional): list of Torch extensions (dynamic library) for custom operators, separated by ",". For example, /home/nihui/.cache/torch_extensions/fused/fused.so,...
moduleop (Optional): list of modules to keep as one big operator, separated by ",". for example, models.common.Focus,models.yolo.Detect
7767517
4 3
pnnx.Input input 0 1 0
nn.Conv2d conv_0 1 1 0 1 bias=1 dilation=(1,1) groups=1 in_channels=12 kernel_size=(3,3) out_channels=16 padding=(0,0) stride=(1,1) @bias=(16)f32 @weight=(16,12,3,3)f32
nn.Conv2d conv_1 1 1 1 2 bias=1 dilation=(1,1) groups=1 in_channels=16 kernel_size=(2,2) out_channels=20 padding=(2,2) stride=(2,2) @bias=(20)f32 @weight=(20,16,2,2)f32
pnnx.Output output 1 0 2
[magic]
[operator count] [operand count]
[type] [name] [input count] [output count] [input operands] [output operands] [operator params]
@ symbol, tensor shapes are prefixed by # symbol, input parameter keys are prefixed by $pnnx.bin file is a zip file with store-only mode(no compression)
weight binary file has its name composed by operator name and weight name
For example, nn.Conv2d conv_0 1 1 0 1 bias=1 dilation=(1,1) groups=1 in_channels=12 kernel_size=(3,3) out_channels=16 padding=(0,0) stride=(1,1) @bias=(16) @weight=(16,12,3,3) would pull conv_0.weight and conv_0.bias into pnnx.bin zip archive.
weight binaries can be listed or modified with any archive application eg. 7zip
PNNX always preserve operators from what PyTorch python api provides.
Here is the netron visualization comparison among ONNX, TorchScript and PNNX with the original PyTorch python code shown.
import torch
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.attention = nn.MultiheadAttention(embed_dim=256, num_heads=32)
def forward(self, x):
x, _ = self.attention(x, x, x)
return x
| ONNX | TorchScript | PNNX |
|---|---|---|
PNNX trys to preserve expression from what PyTorch python code writes.
Here is the netron visualization comparison among ONNX, TorchScript and PNNX with the original PyTorch python code shown.
import torch
def foo(x, y):
return torch.sqrt((2 * x + y) / 12)
| ONNX | TorchScript | PNNX |
|---|---|---|
PNNX trys to preserve torch functions and Tensor member functions as one operator from what PyTorch python api provides.
Here is the netron visualization comparison among ONNX, TorchScript and PNNX with the original PyTorch python code shown.
import torch
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
def forward(self, x):
x = F.normalize(x, eps=1e-3)
return x
| ONNX | TorchScript | PNNX |
|---|---|---|
Users could ask PNNX to keep module as one big operator when it has complex logic.
The process is optional and could be enabled via moduleop command line option.
After pass_level0, all modules will be presented in terminal output, then you can pick the interesting ones as module operators.
############# pass_level0
inline module = models.common.Bottleneck
inline module = models.common.C3
inline module = models.common.Concat
inline module = models.common.Conv
inline module = models.common.Focus
inline module = models.common.SPP
inline module = models.yolo.Detect
inline module = utils.activations.SiLU
pnnx yolov5s.pt inputshape=[1,3,640,640] moduleop=models.common.Focus,models.yolo.Detect
Here is the netron visualization comparison among ONNX, TorchScript and PNNX with the original PyTorch python code shown.
import torch
import torch.nn as nn
class Focus(nn.Module):
# Focus wh information into c-space
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
super().__init__()
self.conv = Conv(c1 * 4, c2, k, s, p, g, act)
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))
| ONNX | TorchScript | PNNX | PNNX with module operator |
|---|---|---|---|
A python script will be generated by default when converting TorchScript to pnnx.
This script is the python code representation of PNNX and can be used for model inference.
There are some utility functions for loading weight binary from pnnx.bin.
You can even export the model TorchScript AGAIN from this generated code!
import torch
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear_0 = nn.Linear(in_features=128, out_features=256, bias=True)
self.linear_1 = nn.Linear(in_features=256, out_features=4, bias=True)
def forward(self, x):
x = self.linear_0(x)
x = F.leaky_relu(x, 0.15)
x = self.linear_1(x)
return x
import os
import numpy as np
import tempfile, zipfile
import torch
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear_0 = nn.Linear(bias=True, in_features=128, out_features=256)
self.linear_1 = nn.Linear(bias=True, in_features=256, out_features=4)
archive = zipfile.ZipFile('../../function.pnnx.bin', 'r')
self.linear_0.bias = self.load_pnnx_bin_as_parameter(archive, 'linear_0.bias', (256), 'float32')
self.linear_0.weight = self.load_pnnx_bin_as_parameter(archive, 'linear_0.weight', (256,128), 'float32')
self.linear_1.bias = self.load_pnnx_bin_as_parameter(archive, 'linear_1.bias', (4), 'float32')
self.linear_1.weight = self.load_pnnx_bin_as_parameter(archive, 'linear_1.weight', (4,256), 'float32')
archive.close()
def load_pnnx_bin_as_parameter(self, archive, key, shape, dtype):
return nn.Parameter(self.load_pnnx_bin_as_tensor(archive, key, shape, dtype))
def load_pnnx_bin_as_tensor(self, archive, key, shape, dtype):
fd, tmppath = tempfile.mkstemp()
with os.fdopen(fd, 'wb') as tmpf, archive.open(key) as keyfile:
tmpf.write(keyfile.read())
m = np.memmap(tmppath, dtype=dtype, mode='r', shape=shape).copy()
os.remove(tmppath)
return torch.from_numpy(m)
def forward(self, v_x_1):
v_7 = self.linear_0(v_x_1)
v_input_1 = F.leaky_relu(input=v_7, negative_slope=0.150000)
v_12 = self.linear_1(v_input_1)
return v_12
Users could ask PNNX to resolve all tensor shapes in model graph and constify some common expressions involved when tensor shapes are known.
The process is optional and could be enabled via inputshape command line option.
pnnx shufflenet_v2_x1_0.pt inputshape=[1,3,224,224]
def channel_shuffle(x: Tensor, groups: int) -> Tensor:
batchsize, num_channels, height, width = x.size()
channels_per_group = num_channels // groups
# reshape
x = x.view(batchsize, groups, channels_per_group, height, width)
x = torch.transpose(x, 1, 2).contiguous()
# flatten
x = x.view(batchsize, -1, height, width)
return x
| without shape propagation | with shape propagation |
|---|---|
| ONNX | TorchScript | PNNX without optimization | PNNX with optimization |
|---|---|---|---|
import os
import torch
from torch.autograd import Function
from torch.utils.cpp_extension import load, _import_module_from_library
module_path = os.path.dirname(__file__)
upfirdn2d_op = load(
'upfirdn2d',
sources=[
os.path.join(module_path, 'upfirdn2d.cpp'),
os.path.join(module_path, 'upfirdn2d_kernel.cu'),
],
is_python_module=False
)
def upfirdn2d(input, kernel, up=1, down=1, pad=(0, 0)):
pad_x0 = pad[0]
pad_x1 = pad[1]
pad_y0 = pad[0]
pad_y1 = pad[1]
kernel_h, kernel_w = kernel.shape
batch, channel, in_h, in_w = input.shape
input = input.reshape(-1, in_h, in_w, 1)
out_h = (in_h * up + pad_y0 + pad_y1 - kernel_h) // down + 1
out_w = (in_w * up + pad_x0 + pad_x1 - kernel_w) // down + 1
out = torch.ops.upfirdn2d_op.upfirdn2d(input, kernel, up, up, down, down, pad_x0, pad_x1, pad_y0, pad_y1)
out = out.view(-1, channel, out_h, out_w)
return out
#include <torch/extension.h>
torch::Tensor upfirdn2d(const torch::Tensor& input, const torch::Tensor& kernel,
int64_t up_x, int64_t up_y, int64_t down_x, int64_t down_y,
int64_t pad_x0, int64_t pad_x1, int64_t pad_y0, int64_t pad_y1) {
// operator body
}
TORCH_LIBRARY(upfirdn2d_op, m) {
m.def("upfirdn2d", upfirdn2d);
}
| torch.nn | Is Supported | Export to ncnn |
|---|---|---|
| nn.AdaptiveAvgPool1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AdaptiveAvgPool2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AdaptiveAvgPool3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AdaptiveMaxPool1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AdaptiveMaxPool2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AdaptiveMaxPool3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.AlphaDropout | :heavy_check_mark: | :heavy_check_mark: |
| nn.AvgPool1d | :heavy_check_mark: | :heavy_check_mark:* |
| nn.AvgPool2d | :heavy_check_mark: | :heavy_check_mark:* |
| nn.AvgPool3d | :heavy_check_mark: | :heavy_check_mark:* |
| nn.BatchNorm1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.BatchNorm2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.BatchNorm3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Bilinear | ||
| nn.CELU | :heavy_check_mark: | :heavy_check_mark: |
| nn.ChannelShuffle | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConstantPad1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConstantPad2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConstantPad3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Conv1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Conv2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Conv3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConvTranspose1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConvTranspose2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ConvTranspose3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.CosineSimilarity | ||
| nn.Dropout | :heavy_check_mark: | :heavy_check_mark: |
| nn.Dropout2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Dropout3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ELU | :heavy_check_mark: | :heavy_check_mark: |
| nn.Embedding | :heavy_check_mark: | :heavy_check_mark: |
| nn.EmbeddingBag | ||
| nn.Flatten | :heavy_check_mark: | |
| nn.Fold | :heavy_check_mark: | :heavy_check_mark: |
| nn.FractionalMaxPool2d | ||
| nn.FractionalMaxPool3d | ||
| nn.GELU | :heavy_check_mark: | :heavy_check_mark: |
| nn.GLU | :heavy_check_mark: | :heavy_check_mark: |
| nn.GroupNorm | :heavy_check_mark: | :heavy_check_mark: |
| nn.GRU | :heavy_check_mark: | :heavy_check_mark: |
| nn.GRUCell | ||
| nn.Hardshrink | :heavy_check_mark: | :heavy_check_mark: |
| nn.Hardsigmoid | :heavy_check_mark: | :heavy_check_mark: |
| nn.Hardswish | :heavy_check_mark: | :heavy_check_mark: |
| nn.Hardtanh | :heavy_check_mark: | :heavy_check_mark: |
| nn.Identity | :heavy_check_mark: | :heavy_check_mark: |
| nn.InstanceNorm1d | :heavy_check_mark: | |
| nn.InstanceNorm2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.InstanceNorm3d | :heavy_check_mark: | |
| nn.LayerNorm | :heavy_check_mark: | :heavy_check_mark: |
| nn.LazyBatchNorm1d | ||
| nn.LazyBatchNorm2d | ||
| nn.LazyBatchNorm3d | ||
| nn.LazyConv1d | ||
| nn.LazyConv2d | ||
| nn.LazyConv3d | ||
| nn.LazyConvTranspose1d | ||
| nn.LazyConvTranspose2d | ||
| nn.LazyConvTranspose3d | ||
| nn.LazyLinear | ||
| nn.LeakyReLU | :heavy_check_mark: | :heavy_check_mark: |
| nn.Linear | :heavy_check_mark: | :heavy_check_mark: |
| nn.LocalResponseNorm | :heavy_check_mark: | :heavy_check_mark: |
| nn.LogSigmoid | :heavy_check_mark: | :heavy_check_mark: |
| nn.LogSoftmax | :heavy_check_mark: | :heavy_check_mark: |
| nn.LPPool1d | :heavy_check_mark: | |
| nn.LPPool2d | :heavy_check_mark: | |
| nn.LSTM | :heavy_check_mark: | :heavy_check_mark: |
| nn.LSTMCell | ||
| nn.MaxPool1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.MaxPool2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.MaxPool3d | :heavy_check_mark: | :heavy_check_mark: |
| nn.MaxUnpool1d | ||
| nn.MaxUnpool2d | ||
| nn.MaxUnpool3d | ||
| nn.Mish | :heavy_check_mark: | :heavy_check_mark: |
| nn.MultiheadAttention | :heavy_check_mark: | :heavy_check_mark:* |
| nn.PairwiseDistance | ||
| nn.PixelShuffle | :heavy_check_mark: | :heavy_check_mark: |
| nn.PixelUnshuffle | :heavy_check_mark: | :heavy_check_mark: |
| nn.PReLU | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReflectionPad1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReflectionPad2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReLU | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReLU6 | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReplicationPad1d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReplicationPad2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ReplicationPad3d | :heavy_check_mark: | |
| nn.RMSNorm | :heavy_check_mark: | :heavy_check_mark: |
| nn.RNN | :heavy_check_mark: | :heavy_check_mark:* |
| nn.RNNBase | ||
| nn.RNNCell | ||
| nn.RReLU | :heavy_check_mark: | |
| nn.SELU | :heavy_check_mark: | :heavy_check_mark: |
| nn.Sigmoid | :heavy_check_mark: | :heavy_check_mark: |
| nn.SiLU | :heavy_check_mark: | :heavy_check_mark: |
| nn.Softmax | :heavy_check_mark: | :heavy_check_mark: |
| nn.Softmax2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.Softmin | :heavy_check_mark: | |
| nn.Softplus | :heavy_check_mark: | |
| nn.Softshrink | :heavy_check_mark: | :heavy_check_mark: |
| nn.Softsign | :heavy_check_mark: | |
| nn.SyncBatchNorm | ||
| nn.Tanh | :heavy_check_mark: | :heavy_check_mark: |
| nn.Tanhshrink | :heavy_check_mark: | |
| nn.Threshold | :heavy_check_mark: | |
| nn.Transformer | ||
| nn.TransformerDecoder | ||
| nn.TransformerDecoderLayer | ||
| nn.TransformerEncoder | ||
| nn.TransformerEncoderLayer | ||
| nn.Unflatten | ||
| nn.Unfold | :heavy_check_mark: | :heavy_check_mark: |
| nn.Upsample | :heavy_check_mark: | :heavy_check_mark: |
| nn.UpsamplingBilinear2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.UpsamplingNearest2d | :heavy_check_mark: | :heavy_check_mark: |
| nn.ZeroPad2d | :heavy_check_mark: | :heavy_check_mark: |
| torch.nn.functional | Is Supported | Export to ncnn |
|---|---|---|
| F.adaptive_avg_pool1d | :heavy_check_mark: | :heavy_check_mark: |
| F.adaptive_avg_pool2d | :heavy_check_mark: | :heavy_check_mark: |
| F.adaptive_avg_pool3d | :heavy_check_mark: | :heavy_check_mark: |
| F.adaptive_max_pool1d | :heavy_check_mark: | :heavy_check_mark: |
| F.adaptive_max_pool2d | :heavy_check_mark: | :heavy_check_mark: |
| F.adaptive_max_pool3d | :heavy_check_mark: | :heavy_check_mark: |
| F.affine_grid | :heavy_check_mark: | |
| F.alpha_dropout | :heavy_check_mark: | :heavy_check_mark: |
| F.avg_pool1d | :heavy_check_mark: | :heavy_check_mark:* |
| F.avg_pool2d | :heavy_check_mark: | :heavy_check_mark:* |
| F.avg_pool3d | :heavy_check_mark: | :heavy_check_mark:* |
| F.batch_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.bilinear | ||
| F.celu | :heavy_check_mark: | |
| F.conv1d | :heavy_check_mark: | :heavy_check_mark: |
| F.conv2d | :heavy_check_mark: | :heavy_check_mark: |
| F.conv3d | :heavy_check_mark: | :heavy_check_mark: |
| F.conv_transpose1d | :heavy_check_mark: | :heavy_check_mark: |
| F.conv_transpose2d | :heavy_check_mark: | :heavy_check_mark: |
| F.conv_transpose3d | :heavy_check_mark: | :heavy_check_mark: |
| F.cosine_similarity | ||
| F.dropout | :heavy_check_mark: | :heavy_check_mark: |
| F.dropout2d | :heavy_check_mark: | :heavy_check_mark: |
| F.dropout3d | :heavy_check_mark: | :heavy_check_mark: |
| F.elu | :heavy_check_mark: | :heavy_check_mark: |
| F.embedding | :heavy_check_mark: | :heavy_check_mark: |
| F.embedding_bag | ||
| F.feature_alpha_dropout | :heavy_check_mark: | :heavy_check_mark: |
| F.fold | :heavy_check_mark: | :heavy_check_mark: |
| F.fractional_max_pool2d | ||
| F.fractional_max_pool3d | ||
| F.gelu | :heavy_check_mark: | :heavy_check_mark: |
| F.glu | :heavy_check_mark: | :heavy_check_mark: |
| F.grid_sample | :heavy_check_mark: | :heavy_check_mark: |
| F.group_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.gumbel_softmax | ||
| F.hardshrink | :heavy_check_mark: | :heavy_check_mark: |
| F.hardsigmoid | :heavy_check_mark: | :heavy_check_mark: |
| F.hardswish | :heavy_check_mark: | :heavy_check_mark: |
| F.hardtanh | :heavy_check_mark: | :heavy_check_mark: |
| F.instance_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.interpolate | :heavy_check_mark: | :heavy_check_mark: |
| F.layer_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.leaky_relu | :heavy_check_mark: | :heavy_check_mark: |
| F.linear | :heavy_check_mark: | :heavy_check_mark:* |
| F.local_response_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.logsigmoid | :heavy_check_mark: | :heavy_check_mark: |
| F.log_softmax | :heavy_check_mark: | :heavy_check_mark: |
| F.lp_pool1d | :heavy_check_mark: | |
| F.lp_pool2d | :heavy_check_mark: | |
| F.max_pool1d | :heavy_check_mark: | :heavy_check_mark: |
| F.max_pool2d | :heavy_check_mark: | :heavy_check_mark: |
| F.max_pool3d | :heavy_check_mark: | :heavy_check_mark: |
| F.max_unpool1d | ||
| F.max_unpool2d | ||
| F.max_unpool3d | ||
| F.mish | :heavy_check_mark: | :heavy_check_mark: |
| F.normalize | :heavy_check_mark: | :heavy_check_mark: |
| F.one_hot | ||
| F.pad | :heavy_check_mark: | :heavy_check_mark: |
| F.pairwise_distance | ||
| F.pdist | ||
| F.pixel_shuffle | :heavy_check_mark: | :heavy_check_mark: |
| F.pixel_unshuffle | :heavy_check_mark: | :heavy_check_mark: |
| F.prelu | :heavy_check_mark: | :heavy_check_mark: |
| F.relu | :heavy_check_mark: | :heavy_check_mark: |
| F.relu6 | :heavy_check_mark: | :heavy_check_mark: |
| F.rms_norm | :heavy_check_mark: | :heavy_check_mark: |
| F.rrelu | :heavy_check_mark: | |
| F.scaled_dot_product_attention | :heavy_check_mark: | |
| F.selu | :heavy_check_mark: | :heavy_check_mark: |
| F.sigmoid | :heavy_check_mark: | :heavy_check_mark: |
| F.silu | :heavy_check_mark: | :heavy_check_mark: |
| F.softmax | :heavy_check_mark: | :heavy_check_mark: |
| F.softmin | :heavy_check_mark: | |
| F.softplus | :heavy_check_mark: | |
| F.softshrink | :heavy_check_mark: | :heavy_check_mark: |
| F.softsign | :heavy_check_mark: | |
| F.tanh | :heavy_check_mark: | :heavy_check_mark: |
| F.tanhshrink | :heavy_check_mark: | |
| F.threshold | :heavy_check_mark: | |
| F.unfold | :heavy_check_mark: | :heavy_check_mark: |
| F.upsample | :heavy_check_mark: | :heavy_check_mark: |
| F.upsample_bilinear | :heavy_check_mark: | :heavy_check_mark: |
| F.upsample_nearest | :heavy_check_mark: | :heavy_check_mark: |
| onnx | Is Supported | Export to ncnn | Note |
|---|---|---|---|
| Abs | :heavy_check_mark: | :heavy_check_mark: | |
| Acos | :heavy_check_mark: | :heavy_check_mark: | |
| Add | :heavy_check_mark: | :heavy_check_mark: | |
| Asin | :heavy_check_mark: | :heavy_check_mark: | |
| Atan | :heavy_check_mark: | :heavy_check_mark: | |
| AveragePool | :heavy_check_mark: | :heavy_check_mark: | |
| BatchNormalization | :heavy_check_mark: | :heavy_check_mark: | only training_mode=0 |
| Ceil | :heavy_check_mark: | :heavy_check_mark: | |
| Celu | :heavy_check_mark: | :heavy_check_mark: | |
| Clip | :heavy_check_mark: | :heavy_check_mark: | |
| Concat | :heavy_check_mark: | :heavy_check_mark: | |
| Constant | :heavy_check_mark: | :heavy_check_mark: | |
| Conv | :heavy_check_mark: | :heavy_check_mark: | |
| ConvTranspose | :heavy_check_mark: | :heavy_check_mark: | no auto_pad=SAME |
| Cos | :heavy_check_mark: | :heavy_check_mark: | |
| DepthToSpace | :heavy_check_mark: | :heavy_check_mark: | only mode='CRD' |
| Div | :heavy_check_mark: | :heavy_check_mark: | |
| Dropout | :heavy_check_mark: | :heavy_check_mark: | |
| Elu | :heavy_check_mark: | :heavy_check_mark: | |
| Erf | |||
| Exp | :heavy_check_mark: | :heavy_check_mark: | |
| Flatten | :heavy_check_mark: | :heavy_check_mark: | |
| Floor | :heavy_check_mark: | :heavy_check_mark: | |
| GRU | :heavy_check_mark: | :heavy_check_mark: | with post squeeze/transpose+reshape |
| Gelu | :heavy_check_mark: | :heavy_check_mark: | |
| Gemm | :heavy_check_mark: | :heavy_check_mark: | |
| GlobalAveragePool | :heavy_check_mark: | :heavy_check_mark: | |
| GlobalMaxPool | :heavy_check_mark: | :heavy_check_mark: | |
| GroupNormalization | :heavy_check_mark: | :heavy_check_mark: | |
| HardSigmoid | :heavy_check_mark: | :heavy_check_mark: | |
| HardSwish | :heavy_check_mark: | :heavy_check_mark: | |
| InstanceNormalization | :heavy_check_mark: | :heavy_check_mark: | |
| LRN | :heavy_check_mark: | :heavy_check_mark: | |
| LSTM | :heavy_check_mark: | :heavy_check_mark: | with post squeeze/transpose+reshape |
| LayerNormalization | :heavy_check_mark: | :heavy_check_mark: | |
| LeakyRelu | :heavy_check_mark: | :heavy_check_mark: | |
| Log | :heavy_check_mark: | :heavy_check_mark: | |
| LogSoftmax | :heavy_check_mark: | :heavy_check_mark: | |
| MatMul | :heavy_check_mark: | :heavy_check_mark: | |
| Max | :heavy_check_mark: | :heavy_check_mark: | |
| MaxPool | :heavy_check_mark: | :heavy_check_mark: | |
| Min | :heavy_check_mark: | :heavy_check_mark: | |
| Mish | :heavy_check_mark: | :heavy_check_mark: | |
| Mul | :heavy_check_mark: | :heavy_check_mark: | |
| Neg | :heavy_check_mark: | :heavy_check_mark: | |
| PRelu | :heavy_check_mark: | :heavy_check_mark: | |
| Pad | :heavy_check_mark: | :heavy_check_mark: | |
| Pow | :heavy_check_mark: | :heavy_check_mark: | |
| RNN | :heavy_check_mark: | :heavy_check_mark: | with post squeeze/transpose+reshape |
| Reciprocal | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceL1 | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceL2 | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceLogSum | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceLogSumExp | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceMax | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceMean | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceMin | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceProd | :heavy_check_mark: | :heavy_check_mark: | unroll axes |
| ReduceSum | :heavy_check_mark: | :heavy_check_mark: | |
| ReduceSumSquare | :heavy_check_mark: | :heavy_check_mark: | |
| Relu | :heavy_check_mark: | :heavy_check_mark: | |
| Reshape | :heavy_check_mark: | :heavy_check_mark: | |
| Resize | :heavy_check_mark: | :heavy_check_mark: | |
| RMSNormalization | :heavy_check_mark: | :heavy_check_mark: | |
| Selu | :heavy_check_mark: | :heavy_check_mark: | |
| Shrink | :heavy_check_mark: | :heavy_check_mark: | only bias==0/lambda |
| Sigmoid | :heavy_check_mark: | :heavy_check_mark: | |
| Sin | :heavy_check_mark: | :heavy_check_mark: | |
| Slice | :heavy_check_mark: | :heavy_check_mark: | |
| Softmax | :heavy_check_mark: | :heavy_check_mark: | |
| Softplus | :heavy_check_mark: | :heavy_check_mark: | |
| Split | :heavy_check_mark: | :heavy_check_mark: | |
| Sqrt | :heavy_check_mark: | :heavy_check_mark: | |
| Squeeze | :heavy_check_mark: | :heavy_check_mark: | |
| Sub | :heavy_check_mark: | :heavy_check_mark: | |
| Sum | :heavy_check_mark: | :heavy_check_mark: | |
| Tan | :heavy_check_mark: | :heavy_check_mark: | |
| Tanh | :heavy_check_mark: | :heavy_check_mark: | |
| Transpose | :heavy_check_mark: | :heavy_check_mark: | |
| Unsqueeze | :heavy_check_mark: | :heavy_check_mark: | unroll axes |
| Upsample |