We'll need to include pre-processing step using ImageToNDArrayStep() to convert the input image into an array and specify all characteristics of the input image. To run a model, add Nd4jTensorFlowStep() into the pipeline and specify modelUri, inputNames and outputNames. ClassifierOutputStep() can be included for transforming the output in a way that humans can understand and set the following:
inputName : names for model's output layer
labels : list of output labels classifier
allProbabilities : false
//include pipeline step into the Inference ConfigurationinferenceConfiguration.pipeline(SequencePipeline.builder().add(newImageToNDArrayStep()//add ImageToNDArrayStep() into pipeline to set image to NDArray for input.config(newImageToNDArrayConfig()//image configuration.width(28).height(28).dataType(NDArrayType.FLOAT).aspectRatioHandling(AspectRatioHandling.CENTER_CROP).includeMinibatchDim(true).channelLayout(NDChannelLayout.GRAYSCALE).format(NDFormat.CHANNELS_FIRST).normalization(ImageNormalization.builder().type(ImageNormalization.Type.SCALE).build()) ).keys("image").outputNames("input_layer").keepOtherValues(true).metadata(false).metadataKey(ImageToNDArrayStep.DEFAULT_METADATA_KEY)).add(newNd4jTensorFlowStep()//add Nd4jTensorFlowStep into pipeline.modelUri(modelTrainResult.modelPath()).inputNames(modelTrainResult.inputNames()).outputNames(modelTrainResult.outputNames()) ).add(newClassifierOutputStep().inputName(modelTrainResult.outputNames().get(0)).labels(Arrays.asList(labels.clone())).allProbabilities(false) ).build());
Deploy the server
Let's deploy the model in the server by calling DeployKonduitServing with the configuration made before. The handler, a callback function, is applied, only after a successful or failed server deployment inside the handler block, as shown.
//deploy the model in serverDeployKonduitServing.deploy(newVertxOptions(),newDeploymentOptions(), inferenceConfiguration, handler -> {if (handler.succeeded()) { // If the server is successfully running// Getting the result of the deploymentInferenceDeploymentResult inferenceDeploymentResult =handler.result();int runnningPort =inferenceDeploymentResult.getActualPort(); //get server's portString deploymentId =inferenceDeploymentResult.getDeploymentId(); //get server's deployment idSystem.out.format("The server is running on port %s with deployment id of %s%n", runnningPort, deploymentId);try {String result;try { result =Unirest.post(String.format("http://localhost:%s/predict", runnningPort)).header("Accept","application/json") .field("image", new ClassPathResource("inputs/test_files/test_input_number_2.png").getFile(), "image/png")
.asString().getBody();System.out.format("Result from server : %s%n", result);System.exit(0); } catch (IOException e) {e.printStackTrace();System.exit(1); } } catch (UnirestException e) {e.printStackTrace();System.exit(1); } } else { // If the server failed to runSystem.out.println(handler.cause().getMessage());System.exit(1); } });
Note that we consider only one test input image in this example for inference to show the model's deployment in Konduit-Serving. After implementation, the successful server deployment gives below output text.
The server is running on port 40521 with deployment id of 4b7d8bc5-a711-499f-ad9f-9ccd82c3e142
Result from server : {
"output_layer/Softmax" : [ [ 1.8688768E-8, 0.0962552, 0.7753802, 1.7737559E-8, 0.122773424, 4.7498935E-13, 3.0434896E-6, 0.005588151, 7.329317E-12, 3.4533626E-10 ] ],
"prob" : 0.7753801941871643,
"index" : 2,
"label" : "2"
}
Process finished with exit code 0
The complete inference configuration in YAML format is as follows.