1# Copyright (c) Meta Platforms, Inc. and affiliates. 2# All rights reserved. 3# 4# This source code is licensed under the BSD-style license found in the 5# LICENSE file in the root directory of this source tree. 6 7import torch 8from executorch.exir.dialects._ops import ops as exir_ops 9 10""" 11** How to incorporate a new op into the XNNPACK Partitioner? ** 12 13[1] When the new edge op being added is direct descendent of a core-aten op, 14and is also supported* by XNNPACK, prefer partitioning it via SUPPORTED_OPS 15mechanism e.g. torch.add 16 17[2] When the new op being added is not a core-aten op, 18 19[2.1] If the original torch op is supported* by XNNPACK, prefer partitioning it 20via SUPPORTED_MODULES. This will require "recomposing" the op before lowering 21it to XNNPACK e.g. torch.nn.Linear. Make sure to include all variants of the 22modules in the SUPPORTED_MODULES list. 23 24[2.2] If the original torch op is not supported by XNNPACK, then it is assumed 25that out of all the decomposed core-aten ops, SUPPORTED_OPS will be lowered to 26XNNPACK. 27 28* - Supported fully or partially. The partial support does not mean only few 29ops from the decomposition but means only some variants of the op "modes" 30possible with the arg combinations. 31""" 32 33SUPPORTED_OPS = [ 34 exir_ops.edge.aten.div.Tensor, 35 exir_ops.edge.aten.add.Tensor, 36 exir_ops.edge.aten.clamp.default, 37 exir_ops.edge.aten.sub.Tensor, 38 exir_ops.edge.aten.floor.default, 39 exir_ops.edge.aten.maximum.default, 40 exir_ops.edge.aten.minimum.default, 41 exir_ops.edge.aten.mul.Tensor, 42 exir_ops.edge.aten.constant_pad_nd.default, 43 exir_ops.edge.aten.upsample_bilinear2d.default, 44 exir_ops.edge.aten.mean.dim, 45 exir_ops.edge.aten.max.dim, 46 exir_ops.edge.aten.max_pool2d_with_indices.default, 47 exir_ops.edge.aten.hardtanh.default, 48 exir_ops.edge.aten.sqrt.default, 49 exir_ops.edge.aten.ceil.default, 50 exir_ops.edge.aten.hardswish.default, 51 exir_ops.edge.aten.neg.default, 52 exir_ops.edge.aten.pow.Tensor_Scalar, 53 exir_ops.edge.aten.abs.default, 54 exir_ops.edge.aten._prelu_kernel.default, 55 exir_ops.edge.aten.slice_copy.Tensor, 56 exir_ops.edge.aten.relu.default, 57 exir_ops.edge.aten.hardtanh.default, 58 exir_ops.edge.aten.permute_copy.default, 59 exir_ops.edge.aten.sigmoid.default, 60 exir_ops.edge.aten._softmax.default, 61 exir_ops.edge.aten.cat.default, 62 exir_ops.edge.aten.elu.default, 63 exir_ops.edge.aten.avg_pool2d.default, 64 exir_ops.edge.aten.leaky_relu.default, 65 exir_ops.edge.aten.addmm.default, # TODO(T163877189) add constraint for addmm 66] 67 68SUPPORTED_MODULES = [ 69 torch.nn.Conv1d, 70 # TODO(T161981984) recomposed hardswish into a single node 71 torch.nn.Hardswish, # we need to recompose 72 torch.nn.Hardsigmoid, # we can handle decomposition 73 torch.nn.BatchNorm2d, 74 torch.nn.BatchNorm1d, 75 torch.nn.Conv2d, 76 torch.nn.Linear, 77 torch.nn.functional.linear, 78 torch.nn.PReLU, # Without this, the PReLU weight becomes not a get_attr 79] 80 81# TODO delete this and should use SUPPORTED_OPS instead once we align fp32 and quant support 82SUPPORTED_QUANT_OPS = [ 83 exir_ops.edge.aten.add.Tensor, 84 exir_ops.edge.aten.clamp.default, 85 exir_ops.edge.aten.relu.default, 86 exir_ops.edge.aten.sub.Tensor, 87 exir_ops.edge.aten.mul.Tensor, 88 exir_ops.edge.aten.mean.dim, 89 exir_ops.edge.aten.hardtanh.default, 90 exir_ops.edge.aten.slice_copy.Tensor, 91 exir_ops.edge.aten.permute_copy.default, 92 exir_ops.edge.aten.hardtanh.default, 93 exir_ops.edge.aten.mean.dim, 94 exir_ops.edge.aten.cat.default, 95 exir_ops.edge.aten.max_pool2d_with_indices.default, 96 exir_ops.edge.aten.max_pool2d.default, 97 exir_ops.edge.aten.constant_pad_nd.default, 98 exir_ops.edge.aten.elu.default, 99 exir_ops.edge.aten.t_copy.default, 100 exir_ops.edge.aten.leaky_relu.default, 101 exir_ops.edge.aten.addmm.default, # TODO(T163877189) add constraint for addmm 102] 103 104# This set is used to determine if an op is a supported Quantized Op. This is 105# used to determine whether a quantization op is implicit or explicit. 106SUPPORTED_IMPLICIT_Q_DQ_OP_NAMES_SET = { 107 op.name() 108 for op in ( 109 SUPPORTED_QUANT_OPS 110 + [ 111 exir_ops.edge.aten._to_copy.default, 112 exir_ops.edge.aten.linear.default, 113 exir_ops.edge.aten.convolution.default, 114 ] 115 ) 116} 117 118UNSUPPORTED_QUANT_MODULES = [ 119 torch.nn.Hardswish, 120 torch.nn.Hardsigmoid, 121] 122 123# TODO delete this and should use SUPPORTED_MODULES instead once we align fp32 and quant support 124SUPPORTED_QUANT_MODULES = [ 125 torch.nn.Linear, 126 torch.nn.functional.linear, 127 # TODO - T158982884 128 # torch.ao.nn.quantized.reference.modules.linear.Linear, 129 torch.nn.Conv1d, 130 torch.nn.functional.conv1d, 131 torch.ao.nn.quantized.reference.modules.conv.Conv1d, 132 torch.nn.Conv2d, 133 torch.nn.functional.conv2d, 134 torch.ao.nn.quantized.reference.modules.conv.Conv2d, 135 torch.nn.BatchNorm1d, 136 torch.nn.BatchNorm2d, 137] 138 139SUPPORTED_IMPLICIT_Q_DQ_MODULES_SET = set(SUPPORTED_QUANT_MODULES) 140 141# Modules which support dynamic quantization 142# These already support dynamic shape. 143SUPPORTED_DYN_QUANT_LINEAR_MODULES = [ 144 torch.nn.Linear, 145 torch.nn.functional.linear, 146] 147 148SUPPORTED_DYN_QUANT_MODULES = SUPPORTED_DYN_QUANT_LINEAR_MODULES 149 150# XNNPACK supports majority of shape dynamism, however some ops are 151# explicitly static, so we maintain a set here to exclude them from 152# dynamic shape support. 153STATIC_OPS = [ 154 exir_ops.edge.aten.cat.default, 155 exir_ops.edge.aten.slice_copy.Tensor, 156] 157 158STATIC_MODULES = [] 159