Skip to content

Commit 8fea430

Browse files
authoredJul 2, 2021
ONNX-TensorRT 8.0 GA release (#706)
Signed-off-by: Kevin Chen <[email protected]>
1 parent 868e636 commit 8fea430

26 files changed

+2541
-1504
lines changed
 

‎CMakeLists.txt

+5-18
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ set(PARSER_LINKER_SCRIPT ${ONNX2TRT_ROOT}/libnvonnxparser.version)
2323
#--------------------------------------------------
2424
# Version information
2525
#--------------------------------------------------
26-
set(ONNX2TRT_MAJOR 7)
27-
set(ONNX2TRT_MINOR 2)
28-
set(ONNX2TRT_PATCH 2)
26+
set(ONNX2TRT_MAJOR 8)
27+
set(ONNX2TRT_MINOR 0)
28+
set(ONNX2TRT_PATCH 1)
2929

3030
#--------------------------------------------------
3131
# Build configurations, global to all projects
@@ -36,6 +36,7 @@ set(IMPORTER_SOURCES
3636
ModelImporter.cpp
3737
builtin_op_importers.cpp
3838
onnx2trt_utils.cpp
39+
onnxErrorRecorder.cpp
3940
ShapedWeights.cpp
4041
ShapeTensor.cpp
4142
LoopHelpers.cpp
@@ -72,10 +73,6 @@ if (NOT DEFINED BUILD_LIBRARY_ONLY)
7273
)
7374
endif()
7475

75-
set(HEADERS
76-
NvOnnxParser.h
77-
)
78-
7976
if (NOT TARGET protobuf::libprotobuf)
8077
FIND_PACKAGE(Protobuf REQUIRED)
8178
else()
@@ -102,16 +99,7 @@ find_library(TENSORRT_LIBRARY_INFER nvinfer
10299
find_library(TENSORRT_LIBRARY_INFER_PLUGIN nvinfer_plugin
103100
HINTS ${TENSORRT_ROOT} ${TENSORRT_BUILD} ${CUDA_TOOLKIT_ROOT_DIR}
104101
PATH_SUFFIXES lib lib64 lib/x64)
105-
if(WIN32)
106-
find_library(TENSORRT_LIBRARY_MYELIN myelin64_1
107-
HINTS ${TENSORRT_ROOT} ${TENSORRT_BUILD} ${CUDA_TOOLKIT_ROOT_DIR}
108-
PATH_SUFFIXES lib lib64 lib/x64)
109-
else()
110-
find_library(TENSORRT_LIBRARY_MYELIN myelin
111-
HINTS ${TENSORRT_ROOT} ${TENSORRT_BUILD} ${CUDA_TOOLKIT_ROOT_DIR}
112-
PATH_SUFFIXES lib lib64 lib/x64)
113-
endif()
114-
set(TENSORRT_LIBRARY ${TENSORRT_LIBRARY_INFER} ${TENSORRT_LIBRARY_INFER_PLUGIN} ${TENSORRT_LIBRARY_MYELIN})
102+
set(TENSORRT_LIBRARY ${TENSORRT_LIBRARY_INFER} ${TENSORRT_LIBRARY_INFER_PLUGIN})
115103
MESSAGE(STATUS "Find TensorRT libs at ${TENSORRT_LIBRARY}")
116104
find_package_handle_standard_args(
117105
TENSORRT DEFAULT_MSG TENSORRT_INCLUDE_DIR TENSORRT_LIBRARY)
@@ -175,7 +163,6 @@ install(TARGETS
175163
install(FILES ${HEADERS}
176164
DESTINATION include
177165
)
178-
179166
if (NOT DEFINED BUILD_LIBRARY_ONLY)
180167
install(TARGETS
181168
onnx2trt

‎ImporterContext.hpp

+115-62
Original file line numberDiff line numberDiff line change
@@ -6,88 +6,138 @@
66

77
#include "onnx2trt.hpp"
88
#include "onnx2trt_utils.hpp"
9-
9+
#include "onnxErrorRecorder.hpp"
10+
#include "onnx/common/stl_backports.h"
1011
#include <list>
1112
#include <unordered_map>
1213

1314
namespace onnx2trt
1415
{
1516

17+
class ErrorRecorderWrapper
18+
{
19+
public:
20+
ErrorRecorderWrapper(nvinfer1::INetworkDefinition* network, nvinfer1::ILogger* logger)
21+
: mNetwork(network)
22+
, mLogger(logger)
23+
{
24+
if (mNetwork)
25+
{
26+
mUserErrorRecorder = mNetwork->getErrorRecorder();
27+
mOnnxErrorRecorder = ONNXParserErrorRecorder::create(logger, mUserErrorRecorder);
28+
if (mOnnxErrorRecorder)
29+
{
30+
if (mUserErrorRecorder)
31+
{
32+
mUserErrorRecorder->incRefCount();
33+
}
34+
mNetwork->setErrorRecorder(mOnnxErrorRecorder);
35+
}
36+
}
37+
}
38+
39+
~ErrorRecorderWrapper()
40+
{
41+
if (mNetwork && mOnnxErrorRecorder)
42+
{
43+
mNetwork->setErrorRecorder(mUserErrorRecorder);
44+
if (mUserErrorRecorder)
45+
{
46+
mUserErrorRecorder->decRefCount();
47+
}
48+
ONNXParserErrorRecorder::destroy(mOnnxErrorRecorder);
49+
}
50+
}
51+
52+
bool hasError() const
53+
{
54+
return mOnnxErrorRecorder != nullptr && mOnnxErrorRecorder->getNbErrors() != 0;
55+
}
56+
57+
//! Return recorder used by hasError().
58+
nvinfer1::IErrorRecorder* getErrorRecorder() const
59+
{
60+
return mOnnxErrorRecorder ? mOnnxErrorRecorder : nullptr;
61+
}
62+
private:
63+
nvinfer1::INetworkDefinition* mNetwork{nullptr};
64+
nvinfer1::ILogger* mLogger{nullptr};
65+
ONNXParserErrorRecorder* mOnnxErrorRecorder{nullptr};
66+
nvinfer1::IErrorRecorder* mUserErrorRecorder{nullptr};
67+
};
68+
1669
class ImporterContext final : public IImporterContext
1770
{
18-
nvinfer1::INetworkDefinition* _network;
19-
nvinfer1::ILogger* _logger;
20-
std::list<std::vector<uint8_t>> _temp_bufs;
21-
StringMap<nvinfer1::ITensor*> _user_inputs;
22-
StringMap<nvinfer1::ITensor**> _user_outputs;
23-
StringMap<int64_t> _opsets;
71+
nvinfer1::INetworkDefinition* mNetwork;
72+
nvinfer1::ILogger* mLogger;
73+
std::list<std::vector<uint8_t>> mTempBufs;
74+
StringMap<nvinfer1::ITensor*> mUserInputs;
75+
StringMap<nvinfer1::ITensor**> mUserOutputs;
76+
StringMap<int64_t> mOpsets;
2477
StringMap<TensorOrWeights> mTensors; // All tensors in the graph mapped to their names.
2578
StringMap<nvinfer1::TensorLocation> mTensorLocations;
2679
StringMap<float> mTensorRangeMins;
2780
StringMap<float> mTensorRangeMaxes;
2881
StringMap<nvinfer1::DataType> mLayerPrecisions;
2982
std::set<std::string> mTensorNames; // Keep track of how many times a tensor name shows up, to avoid duplicate naming in TRT.
3083
std::set<std::string> mLayerNames; // Keep track of how many times a tensor name shows up, to avoid duplicate naming in TRT.
31-
int64_t mSuffixCounter = 0; // increasing suffix counter used to uniquify layer names.
84+
int64_t mSuffixCounter{0}; // increasing suffix counter used to uniquify layer names.
3285
std::unordered_set<std::string> mUnsupportedShapeTensors; // Container to hold output tensor names of layers that produce shape tensor outputs but do not natively support them.
3386
StringMap<std::string> mLoopTensors; // Container to map subgraph tensors to their original outer graph names.
3487
std::string mOnnxFileLocation; // Keep track of the directory of the parsed ONNX file
35-
std::list<std::string> mInitializerNames; // Keep track of unique names of any initializers
36-
RefitMap_t* mRefitMap; // Keep track of names of ONNX refittable weights with their corresponding TRT layer and role
88+
std::unique_ptr<ErrorRecorderWrapper> mErrorWrapper; // error recorder to control TRT errors
3789

3890
public:
39-
ImporterContext(nvinfer1::INetworkDefinition* network, nvinfer1::ILogger* logger, RefitMap_t* refitMap)
40-
: _network(network)
41-
, _logger(logger)
42-
, mRefitMap(refitMap)
91+
ImporterContext(nvinfer1::INetworkDefinition* network, nvinfer1::ILogger* logger)
92+
: mNetwork(network)
93+
, mLogger(logger)
94+
// Disable ErrorRecorder for now due to incompatibilities with ONNXRT.
95+
// , mErrorWrapper(ONNX_NAMESPACE::make_unique<ErrorRecorderWrapper>(mNetwork, logger))
96+
, mErrorWrapper(nullptr)
4397
{
4498
}
45-
virtual nvinfer1::INetworkDefinition* network() override
99+
nvinfer1::INetworkDefinition* network() override
46100
{
47-
return _network;
101+
return mNetwork;
48102
}
49-
virtual StringMap<TensorOrWeights>& tensors() override
103+
StringMap<TensorOrWeights>& tensors() override
50104
{
51105
return mTensors;
52106
}
53-
virtual StringMap<nvinfer1::TensorLocation>& tensorLocations() override
107+
StringMap<nvinfer1::TensorLocation>& tensorLocations() override
54108
{
55109
return mTensorLocations;
56110
}
57-
virtual StringMap<float>& tensorRangeMins() override
111+
StringMap<float>& tensorRangeMins() override
58112
{
59113
return mTensorRangeMins;
60114
}
61-
virtual StringMap<float>& tensorRangeMaxes() override
115+
StringMap<float>& tensorRangeMaxes() override
62116
{
63117
return mTensorRangeMaxes;
64118
}
65-
virtual StringMap<nvinfer1::DataType>& layerPrecisions() override
119+
StringMap<nvinfer1::DataType>& layerPrecisions() override
66120
{
67121
return mLayerPrecisions;
68122
}
69-
virtual std::unordered_set<std::string>& unsupportedShapeTensors() override
123+
std::unordered_set<std::string>& unsupportedShapeTensors() override
70124
{
71125
return mUnsupportedShapeTensors;
72126
}
73-
virtual StringMap<std::string>& loopTensors() override
127+
StringMap<std::string>& loopTensors() override
74128
{
75129
return mLoopTensors;
76130
}
77-
virtual void setOnnxFileLocation(std::string location) override
131+
void setOnnxFileLocation(std::string location) override
78132
{
79133
mOnnxFileLocation = location;
80134
}
81-
virtual std::string getOnnxFileLocation() override
135+
std::string getOnnxFileLocation() override
82136
{
83137
return mOnnxFileLocation;
84138
}
85-
virtual void insertRefitMap(std::string weightsName, std::string layerName, nvinfer1::WeightsRole role) override
86-
{
87-
mRefitMap->insert({weightsName, WeightsPair_t{layerName, role}});
88-
}
89139
// This actually handles weights as well, but is named this way to be consistent with the tensors()
90-
virtual void registerTensor(TensorOrWeights tensor, const std::string& basename) override
140+
void registerTensor(TensorOrWeights tensor, const std::string& basename) override
91141
{
92142
// TRT requires unique tensor names.
93143
const std::string uniqueName = generateUniqueName(mTensorNames, basename);
@@ -103,22 +153,22 @@ class ImporterContext final : public IImporterContext
103153
}
104154
else if (tensor.is_weights())
105155
{
106-
mInitializerNames.push_back(uniqueName);
107156
const auto& weights = tensor.weights();
108157
if (tensor.weights().type == ::ONNX_NAMESPACE::TensorProto::INT64)
109158
{
110159
tensor = ShapedWeights{::ONNX_NAMESPACE::TensorProto::INT32,
111160
convertINT64(reinterpret_cast<int64_t*>(weights.values), weights.shape, ctx), weights.shape};
112161
}
113-
tensor.weights().setName(mInitializerNames.back().c_str());
162+
tensor.weights().setName(basename.c_str());
114163
}
164+
115165
}
116166
// Overwrite previous tensors registered with the same name (this only happens when there are subgraphs,
117167
// and in that case, overwriting is the desired behavior).
118168
this->tensors()[basename] = std::move(tensor);
119169
}
120170

121-
virtual void registerLayer(nvinfer1::ILayer* layer, const std::string& basename) override
171+
void registerLayer(nvinfer1::ILayer* layer, const std::string& basename) override
122172
{
123173
// No layer will be added for Constant nodes in ONNX.
124174
if (layer)
@@ -127,99 +177,102 @@ class ImporterContext final : public IImporterContext
127177
const std::string uniqueName = generateUniqueName(mLayerNames, name);
128178

129179
auto* ctx = this; // To enable logging.
130-
if (layer->getType() == nvinfer1::LayerType::kCONSTANT)
131-
{
132-
LOG_VERBOSE("Registering constant layer: " << uniqueName << " for ONNX initializer: " << basename);
133-
}
134-
else
135-
{
136-
LOG_VERBOSE("Registering layer: " << uniqueName << " for ONNX node: " << basename);
137-
}
180+
LOG_VERBOSE("Registering layer: " << uniqueName << " for ONNX node: " << basename);
181+
138182
layer->setName(uniqueName.c_str());
139183
}
140184
}
141185

142-
virtual nvinfer1::ILogger& logger() override
186+
nvinfer1::ILogger& logger() override
143187
{
144-
return *_logger;
188+
return *mLogger;
145189
}
146190

147-
virtual ShapedWeights createTempWeights(ShapedWeights::DataType type, nvinfer1::Dims shape) override
191+
ShapedWeights createTempWeights(ShapedWeights::DataType type, nvinfer1::Dims shape, uint8_t value = 0) override
148192
{
149193
ShapedWeights weights(type, nullptr, shape);
150194
// Need special logic for handling scalars.
151195
if (shape.nbDims == 0)
152196
{
153-
_temp_bufs.push_back(std::vector<uint8_t>(getDtypeSize(type)));
197+
mTempBufs.push_back(std::vector<uint8_t>(getDtypeSize(type), value));
154198
}
155199
else
156200
{
157-
_temp_bufs.push_back(std::vector<uint8_t>(weights.size_bytes()));
201+
mTempBufs.push_back(std::vector<uint8_t>(weights.size_bytes(), value));
158202
}
159-
weights.values = _temp_bufs.back().data();
203+
weights.values = mTempBufs.back().data();
160204
return weights;
161205
}
162206

163207
bool setUserInput(const char* name, nvinfer1::ITensor* input)
164208
{
165-
_user_inputs[name] = input;
209+
mUserInputs[name] = input;
166210
return true;
167211
}
168212
bool setUserOutput(const char* name, nvinfer1::ITensor** output)
169213
{
170-
_user_outputs[name] = output;
214+
mUserOutputs[name] = output;
171215
return true;
172216
}
173217
nvinfer1::ITensor* getUserInput(const char* name)
174218
{
175-
if (!_user_inputs.count(name))
219+
if (!mUserInputs.count(name))
176220
{
177221
return nullptr;
178222
}
179223
else
180224
{
181-
return _user_inputs.at(name);
225+
return mUserInputs.at(name);
182226
}
183227
}
184228
nvinfer1::ITensor** getUserOutput(const char* name)
185229
{
186-
if (!_user_outputs.count(name))
230+
if (!mUserOutputs.count(name))
187231
{
188232
return nullptr;
189233
}
190234
else
191235
{
192-
return _user_outputs.at(name);
236+
return mUserOutputs.at(name);
193237
}
194238
}
195239
StringMap<nvinfer1::ITensor**> const& getUserOutputs() const
196240
{
197-
return _user_outputs;
241+
return mUserOutputs;
198242
}
199243
void clearOpsets()
200244
{
201-
_opsets.clear();
245+
mOpsets.clear();
202246
}
203247
void addOpset(std::string domain, int64_t version)
204248
{
205-
_opsets.emplace(domain, version);
249+
mOpsets.emplace(domain, version);
206250
}
207-
virtual int64_t getOpsetVersion(const char* domain = "") const override
251+
int64_t getOpsetVersion(const char* domain = "") const override
208252
{
209-
if (_opsets.empty())
253+
if (mOpsets.empty())
210254
{
211255
return 1;
212256
}
213-
else if (_opsets.size() == 1)
257+
else if (mOpsets.size() == 1)
214258
{
215-
return _opsets.begin()->second;
259+
return mOpsets.begin()->second;
216260
}
217261
else
218262
{
219-
assert(_opsets.count(domain));
220-
return _opsets.at(domain);
263+
assert(mOpsets.count(domain));
264+
return mOpsets.at(domain);
221265
}
222266
}
267+
bool hasError() const noexcept override
268+
{
269+
return mErrorWrapper != nullptr && mErrorWrapper->hasError();
270+
}
271+
272+
nvinfer1::IErrorRecorder* getErrorRecorder() const noexcept override
273+
{
274+
return mErrorWrapper ? mErrorWrapper->getErrorRecorder() : nullptr;
275+
}
223276
private:
224277
std::string generateUniqueName(std::set<std::string>& namesSet, const std::string& basename)
225278
{

‎ModelImporter.cpp

+112-77
Large diffs are not rendered by default.

‎ModelImporter.hpp

+4-28
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include "NvInferPlugin.h"
99
#include "NvOnnxParser.h"
1010
#include "builtin_op_importers.hpp"
11-
#include "onnx_utils.hpp"
1211
#include "utils.hpp"
1312

1413
namespace onnx2trt
@@ -20,24 +19,21 @@ class ModelImporter : public nvonnxparser::IParser
2019
{
2120
protected:
2221
string_map<NodeImporter> _op_importers;
23-
virtual Status importModel(::ONNX_NAMESPACE::ModelProto const& model, uint32_t weight_count,
24-
onnxTensorDescriptorV1 const* weight_descriptors);
22+
virtual Status importModel(::ONNX_NAMESPACE::ModelProto const& model);
2523

2624
private:
2725
ImporterContext _importer_ctx;
28-
RefitMap_t mRefitMap;
2926
std::list<::ONNX_NAMESPACE::ModelProto> _onnx_models; // Needed for ownership of weights
3027
int _current_node;
3128
std::vector<Status> _errors;
3229

3330
public:
3431
ModelImporter(nvinfer1::INetworkDefinition* network, nvinfer1::ILogger* logger)
3532
: _op_importers(getBuiltinOpImporterMap())
36-
, _importer_ctx(network, logger, &mRefitMap)
33+
, _importer_ctx(network, logger)
3734
{
3835
}
39-
bool parseWithWeightDescriptors(void const* serialized_onnx_model, size_t serialized_onnx_model_size,
40-
uint32_t weight_count, onnxTensorDescriptorV1 const* weight_descriptors) override;
36+
bool parseWithWeightDescriptors(void const* serialized_onnx_model, size_t serialized_onnx_model_size) override;
4137
bool parse(void const* serialized_onnx_model, size_t serialized_onnx_model_size, const char* model_path = nullptr) override;
4238
bool supportsModel(void const* serialized_onnx_model, size_t serialized_onnx_model_size,
4339
SubGraphCollection_t& sub_graph_collection, const char* model_path = nullptr) override;
@@ -68,27 +64,7 @@ class ModelImporter : public nvonnxparser::IParser
6864
{
6965
_errors.clear();
7066
}
71-
virtual int getRefitMap(const char** weightNames, const char** layerNames, nvinfer1::WeightsRole* roles) override
72-
{
73-
int count = 0;
74-
for (const auto& entry: mRefitMap)
75-
{
76-
if (weightNames != nullptr)
77-
{
78-
weightNames[count] = entry.first.c_str();
79-
}
80-
if (layerNames != nullptr)
81-
{
82-
layerNames[count] = entry.second.first.c_str();
83-
}
84-
if (roles != nullptr)
85-
{
86-
roles[count] = entry.second.second;
87-
}
88-
++count;
89-
}
90-
return mRefitMap.size();
91-
}
67+
9268
//...LG: Move the implementation to .cpp
9369
bool parseFromFile(const char* onnxModelFile, int verbosity) override;
9470
};

‎NvOnnxParser.h

+17-48
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,15 @@ static const int NV_ONNX_PARSER_VERSION = ((NV_ONNX_PARSER_MAJOR * 10000) + (NV_
2626
//! \brief The data structure containing the parsing capability of
2727
//! a set of nodes in an ONNX graph.
2828
//!
29-
using SubGraph_t = std::pair<std::vector<size_t>, bool>;
29+
typedef std::pair<std::vector<size_t>, bool> SubGraph_t;
3030

3131
//! \typedef SubGraphCollection_t
3232
//!
3333
//! \brief The data structure containing all SubGraph_t partitioned
3434
//! out of an ONNX graph.
3535
//!
36-
using SubGraphCollection_t = std::vector<SubGraph_t>;
36+
typedef std::vector<SubGraph_t> SubGraphCollection_t;
3737

38-
class onnxTensorDescriptorV1;
3938
//!
4039
//! \namespace nvonnxparser
4140
//!
@@ -108,7 +107,7 @@ class IParser
108107
{
109108
public:
110109
/** \brief Parse a serialized ONNX model into the TensorRT network.
111-
* This method has very limited diagnostic. If parsing the serialized model
110+
* This method has very limited diagnostics. If parsing the serialized model
112111
* fails for any reason (e.g. unsupported IR version, unsupported opset, etc.)
113112
* it the user responsibility to intercept and report the error.
114113
* To obtain a better diagnostic, use the parseFromFile method below.
@@ -125,7 +124,7 @@ class IParser
125124
const char* model_path = nullptr)
126125
= 0;
127126

128-
/** \brief Parse an onnx model file, can be a binary protobuf or a text onnx model
127+
/** \brief Parse an onnx model file, which can be a binary protobuf or a text onnx model
129128
* calls parse method inside.
130129
*
131130
* \param File name
@@ -157,15 +156,11 @@ class IParser
157156
* \param serialized_onnx_model Pointer to the serialized ONNX model
158157
* \param serialized_onnx_model_size Size of the serialized ONNX model
159158
* in bytes
160-
* \param weight_count number of user provided weights
161-
* \param weight_descriptors pointer to user provided weight array
162159
* \return true if the model was parsed successfully
163160
* \see getNbErrors() getError()
164161
*/
165162
virtual bool parseWithWeightDescriptors(
166-
void const* serialized_onnx_model, size_t serialized_onnx_model_size,
167-
uint32_t weight_count,
168-
onnxTensorDescriptorV1 const* weight_descriptors)
163+
void const* serialized_onnx_model, size_t serialized_onnx_model_size)
169164
= 0;
170165

171166
/** \brief Returns whether the specified operator may be supported by the
@@ -178,8 +173,10 @@ class IParser
178173
*/
179174
virtual bool supportsOperator(const char* op_name) const = 0;
180175
/** \brief destroy this object
176+
*
177+
* \warning deprecated and planned on being removed in TensorRT 10.0
181178
*/
182-
virtual void destroy() = 0;
179+
TRT_DEPRECATED virtual void destroy() = 0;
183180
/** \brief Get the number of errors that occurred during prior calls to
184181
* \p parse
185182
*
@@ -197,25 +194,7 @@ class IParser
197194
*/
198195
virtual void clearErrors() = 0;
199196

200-
/** \brief Get description of all ONNX weights that can be refitted.
201-
*
202-
* \param weightsNames Where to write the weight names to
203-
* \param layerNames Where to write the layer names to
204-
* \param roles Where to write the roles to
205-
*
206-
* \return The number of weights from the ONNX model that can be refitted
207-
*
208-
* If weightNames or layerNames != nullptr, each written pointer points to a string owned by
209-
* the parser, and becomes invalid when the parser is destroyed
210-
*
211-
* If the same weight is used in multiple TRT layers it will be represented as a new
212-
* entry in weightNames with name <weightName>_x, with x being the number of times the weight
213-
* has been used before the current layer
214-
*/
215-
virtual int getRefitMap(const char** weightNames, const char** layerNames, nvinfer1::WeightsRole* roles) = 0;
216-
217-
protected:
218-
virtual ~IParser() {}
197+
virtual ~IParser() noexcept = default;
219198
};
220199

221200
} // namespace nvonnxparser
@@ -226,15 +205,6 @@ extern "C" TENSORRTAPI int getNvOnnxParserVersion();
226205
namespace nvonnxparser
227206
{
228207

229-
#ifdef SWIG
230-
inline IParser* createParser(nvinfer1::INetworkDefinition* network,
231-
nvinfer1::ILogger* logger)
232-
{
233-
return static_cast<IParser*>(
234-
createNvOnnxParser_INTERNAL(network, logger, NV_ONNX_PARSER_VERSION));
235-
}
236-
#endif // SWIG
237-
238208
namespace
239209
{
240210

@@ -243,18 +213,17 @@ namespace
243213
* \param network The network definition that the parser will write to
244214
* \param logger The logger to use
245215
* \return a new parser object or NULL if an error occurred
216+
*
217+
* Any input dimensions that are constant should not be changed after parsing,
218+
* because correctness of the translation may rely on those constants.
219+
* Changing a dynamic input dimension, i.e. one that translates to -1 in
220+
* TensorRT, to a constant is okay if the constant is consistent with the model.
221+
*
246222
* \see IParser
247223
*/
248-
#ifdef _MSC_VER
249-
TENSORRTAPI IParser* createParser(nvinfer1::INetworkDefinition& network,
250-
nvinfer1::ILogger& logger)
251-
#else
252-
inline IParser* createParser(nvinfer1::INetworkDefinition& network,
253-
nvinfer1::ILogger& logger)
254-
#endif
224+
inline IParser* createParser(nvinfer1::INetworkDefinition& network, nvinfer1::ILogger& logger)
255225
{
256-
return static_cast<IParser*>(
257-
createNvOnnxParser_INTERNAL(&network, &logger, NV_ONNX_PARSER_VERSION));
226+
return static_cast<IParser*>(createNvOnnxParser_INTERNAL(&network, &logger, NV_ONNX_PARSER_VERSION));
258227
}
259228

260229
} // namespace

‎OnnxAttrs.cpp

+61-3
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,72 @@ nvinfer1::MatrixOperation OnnxAttrs::get<nvinfer1::MatrixOperation>(const std::s
303303
template <>
304304
nvinfer1::ResizeMode OnnxAttrs::get<nvinfer1::ResizeMode>(const std::string& key) const
305305
{
306-
std::string mode = this->get<std::string>(key);
307-
if (mode == std::string("nearest"))
306+
const auto& mode = this->get<std::string>(key);
307+
if (mode == "nearest")
308308
{
309309
return nvinfer1::ResizeMode::kNEAREST;
310310
}
311-
if (mode == std::string("linear"))
311+
if (mode == "linear")
312312
{
313313
return nvinfer1::ResizeMode::kLINEAR;
314314
}
315315
throw std::runtime_error("Unknown ResizeMode: " + mode);
316316
}
317+
318+
template <>
319+
nvinfer1::ResizeCoordinateTransformation OnnxAttrs::get<nvinfer1::ResizeCoordinateTransformation>(
320+
const std::string& key) const
321+
{
322+
const auto& transformation = this->get<std::string>(key);
323+
if (transformation == "align_corners")
324+
{
325+
return nvinfer1::ResizeCoordinateTransformation::kALIGN_CORNERS;
326+
}
327+
if (transformation == "asymmetric")
328+
{
329+
return nvinfer1::ResizeCoordinateTransformation::kASYMMETRIC;
330+
}
331+
if (transformation == "half_pixel")
332+
{
333+
return nvinfer1::ResizeCoordinateTransformation::kHALF_PIXEL;
334+
}
335+
throw std::runtime_error("Unknown ResizeCoordinateTransformation: " + transformation);
336+
}
337+
338+
template <>
339+
nvinfer1::ResizeSelector OnnxAttrs::get<nvinfer1::ResizeSelector>(const std::string& key) const
340+
{
341+
const auto& selector = this->get<std::string>(key);
342+
if (selector == "formula")
343+
{
344+
return nvinfer1::ResizeSelector::kFORMULA;
345+
}
346+
if (selector == "upper")
347+
{
348+
return nvinfer1::ResizeSelector::kUPPER;
349+
}
350+
throw std::runtime_error("Unknown ResizeSelector: " + selector);
351+
}
352+
353+
template <>
354+
nvinfer1::ResizeRoundMode OnnxAttrs::get<nvinfer1::ResizeRoundMode>(const std::string& key) const
355+
{
356+
const auto& roundMode = this->get<std::string>(key);
357+
if (roundMode == "half_up")
358+
{
359+
return nvinfer1::ResizeRoundMode::kHALF_UP;
360+
}
361+
if (roundMode == "half_down")
362+
{
363+
return nvinfer1::ResizeRoundMode::kHALF_DOWN;
364+
}
365+
if (roundMode == "floor")
366+
{
367+
return nvinfer1::ResizeRoundMode::kFLOOR;
368+
}
369+
if (roundMode == "ceil")
370+
{
371+
return nvinfer1::ResizeRoundMode::kCEIL;
372+
}
373+
throw std::runtime_error("Unknown ResizeRoundMode: " + roundMode);
374+
}

‎README.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ For press and other inquiries, please contact Hector Marinez at hmarinez@nvidia.
1616

1717
## Supported TensorRT Versions
1818

19-
Development on the Master branch is for the latest version of [TensorRT 7.2.3.4](https://developer.nvidia.com/nvidia-tensorrt-download) with full-dimensions and dynamic shape support.
19+
Development on the Master branch is for the latest version of [TensorRT 8.0.1.6](https://developer.nvidia.com/nvidia-tensorrt-download) with full-dimensions and dynamic shape support.
2020

2121
For previous versions of TensorRT, refer to their respective branches.
2222

@@ -48,12 +48,12 @@ Current supported ONNX operators are found in the [operator support matrix](docs
4848
### Dependencies
4949

5050
- [Protobuf >= 3.0.x](https://github.com/google/protobuf/releases)
51-
- [TensorRT 7.2.3.4](https://developer.nvidia.com/tensorrt)
52-
- [TensorRT 7.2.3.4 open source libaries (master branch)](https://github.com/NVIDIA/TensorRT/)
51+
- [TensorRT 8.0.1.6](https://developer.nvidia.com/tensorrt)
52+
- [TensorRT 8.0.1.6 open source libaries (master branch)](https://github.com/NVIDIA/TensorRT/)
5353

5454
### Building
5555

56-
For building within docker, we recommend using and setting up the docker containers as instructed in the main (TensorRT repository)[https://github.com/NVIDIA/TensorRT#setting-up-the-build-environment] to build the onnx-tensorrt library.
56+
For building within docker, we recommend using and setting up the docker containers as instructed in the main [TensorRT repository](https://github.com/NVIDIA/TensorRT#setting-up-the-build-environment) to build the onnx-tensorrt library.
5757

5858
Once you have cloned the repository, you can build the parser libraries and executables by running:
5959

@@ -65,6 +65,11 @@ Once you have cloned the repository, you can build the parser libraries and exec
6565

6666
For building only the libraries, append `-DBUILD_LIBRARY_ONLY=1` to the CMake build command. If your model has Gather or GatherElements operations with negative indices, add `-DSUPPORT_NEGATIVE_GATHER` to the build command. Note that enabling negative-indices gather will have a performance impact on gathers with non-negative indices.
6767

68+
### Experimental Ops
69+
All experimental operators will be considered unsupported by the ONNX-TRT's `supportsModel()` function.
70+
71+
`NonMaxSuppression` is available as an experimental operator in TensorRT 8. It has the limitation that the output shape is always padded to length [`max_output_boxes_per_class`, 3], therefore some post processing is required to extract the valid indices.
72+
6873
## Executable Usage
6974

7075
ONNX models can be converted to serialized TensorRT engines using the `onnx2trt` executable:
@@ -92,9 +97,9 @@ See more usage information by running:
9297

9398
Python bindings for the ONNX-TensorRT parser are packaged in the shipped `.whl` files. Install them with
9499

95-
python3 -m pip install <tensorrt_install_dir>/python/tensorrt-7.x.x.x-cp<python_ver>-none-linux_x86_64.whl
100+
python3 -m pip install <tensorrt_install_dir>/python/tensorrt-8.x.x.x-cp<python_ver>-none-linux_x86_64.whl
96101

97-
TensorRT 7.2.3.4 supports ONNX release 1.6.0. Install it with:
102+
TensorRT 8.0.1.6 supports ONNX release 1.6.0. Install it with:
98103

99104
python3 -m pip install onnx==1.6.0
100105

‎ShapeTensor.cpp

+51-24
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66
#include "TensorOrWeights.hpp"
77
#include "onnx2trt_utils.hpp"
88
#include <algorithm>
9-
#include <cassert>
109
#include <functional>
1110

1211
namespace onnx2trt
1312
{
1413

14+
//! If true, tolerate bug where scalar constant of type FLOAT is missing its value,
15+
//! and a shape tensor is expected.
16+
static const bool gTolerateTRT_12408 = true;
17+
1518
ShapeTensor::ShapeTensor(int rank_, std::vector<int64_t>&& values_)
1619
: mDepth(0)
1720
, mAllValuesKnown(true)
@@ -23,7 +26,7 @@ ShapeTensor::ShapeTensor(int rank_, std::vector<int64_t>&& values_)
2326
assert(rank_ > 0 || mValues.size() == 1);
2427
}
2528

26-
ShapeTensor::ShapeTensor(TensorOrWeights& t)
29+
ShapeTensor::ShapeTensor(IImporterContext* ctx, TensorOrWeights& t)
2730
: mDepth(0)
2831
{
2932
if (t.is_tensor())
@@ -33,11 +36,24 @@ ShapeTensor::ShapeTensor(TensorOrWeights& t)
3336
else
3437
{
3538
const nvinfer1::Dims d = t.shape();
39+
const auto& weights = t.weights();
40+
if (gTolerateTRT_12408 && weights.type == ::ONNX_NAMESPACE::TensorProto::FLOAT && d.nbDims == 0 && weights.count() == 0)
41+
{
42+
LOG_WARNING("Scalar constant of type FLOAT with no value encountered where ONNX specification requires tensor describing a shape. Assuming it's an INT64 empty vector.");
43+
mRank = 1;
44+
mSize = 0;
45+
mAllValuesKnown = true;
46+
return;
47+
}
3648
assert(0 <= d.nbDims);
3749
assert(d.nbDims <= 1 && "shape tensor must be 0D or 1D");
3850
mRank = d.nbDims;
3951
mSize = d.nbDims == 0 ? 1 : d.d[0];
40-
weightsToVector(t.weights(), &mValues);
52+
auto status = weightsToVector(weights, &mValues);
53+
if (status.code() != ErrorCode::kSUCCESS)
54+
{
55+
throw std::runtime_error("constant " + t.getName() + " is not a valid shape tensor");
56+
}
4157
mAllValuesKnown = true;
4258
}
4359
}
@@ -142,7 +158,7 @@ nvinfer1::ITensor& ShapeTensor::tensor(IImporterContext* ctx) const
142158
if (allValuesKnown())
143159
{
144160
// Create constant
145-
const nvinfer1::Dims dims{rank(), {size()}, {}};
161+
const nvinfer1::Dims dims{rank(), {size()}};
146162
const nvinfer1::Weights w{nvinfer1::DataType::kINT32, convertINT64(mValues.data(), dims, ctx), size()};
147163
mTensor = ctx->network()->addConstant(dims, w)->getOutput(0);
148164
mDepth = 0;
@@ -328,11 +344,8 @@ ShapeTensor shapeOf(TensorOrWeights& t)
328344
{
329345
return shapeOf(t.tensor());
330346
}
331-
else
332-
{
333-
const nvinfer1::Dims& d = t.weights().shape;
334-
return ShapeTensor(1, std::vector<int64_t>(d.d, d.d + d.nbDims));
335-
}
347+
const nvinfer1::Dims& d = t.weights().shape;
348+
return ShapeTensor(1, std::vector<int64_t>(d.d, d.d + d.nbDims));
336349
}
337350

338351
ShapeTensor shapeOf(const ShapeTensor& t)
@@ -342,15 +355,12 @@ ShapeTensor shapeOf(const ShapeTensor& t)
342355
{
343356
return ShapeTensor(*t.mTensor, t.mDepth + 1);
344357
}
345-
else
346-
{
347-
assert(t.rankKnown());
348-
assert(t.sizeKnown());
349-
// ShapeTensor is either a scalar or vector.
350-
// shape of a scalar is an empty tensor.
351-
// shape of a vector is a one-element tensor containing the length of the vector.
352-
return t.rank() == 0 ? ShapeTensor(0, {}) : ShapeTensor(1, {t.size()});
353-
}
358+
assert(t.rankKnown());
359+
assert(t.sizeKnown());
360+
// ShapeTensor is either a scalar or vector.
361+
// shape of a scalar is an empty tensor.
362+
// shape of a vector is a one-element tensor containing the length of the vector.
363+
return t.rank() == 0 ? ShapeTensor(0, {}) : ShapeTensor(1, {t.size()});
354364
}
355365

356366
ShapeTensor convertTo1D(IImporterContext* ctx, const ShapeTensor& tensor)
@@ -364,17 +374,30 @@ ShapeTensor convertTo1D(IImporterContext* ctx, const ShapeTensor& tensor)
364374
return ShapeTensor(*addShuffle(ctx, tensor.tensor(ctx), shapeVector(1))->getOutput(0));
365375
}
366376

367-
//! If all values of x are known, return Dims with those values.
377+
//! If all values of x are known, return Dims with those values,
378+
//! but throw exception if any value is outside specified bounds.
368379
//! Otherwise return Dims with zeros.
369-
static nvinfer1::Dims toDims(const ShapeTensor& x)
380+
//!
381+
//! The string that should describe the context of the dimensions,
382+
//! e.g. "reshape" or "fill output".
383+
static nvinfer1::Dims toDims(const ShapeTensor& x, const char* what, int32_t minAllowed, int32_t maxAllowed)
370384
{
371-
nvinfer1::Dims d{-1, {}, {}};
385+
nvinfer1::Dims d{-1, {}};
372386
if (x.sizeKnown())
373387
{
374388
d.nbDims = x.size();
375389
if (x.allValuesKnown())
376390
{
377391
assert(x.size() <= nvinfer1::Dims::MAX_DIMS);
392+
for (const auto& dim : x)
393+
{
394+
if (dim < minAllowed || dim > maxAllowed)
395+
{
396+
std::ostringstream msg;
397+
msg << what << " dimensions have value " << dim << " beyond allowed bounds." << std::endl;
398+
throw std::runtime_error(msg.str());
399+
}
400+
}
378401
std::copy(x.begin(), x.end(), d.d);
379402
}
380403
}
@@ -417,7 +440,7 @@ nvinfer1::IShuffleLayer* addShuffle(
417440
nvinfer1::IShuffleLayer* shuffle = ctx->network()->addShuffle(data);
418441
if (reshapeDims.allValuesKnown())
419442
{
420-
shuffle->setReshapeDimensions(toDims(reshapeDims));
443+
shuffle->setReshapeDimensions(toDims(reshapeDims, "reshape", -1, std::numeric_limits<int32_t>::max()));
421444
}
422445
else
423446
{
@@ -430,7 +453,10 @@ nvinfer1::IShuffleLayer* addShuffle(
430453
nvinfer1::ISliceLayer* addSlice(IImporterContext* ctx, nvinfer1::ITensor& data, const ShapeTensor& starts,
431454
const ShapeTensor& sizes, const ShapeTensor& strides)
432455
{
433-
nvinfer1::ISliceLayer* slice = ctx->network()->addSlice(data, toDims(starts), toDims(sizes), toDims(strides));
456+
constexpr int32_t minDim = std::numeric_limits<int32_t>::min();
457+
constexpr int32_t maxDim = std::numeric_limits<int32_t>::max();
458+
nvinfer1::ISliceLayer* slice = ctx->network()->addSlice(data, toDims(starts, "slice start", 0, maxDim),
459+
toDims(sizes, "slice size", 0, maxDim), toDims(strides, "slide strides", minDim, maxDim));
434460
setShapeInputIfDynamic(ctx, slice, 1, starts);
435461
setShapeInputIfDynamic(ctx, slice, 2, sizes);
436462
setShapeInputIfDynamic(ctx, slice, 3, strides);
@@ -439,7 +465,8 @@ nvinfer1::ISliceLayer* addSlice(IImporterContext* ctx, nvinfer1::ITensor& data,
439465

440466
nvinfer1::IFillLayer* addFill(IImporterContext* ctx, const ShapeTensor& shape, nvinfer1::FillOperation op)
441467
{
442-
nvinfer1::IFillLayer* fill = ctx->network()->addFill(toDims(shape), op);
468+
nvinfer1::IFillLayer* fill
469+
= ctx->network()->addFill(toDims(shape, "fill output", 0, std::numeric_limits<int32_t>::max()), op);
443470
setShapeInputIfDynamic(ctx, fill, 0, shape);
444471
return fill;
445472
}

‎ShapeTensor.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ShapeTensor
2626
ShapeTensor(int rank_, std::vector<int64_t>&& values_);
2727

2828
//! Create ShapeTensor representing value of TensorOrWeights.
29-
ShapeTensor(TensorOrWeights& t);
29+
ShapeTensor(IImporterContext* ctx, TensorOrWeights& t);
3030

3131
//! Construct ShapeTensor equivalent to applying IShapeLayer depth times.
3232
//! The depth may be in [0,3].
@@ -133,7 +133,7 @@ class ShapeTensor
133133
//! When mAllValuesKnown==true, all the values in mValues are correct
134134
//! and mValues.size() == mSize.
135135
//! When mAllValuesKnown==false, only the non-negative values in mValues
136-
//! are guranteed to be correct, and only so if mValues.size() == mSize.
136+
//! are guaranteed to be correct, and only so if mValues.size() == mSize.
137137
std::vector<int64_t> mValues;
138138
};
139139

‎ShapedWeights.cpp

+21-14
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,6 @@ size_t ShapedWeights::size_bytes() const
5050
return this->count() * getDtypeSize(this->type);
5151
}
5252

53-
const char* ShapedWeights::getName() const
54-
{
55-
return this->name;
56-
}
57-
58-
void ShapedWeights::setName(const char* name)
59-
{
60-
this->name = name;
61-
}
62-
6353
ShapedWeights::operator bool() const
6454
{
6555
return (bool) this->values;
@@ -76,6 +66,16 @@ ShapedWeights::operator nvinfer1::Weights() const
7666
return w;
7767
}
7868

69+
const char* ShapedWeights::getName() const
70+
{
71+
return this->name;
72+
}
73+
74+
void ShapedWeights::setName(const char* name)
75+
{
76+
this->name = name;
77+
}
78+
7979
template <typename DType>
8080
void transpose4DWeights(ShapedWeights const& weights, nvinfer1::Permutation const perm, ShapedWeights* result)
8181
{
@@ -88,7 +88,7 @@ void transpose4DWeights(ShapedWeights const& weights, nvinfer1::Permutation cons
8888
nvinfer1::Dims expanded_original_shape{4, {1, 1, 1, 1}};
8989
nvinfer1::Dims expanded_new_shape{4, {1, 1, 1, 1}};
9090
nvinfer1::Permutation expanded_perm{0, 1, 2, 3};
91-
91+
9292
int pad = 4 - nbDims;
9393
for (int i = 0; i < nbDims; ++i)
9494
{
@@ -97,14 +97,15 @@ void transpose4DWeights(ShapedWeights const& weights, nvinfer1::Permutation cons
9797
expanded_perm.order[pad + i] = perm.order[i] + pad;
9898
}
9999

100+
100101
int src_strides[4] = {1, 1, 1, 1};
101102
int dst_strides[4] = {1, 1, 1, 1};
102-
103+
103104
for (int i = 2; i >= 0; --i)
104105
{
105106
src_strides[i] = expanded_original_shape.d[i + 1] * src_strides[i + 1];
106107
dst_strides[i] = expanded_new_shape.d[i + 1] * dst_strides[i + 1];
107-
}
108+
}
108109

109110
for (int n = 0; n < expanded_original_shape.d[0]; ++n)
110111
{
@@ -131,7 +132,7 @@ void transpose4DWeights(ShapedWeights const& weights, nvinfer1::Permutation cons
131132
}
132133
}
133134

134-
bool transposeWeights(ShapedWeights const& weights, nvinfer1::Permutation const& perm, ShapedWeights* result)
135+
bool transposeWeights(ShapedWeights const& weights, nvinfer1::Permutation const& perm, ShapedWeights* result, IImporterContext* ctx)
135136
{
136137
nvinfer1::Dims shape = weights.shape;
137138
int nbDims = shape.nbDims;
@@ -164,6 +165,12 @@ bool transposeWeights(ShapedWeights const& weights, nvinfer1::Permutation const&
164165
// Unsupported weights transpose
165166
return false;
166167
}
168+
nvinfer1::Dims permDims{nbDims, {}};
169+
std::copy_n(perm.order, nbDims, permDims.d);
170+
LOG_WARNING("Weights "
171+
<< weights.getName() << " has been transposed with permutation of " << permDims
172+
<< "! If you plan on overwriting the weights with the Refitter API, the new weights must be pre-transposed.");
173+
result->setName(weights.getName());
167174
return true;
168175
}
169176

‎ShapedWeights.hpp

+31-5
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,47 @@ class ShapedWeights
1414
{
1515
public:
1616
using DataType = int32_t;
17-
DataType type;
18-
void* values;
19-
nvinfer1::Dims shape;
20-
const char* name = nullptr;
17+
2118
static ShapedWeights empty(DataType type);
19+
2220
ShapedWeights();
21+
2322
explicit ShapedWeights(DataType type, void* values, nvinfer1::Dims shape_);
23+
2424
size_t count() const;
25+
2526
size_t size_bytes() const;
27+
2628
const char* getName() const;
29+
2730
void setName(const char* name);
31+
2832
explicit operator bool() const;
33+
2934
operator nvinfer1::Weights() const;
35+
36+
template <typename T>
37+
T& at(size_t index)
38+
{
39+
assert(index >= 0 && (index * sizeof(T)) < size_bytes());
40+
return static_cast<T*>(values)[index];
41+
}
42+
43+
template <typename T>
44+
const T& at(size_t index) const
45+
{
46+
assert(index >= 0 && (index * sizeof(T)) < size_bytes());
47+
return static_cast<const T*>(values)[index];
48+
}
49+
50+
public:
51+
DataType type;
52+
void* values;
53+
nvinfer1::Dims shape;
54+
const char* name{};
3055
};
3156

32-
bool transposeWeights(ShapedWeights const& weights, nvinfer1::Permutation const& perm, ShapedWeights* result);
57+
class IImporterContext;
58+
bool transposeWeights(ShapedWeights const& weights, nvinfer1::Permutation const& perm, ShapedWeights* result, IImporterContext* ctx);
3359

3460
} // namespace onnx2trt

‎Status.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <cassert>
1010
#include <string>
1111

12-
// Used to strip out Eris build path information from debug prints
12+
// Used to strip out build path information from debug prints
1313
#if defined(SOURCE_LENGTH)
1414
#define __FILENAME__ (__FILE__ + SOURCE_LENGTH)
1515
#else
@@ -61,7 +61,7 @@
6161
} \
6262
} while (0)
6363

64-
#define TRT_CHECK(call) \
64+
#define CHECK(call) \
6565
do \
6666
{ \
6767
Status status = call; \

‎TensorOrWeights.hpp

+29
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ class TensorOrWeights
9393
{
9494
return is_tensor() ? _tensor->getName() : _weights.getName();
9595
}
96+
std::string getType() const
97+
{
98+
if (is_tensor())
99+
{
100+
switch(_tensor->getType())
101+
{
102+
case nvinfer1::DataType::kFLOAT:return "FLOAT";
103+
case nvinfer1::DataType::kHALF: return "HALF";
104+
case nvinfer1::DataType::kINT8: return "INT8";
105+
case nvinfer1::DataType::kINT32: return "INT32";
106+
case nvinfer1::DataType::kBOOL: return "BOOL";
107+
default: return "UNKNOWN TYPE";
108+
}
109+
}
110+
else
111+
{
112+
switch(_weights.type)
113+
{
114+
case ::ONNX_NAMESPACE::TensorProto::DOUBLE: return "DOUBLE -> FLOAT";
115+
case ::ONNX_NAMESPACE::TensorProto::FLOAT: return "FLOAT";
116+
case ::ONNX_NAMESPACE::TensorProto::INT8: return "INT8";
117+
case ::ONNX_NAMESPACE::TensorProto::FLOAT16: return "HALF";
118+
case ::ONNX_NAMESPACE::TensorProto::BOOL: return "BOOL";
119+
case ::ONNX_NAMESPACE::TensorProto::INT32: return "INT32";
120+
case ::ONNX_NAMESPACE::TensorProto::INT64: return "INT64 -> INT32";
121+
default: return "UNKNOWN TYPE";
122+
}
123+
}
124+
}
96125
};
97126

98127
} // namespace onnx2trt

‎builtin_op_importers.cpp

+884-531
Large diffs are not rendered by default.

‎docs/Changelog.md

+18-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,25 @@
22

33
# ONNX-TensorRT Changelog
44

5-
## 21.05 Container Release - 2021-05-19
5+
## TensorRT 8.0 Release - 2021-07-02
6+
### Added
7+
- Rehauled resize operator, now fully supporting the following modes:
8+
- Coordinate Transformation modes: `half_pixel`, `pytorch_half_pixel`, `tf_half_pixel_for_nn`, `asymmetric`, and `align_corners`
9+
- Modes: `nearest`, `linear`
10+
- Nearest Modes: `floor`, `ceil`, `round_prefer_floor`, `round_prefer_ceil`
11+
- QuantizeLinear/DequantizeLinear updates:
12+
- Added support for tensor scales
13+
- Added support for per-axis quantization
14+
- Added support for multi-input ConvTranpose
15+
- Added support for generic 2D padding
16+
- Added experimental support for `NonMaxSuppression`
17+
18+
### Updated
19+
- Moved `RefitMap` API to core TensorRT.
20+
- Added Datatype column to [operators.md](https://github.com/onnx/onnx-tensorrt/blob/master/docs/operators.md)
21+
22+
## 21.05 Container Release - 2021-05-17
623
### Added
7-
- Added support for InstanceNormalization on 5D tensors
824
- Added library only build target [#659](https://github.com/onnx/onnx-tensorrt/pull/659)
925
- Added support for negative gather indices [#681](https://github.com/onnx/onnx-tensorrt/pull/681)
1026
- Added support for `DOUBLE`-typed inputs and weights through downcast to float [#674](https://github.com/onnx/onnx-tensorrt/pull/674)

‎docs/contributing.md

+1-58
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,4 @@
22

33
# Contributing
44

5-
Contributions are always welcome to improve the onnx-tensorrt parser. For those looking to contribute, please follow the PR process as outlined in the [TensorRT Open Source Software repository](https://github.com/NVIDIA/TensorRT/blob/master/CONTRIBUTING.md).
6-
7-
#### Signing Your Work
8-
9-
* We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
10-
11-
* Any contribution which contains commits that are not Signed-Off will not be accepted.
12-
13-
* To sign off on a commit you simply use the `--signoff` (or `-s`) option when committing your changes:
14-
```bash
15-
$ git commit -s -m "Add cool feature."
16-
```
17-
This will append the following to your commit message:
18-
```
19-
Signed-off-by: Your Name <your@email.com>
20-
```
21-
22-
* Full text of the DCO:
23-
24-
```
25-
Developer Certificate of Origin
26-
Version 1.1
27-
28-
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
29-
1 Letterman Drive
30-
Suite D4700
31-
San Francisco, CA, 94129
32-
33-
Everyone is permitted to copy and distribute verbatim copies of this
34-
license document, but changing it is not allowed.
35-
36-
37-
Developer's Certificate of Origin 1.1
38-
39-
By making a contribution to this project, I certify that:
40-
41-
(a) The contribution was created in whole or in part by me and I
42-
have the right to submit it under the open source license
43-
indicated in the file; or
44-
45-
(b) The contribution is based upon previous work that, to the best
46-
of my knowledge, is covered under an appropriate open source
47-
license and I have the right under that license to submit that
48-
work with modifications, whether created in whole or in part
49-
by me, under the same open source license (unless I am
50-
permitted to submit under a different license), as indicated
51-
in the file; or
52-
53-
(c) The contribution was provided directly to me by some other
54-
person who certified (a), (b) or (c) and I have not modified
55-
it.
56-
57-
(d) I understand and agree that this project and the contribution
58-
are public and that a record of the contribution (including all
59-
personal information I submit with it, including my sign-off) is
60-
maintained indefinitely and may be redistributed consistent with
61-
this project or the open source license(s) involved.
62-
```
5+
Contributions are always welcome to improve the onnx-tensorrt parser. For those looking to contribute, please follow the PR process as outlined in [the main TensorRT open source repository](https://github.com/NVIDIA/TensorRT/blob/master/CONTRIBUTING.md).

‎docs/operators.md

+128-126
Large diffs are not rendered by default.

‎getSupportedAPITest.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ int main(int argc, char* argv[]) {
8787
common::TRT_Logger trt_logger((nvinfer1::ILogger::Severity)verbosity);
8888

8989
auto trt_builder = common::infer_object(nvinfer1::createInferBuilder(trt_logger));
90-
9190
auto trt_network = common::infer_object(trt_builder->createNetworkV2(1U << static_cast<uint32_t>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH)));
9291
auto trt_parser = common::infer_object(nvonnxparser::createParser(*trt_network, trt_logger));
9392

@@ -129,14 +128,15 @@ int main(int argc, char* argv[]) {
129128
// Note we do not call trt_parser->parse() here since it's already done above in parser->supportsModel()
130129
if( !engine_filename.empty() ) {
131130
trt_builder->setMaxBatchSize(max_batch_size);
132-
trt_builder->setMaxWorkspaceSize(max_workspace_size);
131+
auto builder_config = common::infer_object(trt_builder->createBuilderConfig());
132+
builder_config->setMaxWorkspaceSize(max_workspace_size);
133133

134134
cout << "input name: " << trt_network->getInput(0)->getName() << endl;
135135
cout << "output name: " << trt_network->getOutput(0)->getName() << endl;
136136
cout << "num layers: " << trt_network->getNbLayers() << endl;
137137
cout << "outputs: " << trt_network->getNbOutputs() << endl;
138138

139-
auto trt_engine = common::infer_object(trt_builder->buildCudaEngine(*trt_network.get()));
139+
auto trt_engine = common::infer_object(trt_builder->buildEngineWithConfig(*trt_network.get(), *builder_config.get()));
140140

141141
if( verbosity >= (int)nvinfer1::ILogger::Severity::kWARNING ) {
142142
cout << "Writing TensorRT engine to " << engine_filename << endl;

‎main.cpp

+4-8
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ void print_usage() {
3434
<< " [-O passes] (optimize onnx model. Argument is a semicolon-separated list of passes)" << "\n"
3535
<< " [-p] (list available optimization passes and exit)" << "\n"
3636
<< " [-l] (list layers and their shapes)" << "\n"
37-
<< " [-g] (debug mode)" << "\n"
3837
<< " [-F] (optimize onnx model in fixed mode)" << "\n"
3938
<< " [-v] (increase verbosity)" << "\n"
4039
<< " [-q] (decrease verbosity)" << "\n"
@@ -58,7 +57,6 @@ int main(int argc, char* argv[]) {
5857
bool optimize_model_fixed = false;
5958
bool print_optimization_passes_info = false;
6059
bool print_layer_info = false;
61-
bool debug_builder = false;
6260

6361
int arg = 0;
6462
while( (arg = ::getopt(argc, argv, "o:b:w:t:T:m:d:O:plgFvqVh")) != -1 ) {
@@ -90,7 +88,6 @@ int main(int argc, char* argv[]) {
9088
else { cerr << "ERROR: -O flag requires argument" << endl; return -1; }
9189
case 'p': print_optimization_passes_info = true; break;
9290
case 'l': print_layer_info = true; break;
93-
case 'g': debug_builder = true; break;
9491
case 'F': optimize_model_fixed = true; optimize_model = true; break;
9592
case 'v': ++verbosity; break;
9693
case 'q': --verbosity; break;
@@ -273,18 +270,17 @@ int main(int argc, char* argv[]) {
273270
cout << " Max batch size: " << max_batch_size << endl;
274271
cout << " Max workspace size: " << max_workspace_size / (1024. * 1024) << " MiB" << endl;
275272
}
276-
trt_builder->setMaxBatchSize(max_batch_size);
277-
trt_builder->setMaxWorkspaceSize(max_workspace_size);
273+
auto builder_config = common::infer_object(trt_builder->createBuilderConfig());
274+
builder_config->setMaxWorkspaceSize(max_workspace_size);
278275
if( fp16 && model_dtype == nvinfer1::DataType::kHALF) {
279-
trt_builder->setHalf2Mode(true);
276+
builder_config->setFlag(nvinfer1::BuilderFlag::kFP16);
280277
} else if( model_dtype == nvinfer1::DataType::kINT8 ) {
281278
// TODO: Int8 support
282279
//trt_builder->setInt8Mode(true);
283280
cerr << "ERROR: Int8 mode not yet supported" << endl;
284281
return -5;
285282
}
286-
trt_builder->setDebugSync(debug_builder);
287-
auto trt_engine = common::infer_object(trt_builder->buildCudaEngine(*trt_network.get()));
283+
auto trt_engine = common::infer_object(trt_builder->buildEngineWithConfig(*trt_network.get(), *builder_config.get()));
288284

289285
auto engine_plan = common::infer_object(trt_engine->serialize());
290286
std::ofstream engine_file(engine_filename.c_str());

‎onnx2trt.hpp

+3-7
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,11 @@
1212
#include <NvInfer.h>
1313
#include <functional>
1414
#include <onnx/onnx_pb.h>
15-
#include <map>
1615
#include <unordered_map>
1716
#include <unordered_set>
1817
#include <fstream>
1918
#include <vector>
2019

21-
using WeightsPair_t = std::pair<std::string, nvinfer1::WeightsRole>;
22-
23-
using RefitMap_t = std::multimap<std::string, WeightsPair_t>;
24-
2520
namespace onnx2trt
2621
{
2722

@@ -54,10 +49,11 @@ class IImporterContext
5449
virtual std::string getOnnxFileLocation() = 0;
5550
virtual void registerTensor(TensorOrWeights tensor, const std::string& basename) = 0;
5651
virtual void registerLayer(nvinfer1::ILayer* layer, const std::string& basename) = 0;
57-
virtual ShapedWeights createTempWeights(ShapedWeights::DataType type, nvinfer1::Dims shape) = 0;
52+
virtual ShapedWeights createTempWeights(ShapedWeights::DataType type, nvinfer1::Dims shape, uint8_t value = 0) = 0;
5853
virtual int64_t getOpsetVersion(const char* domain = "") const = 0;
5954
virtual nvinfer1::ILogger& logger() = 0;
60-
virtual void insertRefitMap(std::string weightsName, std::string layerName, nvinfer1::WeightsRole role) = 0;
55+
virtual bool hasError() const = 0;
56+
virtual nvinfer1::IErrorRecorder* getErrorRecorder() const = 0;
6157

6258
protected:
6359
virtual ~IImporterContext()

‎onnx2trt_common.hpp

+15-7
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,29 @@ enum class PluginFormat : uint8_t
2222
class IPluginExt : public IPlugin
2323
{
2424
public:
25-
virtual int getTensorRTVersion() const
25+
virtual int getTensorRTVersion() const noexcept
2626
{
2727
return NV_TENSORRT_VERSION;
2828
}
29-
virtual bool supportsFormat(DataType type, PluginFormat format) const = 0;
29+
virtual bool supportsFormat(DataType type, PluginFormat format) const noexcept = 0;
3030
virtual void configureWithFormat(const Dims* inputDims, int nbInputs, const Dims* outputDims, int nbOutputs,
31-
DataType type, PluginFormat format, int maxBatchSize)
31+
DataType type, PluginFormat format, int maxBatchSize) noexcept
3232
= 0;
3333

3434
protected:
35-
void configure(const Dims* inputDims, int nbInputs, const Dims* outputDims, int nbOutputs, int maxBatchSize) final
35+
void configure(
36+
const Dims* inputDims, int nbInputs, const Dims* outputDims, int nbOutputs, int maxBatchSize) noexcept final
3637
{
37-
DataType type = nvinfer1::DataType::kFLOAT;
38-
PluginFormat format = nvinfer1::PluginFormat::kNCHW;
39-
return this->configureWithFormat(inputDims, nbInputs, outputDims, nbOutputs, type, format, maxBatchSize);
38+
try
39+
{
40+
DataType type = nvinfer1::DataType::kFLOAT;
41+
PluginFormat format = nvinfer1::PluginFormat::kLINEAR;
42+
return this->configureWithFormat(inputDims, nbInputs, outputDims, nbOutputs, type, format, maxBatchSize);
43+
}
44+
catch (const std::exception& e)
45+
{
46+
nvinfer1::getLogger()->log(nvinfer1::ILogger::Severity::kERROR, e.what().c_str());
47+
}
4048
}
4149
virtual ~IPluginExt()
4250
{

‎onnx2trt_utils.cpp

+730-445
Large diffs are not rendered by default.

‎onnx2trt_utils.hpp

+66-28
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
#pragma once
66

77
#include "ShapedWeights.hpp"
8+
#include "ShapeTensor.hpp"
89
#include "Status.hpp"
910
#include "trt_utils.hpp"
1011

1112
#include <NvInfer.h>
1213
#include <onnx/onnx_pb.h>
13-
#include <onnx/onnxifi.h>
1414

1515
#include <cstring> // For std::memcpy
1616
#include <iostream>
17-
#include <limits>
1817
#include <numeric>
1918
#include <sstream>
19+
#include <limits>
2020

2121
#define LOG(msg, severity) \
2222
do \
@@ -79,7 +79,10 @@ static std::ostream& operator<<(std::ostream& stream, const nvinfer1::DataType&
7979
namespace onnx2trt
8080
{
8181

82-
class ShapeTensor;
82+
struct PluginDeleter
83+
{
84+
void operator()(nvinfer1::IPluginV2* t);
85+
};
8386

8487
// Helper function to calculate the volume of a Dims object
8588
int64_t volume(const nvinfer1::Dims& dims);
@@ -138,6 +141,9 @@ Status broadcastTensors(IImporterContext* ctx, nvinfer1::ITensor*& t1, nvinfer1:
138141
// Helper function to broadcast three tensors to the largest one's shape
139142
Status broadcastTensors(IImporterContext* ctx, nvinfer1::ITensor*& t1, nvinfer1::ITensor*& t2, nvinfer1::ITensor*& t3);
140143

144+
// Helper funtion to check that two shapes conform to the broadcasting rules
145+
Status isBroadcastValid(IImporterContext* ctx, const nvinfer1::Dims& firstShape, const nvinfer1::Dims& secondShape);
146+
141147
// Helper function to calculate the bias tensor for GatherElements.
142148
std::vector<int32_t> calculateBias(
143149
const nvinfer1::Dims& daDims, const nvinfer1::Dims& idxDims, const std::vector<int32_t>& pitches, int32_t axis);
@@ -152,7 +158,8 @@ bool canUseLinearResize(const size_t scaleSize, const float* scaleFactors);
152158
nvinfer1::ITensor* castHelper(IImporterContext* ctx, nvinfer1::ITensor* input, nvinfer1::DataType dtype);
153159

154160
// Helper function for constantOfShape operator. Input shape must be a shape tensor
155-
nvinfer1::ITensor* constantOfShape(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, nvinfer1::ITensor* constant, nvinfer1::ITensor* shape);
161+
nvinfer1::ITensor* constantOfShape(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node,
162+
nvinfer1::ITensor* constant, nvinfer1::ITensor* shape);
156163

157164
// Helper function to convert an ONNX axis into a TRT axis
158165
Status convertAxis(int& axis, int nbDims);
@@ -163,12 +170,14 @@ bool convertDtype(int32_t onnx_dtype, nvinfer1::DataType* trt_dtype);
163170
// Helper function to convert INT64 weight values into INT32
164171
int32_t* convertINT64(const int64_t* weightValues, nvinfer1::Dims shape, IImporterContext* ctx);
165172

166-
// Helper function to convert negative gather indices into positive ones
173+
// Helper function to convert negative gather indices into non-negative indices.
167174
nvinfer1::ITensor* convertGatherIndices(IImporterContext* ctx, nvinfer1::ITensor* data, nvinfer1::ITensor* indices, int32_t axis);
168175

169-
// Helper function to convert ONNX padding into TRT padding
170-
bool convertOnnxPadding(
171-
const std::vector<int64_t>& onnxPadding, nvinfer1::Dims2* begPadding, nvinfer1::Dims2* endPadding);
176+
// Helper function to convert ONNX padding into TRT padding. Will update begPadding, endPadding, firstPerm, and secondPerm by reference
177+
bool convertOnnxPadding(std::vector<int64_t>& onnxPadding, nvinfer1::Dims2& begPadding, nvinfer1::Dims2& endPadding, nvinfer1::Permutation& firstPerm, nvinfer1::Permutation& secondPerm);
178+
179+
// Helper function to check if all of the values in the shift tensor are zeros
180+
bool shiftIsAllZeros(const ShapedWeights& shiftInt8);
172181

173182
// Helper function to create zero shifts for QuantizeLinear/DequantizeLinear ops
174183
onnx2trt::ShapedWeights createZeroShifts(const onnx2trt::ShapedWeights& shiftInt8, int32_t type, IImporterContext* ctx);
@@ -180,9 +189,9 @@ nvinfer1::ITensor* createZeroTensor(IImporterContext* ctx, nvinfer1::ITensor* da
180189
bool convertOnnxWeights(
181190
const ::ONNX_NAMESPACE::TensorProto& onnxTensor, onnx2trt::ShapedWeights* weights, IImporterContext* ctx);
182191

183-
// Helper function to convert multi input convolution
184-
NodeImportResult convMultiInput(
185-
IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, std::vector<TensorOrWeights>& inputs);
192+
// Helper function to convert multi input convolution/deconvolution
193+
NodeImportResult convDeconvMultiInput(
194+
IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, std::vector<TensorOrWeights>& inputs, bool isConv);
186195

187196
// Helper function to convert a 1D tensor into a scalar
188197
nvinfer1::ITensor* convertToScalar(IImporterContext* ctx, nvinfer1::ITensor* inpTensor);
@@ -193,10 +202,6 @@ nvinfer1::ITensor& convertToTensor(TensorOrWeights& input, IImporterContext* ctx
193202
// Helper function to convert a ShapedWeights object into a scalar
194203
nvinfer1::ITensor* convertToScalar(TensorOrWeights& input, IImporterContext* ctx);
195204

196-
// Helper function to convert an ONNX weight descriptor into a ShapedWeights object
197-
bool convertWeightDescriptor(
198-
onnxTensorDescriptorV1 const& desc, onnx2trt::ShapedWeights* weights, IImporterContext* ctx);
199-
200205
// Helper function to provide a ceiling-rounding division between two integers
201206
int divCeil(int n, int d);
202207

@@ -242,9 +247,6 @@ void getKernelParams(IImporterContext* ctx, ::ONNX_NAMESPACE::NodeProto const& o
242247
nvinfer1::PaddingMode& paddingMode, bool& count_exclude_padding, nvinfer1::Dims* dilations = nullptr,
243248
nvinfer1::Dims* output_padding = nullptr, const bool poolingCeilMode = false);
244249

245-
// Helper function to convert ONNX node name. If no node name is provided, use the name of the first output.
246-
const std::string getNodeName(const ::ONNX_NAMESPACE::NodeProto& node);
247-
248250
// Helper function to get the scaling mode for TRT's scale layer
249251
nvinfer1::ScaleMode getScaleMode(nvinfer1::Dims const& weights_shape, nvinfer1::Dims const& tensor_shape);
250252

@@ -258,10 +260,11 @@ bool isDynamic(const nvinfer1::Dims& shape);
258260
bool isOnnxTensorEmpty(const ::ONNX_NAMESPACE::TensorProto& onnxTensor);
259261

260262
// Helper function to load a creator from the registry
261-
nvinfer1::IPluginCreator* importPluginCreator(const std::string& pluginName, const std::string& pluginVersion, const std::string& pluginNamespace="");
263+
nvinfer1::IPluginCreator* importPluginCreator(
264+
const std::string& pluginName, const std::string& pluginVersion, const std::string& pluginNamespace = "");
262265

263266
// Helper function to get a plugin from the PluginRegistry
264-
nvinfer1::IPluginV2* createPlugin(const std::string& name,
267+
std::unique_ptr<nvinfer1::IPluginV2, PluginDeleter> createPlugin(const std::string& name,
265268
nvinfer1::IPluginCreator* pluginCreator, const std::vector<nvinfer1::PluginField>& pluginFields);
266269

267270
// Helper function to determine if a transpose is required
@@ -275,7 +278,7 @@ NodeImportResult lstmLegacyImporter(
275278
nvinfer1::Dims makeDims(int nbDims, int val);
276279

277280
// Helper function to read weights from an external file
278-
bool parseExternalWeights(IImporterContext* ctx, std::string file, std::string path, int offset, int length,
281+
bool parseExternalWeights(IImporterContext* ctx, std::string file, std::string path, int64_t offset, int64_t length,
279282
std::vector<char>& weightsBuf, size_t& size);
280283

281284
// Helper function to map various ONNX pooling ops into TensorRT.
@@ -284,7 +287,7 @@ NodeImportResult poolingHelper(IImporterContext* ctx, ::ONNX_NAMESPACE::NodeProt
284287

285288
// Helper function to import reduce ops into TRT
286289
NodeImportResult reduceTensor(IImporterContext* ctx, ::ONNX_NAMESPACE::NodeProto const& node, TensorOrWeights input,
287-
nvinfer1::ReduceOperation operation);
290+
nvinfer1::ReduceOperation operation, TensorOrWeights inputAxes = TensorOrWeights());
288291

289292
// Helper function to shape a Tensor given a new shape
290293
nvinfer1::ITensor* reshapeTensor(IImporterContext* ctx, nvinfer1::ITensor& tensor, nvinfer1::Dims shape);
@@ -298,24 +301,59 @@ NodeImportResult scaleHelper(IImporterContext* ctx, const ::ONNX_NAMESPACE::Node
298301
void setAttr(
299302
nvinfer1::Dims* trtAttr, ::ONNX_NAMESPACE::AttributeProto const* onnxAttr, int nbSpatialDims, int defaultVal);
300303

304+
// Helper function to slice away elements on a given axis dimension
305+
nvinfer1::ITensor* sliceAcrossAxis(
306+
IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, nvinfer1::ITensor* data, const int axis);
307+
301308
// Helper function to filter out shape tensor outputs for layers that do not support it
302-
bool supportsShapeTensor(nvinfer1::LayerType type, nvinfer1::ElementWiseOperation eleOp, nvinfer1::ReduceOperation redOp);
309+
bool supportsShapeTensor(nvinfer1::LayerType type, nvinfer1::ElementWiseOperation eleOp,
310+
nvinfer1::ReduceOperation redOp, nvinfer1::FillOperation fillOp);
303311

304312
// Helper function to squeeze a tensor on a given set of axes
305313
nvinfer1::ITensor* squeezeTensor(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, nvinfer1::ITensor& tensor, const std::vector<int>& axes, bool regLayer = false);
306314

307315
// Helper function to transpose a tensor given a permutation
308-
nvinfer1::ITensor* transposeTensor(
309-
IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, nvinfer1::ITensor& tensor, nvinfer1::Permutation const& perm, bool permute_dim_types = true);
316+
nvinfer1::ITensor* transposeTensor(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node,
317+
nvinfer1::ITensor& tensor, nvinfer1::Permutation const& perm);
310318

311319
// Helper function to import ONNX unary ops into TRT
312-
NodeImportResult unaryHelper(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, TensorOrWeights& input, nvinfer1::UnaryOperation op);
320+
NodeImportResult unaryHelper(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, TensorOrWeights& input,
321+
nvinfer1::UnaryOperation op);
313322

314323
// Helper function to unsqueeze tensors on a given set of axes
315-
nvinfer1::ITensor* unsqueezeTensor(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node, nvinfer1::ITensor& tensor, const std::vector<int>& axes, bool regLayer = false);
324+
nvinfer1::ITensor* unsqueezeTensor(IImporterContext* ctx, const ::ONNX_NAMESPACE::NodeProto& node,
325+
nvinfer1::ITensor& tensor, const std::vector<int>& axes, bool regLayer = false);
316326

317327
// Helper function to convert a ShapedWeights object into a vector
318-
Status weightsToVector(TensorOrWeights weights, std::vector<int64_t>* weightVector);
328+
template <typename WeightType>
329+
Status weightsToVector(TensorOrWeights weights, std::vector<WeightType>* weightVector)
330+
{
331+
ASSERT(weights.is_weights(), ErrorCode::kUNSUPPORTED_NODE);
332+
ASSERT((weights.weights().type == ::ONNX_NAMESPACE::TensorProto::INT32)
333+
|| (weights.weights().type == ::ONNX_NAMESPACE::TensorProto::INT64)
334+
|| (weights.weights().type == ::ONNX_NAMESPACE::TensorProto::BOOL),
335+
ErrorCode::kINVALID_NODE);
336+
weightVector->resize(weights.weights().count());
337+
if (weights.weights().type == ::ONNX_NAMESPACE::TensorProto::INT64)
338+
{
339+
auto array_start = static_cast<int64_t*>(weights.weights().values);
340+
std::copy(array_start, array_start + weights.weights().count(), weightVector->begin());
341+
}
342+
else if (weights.weights().type == ::ONNX_NAMESPACE::TensorProto::INT32)
343+
{
344+
auto array_start = static_cast<int32_t*>(weights.weights().values);
345+
std::copy(array_start, array_start + weights.weights().count(), weightVector->begin());
346+
}
347+
else if (weights.weights().type == ::ONNX_NAMESPACE::TensorProto::BOOL)
348+
{
349+
auto array_start = static_cast<bool*>(weights.weights().values);
350+
std::copy(array_start, array_start + weights.weights().count(), weightVector->begin());
351+
}
352+
return Status(ErrorCode::kSUCCESS);
353+
}
354+
355+
// Helper function to convert ONNX node name. If no node name, using name of first output.
356+
const std::string getNodeName(const ::ONNX_NAMESPACE::NodeProto& node);
319357

320358
//! Decode in place the starts and ends indices according to ONNX Slice rules.
321359
void decodeOnnxStartsAndEnds(IImporterContext* ctx, const ShapeTensor& inputDims, const ShapeTensor& steps, ShapeTensor& starts, ShapeTensor& ends);

‎onnxErrorRecorder.cpp

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#include "onnxErrorRecorder.hpp"
6+
#include <exception>
7+
8+
namespace onnx2trt
9+
{
10+
11+
12+
ONNXParserErrorRecorder* ONNXParserErrorRecorder::create(
13+
nvinfer1::ILogger* logger, nvinfer1::IErrorRecorder* otherRecorder)
14+
{
15+
try
16+
{
17+
auto recorder = new ONNXParserErrorRecorder(logger, otherRecorder);
18+
if (recorder)
19+
{
20+
recorder->incRefCount();
21+
}
22+
return recorder;
23+
}
24+
catch (const std::exception& e)
25+
{
26+
logError(logger, e.what());
27+
return nullptr;
28+
}
29+
}
30+
31+
void ONNXParserErrorRecorder::destroy(ONNXParserErrorRecorder*& recorder)
32+
{
33+
if (recorder)
34+
{
35+
recorder->decRefCount();
36+
recorder = nullptr;
37+
}
38+
}
39+
40+
void ONNXParserErrorRecorder::logError(nvinfer1::ILogger* logger, const char* str)
41+
{
42+
if (logger)
43+
{
44+
logger->log(ILogger::Severity::kERROR, str);
45+
}
46+
}
47+
48+
ONNXParserErrorRecorder::ONNXParserErrorRecorder(
49+
nvinfer1::ILogger* logger, nvinfer1::IErrorRecorder* otherRecorder)
50+
: mUserRecorder(otherRecorder)
51+
, mLogger(logger)
52+
{
53+
if (mUserRecorder)
54+
{
55+
mUserRecorder->incRefCount();
56+
}
57+
}
58+
59+
ONNXParserErrorRecorder::~ONNXParserErrorRecorder() noexcept
60+
{
61+
if (mUserRecorder)
62+
{
63+
mUserRecorder->decRefCount();
64+
}
65+
}
66+
67+
void ONNXParserErrorRecorder::clear() noexcept
68+
{
69+
try
70+
{
71+
// grab a lock so that there is no addition while clearing.
72+
std::lock_guard<std::mutex> guard(mStackLock);
73+
mErrorStack.clear();
74+
}
75+
catch (const std::exception& e)
76+
{
77+
logError(mLogger, e.what());
78+
}
79+
};
80+
81+
bool ONNXParserErrorRecorder::reportError(
82+
nvinfer1::ErrorCode val, nvinfer1::IErrorRecorder::ErrorDesc desc) noexcept
83+
{
84+
try
85+
{
86+
std::lock_guard<std::mutex> guard(mStackLock);
87+
mErrorStack.push_back(errorPair(val, desc));
88+
if (mUserRecorder)
89+
{
90+
mUserRecorder->reportError(val, desc);
91+
}
92+
else
93+
{
94+
logError(mLogger, desc);
95+
}
96+
}
97+
catch (const std::exception& e)
98+
{
99+
logError(mLogger, e.what());
100+
}
101+
// All errors are considered fatal.
102+
return true;
103+
}
104+
105+
nvinfer1::IErrorRecorder::RefCount ONNXParserErrorRecorder::incRefCount() noexcept
106+
{
107+
// Atomically increment or decrement the ref counter.
108+
return ++mRefCount;
109+
}
110+
111+
nvinfer1::IErrorRecorder::RefCount ONNXParserErrorRecorder::decRefCount() noexcept
112+
{
113+
auto newVal = --mRefCount;
114+
if (newVal == 0)
115+
{
116+
delete this;
117+
}
118+
return newVal;
119+
}
120+
121+
} // namespace onnx2trt

‎onnxErrorRecorder.hpp

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#pragma once
6+
7+
#include "NvInferRuntimeCommon.h"
8+
#include "onnx2trt_utils.hpp"
9+
#include <atomic>
10+
#include <cstdint>
11+
#include <exception>
12+
#include <mutex>
13+
#include <vector>
14+
15+
namespace onnx2trt
16+
{
17+
18+
//!
19+
//! A simple implementation of the IErrorRecorder interface for
20+
//! use by ONNX importer.
21+
//! ONNX-importer Error recorder is based on a vector that pairs the error
22+
//! code and the error string into a single element. It also uses
23+
//! standard mutex and atomics in order to make sure that the code
24+
//! works in a multi-threaded environment.
25+
//!
26+
class ONNXParserErrorRecorder : public nvinfer1::IErrorRecorder
27+
{
28+
using RefCount = nvinfer1::IErrorRecorder::RefCount;
29+
using ErrorDesc = nvinfer1::IErrorRecorder::ErrorDesc;
30+
using ErrorCode = nvinfer1::ErrorCode;
31+
using IErrorRecorder = nvinfer1::IErrorRecorder;
32+
using ILogger = nvinfer1::ILogger;
33+
34+
using errorPair = std::pair<ErrorCode, std::string>;
35+
using errorStack = std::vector<errorPair>;
36+
37+
public:
38+
static ONNXParserErrorRecorder* create(
39+
ILogger* logger, IErrorRecorder* otherRecorder = nullptr);
40+
41+
static void destroy(ONNXParserErrorRecorder*& recorder);
42+
43+
void clear() noexcept final;
44+
RefCount incRefCount() noexcept final;
45+
RefCount decRefCount() noexcept final;
46+
bool reportError(ErrorCode val, ErrorDesc desc) noexcept final;
47+
48+
int32_t getNbErrors() const noexcept final
49+
{
50+
return mErrorStack.size();
51+
}
52+
53+
ErrorCode getErrorCode(int32_t errorIdx) const noexcept final
54+
{
55+
return invalidIndexCheck(errorIdx) ? ErrorCode::kINVALID_ARGUMENT : (*this)[errorIdx].first;
56+
}
57+
58+
ErrorDesc getErrorDesc(int32_t errorIdx) const noexcept final
59+
{
60+
return invalidIndexCheck(errorIdx) ? "errorIdx out of range." : (*this)[errorIdx].second.c_str();
61+
}
62+
63+
bool hasOverflowed() const noexcept final
64+
{
65+
// This class can never overflow since we have dynamic resize via std::vector usage.
66+
return false;
67+
}
68+
69+
protected:
70+
ONNXParserErrorRecorder(ILogger* logger, IErrorRecorder* otherRecorder = nullptr);
71+
72+
virtual ~ONNXParserErrorRecorder() noexcept;
73+
74+
static void logError(ILogger* logger, const char* str);
75+
76+
// Simple helper functions.
77+
const errorPair& operator[](size_t index) const noexcept
78+
{
79+
return mErrorStack[index];
80+
}
81+
82+
bool invalidIndexCheck(int32_t index) const noexcept
83+
{
84+
// By converting signed to unsigned, we only need a single check since
85+
// negative numbers turn into large positive greater than the size.
86+
size_t sIndex = index;
87+
return sIndex >= mErrorStack.size();
88+
}
89+
// Mutex to hold when locking mErrorStack.
90+
std::mutex mStackLock;
91+
92+
// Reference count of the class. Destruction of the class when mRefCount
93+
// is not zero causes undefined behavior.
94+
std::atomic<int32_t> mRefCount{0};
95+
96+
// The error stack that holds the errors recorded by TensorRT.
97+
errorStack mErrorStack;
98+
99+
// Original error recorder (set by user)
100+
IErrorRecorder* mUserRecorder{nullptr};
101+
102+
// logger
103+
ILogger* mLogger{nullptr};
104+
}; // class ONNXParserErrorRecorder
105+
106+
} // namespace onnx2trt

‎onnx_backend_test.py

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
backend_test.include(r'.*test_AvgPool.*')
3434
backend_test.include(r'.*test_BatchNorm.*eval.*')
3535
backend_test.include(r'.*test_ceil.*')
36+
backend_test.include(r'.*test_celu.*')
3637
backend_test.include(r'.*test_clip.*')
3738
backend_test.include(r'.*test_concat.*')
3839
backend_test.include(r'.*test_constant.*')

0 commit comments

Comments
 (0)
Please sign in to comment.