Repository: deepjavalibrary/djl
Pull request #1768 (2022-07-05 16:12:48)

Implementing inverse operation
## Description ##

Brief description of what this PR is about

Implementing inverse of an NDArray. Issue [https://github.com/deepjavalibrary/djl/issues/1068](https://github.com/deepjavalibrary/djl/issues/1068)




codecov-commenter: # [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) Report
> Merging [#1768](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (ac41b69) into [master](https://codecov.io/gh/deepjavalibrary/djl/commit/bb5073f7ffc33f1883621fc1783dbb01e70b418f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (bb5073f) will **decrease** coverage by `1.55%`.
> The diff coverage is `70.97%`.

```diff
@@             Coverage Diff              @@
##             master    #1768      +/-   ##
============================================
- Coverage     72.08%   70.53%   -1.56%     
- Complexity     5126     5586     +460     
============================================
  Files           473      527      +54     
  Lines         21970    24795    +2825     
  Branches       2351     2699     +348     
============================================
+ Hits          15838    17489    +1651     
- Misses         4925     5971    +1046     
- Partials       1207     1335     +128     
```


| [Impacted Files](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | Coverage Δ | |
|---|---|---|
| [api/src/main/java/ai/djl/modality/cv/Image.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L0ltYWdlLmphdmE=) | `69.23% <ø> (-4.11%)` | :arrow_down: |
| [...rc/main/java/ai/djl/modality/cv/MultiBoxPrior.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L011bHRpQm94UHJpb3IuamF2YQ==) | `76.00% <ø> (ø)` | |
| [...rc/main/java/ai/djl/modality/cv/output/Joints.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9Kb2ludHMuamF2YQ==) | `71.42% <ø> (ø)` | |
| [.../main/java/ai/djl/modality/cv/output/Landmark.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9MYW5kbWFyay5qYXZh) | `100.00% <ø> (ø)` | |
| [...main/java/ai/djl/modality/cv/output/Rectangle.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9SZWN0YW5nbGUuamF2YQ==) | `72.41% <0.00%> (ø)` | |
| [...i/djl/modality/cv/translator/BigGANTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvci5qYXZh) | `21.42% <ø> (-5.24%)` | :arrow_down: |
| [...odality/cv/translator/BigGANTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvckZhY3RvcnkuamF2YQ==) | `33.33% <0.00%> (+8.33%)` | :arrow_up: |
| [...nslator/InstanceSegmentationTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvSW5zdGFuY2VTZWdtZW50YXRpb25UcmFuc2xhdG9yRmFjdG9yeS5qYXZh) | `14.28% <0.00%> (-3.90%)` | :arrow_down: |
| [.../cv/translator/StyleTransferTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvU3R5bGVUcmFuc2ZlclRyYW5zbGF0b3JGYWN0b3J5LmphdmE=) | `40.00% <ø> (ø)` | |
| [.../ai/djl/modality/cv/translator/YoloTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvWW9sb1RyYW5zbGF0b3IuamF2YQ==) | `8.33% <0.00%> (-0.50%)` | :arrow_down: |
| ... and [411 more](https://codecov.io/gh/deepjavalibrary/djl/pull/1768/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Last update [499d4f2...ac41b69](https://codecov.io/gh/deepjavalibrary/djl/pull/1768?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).

sindhuvahinis: @KexinFeng 

Patch:
diff --git a/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslator.java b/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslator.java
new file mode 100644
index 000000000..5baaec52f
--- /dev/null
+++ b/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslator.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2022 Amazon.com, Inc. or its affiliates. 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. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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.
+ */
+package ai.djl.modality.cv.translator;
+
+import ai.djl.modality.cv.BufferedImageFactory;
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.output.DetectedObjects;
+import ai.djl.modality.cv.util.NDImageUtils;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.index.NDIndex;
+import ai.djl.ndarray.types.DataType;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.translate.ArgumentsUtil;
+import ai.djl.translate.Transform;
+import ai.djl.translate.TranslatorContext;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+/**
+ * A {@link BaseImageTranslator} that post-process the {@link NDArray} into {@link DetectedObjects}
+ * with boundaries at the detailed pixel level.
+ */
+public class SemanticSegmentationTranslator extends BaseImageTranslator<Image> {
+    private final int shortEdge;
+    private final int maxEdge;
+
+    private static final int CHANNEL = 3;
+    private static final int CLASSNUM = 21;
+    private static final int BIKE = 2;
+    private static final int CAR = 7;
+    private static final int DOG = 8;
+    private static final int CAT = 12;
+    private static final int PERSON = 15;
+
+    // sheep is also identified with id 13 as well, this is taken into account when coloring pixels
+    private static final int SHEEP = 17; // 13
+
+    /**
+     * Creates the Semantic Segmentation translator from the given builder.
+     *
+     * @param builder the builder for the translator
+     */
+    public SemanticSegmentationTranslator(Builder builder) {
+        super(builder);
+        this.shortEdge = builder.shortEdge;
+        this.maxEdge = builder.maxEdge;
+
+        pipeline.insert(0, null, new ResizeShort());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDList processInput(TranslatorContext ctx, Image image) {
+        ctx.setAttachment("originalHeight", image.getHeight());
+        ctx.setAttachment("originalWidth", image.getWidth());
+        return super.processInput(ctx, image);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Image processOutput(TranslatorContext ctx, NDList list) {
+        // scores contains the probabilities of each pixel being a certain object
+        float[] scores = list.get(1).toFloatArray();
+
+        // get dimensions of image
+        int width = (int) ctx.getAttachment("originalWidth");
+        int height = (int) ctx.getAttachment("originalHeight");
+
+        // build image array
+        try (NDManager manager = NDManager.newBaseManager()) {
+            ByteBuffer bb = manager.allocateDirect(CHANNEL * height * width);
+            NDArray intRet = manager.create(bb, new Shape(CHANNEL, height, width), DataType.UINT8);
+
+            // change color of pixels in image array where objects have been detected
+            for (int j = 0; j < height; j++) {
+                for (int k = 0; k < width; k++) {
+                    int maxi = 0;
+                    double maxnum = -Double.MAX_VALUE;
+                    for (int i = 0; i < CLASSNUM; i++) {
+
+                        // get score for each i at the k,j pixel of the image
+                        float score = scores[i * (width * height) + j * width + k];
+                        if (score > maxnum) {
+                            maxnum = score;
+                            maxi = i;
+                        }
+                    }
+
+                    // color pixel if object was found, otherwise leave as is (black)
+                    if (maxi == PERSON || maxi == BIKE) {
+                        NDIndex index = new NDIndex(0, j, k);
+                        intRet.set(index, 0xFF00FF);
+                    } else if (maxi == CAT || maxi == SHEEP || maxi == 13) {
+                        NDIndex index = new NDIndex(1, j, k);
+                        intRet.set(index, 0xFF00FF);
+                    } else if (maxi == CAR || maxi == DOG) {
+                        NDIndex index = new NDIndex(2, j, k);
+                        intRet.set(index, 0xFF00FF);
+                    }
+                }
+            }
+            return BufferedImageFactory.getInstance().fromNDArray(intRet);
+        }
+    }
+
+    /**
+     * Creates a builder to build a {@code SemanticSegmentationTranslator}.
+     *
+     * @return a new builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Creates a builder to build a {@code SemanticSegmentationTranslator} with specified arguments.
+     *
+     * @param arguments arguments to specify builder options
+     * @return a new builder
+     */
+    public static Builder builder(Map<String, ?> arguments) {
+        Builder builder = new Builder();
+
+        builder.configPreProcess(arguments);
+        builder.configPostProcess(arguments);
+
+        return builder;
+    }
+
+    /** Resizes the image based on the shorter edge or maximum edge length. */
+    private class ResizeShort implements Transform {
+        /** {@inheritDoc} */
+        @Override
+        public NDArray transform(NDArray array) {
+            Shape shape = array.getShape();
+            int width = (int) shape.get(1);
+            int height = (int) shape.get(0);
+            int min = Math.min(width, height);
+            int max = Math.max(width, height);
+            float scale = shortEdge / (float) min;
+            if (Math.round(scale * max) > maxEdge) {
+                scale = maxEdge / (float) max;
+            }
+            int rescaledHeight = Math.round(height * scale);
+            int rescaledWidth = Math.round(width * scale);
+
+            return NDImageUtils.resize(array, rescaledWidth, rescaledHeight);
+        }
+    }
+
+    /** The builder for Semantic Segmentation translator. */
+    public static class Builder extends ClassificationBuilder<Builder> {
+        int shortEdge = 600;
+        int maxEdge = 1000;
+
+        Builder() {}
+
+        /** {@inheritDoc} */
+        @Override
+        protected Builder self() {
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected void configPostProcess(Map<String, ?> arguments) {
+            super.configPostProcess(arguments);
+            shortEdge = ArgumentsUtil.intValue(arguments, "shortEdge", 600);
+            maxEdge = ArgumentsUtil.intValue(arguments, "maxEdge", 1000);
+        }
+
+        /**
+         * Builds the translator.
+         *
+         * @return the new translator
+         */
+        public SemanticSegmentationTranslator build() {
+            validate();
+            return new SemanticSegmentationTranslator(this);
+        }
+    }
+}
diff --git a/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslatorFactory.java b/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslatorFactory.java
new file mode 100644
index 000000000..ddb61b81c
--- /dev/null
+++ b/api/src/main/java/ai/djl/modality/cv/translator/SemanticSegmentationTranslatorFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 Amazon.com, Inc. or its affiliates. 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. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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.
+ */
+package ai.djl.modality.cv.translator;
+
+import ai.djl.Model;
+import ai.djl.modality.Input;
+import ai.djl.modality.Output;
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.translator.wrapper.FileTranslator;
+import ai.djl.modality.cv.translator.wrapper.InputStreamTranslator;
+import ai.djl.modality.cv.translator.wrapper.UrlTranslator;
+import ai.djl.translate.Translator;
+import ai.djl.translate.TranslatorFactory;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.Map;
+
+/** A {@link TranslatorFactory} that creates a {@link SemanticSegmentationTranslator} instance. */
+public class SemanticSegmentationTranslatorFactory extends ObjectDetectionTranslatorFactory {
+
+    /** {@inheritDoc} */
+    @Override
+    public Translator<?, ?> newInstance(
+            Class<?> input, Class<?> output, Model model, Map<String, ?> arguments) {
+        if (input == Image.class && output == Image.class) {
+            return SemanticSegmentationTranslator.builder(arguments).build();
+        } else if (input == Path.class && output == Image.class) {
+            return new FileTranslator<>(SemanticSegmentationTranslator.builder(arguments).build());
+        } else if (input == URL.class && output == Image.class) {
+            return new UrlTranslator<>(SemanticSegmentationTranslator.builder(arguments).build());
+        } else if (input == InputStream.class && output == Image.class) {
+            return new InputStreamTranslator<>(
+                    SemanticSegmentationTranslator.builder(arguments).build());
+        } else if (input == Input.class && output == Output.class) {
+            return new ImageServingTranslator(
+                    SemanticSegmentationTranslator.builder(arguments).build());
+        }
+        throw new IllegalArgumentException("Unsupported input/output types.");
+    }
+}
diff --git a/api/src/main/java/ai/djl/ndarray/NDArray.java b/api/src/main/java/ai/djl/ndarray/NDArray.java
index 516e279a2..5b8a2008d 100644
--- a/api/src/main/java/ai/djl/ndarray/NDArray.java
+++ b/api/src/main/java/ai/djl/ndarray/NDArray.java
@@ -3644,6 +3644,13 @@ public interface NDArray extends NDResource, BytesSupplier {
      */
     NDArray isInfinite();
 
+    /**
+     * Computes the inverse of square {@code NDArray} if it exists.
+     *
+     * @return the inverse of square {@code NDArray}.
+     */
+    NDArray inverse();
+
     /**
      * Returns the boolean {@code NDArray} with value {@code true} where this {@code NDArray}'s
      * entries are NaN, or {@code false} where they are not NaN.
diff --git a/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java b/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
index ab619bf9c..60d1d02a9 100644
--- a/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
+++ b/api/src/main/java/ai/djl/ndarray/NDArrayAdapter.java
@@ -1042,6 +1042,12 @@ public abstract class NDArrayAdapter implements NDArray {
         return getAlternativeArray().erfinv();
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray inverse() {
+        throw new UnsupportedOperationException("Not implemented yet.");
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray norm(boolean keepDims) {
diff --git a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
index 1db6a819c..2f75d565f 100644
--- a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
+++ b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxNDArray.java
@@ -1225,6 +1225,12 @@ public class MxNDArray extends NativeResource<Pointer> implements LazyNDArray {
         throw new UnsupportedOperationException("Not implemented yet.");
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray inverse() {
+        return manager.invoke("inverse", this, null);
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray isNaN() {
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
index 70654e6c4..e6c128728 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtNDArray.java
@@ -1386,6 +1386,12 @@ public class PtNDArray extends NativeResource<Long> implements NDArray {
         return JniUtils.erfinv(this);
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public PtNDArray inverse() {
+        return JniUtils.inverse(this);
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray norm(boolean keepDims) {
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
index 3364cd45e..7ce5076af 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/JniUtils.java
@@ -1166,6 +1166,11 @@ public final class JniUtils {
                 ndArray.getManager(), PyTorchLibrary.LIB.torchErfinv(ndArray.getHandle()));
     }
 
+    public static PtNDArray inverse(PtNDArray ndArray) {
+        return new PtNDArray(
+                ndArray.getManager(), PyTorchLibrary.LIB.torchInverse(ndArray.getHandle()));
+    }
+
     public static PtNDArray interpolate(
             PtNDArray ndArray, long[] size, int mode, boolean alignCorners) {
         return new PtNDArray(
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
index 542ef3b54..c3fcc64a5 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/PyTorchLibrary.java
@@ -363,6 +363,8 @@ final class PyTorchLibrary {
 
     native long torchErfinv(long handle);
 
+    native long torchInverse(long self);
+
     native long torchNNInterpolate(long handle, long[] size, int mode, boolean alignCorners);
 
     native long torchNNLinear(long handle, long weightHandle, long biasHandle);
diff --git a/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_pointwise.cc b/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_pointwise.cc
index 0cb015908..507d566e9 100644
--- a/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_pointwise.cc
+++ b/engines/pytorch/pytorch-native/src/main/native/ai_djl_pytorch_jni_PyTorchLibrary_torch_pointwise.cc
@@ -460,3 +460,11 @@ JNIEXPORT jlong JNICALL Java_ai_djl_pytorch_jni_PyTorchLibrary_torchErfinv(JNIEn
   return reinterpret_cast<uintptr_t>(result_ptr);
   API_END_RETURN()
 }
+
+JNIEXPORT jlong JNICALL Java_ai_djl_pytorch_jni_PyTorchLibrary_torchInverse(JNIEnv* env, jobject jthis, jlong jself) {
+  API_BEGIN()
+  const auto* self_ptr = reinterpret_cast<torch::Tensor*>(jself);
+  const auto* result_ptr = new torch::Tensor(torch::linalg_inv(*self_ptr));
+  return reinterpret_cast<uintptr_t>(result_ptr);
+  API_END_RETURN()
+}
diff --git a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
index a48f03aa5..9afcf7575 100644
--- a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
+++ b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/TfNDArray.java
@@ -1337,6 +1337,12 @@ public class TfNDArray extends NativeResource<TFE_TensorHandle> implements NDArr
         return manager.opExecutor("IsInf").addInput(this).buildSingletonOrThrow();
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public NDArray inverse() {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
     /** {@inheritDoc} */
     @Override
     public NDArray isNaN() {
diff --git a/examples/docs/instance_segmentation.md b/examples/docs/instance_segmentation.md
index 24e534a48..ce8fde006 100644
--- a/examples/docs/instance_segmentation.md
+++ b/examples/docs/instance_segmentation.md
@@ -38,6 +38,6 @@ This should produce the following output
 ```
 
 
-With the previous command, an output image with bounding box around all objects will be saved at: build/output/instances.jpg:
+With the previous command, an output image with bounding box around all objects will be saved at: build/output/instances.png:
 
 ![detected-instances](img/detected_instances.png)
diff --git a/examples/docs/semantic_segmentation.md b/examples/docs/semantic_segmentation.md
new file mode 100644
index 000000000..c1d242df5
--- /dev/null
+++ b/examples/docs/semantic_segmentation.md
@@ -0,0 +1,72 @@
+# Semantic segmentation example
+
+Semantic segmentation refers to the task of detecting objects of various classes at pixel level. It colors the pixels based on the objects detected in that space.
+
+In this example, you learn how to implement inference code with Deep Java Library (DJL) to segment classes at instance level in an image.
+
+The following is the semantic segmentation example source code:
+
+[SemanticSegmentation.java](https://github.com/deepjavalibrary/djl/blob/master/examples/src/main/java/ai/djl/examples/inference/SemanticSegmentation.java).
+
+
+## Setup guide
+
+Follow [setup](../../docs/development/setup.md) to configure your development environment.
+
+## Run semantic segmentation example
+
+### Input image file
+You can find the image used in this example in project test resource folder: `src/test/resources/segmentation.jpg`
+
+![segmentation](../src/test/resources/segmentation.jpg)
+
+### Build the project and run
+
+```
+cd examples
+./gradlew run -Dmain=ai.djl.examples.inference.SemanticSegmentation
+```
+
+This should produce the following output
+
+```text
+[INFO ] - Segmentation result image has been saved in: build/output/semantic_instances.png
+```
+
+
+With the previous command, an output image with bounding box around all objects will be saved at: build/output/semantic_instances.png:
+
+![detected-instances](https://resources.djl.ai/images/semantic_segmentation/semantic_instance_bikes.png)
+
+## Run another semantic segmentation example
+
+### Input image file
+You can find the image used in this example in project test resource folder: `src/test/resources/dog_bike_car.jpg`
+
+![segmentation](../src/test/resources/dog_bike_car.jpg)
+
+### Edit project to run inference with new image
+
+In the `SemanticSegmentation.java` file, find the `predict()` method. Change the `imageFile` path to look like this:
+
+```
+Path imageFile = Paths.get("src/test/resources/dog_bike_car.jpg");
+```
+
+### Build the project and run
+
+```
+cd examples
+./gradlew run -Dmain=ai.djl.examples.inference.InstanceSegmentation
+```
+
+This should produce the following output
+
+```text
+[INFO ] - Segmentation result image has been saved in: build/output/semantic_instances.png
+```
+
+
+With the previous command, an output image with bounding box around all objects will be saved at: build/output/semantic_instances.png:
+
+![detected-instances](https://resources.djl.ai/images/semantic_segmentation/semantic_instance_dog_bike_car.png)
diff --git a/examples/src/main/java/ai/djl/examples/inference/SemanticSegmentation.java b/examples/src/main/java/ai/djl/examples/inference/SemanticSegmentation.java
new file mode 100644
index 000000000..0ee791de5
--- /dev/null
+++ b/examples/src/main/java/ai/djl/examples/inference/SemanticSegmentation.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2022 Amazon.com, Inc. or its affiliates. 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. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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.
+ */
+package ai.djl.examples.inference;
+
+import ai.djl.ModelException;
+import ai.djl.inference.Predictor;
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.ImageFactory;
+import ai.djl.modality.cv.translator.SemanticSegmentationTranslator;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ZooModel;
+import ai.djl.training.util.ProgressBar;
+import ai.djl.translate.TranslateException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * An example of inference using a semantic segmentation model.
+ *
+ * <p>See this <a
+ * href="https://github.com/deepjavalibrary/djl/blob/master/examples/docs/semantic_segmentation.md">doc</a>
+ * for information about this example.
+ */
+public final class SemanticSegmentation {
+
+    private static final Logger logger =
+            LoggerFactory.getLogger(SemanticSegmentationTranslator.class);
+
+    private SemanticSegmentation() {}
+
+    public static void main(String[] args) throws IOException, ModelException, TranslateException {
+        SemanticSegmentation.predict();
+    }
+
+    public static void predict() throws IOException, ModelException, TranslateException {
+        Path imageFile = Paths.get("src/test/resources/dog_bike_car.jpg");
+        Image img = ImageFactory.getInstance().fromFile(imageFile);
+
+        int height = img.getHeight();
+        int width = img.getWidth();
+
+        String url =
+                "https://mlrepo.djl.ai/model/cv/semantic_segmentation/ai/djl/pytorch/deeplabv3/0.0.1/deeplabv3.zip";
+        Map<String, String> arguments = new ConcurrentHashMap<>();
+        arguments.put("toTensor", "true");
+        arguments.put("normalize", "true");
+        arguments.put("resize", "true");
+        arguments.put("width", String.valueOf(width));
+        arguments.put("height", String.valueOf(height));
+        SemanticSegmentationTranslator translator =
+                SemanticSegmentationTranslator.builder(arguments).build();
+
+        Criteria<Image, Image> criteria =
+                Criteria.builder()
+                        .setTypes(Image.class, Image.class)
+                        .optModelUrls(url)
+                        .optTranslator(translator)
+                        .optEngine("PyTorch")
+                        .optProgress(new ProgressBar())
+                        .build();
+        try (ZooModel<Image, Image> model = criteria.loadModel()) {
+            try (Predictor<Image, Image> predictor = model.newPredictor()) {
+                Image semanticImage = predictor.predict(img);
+                saveSemanticImage(semanticImage);
+            }
+        }
+    }
+
+    private static void saveSemanticImage(Image img) throws IOException {
+        Path outputDir = Paths.get("build/output");
+        Files.createDirectories(outputDir);
+
+        Path imagePath = outputDir.resolve("semantic_instances.png");
+        img.save(Files.newOutputStream(imagePath), "png");
+        logger.info("Segmentation result image has been saved in: {}", imagePath);
+    }
+}


Test patch:
diff --git a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
index b69359ff0..4d576127d 100644
--- a/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/ndarray/NDArrayOtherOpTest.java
@@ -869,6 +869,26 @@ public class NDArrayOtherOpTest {
         }
     }
 
+    @Test
+    public void testInverse() {
+        try (NDManager manager = NDManager.newBaseManager()) {
+            NDArray array =
+                    manager.create(
+                                    new float[] {
+                                        1.0f, -4.0f, 2.0f, -2.0f, 1.0f, 3.0f, 2.0f, 6.0f, 8.0f
+                                    })
+                            .reshape(3, 3);
+            NDArray expected =
+                    manager.create(
+                                    new float[] {
+                                        0.0794f, -0.3492f, 0.1111f, -0.1746f, -0.0317f, 0.0556f,
+                                        0.1111f, 0.1111f, 0.0556f
+                                    })
+                            .reshape(3, 3);
+            Assertions.assertAlmostEquals(array.inverse(), expected);
+        }
+    }
+
     @Test
     public void testNorm() {
         try (NDManager manager = NDManager.newBaseManager()) {