Repository: deepjavalibrary/djl
Pull request #1344 (2021-11-04 17:29:28)

[examples] include all engines in example project build.gradle
Change-Id: I06de6be02f20bc1f09b9a2a2d067f5c25aba9c8f

1. Fixed MxBertQATranslator processing out inconsistency
2. User now can run examples directly from their IDE
3. User no longer need pass -Dai.djl.default_engine=PyTorch in gradle command line



Patch:
diff --git a/api/src/main/java/ai/djl/engine/Engine.java b/api/src/main/java/ai/djl/engine/Engine.java
index 8e9ac70bf..9caf2c081 100644
--- a/api/src/main/java/ai/djl/engine/Engine.java
+++ b/api/src/main/java/ai/djl/engine/Engine.java
@@ -114,7 +114,7 @@ public abstract class Engine {
      * @return the default Engine name
      */
     public static String getDefaultEngineName() {
-        return DEFAULT_ENGINE;
+        return System.getProperty("ai.djl.default_engine", DEFAULT_ENGINE);
     }
 
     /**
@@ -130,7 +130,7 @@ public abstract class Engine {
                             + System.lineSeparator()
                             + "Please refer to https://github.com/deepjavalibrary/djl/blob/master/docs/development/troubleshooting.md for more details.");
         }
-        return getEngine(System.getProperty("ai.djl.default_engine", DEFAULT_ENGINE));
+        return getEngine(getDefaultEngineName());
     }
 
     /**
diff --git a/api/src/main/java/ai/djl/training/loss/SigmoidBinaryCrossEntropyLoss.java b/api/src/main/java/ai/djl/training/loss/SigmoidBinaryCrossEntropyLoss.java
index ce84a6545..f6f77c9c9 100644
--- a/api/src/main/java/ai/djl/training/loss/SigmoidBinaryCrossEntropyLoss.java
+++ b/api/src/main/java/ai/djl/training/loss/SigmoidBinaryCrossEntropyLoss.java
@@ -69,16 +69,25 @@ public class SigmoidBinaryCrossEntropyLoss extends Loss {
                             .sub(pred.mul(lab))
                             .add(Activation.softPlus(pred.abs().neg()));
         } else {
-            double eps = 1e-12;
             loss =
-                    pred.add(eps)
-                            .log()
+                    epsLog(pred)
                             .mul(lab)
-                            .add(NDArrays.sub(1., pred).add(eps).mul(NDArrays.sub(1., lab)));
+                            .add(epsLog(NDArrays.sub(1., pred)).mul(NDArrays.sub(1., lab)));
         }
         if (weight != 1f) {
             loss = loss.mul(weight);
         }
         return loss.mean();
     }
+
+    /**
+     * Computes a log with added epsilon to avoid errors.
+     *
+     * @param a the input array
+     * @return the computed value
+     */
+    private NDArray epsLog(NDArray a) {
+        double eps = 1e-12;
+        return a.add(eps).log();
+    }
 }
diff --git a/docs/load_model.md b/docs/load_model.md
index 39ff6afa7..727ef7bc1 100644
--- a/docs/load_model.md
+++ b/docs/load_model.md
@@ -185,7 +185,7 @@ You can use [ModelZoo.listModels()](https://javadoc.io/static/ai.djl/api/0.13.0/
 
 #### List available models using DJL command line
 
-Use the following command to list models in examples module for MXNet engine:
+Use the following command to list models in the DJL model zoo:
 
 ```shell
 ./gradlew :examples:listmodels
@@ -200,8 +200,8 @@ Use the following command to list models in examples module for MXNet engine:
 
 ```
 
-You can list models from your model folder and only list models for specific Engine with debug log:
+You can list models from your model folder with debug log:
 
 ```shell
-./gradlew :examples:listmodels -Dai.djl.default_engine=PyTorch -Dai.djl.logging.level=debug -Dai.djl.repository.zoo.location=file:///mymodels
+./gradlew :examples:listmodels -Dai.djl.logging.level=debug -Dai.djl.repository.zoo.location=file:///mymodels
 ```
diff --git a/engines/mxnet/mxnet-model-zoo/src/main/java/ai/djl/mxnet/zoo/nlp/qa/MxBertQATranslator.java b/engines/mxnet/mxnet-model-zoo/src/main/java/ai/djl/mxnet/zoo/nlp/qa/MxBertQATranslator.java
index 627bf7420..86b2f6e86 100644
--- a/engines/mxnet/mxnet-model-zoo/src/main/java/ai/djl/mxnet/zoo/nlp/qa/MxBertQATranslator.java
+++ b/engines/mxnet/mxnet-model-zoo/src/main/java/ai/djl/mxnet/zoo/nlp/qa/MxBertQATranslator.java
@@ -111,7 +111,7 @@ public class MxBertQATranslator extends QATranslator {
         NDArray endLogits = output.get(1).reshape(new Shape(1, -1));
         int startIdx = (int) startLogits.argMax(1).getLong();
         int endIdx = (int) endLogits.argMax(1).getLong();
-        return tokens.subList(startIdx, endIdx + 1).toString();
+        return tokenizer.tokenToString(tokens.subList(startIdx, endIdx + 1));
     }
 
     /**
diff --git a/examples/build.gradle b/examples/build.gradle
index fa974152e..33f1279f5 100644
--- a/examples/build.gradle
+++ b/examples/build.gradle
@@ -8,13 +8,9 @@ dependencies {
     implementation project(":basicdataset")
     implementation project(":model-zoo")
 
-    if (System.getProperty("ai.djl.default_engine") == "PyTorch") {
-        runtimeOnly project(":engines:pytorch:pytorch-model-zoo")
-    } else if (System.getProperty("ai.djl.default_engine") == "TensorFlow") {
-        runtimeOnly project(":engines:tensorflow:tensorflow-model-zoo")
-    } else {
-        runtimeOnly project(":engines:mxnet:mxnet-model-zoo")
-    }
+    runtimeOnly project(":engines:pytorch:pytorch-model-zoo")
+    runtimeOnly project(":engines:tensorflow:tensorflow-model-zoo")
+    runtimeOnly project(":engines:mxnet:mxnet-model-zoo")
 
     testImplementation("org.testng:testng:${testng_version}") {
         exclude group: "junit", module: "junit"
diff --git a/examples/docs/biggan.md b/examples/docs/biggan.md
index 82804ab98..8b79f2a95 100644
--- a/examples/docs/biggan.md
+++ b/examples/docs/biggan.md
@@ -30,7 +30,7 @@ Use the following commands to run the project:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.BigGAN -Dai.djl.default_engine=PyTorch
+./gradlew run -Dmain=ai.djl.examples.inference.BigGAN
 ```
 
 ### Output
diff --git a/examples/docs/face_detection.md b/examples/docs/face_detection.md
index fa3654f6c..0dc6caf86 100644
--- a/examples/docs/face_detection.md
+++ b/examples/docs/face_detection.md
@@ -26,8 +26,8 @@ Use the following command to run the project:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.face.RetinaFaceDetection -Dai.djl.default_engine=PyTorch
-./gradlew run -Dmain=ai.djl.examples.inference.face.LightFaceDetection -Dai.djl.default_engine=PyTorch
+./gradlew run -Dmain=ai.djl.examples.inference.face.RetinaFaceDetection
+./gradlew run -Dmain=ai.djl.examples.inference.face.LightFaceDetection
 ```
 
 Your output should look like the following:
diff --git a/examples/docs/face_recognition.md b/examples/docs/face_recognition.md
index a9beaf1c6..08c7b609e 100644
--- a/examples/docs/face_recognition.md
+++ b/examples/docs/face_recognition.md
@@ -27,7 +27,7 @@ Use the following command to run the project:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.face.FeatureExtraction -Dai.djl.default_engine=PyTorch
+./gradlew run -Dmain=ai.djl.examples.inference.face.FeatureExtraction
 ```
 
 Your output should look like the following:
@@ -38,7 +38,7 @@ Your output should look like the following:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.face.FeatureComparison -Dai.djl.default_engine=PyTorch
+./gradlew run -Dmain=ai.djl.examples.inference.face.FeatureComparison
 ```
 
 Your output should look like the following:
diff --git a/examples/docs/object_detection_with_tensorflow_saved_model.md b/examples/docs/object_detection_with_tensorflow_saved_model.md
index e954e5ef9..88e8a8b5c 100644
--- a/examples/docs/object_detection_with_tensorflow_saved_model.md
+++ b/examples/docs/object_detection_with_tensorflow_saved_model.md
@@ -45,7 +45,7 @@ Use the following command to run the project:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.ObjectDetectionWithTensorflowSavedModel -Dai.djl.default_engine=TensorFlow
+./gradlew run -Dmain=ai.djl.examples.inference.ObjectDetectionWithTensorflowSavedModel
 ```
 
 Your output should look like the following:
diff --git a/examples/docs/sentiment_analysis.md b/examples/docs/sentiment_analysis.md
index 5b7578f88..81dbba929 100644
--- a/examples/docs/sentiment_analysis.md
+++ b/examples/docs/sentiment_analysis.md
@@ -29,5 +29,5 @@ Follow [setup](../../docs/development/setup.md) to configure your development en
 
 ```
 cd examples
-./gradlew run -Dai.djl.default_engine=PyTorch -Dmain=ai.djl.examples.inference.SentimentAnalysis
+./gradlew run -Dmain=ai.djl.examples.inference.SentimentAnalysis
 ```
diff --git a/examples/docs/super_resolution.md b/examples/docs/super_resolution.md
index 50905a70c..db138104d 100644
--- a/examples/docs/super_resolution.md
+++ b/examples/docs/super_resolution.md
@@ -30,7 +30,7 @@ Use the following commands to run the project:
 
 ```
 cd examples
-./gradlew run -Dmain=ai.djl.examples.inference.sr.SuperResolution -Dai.djl.default_engine=TensorFlow
+./gradlew run -Dmain=ai.djl.examples.inference.sr.SuperResolution
 ```
 
 ### Output
diff --git a/examples/src/main/java/ai/djl/examples/inference/ActionRecognition.java b/examples/src/main/java/ai/djl/examples/inference/ActionRecognition.java
index 426cfb7bc..0eea3cbf9 100644
--- a/examples/src/main/java/ai/djl/examples/inference/ActionRecognition.java
+++ b/examples/src/main/java/ai/djl/examples/inference/ActionRecognition.java
@@ -56,6 +56,7 @@ public final class ActionRecognition {
                         .setTypes(Image.class, Classifications.class)
                         .optFilter("backbone", "inceptionv3")
                         .optFilter("dataset", "ucf101")
+                        .optEngine("MXNet")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/BertClassification.java b/examples/src/main/java/ai/djl/examples/inference/BertClassification.java
index 4a6e071fa..812796ac9 100644
--- a/examples/src/main/java/ai/djl/examples/inference/BertClassification.java
+++ b/examples/src/main/java/ai/djl/examples/inference/BertClassification.java
@@ -14,7 +14,6 @@ package ai.djl.examples.inference;
 
 import ai.djl.MalformedModelException;
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.Classifications;
 import ai.djl.modality.nlp.DefaultVocabulary;
@@ -57,21 +56,14 @@ public final class BertClassification {
         inputs.add("class3\tDJL is good");
 
         Classifications[] results = predict(inputs);
-        if (results == null) {
-            logger.info("This example only works for TensorFlow Engine");
-        } else {
-            for (int i = 0; i < inputs.size(); i++) {
-                logger.info("Prediction for: " + inputs.get(i) + "\n" + results[i].toString());
-            }
+        for (int i = 0; i < inputs.size(); i++) {
+            logger.info("Prediction for: " + inputs.get(i) + "\n" + results[i].toString());
         }
     }
 
     public static Classifications[] predict(List<String> inputs)
             throws MalformedModelException, ModelNotFoundException, IOException,
                     TranslateException {
-        if (!"TensorFlow".equals(Engine.getInstance().getEngineName())) {
-            return null;
-        }
         // refer to
         // https://medium.com/delvify/bert-rest-inference-from-the-fine-tuned-model-499997b32851 and
         // https://github.com/google-research/bert
@@ -84,6 +76,7 @@ public final class BertClassification {
                         .setTypes(String[].class, Classifications[].class)
                         .optModelUrls(modelUrl)
                         .optTranslator(new MyTranslator(vocabularyPath, 128))
+                        .optEngine("TensorFlow")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/BertQaInference.java b/examples/src/main/java/ai/djl/examples/inference/BertQaInference.java
index f93a720fc..3230ba0f4 100644
--- a/examples/src/main/java/ai/djl/examples/inference/BertQaInference.java
+++ b/examples/src/main/java/ai/djl/examples/inference/BertQaInference.java
@@ -15,6 +15,7 @@ package ai.djl.examples.inference;
 
 import ai.djl.Application;
 import ai.djl.ModelException;
+import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.nlp.qa.QAInput;
 import ai.djl.repository.zoo.Criteria;
@@ -68,6 +69,7 @@ public final class BertQaInference {
                         .optApplication(Application.NLP.QUESTION_ANSWER)
                         .setTypes(QAInput.class, String.class)
                         .optFilter("backbone", "bert")
+                        .optEngine(Engine.getDefaultEngineName())
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/BigGAN.java b/examples/src/main/java/ai/djl/examples/inference/BigGAN.java
index 44132352d..f84e693f7 100644
--- a/examples/src/main/java/ai/djl/examples/inference/BigGAN.java
+++ b/examples/src/main/java/ai/djl/examples/inference/BigGAN.java
@@ -14,7 +14,6 @@ package ai.djl.examples.inference;
 
 import ai.djl.Application;
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.repository.zoo.Criteria;
@@ -36,11 +35,6 @@ public final class BigGAN {
     private BigGAN() {}
 
     public static void main(String[] args) throws ModelException, TranslateException, IOException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch Engine");
-            return;
-        }
-
         Image[] generatedImages = BigGAN.generate();
         logger.info("Using PyTorch Engine. {} images generated.", generatedImages.length);
         saveImages(generatedImages);
@@ -58,13 +52,13 @@ public final class BigGAN {
     }
 
     public static Image[] generate() throws IOException, ModelException, TranslateException {
-
         Criteria<int[], Image[]> criteria =
                 Criteria.builder()
                         .optApplication(Application.CV.IMAGE_GENERATION)
                         .setTypes(int[].class, Image[].class)
                         .optFilter("size", "256")
                         .optArgument("truncation", 0.4f)
+                        .optEngine("PyTorch")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/ObjectDetection.java b/examples/src/main/java/ai/djl/examples/inference/ObjectDetection.java
index 5973035dc..e0d63afc7 100644
--- a/examples/src/main/java/ai/djl/examples/inference/ObjectDetection.java
+++ b/examples/src/main/java/ai/djl/examples/inference/ObjectDetection.java
@@ -53,7 +53,7 @@ public final class ObjectDetection {
         Image img = ImageFactory.getInstance().fromFile(imageFile);
 
         String backbone;
-        if ("TensorFlow".equals(Engine.getInstance().getEngineName())) {
+        if ("TensorFlow".equals(Engine.getDefaultEngineName())) {
             backbone = "mobilenet_v2";
         } else {
             backbone = "resnet50";
@@ -64,6 +64,7 @@ public final class ObjectDetection {
                         .optApplication(Application.CV.OBJECT_DETECTION)
                         .setTypes(Image.class, DetectedObjects.class)
                         .optFilter("backbone", backbone)
+                        .optEngine(Engine.getDefaultEngineName())
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/ObjectDetectionWithTensorflowSavedModel.java b/examples/src/main/java/ai/djl/examples/inference/ObjectDetectionWithTensorflowSavedModel.java
index cc6197d74..73578b774 100644
--- a/examples/src/main/java/ai/djl/examples/inference/ObjectDetectionWithTensorflowSavedModel.java
+++ b/examples/src/main/java/ai/djl/examples/inference/ObjectDetectionWithTensorflowSavedModel.java
@@ -14,7 +14,6 @@ package ai.djl.examples.inference;
 
 import ai.djl.Application;
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
@@ -69,17 +68,11 @@ public final class ObjectDetectionWithTensorflowSavedModel {
     private ObjectDetectionWithTensorflowSavedModel() {}
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"TensorFlow".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for TensorFlow Engine");
-            return;
-        }
-
         DetectedObjects detection = ObjectDetectionWithTensorflowSavedModel.predict();
         logger.info("{}", detection);
     }
 
     public static DetectedObjects predict() throws IOException, ModelException, TranslateException {
-
         Path imageFile = Paths.get("src/test/resources/dog_bike_car.jpg");
         Image img = ImageFactory.getInstance().fromFile(imageFile);
 
@@ -94,6 +87,7 @@ public final class ObjectDetectionWithTensorflowSavedModel {
                         // saved_model.pb file is in the subfolder of the model archive file
                         .optModelName("ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")
                         .optTranslator(new MyTranslator())
+                        .optEngine("TensorFlow")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/PoseEstimation.java b/examples/src/main/java/ai/djl/examples/inference/PoseEstimation.java
index 8462059f0..b5b8e0c42 100644
--- a/examples/src/main/java/ai/djl/examples/inference/PoseEstimation.java
+++ b/examples/src/main/java/ai/djl/examples/inference/PoseEstimation.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Collections;
 import java.util.List;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,7 +61,7 @@ public final class PoseEstimation {
 
         if (person == null) {
             logger.warn("No person found in image.");
-            return null;
+            return new Joints(Collections.emptyList());
         }
 
         return predictJointsInPerson(person);
@@ -78,6 +79,7 @@ public final class PoseEstimation {
                         .optFilter("backbone", "resnet50")
                         .optFilter("flavor", "v1")
                         .optFilter("dataset", "voc")
+                        .optEngine("MXNet")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/StyleTransfer.java b/examples/src/main/java/ai/djl/examples/inference/StyleTransfer.java
index e4e3679f9..cbaed9525 100644
--- a/examples/src/main/java/ai/djl/examples/inference/StyleTransfer.java
+++ b/examples/src/main/java/ai/djl/examples/inference/StyleTransfer.java
@@ -15,7 +15,6 @@ package ai.djl.examples.inference;
 import ai.djl.Application;
 import ai.djl.MalformedModelException;
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
@@ -46,11 +45,6 @@ public final class StyleTransfer {
     }
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch Engine");
-            return;
-        }
-
         Artist artist = Artist.MONET;
         String imagePath = "src/test/resources/mountains.png";
         Image input = ImageFactory.getInstance().fromFile(Paths.get(imagePath));
@@ -63,11 +57,6 @@ public final class StyleTransfer {
     public static Image transfer(Image image, Artist artist)
             throws IOException, ModelNotFoundException, MalformedModelException,
                     TranslateException {
-
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            return null;
-        }
-
         String modelName = "style_" + artist.toString().toLowerCase() + ".zip";
         String modelUrl =
                 "https://mlrepo.djl.ai/model/cv/image_generation/ai/djl/pytorch/cyclegan/0.0.1/"
@@ -80,6 +69,7 @@ public final class StyleTransfer {
                         .optModelUrls(modelUrl)
                         .optProgress(new ProgressBar())
                         .optTranslatorFactory(new StyleTransferTranslatorFactory())
+                        .optEngine("PyTorch")
                         .build();
 
         try (ZooModel<Image, Image> model = criteria.loadModel();
diff --git a/examples/src/main/java/ai/djl/examples/inference/UniversalSentenceEncoder.java b/examples/src/main/java/ai/djl/examples/inference/UniversalSentenceEncoder.java
index afb97415f..7202f93d4 100644
--- a/examples/src/main/java/ai/djl/examples/inference/UniversalSentenceEncoder.java
+++ b/examples/src/main/java/ai/djl/examples/inference/UniversalSentenceEncoder.java
@@ -15,7 +15,6 @@ package ai.djl.examples.inference;
 import ai.djl.Application;
 import ai.djl.MalformedModelException;
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.ndarray.NDArray;
 import ai.djl.ndarray.NDArrays;
@@ -53,23 +52,14 @@ public final class UniversalSentenceEncoder {
         inputs.add("I am a sentence for which I would like to get its embedding");
 
         float[][] embeddings = UniversalSentenceEncoder.predict(inputs);
-        if (embeddings == null) {
-            logger.info("This example only works for TensorFlow Engine");
-        } else {
-            for (int i = 0; i < inputs.size(); i++) {
-                logger.info(
-                        "Embedding for: " + inputs.get(i) + "\n" + Arrays.toString(embeddings[i]));
-            }
+        for (int i = 0; i < inputs.size(); i++) {
+            logger.info("Embedding for: " + inputs.get(i) + "\n" + Arrays.toString(embeddings[i]));
         }
     }
 
     public static float[][] predict(List<String> inputs)
             throws MalformedModelException, ModelNotFoundException, IOException,
                     TranslateException {
-        if (!"TensorFlow".equals(Engine.getInstance().getEngineName())) {
-            return null;
-        }
-
         String modelUrl =
                 "https://storage.googleapis.com/tfhub-modules/google/universal-sentence-encoder/4.tar.gz";
 
@@ -79,6 +69,7 @@ public final class UniversalSentenceEncoder {
                         .setTypes(String[].class, float[][].class)
                         .optModelUrls(modelUrl)
                         .optTranslator(new MyTranslator())
+                        .optEngine("TensorFlow")
                         .optProgress(new ProgressBar())
                         .build();
         try (ZooModel<String[], float[][]> model = criteria.loadModel();
diff --git a/examples/src/main/java/ai/djl/examples/inference/face/FeatureComparison.java b/examples/src/main/java/ai/djl/examples/inference/face/FeatureComparison.java
index 28403b940..c8afa2fe6 100644
--- a/examples/src/main/java/ai/djl/examples/inference/face/FeatureComparison.java
+++ b/examples/src/main/java/ai/djl/examples/inference/face/FeatureComparison.java
@@ -13,7 +13,6 @@
 package ai.djl.examples.inference.face;
 
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
 import ai.djl.translate.TranslateException;
@@ -30,11 +29,6 @@ public final class FeatureComparison {
     private FeatureComparison() {}
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch.");
-            return;
-        }
-
         Path imageFile1 = Paths.get("src/test/resources/kana1.jpg");
         Image img1 = ImageFactory.getInstance().fromFile(imageFile1);
         Path imageFile2 = Paths.get("src/test/resources/kana2.jpg");
diff --git a/examples/src/main/java/ai/djl/examples/inference/face/FeatureExtraction.java b/examples/src/main/java/ai/djl/examples/inference/face/FeatureExtraction.java
index 4062c2e8c..97c36af08 100644
--- a/examples/src/main/java/ai/djl/examples/inference/face/FeatureExtraction.java
+++ b/examples/src/main/java/ai/djl/examples/inference/face/FeatureExtraction.java
@@ -13,7 +13,6 @@
 package ai.djl.examples.inference.face;
 
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
@@ -42,11 +41,6 @@ public final class FeatureExtraction {
     private FeatureExtraction() {}
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch.");
-            return;
-        }
-
         Path imageFile = Paths.get("src/test/resources/kana1.jpg");
         Image img = ImageFactory.getInstance().fromFile(imageFile);
 
diff --git a/examples/src/main/java/ai/djl/examples/inference/face/LightFaceDetection.java b/examples/src/main/java/ai/djl/examples/inference/face/LightFaceDetection.java
index 153eeee3e..2a89d96a5 100644
--- a/examples/src/main/java/ai/djl/examples/inference/face/LightFaceDetection.java
+++ b/examples/src/main/java/ai/djl/examples/inference/face/LightFaceDetection.java
@@ -13,7 +13,6 @@
 package ai.djl.examples.inference.face;
 
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
@@ -43,11 +42,6 @@ public final class LightFaceDetection {
     private LightFaceDetection() {}
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch.");
-            return;
-        }
-
         DetectedObjects detection = LightFaceDetection.predict();
         logger.info("{}", detection);
     }
diff --git a/examples/src/main/java/ai/djl/examples/inference/face/RetinaFaceDetection.java b/examples/src/main/java/ai/djl/examples/inference/face/RetinaFaceDetection.java
index a64914e16..871d53948 100644
--- a/examples/src/main/java/ai/djl/examples/inference/face/RetinaFaceDetection.java
+++ b/examples/src/main/java/ai/djl/examples/inference/face/RetinaFaceDetection.java
@@ -13,7 +13,6 @@
 package ai.djl.examples.inference.face;
 
 import ai.djl.ModelException;
-import ai.djl.engine.Engine;
 import ai.djl.inference.Predictor;
 import ai.djl.modality.cv.Image;
 import ai.djl.modality.cv.ImageFactory;
@@ -43,11 +42,6 @@ public final class RetinaFaceDetection {
     private RetinaFaceDetection() {}
 
     public static void main(String[] args) throws IOException, ModelException, TranslateException {
-        if (!"PyTorch".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for PyTorch.");
-            return;
-        }
-
         DetectedObjects detection = RetinaFaceDetection.predict();
         logger.info("{}", detection);
     }
diff --git a/examples/src/main/java/ai/djl/examples/inference/sr/SuperResolution.java b/examples/src/main/java/ai/djl/examples/inference/sr/SuperResolution.java
index 3ae45ae8f..4830c9cbb 100644
--- a/examples/src/main/java/ai/djl/examples/inference/sr/SuperResolution.java
+++ b/examples/src/main/java/ai/djl/examples/inference/sr/SuperResolution.java
@@ -45,10 +45,6 @@ public final class SuperResolution {
     private SuperResolution() {}
 
     public static void main(String[] args) throws ModelException, TranslateException, IOException {
-        if (!"TensorFlow".equals(Engine.getInstance().getEngineName())) {
-            logger.info("This example only works for TensorFlow Engine");
-            return;
-        }
         String imagePath = "src/test/resources/";
         ImageFactory imageFactory = ImageFactory.getInstance();
 
@@ -81,7 +77,7 @@ public final class SuperResolution {
     private static List<Image> group(List<Image> input, List<Image> generated) {
         NDList stitches = new NDList(input.size());
 
-        try (NDManager manager = Engine.getInstance().newBaseManager()) {
+        try (NDManager manager = Engine.getEngine("TensorFlow").newBaseManager()) {
             for (int i = 0; i < input.size(); i++) {
                 int scale = 4;
                 int width = scale * input.get(i).getWidth();
@@ -116,6 +112,7 @@ public final class SuperResolution {
                         .optOption("Tags", "serve")
                         .optOption("SignatureDefKey", "serving_default")
                         .optTranslator(new SuperResolutionTranslator())
+                        .optEngine("TensorFlow")
                         .optProgress(new ProgressBar())
                         .build();
 
diff --git a/examples/src/main/java/ai/djl/examples/training/transferlearning/TrainAmazonReviewRanking.java b/examples/src/main/java/ai/djl/examples/training/transferlearning/TrainAmazonReviewRanking.java
index 6d437e583..1db9470c4 100644
--- a/examples/src/main/java/ai/djl/examples/training/transferlearning/TrainAmazonReviewRanking.java
+++ b/examples/src/main/java/ai/djl/examples/training/transferlearning/TrainAmazonReviewRanking.java
@@ -72,7 +72,7 @@ public final class TrainAmazonReviewRanking {
 
         // MXNet base model
         String modelUrls = "https://resources.djl.ai/test-models/distilbert.zip";
-        if ("PyTorch".equals(Engine.getInstance().getEngineName())) {
+        if ("PyTorch".equals(Engine.getDefaultEngineName())) {
             modelUrls =
                     "https://resources.djl.ai/test-models/traced_distilbert_wikipedia_uncased.zip";
         }
@@ -82,6 +82,7 @@ public final class TrainAmazonReviewRanking {
                         .optApplication(Application.NLP.WORD_EMBEDDING)
                         .setTypes(NDList.class, NDList.class)
                         .optModelUrls(modelUrls)
+                        .optEngine(Engine.getDefaultEngineName())
                         .optProgress(new ProgressBar())
                         .build();
         int maxTokenLength = 64;
@@ -142,7 +143,7 @@ public final class TrainAmazonReviewRanking {
     }
 
     private static Block addFreezeLayer(Predictor<NDList, NDList> embedder) {
-        if ("PyTorch".equals(Engine.getInstance().getEngineName())) {
+        if ("PyTorch".equals(Engine.getDefaultEngineName())) {
             return new LambdaBlock(
                     ndList -> {
                         NDArray data = ndList.singletonOrThrow();


Test patch:
diff --git a/engines/mxnet/mxnet-model-zoo/src/test/java/ai/djl/mxnet/integration/MxSymbolBlockTest.java b/engines/mxnet/mxnet-model-zoo/src/test/java/ai/djl/mxnet/integration/MxSymbolBlockTest.java
index 973281b6e..204ad2e0b 100644
--- a/engines/mxnet/mxnet-model-zoo/src/test/java/ai/djl/mxnet/integration/MxSymbolBlockTest.java
+++ b/engines/mxnet/mxnet-model-zoo/src/test/java/ai/djl/mxnet/integration/MxSymbolBlockTest.java
@@ -96,7 +96,7 @@ public class MxSymbolBlockTest {
     @Test
     public void trainWithNewParam()
             throws IOException, ModelNotFoundException, MalformedModelException {
-        if ("MXNet".equals(Engine.getInstance().getEngineName())) {
+        if ("MXNet".equals(Engine.getDefaultEngineName())) {
             // TODO: WARN The gradMeans (but not predictions or loss) changed during the upgrade
             // to MXNet 1.8. The issue affect only CPU, but GPU has not changed.
             TestRequirements.gpu();
diff --git a/examples/src/test/java/ai/djl/examples/inference/ActionRecognitionTest.java b/examples/src/test/java/ai/djl/examples/inference/ActionRecognitionTest.java
index f7fb791f9..02f2100d1 100644
--- a/examples/src/test/java/ai/djl/examples/inference/ActionRecognitionTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/ActionRecognitionTest.java
@@ -14,6 +14,7 @@ package ai.djl.examples.inference;
 
 import ai.djl.ModelException;
 import ai.djl.modality.Classifications;
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import org.testng.Assert;
@@ -23,6 +24,8 @@ public class ActionRecognitionTest {
 
     @Test
     public void testActionRecognition() throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet");
+
         Classifications result = ActionRecognition.predict();
         Classifications.Classification best = result.best();
         Assert.assertEquals(best.getClassName(), "ThrowDiscus");
diff --git a/examples/src/test/java/ai/djl/examples/inference/BertQaTest.java b/examples/src/test/java/ai/djl/examples/inference/BertQaTest.java
index 3bca1b8f9..b80a1e6e7 100644
--- a/examples/src/test/java/ai/djl/examples/inference/BertQaTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/BertQaTest.java
@@ -13,6 +13,7 @@
 package ai.djl.examples.inference;
 
 import ai.djl.ModelException;
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import org.testng.Assert;
@@ -22,7 +23,9 @@ public class BertQaTest {
 
     @Test
     public void testBertQa() throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet", "PyTorch");
+
         String result = BertQaInference.predict();
-        Assert.assertEquals(result, "[december, 2004]");
+        Assert.assertEquals(result, "december 2004");
     }
 }
diff --git a/examples/src/test/java/ai/djl/examples/inference/FeatureComparisonTest.java b/examples/src/test/java/ai/djl/examples/inference/FeatureComparisonTest.java
index 841b4d739..a2377c9a2 100644
--- a/examples/src/test/java/ai/djl/examples/inference/FeatureComparisonTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/FeatureComparisonTest.java
@@ -30,18 +30,17 @@ public class FeatureComparisonTest {
     @Test
     public void testFeatureComparison() throws ModelException, TranslateException, IOException {
         TestRequirements.engine("PyTorch");
+        TestRequirements.nightly();
 
-        if (Boolean.getBoolean("nightly")) {
-            Path imageFile1 = Paths.get("src/test/resources/kana1.jpg");
-            Image img1 = ImageFactory.getInstance().fromFile(imageFile1);
-            Path imageFile2 = Paths.get("src/test/resources/kana2.jpg");
-            Image img2 = ImageFactory.getInstance().fromFile(imageFile2);
+        Path imageFile1 = Paths.get("src/test/resources/kana1.jpg");
+        Image img1 = ImageFactory.getInstance().fromFile(imageFile1);
+        Path imageFile2 = Paths.get("src/test/resources/kana2.jpg");
+        Image img2 = ImageFactory.getInstance().fromFile(imageFile2);
 
-            float[] feature1 = FeatureExtraction.predict(img1);
-            float[] feature2 = FeatureExtraction.predict(img2);
+        float[] feature1 = FeatureExtraction.predict(img1);
+        float[] feature2 = FeatureExtraction.predict(img2);
 
-            Assert.assertTrue(
-                    Double.compare(FeatureComparison.calculSimilar(feature1, feature2), 0.6) > 0);
-        }
+        Assert.assertTrue(
+                Double.compare(FeatureComparison.calculSimilar(feature1, feature2), 0.6) > 0);
     }
 }
diff --git a/examples/src/test/java/ai/djl/examples/inference/InstanceSegmentationTest.java b/examples/src/test/java/ai/djl/examples/inference/InstanceSegmentationTest.java
index afc29a710..658aea83c 100644
--- a/examples/src/test/java/ai/djl/examples/inference/InstanceSegmentationTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/InstanceSegmentationTest.java
@@ -15,6 +15,7 @@ package ai.djl.examples.inference;
 import ai.djl.ModelException;
 import ai.djl.modality.Classifications;
 import ai.djl.modality.cv.output.DetectedObjects;
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import org.testng.Assert;
@@ -24,6 +25,8 @@ public class InstanceSegmentationTest {
 
     @Test
     public void testInstanceSegmentation() throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet");
+
         DetectedObjects result = InstanceSegmentation.predict();
         Classifications.Classification best = result.best();
         Assert.assertEquals(best.getClassName(), "bicycle");
diff --git a/examples/src/test/java/ai/djl/examples/inference/LightFaceDetectionTest.java b/examples/src/test/java/ai/djl/examples/inference/LightFaceDetectionTest.java
index bd98572f8..ec98d4fcf 100644
--- a/examples/src/test/java/ai/djl/examples/inference/LightFaceDetectionTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/LightFaceDetectionTest.java
@@ -29,15 +29,14 @@ public class LightFaceDetectionTest {
     @Test
     public void testLightFaceDetection() throws ModelException, TranslateException, IOException {
         TestRequirements.engine("PyTorch");
+        TestRequirements.nightly();
 
-        if (Boolean.getBoolean("nightly")) {
-            DetectedObjects result = LightFaceDetection.predict();
+        DetectedObjects result = LightFaceDetection.predict();
 
-            List<String> objects = Collections.singletonList("Face");
-            for (Classifications.Classification obj : result.items()) {
-                Assert.assertTrue(objects.contains(obj.getClassName()));
-                Assert.assertTrue(Double.compare(obj.getProbability(), 0.6) > 0);
-            }
+        List<String> objects = Collections.singletonList("Face");
+        for (Classifications.Classification obj : result.items()) {
+            Assert.assertTrue(objects.contains(obj.getClassName()));
+            Assert.assertTrue(Double.compare(obj.getProbability(), 0.6) > 0);
         }
     }
 }
diff --git a/examples/src/test/java/ai/djl/examples/inference/ObjectDetectionTest.java b/examples/src/test/java/ai/djl/examples/inference/ObjectDetectionTest.java
index dcd4a1bde..bf2e85f28 100644
--- a/examples/src/test/java/ai/djl/examples/inference/ObjectDetectionTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/ObjectDetectionTest.java
@@ -19,19 +19,25 @@ import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class ObjectDetectionTest {
 
+    private static final Logger logger = LoggerFactory.getLogger(ObjectDetectionTest.class);
+
     @Test
     public void testObjectDetection() throws ModelException, TranslateException, IOException {
         DetectedObjects result = ObjectDetection.predict();
-        Assert.assertEquals(result.getNumberOfObjects(), 3);
-        List<String> objects = Arrays.asList("dog", "bicycle", "car");
-        for (Classifications.Classification obj : result.items()) {
-            Assert.assertTrue(objects.contains(obj.getClassName()));
-            Assert.assertTrue(Double.compare(obj.getProbability(), 0.9) > 0);
-        }
+        logger.info("{}", result);
+
+        Assert.assertTrue(result.getNumberOfObjects() >= 3);
+        Classifications.Classification obj = result.best();
+        String className = obj.getClassName();
+        List<String> objects = Arrays.asList("dog", "Cat", "car");
+        Assert.assertTrue(objects.contains(className));
+        Assert.assertTrue(obj.getProbability() > 0.6);
     }
 }
diff --git a/examples/src/test/java/ai/djl/examples/inference/PoseEstimationTest.java b/examples/src/test/java/ai/djl/examples/inference/PoseEstimationTest.java
index c4260cba1..9a6efbd53 100644
--- a/examples/src/test/java/ai/djl/examples/inference/PoseEstimationTest.java
+++ b/examples/src/test/java/ai/djl/examples/inference/PoseEstimationTest.java
@@ -14,6 +14,7 @@ package ai.djl.examples.inference;
 
 import ai.djl.ModelException;
 import ai.djl.modality.cv.output.Joints;
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import org.testng.Assert;
@@ -23,6 +24,8 @@ public class PoseEstimationTest {
 
     @Test
     public void testPoseEstimation() throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet");
+
         Joints result = PoseEstimation.predict();
         Assert.assertTrue(result.getJoints().get(0).getConfidence() > 0.6d);
     }
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainAmazonReviewTest.java b/examples/src/test/java/ai/djl/examples/training/TrainAmazonReviewTest.java
index 80b2c8e62..bf299731d 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainAmazonReviewTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainAmazonReviewTest.java
@@ -26,6 +26,7 @@ public class TrainAmazonReviewTest {
     @Test
     public void testRankTraining()
             throws ModelException, TranslateException, IOException, URISyntaxException {
+        TestRequirements.engine("MXNet", "PyTorch");
         TestRequirements.nightly();
 
         String[] args;
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainBertTest.java b/examples/src/test/java/ai/djl/examples/training/TrainBertTest.java
index fc76fe4f9..44712d630 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainBertTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainBertTest.java
@@ -12,6 +12,7 @@
  */
 package ai.djl.examples.training;
 
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
 import org.testng.annotations.Test;
@@ -20,6 +21,8 @@ public class TrainBertTest {
 
     @Test
     public void testTrainBert() throws IOException, TranslateException {
+        TestRequirements.engine("MXNet", "PyTorch");
+
         String[] args = new String[] {"-g", "1", "-m", "1", "-e", "1"};
         TrainBertOnCode.runExample(args);
     }
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainCaptchaTest.java b/examples/src/test/java/ai/djl/examples/training/TrainCaptchaTest.java
index e7d4639e1..27d2311a7 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainCaptchaTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainCaptchaTest.java
@@ -12,6 +12,7 @@
  */
 package ai.djl.examples.training;
 
+import ai.djl.testing.TestRequirements;
 import ai.djl.training.TrainingResult;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
@@ -22,6 +23,8 @@ public class TrainCaptchaTest {
 
     @Test
     public void testTrainCaptcha() throws IOException, TranslateException {
+        TestRequirements.engine("MXNet");
+
         String[] args = new String[] {"-g", "1", "-e", "1", "-m", "2"};
         TrainingResult result = TrainCaptcha.runExample(args);
         Assert.assertNotNull(result);
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainMnistTest.java b/examples/src/test/java/ai/djl/examples/training/TrainMnistTest.java
index de5d00ea0..511e780ec 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainMnistTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainMnistTest.java
@@ -15,6 +15,7 @@ package ai.djl.examples.training;
 import ai.djl.ModelException;
 import ai.djl.examples.inference.ImageClassification;
 import ai.djl.modality.Classifications;
+import ai.djl.testing.TestRequirements;
 import ai.djl.training.TrainingResult;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
@@ -25,6 +26,8 @@ public class TrainMnistTest {
 
     @Test
     public void testTrainMnist() throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet", "PyTorch");
+
         if (Boolean.getBoolean("nightly")) {
             String[] args = new String[] {"-g", "1"};
 
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainMnistWithLSTMTest.java b/examples/src/test/java/ai/djl/examples/training/TrainMnistWithLSTMTest.java
index 63f013b09..48fcad879 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainMnistWithLSTMTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainMnistWithLSTMTest.java
@@ -12,6 +12,7 @@
  */
 package ai.djl.examples.training;
 
+import ai.djl.testing.TestRequirements;
 import ai.djl.training.TrainingResult;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
@@ -22,6 +23,8 @@ public class TrainMnistWithLSTMTest {
 
     @Test
     public void testTrainMnistWithLSTM() throws IOException, TranslateException {
+        TestRequirements.engine("MXNet", "PyTorch");
+
         String[] args = new String[] {"-g", "1", "-e", "1", "-m", "2"};
         TrainingResult result = TrainMnistWithLSTM.runExample(args);
         Assert.assertNotNull(result);
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainPikachuTest.java b/examples/src/test/java/ai/djl/examples/training/TrainPikachuTest.java
index b24ceec9c..7bef6f4ea 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainPikachuTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainPikachuTest.java
@@ -25,6 +25,7 @@ public class TrainPikachuTest {
 
     @Test
     public void testDetection() throws IOException, MalformedModelException, TranslateException {
+        TestRequirements.engine("MXNet");
         TestRequirements.nightly();
 
         String[] args;
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainResNetTest.java b/examples/src/test/java/ai/djl/examples/training/TrainResNetTest.java
index 1848266a2..ef35d9612 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainResNetTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainResNetTest.java
@@ -28,6 +28,8 @@ public class TrainResNetTest {
 
     @Test
     public void testTrainResNet() throws ModelException, IOException, TranslateException {
+        TestRequirements.engine("MXNet");
+
         // Limit max 4 gpu for cifar10 training to make it converge faster.
         // and only train 10 batch for unit test.
         String[] args = {"-e", "2", "-g", "4", "-m", "10", "-s", "-p"};
@@ -39,6 +41,7 @@ public class TrainResNetTest {
     @Test
     public void testTrainResNetSymbolicNightly()
             throws ModelException, IOException, TranslateException {
+        TestRequirements.engine("MXNet");
         TestRequirements.nightly();
         TestRequirements.gpu();
 
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainSentimentAnalysisTest.java b/examples/src/test/java/ai/djl/examples/training/TrainSentimentAnalysisTest.java
index 3ee9357d5..472e2351e 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainSentimentAnalysisTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainSentimentAnalysisTest.java
@@ -12,8 +12,7 @@
  */
 package ai.djl.examples.training;
 
-import ai.djl.MalformedModelException;
-import ai.djl.repository.zoo.ModelNotFoundException;
+import ai.djl.ModelException;
 import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
@@ -23,8 +22,8 @@ public class TrainSentimentAnalysisTest {
 
     @Test
     public void testTrainSentimentAnalysis()
-            throws MalformedModelException, ModelNotFoundException, TranslateException,
-                    IOException {
+            throws ModelException, TranslateException, IOException {
+        TestRequirements.engine("MXNet");
         TestRequirements.nightly();
         TestRequirements.gpu();
 
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainSeq2SeqTest.java b/examples/src/test/java/ai/djl/examples/training/TrainSeq2SeqTest.java
index e3f0d1002..19c2305a5 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainSeq2SeqTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainSeq2SeqTest.java
@@ -13,6 +13,7 @@
 
 package ai.djl.examples.training;
 
+import ai.djl.testing.TestRequirements;
 import ai.djl.training.TrainingResult;
 import ai.djl.translate.TranslateException;
 import java.io.IOException;
@@ -23,6 +24,8 @@ public class TrainSeq2SeqTest {
 
     @Test
     public void testTrainSeq2Seq() throws IOException, TranslateException {
+        TestRequirements.engine("MXNet");
+
         String[] args = new String[] {"-g", "1", "-e", "1", "-m", "2"};
         TrainingResult result = TrainSeq2Seq.runExample(args);
         Assert.assertNotNull(result);
diff --git a/examples/src/test/java/ai/djl/examples/training/TrainTicTacToeTest.java b/examples/src/test/java/ai/djl/examples/training/TrainTicTacToeTest.java
index 58df0c4f2..8a76679dd 100644
--- a/examples/src/test/java/ai/djl/examples/training/TrainTicTacToeTest.java
+++ b/examples/src/test/java/ai/djl/examples/training/TrainTicTacToeTest.java
@@ -13,6 +13,7 @@
 package ai.djl.examples.training;
 
 import ai.djl.engine.Engine;
+import ai.djl.testing.TestRequirements;
 import ai.djl.training.TrainingResult;
 import java.io.IOException;
 import org.testng.Assert;
@@ -22,6 +23,8 @@ public class TrainTicTacToeTest {
 
     @Test
     public void testTrainTicTacToe() throws IOException {
+        TestRequirements.engine("MXNet", "PyTorch");
+
         if (Boolean.getBoolean("nightly")) {
             String[] args = new String[] {"-g", "1", "-e", "6"};
             Engine.getInstance().setRandomSeed(1234);
diff --git a/integration/src/main/java/ai/djl/integration/tests/model_zoo/CustomTranslatorTest.java b/integration/src/main/java/ai/djl/integration/tests/model_zoo/CustomTranslatorTest.java
index db2c79e6e..8c7aa5237 100644
--- a/integration/src/main/java/ai/djl/integration/tests/model_zoo/CustomTranslatorTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/model_zoo/CustomTranslatorTest.java
@@ -31,6 +31,7 @@ import ai.djl.ndarray.NDManager;
 import ai.djl.repository.zoo.Criteria;
 import ai.djl.repository.zoo.ModelNotFoundException;
 import ai.djl.repository.zoo.ZooModel;
+import ai.djl.testing.TestRequirements;
 import ai.djl.translate.TranslateException;
 import ai.djl.translate.Translator;
 import ai.djl.util.JsonUtils;
@@ -62,8 +63,8 @@ public class CustomTranslatorTest {
 
     @BeforeClass
     public void setup() throws IOException, ModelNotFoundException, MalformedModelException {
-        if (!"MXNet".equals(Engine.getInstance().getEngineName())) {
-            return;
+        if (!"MXNet".equals(Engine.getDefaultEngineName())) {
+            return; // do not throw exception here
         }
 
         Utils.deleteQuietly(modelDir);
@@ -105,9 +106,7 @@ public class CustomTranslatorTest {
     @Test
     public void testImageClassificationTranslator()
             throws IOException, ModelException, TranslateException {
-        if (!"MXNet".equals(Engine.getInstance().getEngineName())) {
-            return;
-        }
+        TestRequirements.engine("MXNet");
 
         // load RawTranslator
         runRawTranslator();
@@ -157,9 +156,7 @@ public class CustomTranslatorTest {
 
     @Test
     public void testSsdTranslator() throws IOException, ModelException, TranslateException {
-        if (!"MXNet".equals(Engine.getInstance().getEngineName())) {
-            return;
-        }
+        TestRequirements.engine("MXNet");
 
         Criteria<Image, DetectedObjects> c =
                 Criteria.builder()
diff --git a/integration/src/main/java/ai/djl/integration/tests/nn/BlockFactoryTest.java b/integration/src/main/java/ai/djl/integration/tests/nn/BlockFactoryTest.java
index 4f59e0439..fcf671a05 100644
--- a/integration/src/main/java/ai/djl/integration/tests/nn/BlockFactoryTest.java
+++ b/integration/src/main/java/ai/djl/integration/tests/nn/BlockFactoryTest.java
@@ -56,7 +56,7 @@ public class BlockFactoryTest {
             zipPath = prepareModel(savedDir);
         } catch (ModelNotFoundException e) {
             throw new UnsupportedOperationException(
-                    "No test model for engine: " + Engine.getInstance().getEngineName(), e);
+                    "No test model for engine: " + Engine.getDefaultEngineName(), e);
         }
         // load model from here
         Criteria<NDList, NDList> criteria =
@@ -91,8 +91,7 @@ public class BlockFactoryTest {
                 Paths.get(
                         "build/classes/java/main/ai/djl/integration/tests/nn/BlockFactoryTest$TestBlockFactory.class"),
                 classDir.resolve("BlockFactoryTest$TestBlockFactory.class"));
-        Path zipPath =
-                Paths.get("build/testBlockFactory" + Engine.getInstance().getEngineName() + ".zip");
+        Path zipPath = Paths.get("build/testBlockFactory" + Engine.getDefaultEngineName() + ".zip");
         Files.deleteIfExists(zipPath);
         ZipUtils.zip(savedDir, zipPath, false);
         return zipPath;
@@ -112,7 +111,7 @@ public class BlockFactoryTest {
 
         public Model getRemoveLastBlockModel()
                 throws MalformedModelException, ModelNotFoundException, IOException {
-            String name = Engine.getInstance().getEngineName();
+            String name = Engine.getDefaultEngineName();
             Criteria.Builder<Image, Classifications> builder =
                     Criteria.builder()
                             .optApplication(Application.CV.IMAGE_CLASSIFICATION)
diff --git a/integration/src/main/java/ai/djl/integration/util/TestUtils.java b/integration/src/main/java/ai/djl/integration/util/TestUtils.java
index 217ff291a..9329990bd 100644
--- a/integration/src/main/java/ai/djl/integration/util/TestUtils.java
+++ b/integration/src/main/java/ai/djl/integration/util/TestUtils.java
@@ -48,7 +48,7 @@ public final class TestUtils {
 
     public static Device[] getDevices() {
         if (!Engine.getInstance().hasCapability(StandardCapabilities.CUDNN)
-                && "MXNet".equals(Engine.getInstance().getEngineName())) {
+                && "MXNet".equals(Engine.getDefaultEngineName())) {
             return new Device[] {
                 Device.cpu()
             }; // TODO: RNN is not implemented on MXNet without cuDNN
diff --git a/testing/src/main/java/ai/djl/testing/TestRequirements.java b/testing/src/main/java/ai/djl/testing/TestRequirements.java
index 91d0472b1..448f6aed5 100644
--- a/testing/src/main/java/ai/djl/testing/TestRequirements.java
+++ b/testing/src/main/java/ai/djl/testing/TestRequirements.java
@@ -53,7 +53,7 @@ public final class TestRequirements {
      * @param engines the engine(s) to run the test with
      */
     public static void engine(String... engines) {
-        String engineName = Engine.getInstance().getEngineName();
+        String engineName = Engine.getDefaultEngineName();
         for (String e : engines) {
             if (engineName.equals(e)) {
                 return;
@@ -69,7 +69,7 @@ public final class TestRequirements {
      * @param engines the engine(s) to not run the test on
      */
     public static void notEngine(String... engines) {
-        String engineName = Engine.getInstance().getEngineName();
+        String engineName = Engine.getDefaultEngineName();
         for (String e : engines) {
             if (engineName.equals(e)) {
                 throw new SkipException(