|
| 1 | +# Copyright 2020 - 2021 MONAI Consortium |
| 2 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | +# you may not use this file except in compliance with the License. |
| 4 | +# You may obtain a copy of the License at |
| 5 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | +# Unless required by applicable law or agreed to in writing, software |
| 7 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 8 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 9 | +# See the License for the specific language governing permissions and |
| 10 | +# limitations under the License. |
| 11 | + |
| 12 | + |
| 13 | +# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. |
| 14 | +# |
| 15 | +# Redistribution and use in source and binary forms, with or without |
| 16 | +# modification, are permitted provided that the following conditions |
| 17 | +# are met: |
| 18 | +# * Redistributions of source code must retain the above copyright |
| 19 | +# notice, this list of conditions and the following disclaimer. |
| 20 | +# * Redistributions in binary form must reproduce the above copyright |
| 21 | +# notice, this list of conditions and the following disclaimer in the |
| 22 | +# documentation and/or other materials provided with the distribution. |
| 23 | +# * Neither the name of NVIDIA CORPORATION nor the names of its |
| 24 | +# contributors may be used to endorse or promote products derived |
| 25 | +# from this software without specific prior written permission. |
| 26 | +# |
| 27 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
| 28 | +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 29 | +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 30 | +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 31 | +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 32 | +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 33 | +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 34 | +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 35 | +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 36 | +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 37 | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 38 | + |
| 39 | +from tritonclient.utils import * |
| 40 | +import tritonclient.grpc as grpcclient |
| 41 | +import tritonclient.http as httpclient |
| 42 | + |
| 43 | +import argparse |
| 44 | +import numpy as np |
| 45 | +import os |
| 46 | +import sys |
| 47 | +import time |
| 48 | +from uuid import uuid4 |
| 49 | +import glob |
| 50 | + |
| 51 | +from monai.apps.utils import download_and_extract |
| 52 | +from monai.transforms.utils import convert_to_numpy |
| 53 | + |
| 54 | +MEDNIST_CLASSES = ["AbdomenCT", "BreastMRI", "CXR", "ChestCT", "Hand", "HeadCT"] |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +model_name = "mednist_class" |
| 59 | +gdrive_path = "https://drive.google.com/uc?id=1HQk4i4vXKUX_aAYR4wcZQKd-qk5Lcm_W" |
| 60 | +mednist_filename = "MedNIST_demo.tar.gz" |
| 61 | +md5_check = "3f24a5833bb0455a7815c4e0ecc8a810" |
| 62 | + |
| 63 | + |
| 64 | +def open_jpeg_files(input_path): |
| 65 | + return sorted(glob.glob(os.path.join(input_path, "*.jpeg"))) |
| 66 | + |
| 67 | + |
| 68 | +if __name__ == "__main__": |
| 69 | + |
| 70 | + parser = argparse.ArgumentParser(description='Triton CLI for MedNist classification inference from JPEG data') |
| 71 | + parser.add_argument( |
| 72 | + 'input', |
| 73 | + type=str, |
| 74 | + help="Path to JPEG file or directory containing JPEG files to send for MedNist classification" |
| 75 | + ) |
| 76 | + args = parser.parse_args() |
| 77 | + |
| 78 | + jpeg_files = [] |
| 79 | + extract_dir = "./client/test_data/MedNist" |
| 80 | + tar_save_path = os.path.join(extract_dir, mednist_filename) |
| 81 | + if os.path.isdir(args.input): # check for directory existence |
| 82 | + # Grab files from Google Drive and place in directory |
| 83 | + download_and_extract(gdrive_path, tar_save_path, output_dir=extract_dir, hash_val=md5_check, hash_type="md5") |
| 84 | + jpeg_files = open_jpeg_files(args.input) |
| 85 | + |
| 86 | + elif os.path.isfile(args.input): |
| 87 | + jpeg_files = [args.input] |
| 88 | + |
| 89 | + if not jpeg_files: |
| 90 | + print("No valid inputs provided") |
| 91 | + sys.exit(1) |
| 92 | + |
| 93 | + with httpclient.InferenceServerClient("localhost:7555") as client: |
| 94 | + image_bytes = b'' |
| 95 | + for jpeg_file in jpeg_files: |
| 96 | + with open(jpeg_file, 'rb') as f: |
| 97 | + image_bytes = f.read() |
| 98 | + |
| 99 | + input0_data = np.array([[image_bytes]], dtype=np.bytes_) |
| 100 | + |
| 101 | + inputs = [ |
| 102 | + httpclient.InferInput("INPUT0", input0_data.shape, np_to_triton_dtype(input0_data.dtype)), |
| 103 | + ] |
| 104 | + |
| 105 | + inputs[0].set_data_from_numpy(input0_data) |
| 106 | + |
| 107 | + outputs = [ |
| 108 | + httpclient.InferRequestedOutput("OUTPUT0"), |
| 109 | + ] |
| 110 | + |
| 111 | + inference_start_time = time.time() * 1000 |
| 112 | + response = client.infer(model_name, |
| 113 | + inputs, |
| 114 | + request_id=str(uuid4().hex), |
| 115 | + outputs=outputs,) |
| 116 | + inference_time = time.time() * 1000 - inference_start_time |
| 117 | + |
| 118 | + result = response.get_response() |
| 119 | + print("Classification result for `{}`: {}. (Inference time: {:6.0f} ms)".format( |
| 120 | + jpeg_file, |
| 121 | + response.as_numpy("OUTPUT0").astype(str)[0], |
| 122 | + inference_time, |
| 123 | + )) |
0 commit comments