@@ -1119,6 +1119,54 @@ DEFINE_BUILTIN_OP_IMPORTER(Expand)
11191119 RETURN_FIRST_OUTPUT (sliceLayer);
11201120}
11211121
1122+ DEFINE_BUILTIN_OP_IMPORTER (EyeLike)
1123+ {
1124+ // Get input node.
1125+ nvinfer1::ITensor& tensor = convertToTensor (inputs.at (0 ), ctx);
1126+ OnnxAttrs attrs (node, ctx);
1127+ int k = attrs.get (" k" , 0 );
1128+
1129+ // "Only 2D tensors are supported, i.e. input T1 must be of rank 2..."
1130+ nvinfer1::Dims dims = tensor.getDimensions ();
1131+ ASSERT (dims.nbDims == 2 && " Only 2D tensors are supported. Input must be of rank 2." , ErrorCode::kUNSUPPORTED_NODE );
1132+
1133+ // The data type can be specified by the 'dtype' argument
1134+ nvinfer1::DataType dtype = tensor.getType ();
1135+ if (attrs.count (" dtype" ))
1136+ {
1137+ auto onnxType = attrs.get <int32_t >(" dtype" );
1138+ ASSERT (convertDtype (onnxType, &dtype) && " Unsupported cast!" , ErrorCode::kINVALID_NODE );
1139+ LOG_VERBOSE (" Casting to type: " << dtype);
1140+ }
1141+
1142+ // Create weights and constant layer
1143+ ASSERT (!isDynamic (dims) && " Eyelike does not work for dynamically shaped tensors." , ErrorCode::kUNSUPPORTED_NODE );
1144+ int totalWeights = dims.d [0 ]*dims.d [1 ];
1145+ std::vector<int > values (totalWeights);
1146+ for (int r = 0 ; r < dims.d [0 ]; ++r)
1147+ {
1148+ for (int c = 0 ; c < dims.d [1 ]; ++c)
1149+ {
1150+ values[r*dims.d [1 ] + c] = 0 ;
1151+ if (c - r == k)
1152+ {
1153+ values[r*dims.d [1 ] + c] = 1 ;
1154+ }
1155+ }
1156+ }
1157+
1158+ ShapedWeights tempWeights = ctx->createTempWeights (::ONNX_NAMESPACE::TensorProto::INT32, dims);
1159+ std::memcpy (tempWeights.values , values.data (), values.size () * sizeof (int ));
1160+ auto * layer = ctx->network ()->addConstant (dims, tempWeights);
1161+ layer->setOutputType (0 , nvinfer1::DataType::kINT32 );
1162+ ctx->registerLayer (layer, node.name ());
1163+
1164+ if (dtype != nvinfer1::DataType::kINT32 ) {
1165+ return {{castHelper (ctx, layer->getOutput (0 ), dtype)}};
1166+ }
1167+ return {{layer->getOutput (0 )}};
1168+ }
1169+
11221170DEFINE_BUILTIN_OP_IMPORTER (Flatten)
11231171{
11241172 OnnxAttrs attrs (node, ctx);
@@ -1156,6 +1204,92 @@ DEFINE_BUILTIN_OP_IMPORTER(Gather)
11561204 RETURN_FIRST_OUTPUT (layer);
11571205}
11581206
1207+ DEFINE_BUILTIN_OP_IMPORTER (GatherElements)
1208+ {
1209+ nvinfer1::ITensor& data = convertToTensor (inputs.at (0 ), ctx);
1210+ nvinfer1::ITensor& index = convertToTensor (inputs.at (1 ), ctx);
1211+
1212+ const nvinfer1::Dims& idxDims = index.getDimensions ();
1213+ const nvinfer1::Dims& dataDims = data.getDimensions ();
1214+
1215+ OnnxAttrs attrs (node, ctx);
1216+ int32_t axis = attrs.get <int32_t >(" axis" , 0 );
1217+ int32_t dataNbDims = dataDims.nbDims ;
1218+
1219+ TRT_CHECK (convertAxis (axis, dataNbDims));
1220+ LOG_VERBOSE (" Using Gather axis: " << axis);
1221+
1222+ // Calculate how many indices
1223+ int64_t nIndx = volume (idxDims);
1224+
1225+ // Calculate pitches of input tensor
1226+ int32_t nDataElements = volume (dataDims), pitch = 1 ;
1227+ int32_t pitches[nvinfer1::Dims::MAX_DIMS] = {0 };
1228+ pitches[dataDims.nbDims -1 ] = pitch;
1229+ for (int32_t i = dataDims.nbDims -2 ; i >= 0 ; i--)
1230+ {
1231+ pitch *= dataDims.d [i];
1232+ pitches[i] = pitch;
1233+ }
1234+
1235+ // Generate constants based on axis
1236+ std::vector<int32_t > sCoeff (nIndx, pitches[axis]);
1237+ std::vector<int32_t > aCoeff;
1238+
1239+ // Transform a 1-d index back to the nDims
1240+ for (int32_t i = 0 ; i < nIndx; i++)
1241+ {
1242+ std::vector<int32_t > nDimsIdx; // this can be an array
1243+ int32_t currI = i;
1244+
1245+ for (int32_t j = 0 ; j < dataDims.nbDims ; j++)
1246+ {
1247+ int32_t currIdxVal = currI / pitches[j];
1248+ nDimsIdx.push_back (currIdxVal);
1249+ currI = currI % pitches[j];
1250+ }
1251+
1252+ int32_t bias = 0 ;
1253+ // calculate the aCoeff
1254+ for (size_t j = 0 ; j < nDimsIdx.size (); j++)
1255+ {
1256+
1257+ if (j == (size_t )axis)
1258+ {
1259+ continue ;
1260+ }
1261+ bias += nDimsIdx[j] * pitches[j];
1262+ }
1263+ aCoeff.push_back (bias);
1264+ }
1265+
1266+ auto * sCoeffLayer = addConstant (ctx, sCoeff , ::ONNX_NAMESPACE::TensorProto::INT32, idxDims);
1267+ auto * aCoeffLayer = addConstant (ctx, aCoeff, ::ONNX_NAMESPACE::TensorProto::INT32, idxDims);
1268+
1269+ nvinfer1::ITensor* sCoeffTensor = sCoeffLayer ->getOutput (0 );
1270+ nvinfer1::ITensor* aCoeffTensor = aCoeffLayer->getOutput (0 );
1271+ auto * mul = ctx->network ()->addElementWise (index, *sCoeffTensor , nvinfer1::ElementWiseOperation::kPROD );
1272+
1273+ nvinfer1::ITensor* mulTensor = mul->getOutput (0 );
1274+ auto * add = ctx->network ()->addElementWise (*mulTensor, *aCoeffTensor, nvinfer1::ElementWiseOperation::kSUM );
1275+
1276+ nvinfer1::ITensor* addTensor = add->getOutput (0 );
1277+
1278+ nvinfer1::Dims flattenDataDims{1 };
1279+
1280+ flattenDataDims.nbDims = 1 ;
1281+ flattenDataDims.d [0 ] = nDataElements;
1282+ auto * reshape = ctx->network ()->addShuffle (data);
1283+ reshape->setReshapeDimensions (flattenDataDims);
1284+ reshape->setZeroIsPlaceholder (false );
1285+
1286+ nvinfer1::ITensor* flattenData = reshape->getOutput (0 );
1287+ auto * layer = ctx->network ()->addGather (*flattenData, *addTensor, 0 );
1288+ ctx->registerLayer (layer, getNodeName (node));
1289+ RETURN_FIRST_OUTPUT (layer);
1290+ }
1291+
1292+
11591293DEFINE_BUILTIN_OP_IMPORTER (Gemm)
11601294{
11611295 OnnxAttrs attrs (node, ctx);
@@ -1859,30 +1993,13 @@ DEFINE_BUILTIN_OP_IMPORTER(Log)
18591993
18601994DEFINE_BUILTIN_OP_IMPORTER (LogSoftmax)
18611995{
1996+ auto & input = convertToTensor (inputs.at (0 ), ctx);
18621997 // Don't use softmax converter since it adds a shuffle layer
18631998 // which prevents the builder to fuse softmax and log operations.
1864-
1865- OnnxAttrs attrs (node, ctx);
1866- // "input : T"
1867- nvinfer1::ITensor& input = convertToTensor (inputs.at (0 ), ctx);
1868- const auto dims = shapeOf (input);
1869- // "axis : int (default is 1)"
1870- int axis = attrs.get (" axis" , 1 );
1871-
1872- // "Negative value means counting dimensions from the back.
1873- // Accepted range is [-r, r-1] where r = rank(input)."
1874- TRT_CHECK (convertAxis (axis, dims.size ()));
1875-
1876- // "The input does not need to explicitly be a 2D vector; rather, it will be coerced into one."
1877- auto * flattened = flattenTensor (ctx, node, input, axis);
1878- auto * softMax = ctx->network ()->addSoftMax (*flattened);
1879- ctx->registerLayer (softMax, node.name ());
1880- // ONNX softmax is always on second dimension.
1881- softMax->setAxes (1 << 1 );
1882-
1999+ auto * softmax = addSoftmax (ctx, node, input);
2000+ nvinfer1::IUnaryLayer* unaryLayer = ctx->network ()->addUnary (*softmax, nvinfer1::UnaryOperation::kLOG );
18832001 // Reshape back to original shape
1884- nvinfer1::IUnaryLayer* unaryLayer = ctx->network ()->addUnary (*softMax->getOutput (0 ), nvinfer1::UnaryOperation::kLOG );
1885- auto *reshapeLayer = addShuffle (ctx, *unaryLayer->getOutput (0 ), dims);
2002+ auto * reshapeLayer = addShuffle (ctx, *unaryLayer->getOutput (0 ), shapeOf (input));
18862003 RETURN_FIRST_OUTPUT (reshapeLayer);
18872004}
18882005
@@ -3573,27 +3690,10 @@ DEFINE_BUILTIN_OP_IMPORTER(Slice)
35733690
35743691DEFINE_BUILTIN_OP_IMPORTER (Softmax)
35753692{
3576- OnnxAttrs attrs (node, ctx);
3577- // "input : T"
3578- nvinfer1::ITensor& input = convertToTensor (inputs.at (0 ), ctx);
3579- const auto dims = shapeOf (input);
3580-
3581- // "axis : int (default is 1)"
3582- int axis = attrs.get (" axis" , 1 );
3583-
3584- // "Negative value means counting dimensions from the back.
3585- // Accepted range is [-r, r-1] where r = rank(input)."
3586- TRT_CHECK (convertAxis (axis, dims.size ()));
3587-
3588- // "The input does not need to explicitly be a 2D vector; rather, it will be coerced into one."
3589- auto * flattened = flattenTensor (ctx, node, input, axis);
3590- auto * softMax = ctx->network ()->addSoftMax (*flattened);
3591- ctx->registerLayer (softMax, node.name ());
3592- // ONNX softmax is always on second dimension.
3593- softMax->setAxes (1 << 1 );
3594-
3693+ auto & input = convertToTensor (inputs.at (0 ), ctx);
3694+ auto * softmax = addSoftmax (ctx, node, input);
35953695 // Reshape back to original shape
3596- auto * reshapeLayer = addShuffle (ctx, *softMax-> getOutput ( 0 ), dims );
3696+ auto * reshapeLayer = addShuffle (ctx, *softmax, shapeOf (input) );
35973697 RETURN_FIRST_OUTPUT (reshapeLayer);
35983698}
35993699
@@ -3684,11 +3784,26 @@ DEFINE_BUILTIN_OP_IMPORTER(Split)
36843784 std::vector<int > splitList;
36853785 ShapeTensor sizes;
36863786 ShapeTensor sizeSliceAxis;
3687- const bool hasSplitList = attrs.count (" split" );
3787+ const bool hasSplitList = (ctx-> getOpsetVersion () >= 13 ) ? (inputs. size () == 2 ) : attrs.count (" split" );
36883788 if (hasSplitList)
36893789 {
36903790 // "Lengths of the parts can be specified using argument split."
3691- splitList = attrs.get <std::vector<int >>(" split" );
3791+ // In opset >= 13, split lengths are an optional input
3792+ if (ctx->getOpsetVersion () >= 13 )
3793+ {
3794+ ASSERT (inputs.at (1 ).is_weights () && " Split input 'split', if specified, must be an initializer!" , ErrorCode::kUNSUPPORTED_NODE );
3795+ auto splitWeights = inputs.at (1 ).weights ();
3796+ int32_t * splitValues = static_cast <int32_t *>(splitWeights.values );
3797+ for (size_t i = 0 ; i < splitWeights.count (); i++)
3798+ {
3799+ splitList.push_back (splitValues[i]);
3800+ }
3801+ }
3802+ // Pre-opset 13 split lengths are provided as an attribute
3803+ else
3804+ {
3805+ splitList = attrs.get <std::vector<int >>(" split" );
3806+ }
36923807 ASSERT (static_cast <int >(splitList.size ()) == numOutputs, ErrorCode::kINVALID_NODE );
36933808 }
36943809 else
@@ -3737,9 +3852,45 @@ DEFINE_BUILTIN_OP_IMPORTER(Squeeze)
37373852 // "data : T
37383853 // Tensor with at least max(dims) dimensions."
37393854 nvinfer1::ITensor& data = convertToTensor (inputs.at (0 ), ctx);
3855+ std::vector<int > axes;
3856+ // In opset >= 13, axes are an optional input
3857+ if (ctx->getOpsetVersion () >= 13 )
3858+ {
3859+ if (inputs.size () == 2 )
3860+ {
3861+ ASSERT (inputs.at (1 ).is_weights () && " Squeeze axes input must an initializer!" , ErrorCode::kUNSUPPORTED_NODE );
3862+ // Map weights value to axes
3863+ auto axesWeights = inputs.at (1 ).weights ();
3864+ int32_t * axesValues = static_cast <int32_t *>(axesWeights.values );
3865+ for (size_t i = 0 ; i < axesWeights.count (); i++)
3866+ {
3867+ axes.push_back (axesValues[i]);
3868+ }
3869+ }
3870+ }
3871+ // Pre-opset 13 axes are provided as an attribute
3872+ else
3873+ {
3874+ OnnxAttrs attrs (node, ctx);
3875+ if (attrs.count (" axes" ))
3876+ {
3877+ axes = attrs.get <std::vector<int >>(" axes" );
3878+ }
3879+ }
37403880
3741- OnnxAttrs attrs (node, ctx);
3742- auto axes = attrs.get <std::vector<int >>(" axes" );
3881+ // If axes are ommitted, squeeze all dimensions with values 1
3882+ if (axes.size () == 0 )
3883+ {
3884+ const auto shape = data.getDimensions ();
3885+ ASSERT (!isDynamic (shape) && " Cannot infer squeeze dimensions from a dynamic shape! Please re-export your model with the Squeeze axes input set." , ErrorCode::kUNSUPPORTED_NODE );
3886+ for (int i = 0 ; i < shape.nbDims ; i++)
3887+ {
3888+ if (shape.d [i] == 1 )
3889+ {
3890+ axes.push_back (i);
3891+ }
3892+ }
3893+ }
37433894
37443895 int rank = data.getDimensions ().nbDims ;
37453896 for (auto & axis : axes)
@@ -3750,7 +3901,6 @@ DEFINE_BUILTIN_OP_IMPORTER(Squeeze)
37503901 // "squeezed : T
37513902 // Reshaped tensor with same data as input."
37523903 auto * squeezed = squeezeTensor (ctx, node, data, axes, true );
3753-
37543904 ASSERT (squeezed && " Failed to squeeze tensor!" , ErrorCode::kUNSUPPORTED_NODE );
37553905
37563906 return {{squeezed}};
@@ -3893,11 +4043,25 @@ DEFINE_BUILTIN_OP_IMPORTER(Unsqueeze)
38934043 // "data : T
38944044 // Original tensor"
38954045 nvinfer1::ITensor& data = convertToTensor (inputs.at (0 ), ctx);
3896- OnnxAttrs attrs (node, ctx) ;
4046+ std::vector< int > axes ;
38974047
3898- // "axes : list of ints (required)
3899- // List of integers indicating the dimensions to be inserted."
3900- auto axes = attrs.get <std::vector<int >>(" axes" );
4048+ if (ctx->getOpsetVersion () >= 13 )
4049+ {
4050+ const ShapeTensor axesInput{inputs.at (1 )};
4051+ ASSERT (axesInput.allValuesKnown () && " Axes input for unsqueeze operation should be a constant tensor." ,
4052+ ErrorCode::kUNSUPPORTED_NODE );
4053+ for (auto & a : axesInput)
4054+ {
4055+ axes.push_back (a);
4056+ }
4057+ }
4058+ else
4059+ {
4060+ OnnxAttrs attrs (node, ctx);
4061+ // "axes : list of ints (required)
4062+ // List of integers indicating the dimensions to be inserted."
4063+ axes = attrs.get <std::vector<int >>(" axes" );
4064+ }
39014065
39024066 // "Negative value means counting dimensions from the back."
39034067 const int newSize = data.getDimensions ().nbDims + axes.size ();
@@ -3909,7 +4073,6 @@ DEFINE_BUILTIN_OP_IMPORTER(Unsqueeze)
39094073 // "expanded : T
39104074 // Reshaped tensor with same data as input."
39114075 auto * expanded = unsqueezeTensor (ctx, node, data, axes, true );
3912-
39134076 ASSERT (expanded && " Failed to unsqueeze tensor!" , ErrorCode::kUNSUPPORTED_NODE );
39144077
39154078 return {{expanded}};
0 commit comments