Files
Rajeev Rao 2d517d270e TensorRT OSS v8.2 Early Access Release
Signed-off-by: Rajeev Rao <rajeevrao@nvidia.com>
2021-10-05 11:30:06 -07:00

165 lines
7.0 KiB
Python

#
# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import sys
# This sample uses an MNIST PyTorch model to create a TensorRT Inference Engine
import model
import numpy as np
import pycuda.autoinit
import tensorrt as trt
sys.path.insert(1, os.path.join(sys.path[0], os.path.pardir))
import common
# You can set the logger severity higher to suppress messages (or lower to display more messages).
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
class ModelData(object):
INPUT_NAME = "data"
INPUT_SHAPE = (1, 28, 28)
OUTPUT_NAME = "prob"
OUTPUT_SIZE = 10
DTYPE = trt.float32
# Populate the TRT network, injecting some dummy weights
def populate_network_with_some_dummy_weights(network, weights):
# Configure the network layers based on the weights provided.
input_tensor = network.add_input(name=ModelData.INPUT_NAME, dtype=ModelData.DTYPE, shape=ModelData.INPUT_SHAPE)
# Set dummy weights for the kernel and bias weights in the conv1 layer. We
# will refit the engine with the actual weights later.
conv1_w = np.zeros((20,5,5), dtype=np.float32)
conv1_b = np.zeros(20, dtype=np.float32)
conv1 = network.add_convolution(input=input_tensor, num_output_maps=20, kernel_shape=(5, 5), kernel=conv1_w, bias=conv1_b)
conv1.name = "conv_1"
conv1.stride = (1, 1)
# Associate weights with name and refit weights via name later in refitter.
network.set_weights_name(conv1_w, 'conv1.weight')
pool1 = network.add_pooling(input=conv1.get_output(0), type=trt.PoolingType.MAX, window_size=(2, 2))
pool1.stride = (2, 2)
conv2_w = weights['conv2.weight'].numpy()
conv2_b = weights['conv2.bias'].numpy()
conv2 = network.add_convolution(pool1.get_output(0), 50, (5, 5), conv2_w, conv2_b)
conv2.stride = (1, 1)
pool2 = network.add_pooling(conv2.get_output(0), trt.PoolingType.MAX, (2, 2))
pool2.stride = (2, 2)
fc1_w = weights['fc1.weight'].numpy()
fc1_b = weights['fc1.bias'].numpy()
fc1 = network.add_fully_connected(input=pool2.get_output(0), num_outputs=500, kernel=fc1_w, bias=fc1_b)
relu1 = network.add_activation(input=fc1.get_output(0), type=trt.ActivationType.RELU)
fc2_w = weights['fc2.weight'].numpy()
fc2_b = weights['fc2.bias'].numpy()
fc2 = network.add_fully_connected(relu1.get_output(0), ModelData.OUTPUT_SIZE, fc2_w, fc2_b)
fc2.get_output(0).name = ModelData.OUTPUT_NAME
network.mark_output(tensor=fc2.get_output(0))
# Build a TRT engine, but leave out some weights
def build_engine_with_some_missing_weights(weights):
# For more information on TRT basics, refer to the introductory samples.
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network()
config = builder.create_builder_config()
runtime = trt.Runtime(TRT_LOGGER)
config.max_workspace_size = common.GiB(1)
# Set the refit flag in the builder
config.set_flag(trt.BuilderFlag.REFIT)
# Populate the network using weights from the PyTorch model.
populate_network_with_some_dummy_weights(network, weights)
# Build and return an engine.
plan = builder.build_serialized_network(network, config)
return runtime.deserialize_cuda_engine(plan)
# Copy an image to the pagelocked input buffer
def load_img_to_input_buffer(img, pagelocked_buffer):
np.copyto(pagelocked_buffer, img)
# Get the accuracy on the test set using TensorRT
def get_trt_test_accuracy(engine, inputs, outputs, bindings, stream, mnist_model):
context = engine.create_execution_context()
correct = 0
total = 0
# Run inference on every sample.
# Technically this could be batched, however this only comprises a fraction of total
# time spent in the test.
for test_img, test_name in mnist_model.get_all_test_samples():
load_img_to_input_buffer(test_img, pagelocked_buffer=inputs[0].host)
# For more information on performing inference, refer to the introductory samples.
# The common.do_inference function will return a list of outputs - we only have one in this case.
[output] = common.do_inference(context, bindings=bindings, inputs=inputs, outputs=outputs, stream=stream)
pred = np.argmax(output)
correct += (test_name == pred)
total += 1
accuracy = float(correct)/total
print("Got {} correct predictions out of {} ({:.1f}%)".format(correct, total, 100 * accuracy))
return accuracy
def main():
common.add_help(description="Runs an MNIST network using a PyTorch model")
# Train the PyTorch model
mnist_model = model.MnistModel()
mnist_model.learn()
weights = mnist_model.get_weights()
# Do inference with TensorRT.
engine = build_engine_with_some_missing_weights(weights)
# Build an engine, allocate buffers and create a stream.
# For more information on buffer allocation, refer to the introductory samples.
inputs, outputs, bindings, stream = common.allocate_buffers(engine)
print("Accuracy Before Engine Refit")
get_trt_test_accuracy(engine, inputs, outputs, bindings, stream, mnist_model)
# Refit the engine with the actual trained weights for the conv_1 layer.
refitter = trt.Refitter(engine, TRT_LOGGER)
# To get a list of all refittable layers and associated weightRoles
# in the network, use refitter.get_all()
# Set the actual weights for the conv_1 layer. Since it consists of
# kernel weights and bias weights, set each of them by specifying
# the WeightsRole.
# Prefer to refit named weights via set_named_weights
refitter.set_named_weights('conv1.weight', weights['conv1.weight'].numpy())
# set_named_weights is not available for unnamed weights. Call set_weights instead.
refitter.set_weights("conv_1", trt.WeightsRole.BIAS,
weights['conv1.bias'].numpy())
# Get missing weights names. This should return empty
# lists in this case.
missing_weights = refitter.get_missing_weights()
assert len(missing_weights) == 0, "Refitter found missing weights. Call set_named_weights() or set_weights() for all missing weights"
# Refit the engine with the new weights. This will return True if
# the refit operation succeeded.
assert refitter.refit_cuda_engine()
expected_correct_predictions = mnist_model.get_latest_test_set_accuracy()
print("Accuracy After Engine Refit (expecting {:.1f}% correct predictions)".format(100 * expected_correct_predictions))
assert get_trt_test_accuracy(engine, inputs, outputs, bindings, stream, mnist_model) >= expected_correct_predictions
if __name__ == '__main__':
main()