Repository: deepjavalibrary/djl
Pull request #1903 (2022-08-14 06:19:56)

[Extension] Add GluonTS extension
## Description ##

We create GluonTS extension based on djl.

It contains three parts including: **data entry**, **transform**, **translator**.
In the **data entry** section, we provide efficient key-value pairs for data preprocessing and conversion into `NDList` in GluonTS datasets and translators. And in the inference task, we also designed a `Forecast` class similar to GluonTS, and provided related query methods.

In the **transform** part, the corresponding data pre-processing process is provided through `GluonTSData`, and the easy-to-use interface and static methods are provided to complete this process.
Among them, convert is responsible for the shape transformation of `NDArray`, feature is responsible for generating time series features, field is responsible for field modification, and split is responsible for sampling time series data in different time periods during inference and train.

In the **translator** section, we provide translators for two commonly used GluonTS time series models. Most of the content of these two Translators are similar, only some parameters have been modified. Please note that users can quickly build their own GluonTS model Translator according to the transform we provide.

At the same time, we also added two examples of inference with the GluonTS model in the examples.

See README.md for detailed description.


codecov-commenter: # [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1903?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) Report
> Merging [#1903](https://codecov.io/gh/deepjavalibrary/djl/pull/1903?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (fdc9095) 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 `2.93%`.
> The diff coverage is `67.01%`.

```diff
@@             Coverage Diff              @@
##             master    #1903      +/-   ##
============================================
- Coverage     72.08%   69.15%   -2.94%     
- Complexity     5126     5730     +604     
============================================
  Files           473      568      +95     
  Lines         21970    25591    +3621     
  Branches       2351     2756     +405     
============================================
+ Hits          15838    17698    +1860     
- Misses         4925     6541    +1616     
- Partials       1207     1352     +145     
```


| [Impacted Files](https://codecov.io/gh/deepjavalibrary/djl/pull/1903?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/1903/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/1903/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/1903/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/1903/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/1903/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/1903/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% <0.00%> (-5.24%)` | :arrow_down: |
| [...odality/cv/translator/BigGANTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1903/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/1903/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/SemanticSegmentationTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1903/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvU2VtYW50aWNTZWdtZW50YXRpb25UcmFuc2xhdG9yLmphdmE=) | `0.00% <0.00%> (ø)` | |
| [.../cv/translator/StyleTransferTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1903/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% <ø> (ø)` | |
| ... and [471 more](https://codecov.io/gh/deepjavalibrary/djl/pull/1903/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)

Carkham: > Example still failing. Please make sure output NDArrays are created with the same NDManager as input NDArray.

Before modifying NDManager in this line, my local test can pass this example, but it fails after modification, and an error is reported as "Native resource has been release already". So I set the NDManager of SampleForecast.sample to another NDManager later and it works.
KexinFeng: > Before modifying NDManager in this line, my local test can pass this example, but it fails after modification, and an error is reported as "Native resource has been release already".

It looks like this error is not triggered in the PR test. If the error happens after the modification, would it be detected in the PR test?

Patch:
diff --git a/engines/onnxruntime/onnxruntime-engine/src/main/java/ai/djl/onnxruntime/engine/OrtEngine.java b/engines/onnxruntime/onnxruntime-engine/src/main/java/ai/djl/onnxruntime/engine/OrtEngine.java
index 66adeb4b6..f96db2bfb 100644
--- a/engines/onnxruntime/onnxruntime-engine/src/main/java/ai/djl/onnxruntime/engine/OrtEngine.java
+++ b/engines/onnxruntime/onnxruntime-engine/src/main/java/ai/djl/onnxruntime/engine/OrtEngine.java
@@ -78,7 +78,7 @@ public final class OrtEngine extends Engine {
     /** {@inheritDoc} */
     @Override
     public String getVersion() {
-        return "1.11.0";
+        return "1.12.1";
     }
 
     /** {@inheritDoc} */
diff --git a/engines/pytorch/pytorch-engine/README.md b/engines/pytorch/pytorch-engine/README.md
index 302ee497d..9c56491c6 100644
--- a/engines/pytorch/pytorch-engine/README.md
+++ b/engines/pytorch/pytorch-engine/README.md
@@ -43,23 +43,24 @@ ways to specify PyTorch version:
 
 The following table illustrates which pytorch version that DJL supports:
 
-| PyTorch engine version | PyTorch native library version             |
-|------------------------|--------------------------------------------|
-| pytorch-engine:0.18.0  | 1.9.1, 1.10.0, 1.11.0                      |
-| pytorch-engine:0.17.0  | 1.9.1, 1.10.0, 1.11.0                      |
-| pytorch-engine:0.16.0  | 1.8.1, 1.9.1, 1.10.0                       |
-| pytorch-engine:0.15.0  | pytorch-native-auto: 1.8.1, 1.9.1, 1.10.0  |
-| pytorch-engine:0.14.0  | pytorch-native-auto: 1.8.1, 1.9.0, 1.9.1   |
-| pytorch-engine:0.13.0  | pytorch-native-auto:1.9.0                  |
-| pytorch-engine:0.12.0  | pytorch-native-auto:1.8.1                  |
-| pytorch-engine:0.11.0  | pytorch-native-auto:1.8.1                  |
-| pytorch-engine:0.10.0  | pytorch-native-auto:1.7.1                  |
-| pytorch-engine:0.9.0   | pytorch-native-auto:1.7.0                  |
-| pytorch-engine:0.8.0   | pytorch-native-auto:1.6.0                  |
-| pytorch-engine:0.7.0   | pytorch-native-auto:1.6.0                  |
-| pytorch-engine:0.6.0   | pytorch-native-auto:1.5.0                  |
-| pytorch-engine:0.5.0   | pytorch-native-auto:1.4.0                  |
-| pytorch-engine:0.4.0   | pytorch-native-auto:1.4.0                  |
+| PyTorch engine version | PyTorch native library version            |
+|------------------------|-------------------------------------------|
+| pytorch-engine:0.19.0  | 1.10.0, 1.11.0, 1.12.1                    |
+| pytorch-engine:0.18.0  | 1.9.1, 1.10.0, 1.11.0                     |
+| pytorch-engine:0.17.0  | 1.9.1, 1.10.0, 1.11.0                     |
+| pytorch-engine:0.16.0  | 1.8.1, 1.9.1, 1.10.0                      |
+| pytorch-engine:0.15.0  | pytorch-native-auto: 1.8.1, 1.9.1, 1.10.0 |
+| pytorch-engine:0.14.0  | pytorch-native-auto: 1.8.1, 1.9.0, 1.9.1  |
+| pytorch-engine:0.13.0  | pytorch-native-auto:1.9.0                 |
+| pytorch-engine:0.12.0  | pytorch-native-auto:1.8.1                 |
+| pytorch-engine:0.11.0  | pytorch-native-auto:1.8.1                 |
+| pytorch-engine:0.10.0  | pytorch-native-auto:1.7.1                 |
+| pytorch-engine:0.9.0   | pytorch-native-auto:1.7.0                 |
+| pytorch-engine:0.8.0   | pytorch-native-auto:1.6.0                 |
+| pytorch-engine:0.7.0   | pytorch-native-auto:1.6.0                 |
+| pytorch-engine:0.6.0   | pytorch-native-auto:1.5.0                 |
+| pytorch-engine:0.5.0   | pytorch-native-auto:1.4.0                 |
+| pytorch-engine:0.4.0   | pytorch-native-auto:1.4.0                 |
 
 We strongly recommend you to use [Bill of Materials (BOM)](../../../bom/README.md) to manage your dependencies.
 
diff --git a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
index 66d7e18a9..efe6e45cc 100644
--- a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
+++ b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
@@ -188,6 +188,7 @@ public final class LibUtils {
                             cudaArch);
                     return path.toAbsolutePath().toString();
                 }
+                flavor = cpuFlavor;
                 found = downloadFiles(lines, link, os, flavor, tmp);
             }
 
diff --git a/examples/build.gradle b/examples/build.gradle
index da5d70095..c551329e0 100644
--- a/examples/build.gradle
+++ b/examples/build.gradle
@@ -7,6 +7,7 @@ dependencies {
     implementation "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_slf4j_version}"
     implementation project(":basicdataset")
     implementation project(":model-zoo")
+    implementation project(":extensions:timeseries")
 
     runtimeOnly project(":engines:pytorch:pytorch-model-zoo")
     runtimeOnly project(":engines:tensorflow:tensorflow-model-zoo")
diff --git a/extensions/timeseries/README.md b/extensions/timeseries/README.md
new file mode 100644
index 000000000..8c32904d8
--- /dev/null
+++ b/extensions/timeseries/README.md
@@ -0,0 +1,100 @@
+# TimeSeries support
+
+This module contains the time series model support extension with [gluon-ts](https://github.com/awslabs/gluon-ts).
+
+Right now, the package provides the `BaseTimeSeriesTranslator` and transform package that allows you to do inference from your pre-trained time series model.
+
+## Module structure
+
+### Forecast
+
+An abstract class representing the forecast result.
+
+It contains the distribution of the results, the start date of the forecast, the frequency of the time series, etc. User can get all these information by simply invoking the corresponding attribute.
+
+- `SampleForecast` extends the `Forecast` that contain all the sample paths in the form of `NDArray`. User can query the prediction results by accessing the data in the samples.
+
+### TimeSeriesData
+
+The data entry for managing timing data in preprocessing as an input to the transform method. It contains a key-value pair list mapping from the time series name field to `NDArray`.
+
+### dataset
+
+- FieldName -- The name field for time series data including START, TARGET, and so on.
+
+### timefeature
+
+This module contains all the methods for generating time features from the predicted frequency.
+
+- Lag -- Generates a list of lags that are appropriate for the frequency.
+- TimeFeature -- Generates a list of time features that are appropriate for the frequency.
+
+### transform
+
+In general, it gets the `TimeSeriesData` and transform it to another `TimeSeriesData` that can possibly contain more fields. It can be done by defining a set of of "actions" to the raw dataset in training or just invoking at translator in inference.
+
+This action usually create some additional features or transform an existing feature.
+
+#### convert
+
+- Convert -- Convert the array shape to the preprocessing. 
+- VstackFeatures.java -- vstack the inputs name field of the `TimeSeriesData`. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+
+#### feature
+
+- Feature -- Add time features to the preprocessing. 
+- AddAgeFeature -- Creates the `FEAT_DYNAMIC_AGE` name field in the `TimeSeriesData`. Adds a feature that its value is small for distant past timestamps and it monotonically increases the more we approach the current timestamp. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+- AddObservedValueIndicator -- Creates the `OBSERVED_VALUES` name field in the `TimeSeriesData`. Adds a feature that equals to 1 if the value is observed and 0 if the value is missing. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+- AddTimeFeature -- Creates the `FEAT_TIME` name field in the `TimeSeriesData`. Adds a feature that its value is based on the different prediction frequencies. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+
+#### field
+
+- Field -- Process key-value data entry to the preprocessing. It usually add or remove the feature in the `TimeSeriesData`.
+- RemoveFields -- Remove the input name field. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+- SelectField -- Only keep input name fields. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+- SetField -- Set the input name field with `NDArray`. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+
+#### split
+
+- Split -- Split time series data for training and inferring to the preprocessing.
+- InstanceSplit -- Split time series data with the slice from `Sampler` for training and inferring to the preprocessing. We make it implement the `TimeSeriesTransform` interface for **training feature.**
+
+### InstanceSampler
+
+Sample index for splitting based on training or inferring.
+
+`PredictionSampler` extends `InstanceSampler` for the prediction including test and valid. It would return the end of the time series bound as the dividing line between the future and past.
+
+### translator
+
+Existing time series model translators and corresponding factories. Now we have developed `DeepARTranslator` and `TransformerTranslator` for users.
+
+The following pseudocode demonstrates how to create a `DeepARTranslator` with `arguments`.
+
+```java
+	Map<String, Object> arguments = new ConcurrentHashMap<>();
+	arguments.put("prediction_length", 28);
+	arguments.put("use_feat_dynamic_real", false);
+	DeepARTranslator.Builder builder = DeepARTranslator.builder(arguments);
+	DeepARTranslator translator = builder.build();
+```
+
+If you want to customize your own time series model translator, you can easily use the transform package for your data preprocess.
+
+See [examples](../src/main/java/ai/djl/timeseries/examples) for more details.
+
+We plan to add the following features in the future:
+
+- a `TimeSeriesDataset`class to support creating data entry and transforming raw csv data like in TimeSeries.
+- Many time series models that can be trained in djl.
+- ......
+
+## Documentation
+
+You can build the latest javadocs locally using the following command:
+
+```sh
+./gradlew javadoc
+```
+
+The javadocs output is built in the `build/doc/javadoc` folder.
\ No newline at end of file
diff --git a/extensions/timeseries/build.gradle b/extensions/timeseries/build.gradle
new file mode 100644
index 000000000..228874f29
--- /dev/null
+++ b/extensions/timeseries/build.gradle
@@ -0,0 +1,29 @@
+group 'ai.dj.timeseries'
+
+dependencies {
+    api project(":api")
+    api project(":basicdataset")
+    api "tech.tablesaw:tablesaw-core:${tablesaw_version}"
+    api "tech.tablesaw:tablesaw-jsplot:${tablesaw_version}"
+
+    testImplementation("org.testng:testng:${testng_version}") {
+        exclude group: "junit", module: "junit"
+    }
+
+    testImplementation "org.slf4j:slf4j-simple:${slf4j_version}"
+    testImplementation project(":testing")
+
+    testRuntimeOnly project(":engines:mxnet:mxnet-model-zoo")
+}
+
+publishing {
+    publications {
+        maven(MavenPublication) {
+            pom {
+                name = "TimeSeries for DJL"
+                description = "TimeSeries for DJL"
+                url = "http://www.djl.ai/extensions/${project.name}"
+            }
+        }
+    }
+}
diff --git a/extensions/timeseries/gradlew b/extensions/timeseries/gradlew
new file mode 120000
index 000000000..343e0d2ca
--- /dev/null
+++ b/extensions/timeseries/gradlew
@@ -0,0 +1,1 @@
+../../gradlew
\ No newline at end of file
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/Forecast.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/Forecast.java
new file mode 100644
index 000000000..73b35070d
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/Forecast.java
@@ -0,0 +1,90 @@
+/*
+ * 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.timeseries;
+
+import ai.djl.ndarray.NDArray;
+
+import java.time.LocalDateTime;
+
+/** An abstract class representing the forecast results for the time series data. */
+public abstract class Forecast {
+
+    protected LocalDateTime startDate;
+    protected int predictionLength;
+    protected String freq;
+
+    /**
+     * Constructs a {@code Forecast} instance.
+     *
+     * @param startDate the time series start date
+     * @param predictionLength the time length of prediction
+     * @param freq the prediction frequency
+     */
+    public Forecast(LocalDateTime startDate, int predictionLength, String freq) {
+        this.startDate = startDate;
+        this.predictionLength = predictionLength;
+        this.freq = freq;
+    }
+
+    /**
+     * Computes a quantile from the predicted distribution.
+     *
+     * @param q quantile to compute
+     * @return value of the quantile across the prediction range
+     */
+    public abstract NDArray quantile(float q);
+
+    /**
+     * Computes a quantile from the predicted distribution.
+     *
+     * @param q quantile to compute
+     * @return value of the quantile across the prediction range
+     */
+    public NDArray quantile(String q) {
+        return quantile(Float.parseFloat(q));
+    }
+
+    /**
+     * Computes and returns the forecast mean.
+     *
+     * @return forecast mean
+     */
+    public abstract NDArray mean();
+
+    /**
+     * Computes the median of forecast.
+     *
+     * @return value of the median
+     */
+    public NDArray median() {
+        return quantile(0.5f);
+    }
+
+    /**
+     * Returns the prediction frequency like "D", "H"....
+     *
+     * @return the prediction frequency
+     */
+    public String freq() {
+        return freq;
+    }
+
+    /**
+     * Returns the time length of forecast.
+     *
+     * @return the prediction length
+     */
+    public int getPredictionLength() {
+        return predictionLength;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/SampleForecast.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/SampleForecast.java
new file mode 100644
index 000000000..c27e23c9b
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/SampleForecast.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.timeseries;
+
+import ai.djl.ndarray.NDArray;
+
+import java.time.LocalDateTime;
+
+/**
+ * A {@link Forecast} object, where the predicted distribution is represented internally as samples.
+ */
+public class SampleForecast extends Forecast {
+
+    private NDArray samples;
+    private int numSamples;
+
+    /**
+     * Constructs a {@code SampleForeCast}.
+     *
+     * @param samples {@link NDArray} array of size (num_samples, prediction_length) (1D case),
+     *     (num_samples, prediction_length, target_dim) (multivariate case)
+     * @param startDate start of the forecast
+     * @param freq frequency of the forecast
+     */
+    public SampleForecast(NDArray samples, LocalDateTime startDate, String freq) {
+        super(startDate, (int) samples.getShape().get(1), freq);
+        this.samples = samples;
+        this.numSamples = (int) samples.getShape().head();
+    }
+
+    /**
+     * Returns the sorted sample array.
+     *
+     * @return the sorted sample array
+     */
+    public NDArray getSortedSamples() {
+        return samples.sort(0);
+    }
+
+    /**
+     * Returns the number of samples representing the forecast.
+     *
+     * @return the number of samples
+     */
+    public int getNumSamples() {
+        return numSamples;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDArray quantile(float q) {
+        int sampleIdx = Math.round((numSamples - 1) * q);
+        return getSortedSamples().get("{}, :", sampleIdx);
+    }
+
+    /**
+     * Returns a new Forecast object with only the selected sub-dimension.
+     *
+     * @param dim the selected dim
+     * @return a new {@link SampleForecast}.
+     */
+    public SampleForecast copyDim(int dim) {
+        NDArray copySamples;
+        if (samples.getShape().dimension() == 2) {
+            copySamples = samples;
+        } else {
+            int targetDim = (int) samples.getShape().get(2);
+            if (dim >= targetDim) {
+                throw new IllegalArgumentException(
+                        String.format(
+                                "must set 0 <= dim < target_dim, but got dim=%d, target_dim=%d",
+                                dim, targetDim));
+            }
+            copySamples = samples.get(":, :, {}", dim);
+        }
+
+        return new SampleForecast(copySamples, startDate, freq);
+    }
+
+    /** {@inheritDoc}. */
+    @Override
+    public NDArray mean() {
+        return samples.mean(new int[] {0});
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/TimeSeriesData.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/TimeSeriesData.java
new file mode 100644
index 000000000..9638618db
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/TimeSeriesData.java
@@ -0,0 +1,176 @@
+/*
+ * 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.timeseries;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDList;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.util.Pair;
+import ai.djl.util.PairList;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link TimeSeriesData} is a DataEntry for managing time series data in preprocess. It contains a
+ * key-values entries mapping the {@link FieldName} and {@link NDArray} to generate the time
+ * features.
+ *
+ * <p>This class provides a convenient way for user to featurize the data.
+ */
+public class TimeSeriesData extends PairList<String, NDArray> {
+
+    private LocalDateTime startTime;
+    private LocalDateTime forecastStartTime;
+
+    /**
+     * Constructs an empty {@code TimeSeriesData} with the specified initial capacity.
+     *
+     * @param initialCapacity the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity is negative
+     */
+    public TimeSeriesData(int initialCapacity) {
+        super(initialCapacity);
+    }
+
+    /**
+     * Constructs a {@code TimeSeriesData} containing the elements of the specified keys and values.
+     *
+     * @param keys the key list containing elements to be placed into this PairList
+     * @param values the value list containing elements to be placed into this PairList
+     * @throws IllegalArgumentException if the keys and values size are different
+     */
+    public TimeSeriesData(List<String> keys, List<NDArray> values) {
+        super(keys, values);
+    }
+
+    /**
+     * Constructs a {@code TimeSeriesData} containing the elements of the specified list of Pairs.
+     *
+     * @param list the list containing elements to be placed into this PairList
+     */
+    public TimeSeriesData(List<Pair<String, NDArray>> list) {
+        super(list);
+    }
+
+    /**
+     * Constructs a {@code TimeSeriesData} containing the elements of the specified map.
+     *
+     * @param map the map contains keys and values
+     */
+    public TimeSeriesData(Map<String, NDArray> map) {
+        super(map);
+    }
+
+    /**
+     * Constructs a {@link NDList} containing the remaining {@link NDArray} for {@link FieldName}.
+     *
+     * @return a {@link NDList}
+     */
+    public NDList toNDList() {
+        List<NDArray> arrays = this.values();
+        int index = 0;
+        for (NDArray array : arrays) {
+            array.setName("data" + index);
+            index++;
+        }
+        return new NDList(arrays);
+    }
+
+    /**
+     * Returns the time series start time.
+     *
+     * @return a {@link LocalDateTime} representing start time
+     */
+    public LocalDateTime getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * Returns the time series forecasting time.
+     *
+     * @return a {@link LocalDateTime} representing the time to forecast
+     */
+    public LocalDateTime getForecastStartTime() {
+        return forecastStartTime;
+    }
+
+    /**
+     * Adds a fieldName and value to the list.
+     *
+     * @param fieldName the {@link FieldName}.
+     * @param value the {@link NDArray} value
+     */
+    public void add(FieldName fieldName, NDArray value) {
+        add(fieldName.name(), value);
+    }
+
+    /**
+     * Returns the value for the fieldName.
+     *
+     * @param fieldName the {@link FieldName} of the element to get
+     * @return the {@link NDArray} value for the {@link FieldName}
+     */
+    public NDArray get(FieldName fieldName) {
+        return get(fieldName.name());
+    }
+
+    /**
+     * Replaces the existing {@link NDArray} of {@link FieldName} to the value.
+     *
+     * @param fieldName the {@link FieldName}
+     * @param value the {@link NDArray} value
+     */
+    public void setField(String fieldName, NDArray value) {
+        remove(fieldName);
+        add(fieldName, value);
+    }
+
+    /**
+     * Replace the existing {@link NDArray} of {@link FieldName} to the value.
+     *
+     * @param fieldName the {@link FieldName}.
+     * @param value the {@link NDArray} value.
+     */
+    public void setField(FieldName fieldName, NDArray value) {
+        setField(fieldName.name(), value);
+    }
+
+    /**
+     * Set the time series start time.
+     *
+     * @param value the {@link LocalDateTime} start time.
+     */
+    public void setStartTime(LocalDateTime value) {
+        this.startTime = value;
+    }
+
+    /**
+     * Set the time series forecasting time.
+     *
+     * @param value the {@link LocalDateTime} time to forecast
+     */
+    public void setForecastStartTime(LocalDateTime value) {
+        this.forecastStartTime = value;
+    }
+
+    /**
+     * Removes the key-value pair for the {@link FieldName}.
+     *
+     * @param fieldName the {@link FieldName} to be removed.
+     */
+    public void remove(FieldName fieldName) {
+        remove(fieldName.name());
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/FieldName.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/FieldName.java
new file mode 100644
index 000000000..a76df2499
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/FieldName.java
@@ -0,0 +1,43 @@
+/*
+ * 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.timeseries.dataset;
+
+import ai.djl.timeseries.TimeSeriesData;
+
+/** Represents the name field of elements in a {@link TimeSeriesData} as an enum. */
+public enum FieldName {
+    ITEM_ID,
+
+    START,
+    TARGET,
+
+    FEAT_STATIC_CAT,
+    FEAT_STATIC_REAL,
+    FEAT_DYNAMIC_CAT,
+    FEAT_DYNAMIC_REAL,
+    PAST_FEAT_DYNAMIC_REAL,
+    FEAT_DYNAMIC_REAL_LEGACY,
+
+    FEAT_DYNAMIC,
+    PAST_FEAT_DYNAMIC,
+
+    FEAT_TIME,
+    FEAT_CONST,
+    FEAT_AGE,
+
+    OBSERVED_VALUES,
+    IS_PAD,
+    FORECAST_START,
+
+    TARGET_DIM_INDICATOR;
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/package-info.java
new file mode 100644
index 000000000..8d35b7ade
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/dataset/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains the basic dataset classes. */
+package ai.djl.timeseries.dataset;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/package-info.java
new file mode 100644
index 000000000..f45e249a7
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains classes to support TimeSeries in djl. */
+package ai.djl.timeseries;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/Lag.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/Lag.java
new file mode 100644
index 000000000..eec33dbef
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/Lag.java
@@ -0,0 +1,111 @@
+/*
+ * 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.timeseries.timefeature;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** This class contains static method for get lags from frequency. */
+public final class Lag {
+
+    private Lag() {}
+
+    /**
+     * Generates a list of lags that are appropriate for the given frequency string.
+     *
+     * <p>By default all frequencies have the following lags: [1, 2, 3, 4, 5, 6, 7]. Remaining lags
+     * correspond to the same `season` (+/- `delta`) in previous `k` cycles. Here `delta` and `k`
+     * are chosen according to the existing code.
+     *
+     * @param freqStr Frequency string of the form [multiple][granularity] such as "12H", "1D" etc.
+     * @param lagUb The maximum value for a lag
+     * @return a list of lags
+     */
+    public static List<Integer> getLagsForFreq(String freqStr, int lagUb) {
+        List<List<Integer>> lags;
+        if ("D".equals(freqStr)) {
+            lags = makeLagsForDay(1);
+            lags.addAll(makeLagsForWeek(1f / 7f));
+        } else {
+            throw new IllegalArgumentException("invalid frequency: freq now must be D");
+        }
+        List<Integer> ret = new ArrayList<>();
+        for (List<Integer> subList : lags) {
+            for (Integer lag : subList) {
+                if (lag > 7 && lag <= lagUb) {
+                    ret.add(lag);
+                }
+            }
+        }
+        ret = ret.stream().distinct().collect(Collectors.toList());
+        ret.sort(Comparator.naturalOrder());
+        List<Integer> list = new ArrayList<>();
+        for (int i = 1; i < 8; i++) {
+            list.add(i);
+        }
+        ret.addAll(0, list);
+        return ret;
+    }
+
+    /**
+     * Generates a list of lags that are appropriate for the given frequency string. Set the lagUb
+     * to default value 1200.
+     *
+     * @param freqStr Frequency string of the form [multiple][granularity] such as "12H", "1D" etc
+     * @return a list of lags
+     */
+    public static List<Integer> getLagsForFreq(String freqStr) {
+        return getLagsForFreq(freqStr, 1200);
+    }
+
+    private static List<List<Integer>> makeLagsForDay(float multiple) {
+        int numCycles = 4;
+        List<List<Integer>> ret = new ArrayList<>();
+        for (int i = 1; i < numCycles + 1; i++) {
+            ret.add(makeLags((int) (i * 7 / multiple), 1));
+        }
+        ret.add(makeLags((int) (30 / multiple), 1));
+        return ret;
+    }
+
+    private static List<List<Integer>> makeLagsForWeek(float multiple) {
+        int numCycles = 3;
+        List<List<Integer>> ret = new ArrayList<>();
+        for (int i = 1; i < numCycles + 1; i++) {
+            ret.add(makeLags((int) (i * 52 / multiple), 1));
+        }
+        ret.add(
+                Arrays.asList(
+                        (int) (4f / multiple), (int) (8f / multiple), (int) (12f / multiple)));
+        return ret;
+    }
+
+    /**
+     * Creates a set of lags around a middle point including +/- delta.
+     *
+     * @param middle the middle point
+     * @param delta the delta
+     * @return a range between [middle - delta, middle + delta]
+     */
+    private static List<Integer> makeLags(int middle, int delta) {
+        List<Integer> ret = new ArrayList<>();
+        for (int i = middle - delta; i < middle + delta + 1; i++) {
+            ret.add(i);
+        }
+        return ret;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/TimeFeature.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/TimeFeature.java
new file mode 100644
index 000000000..21e7c39a5
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/TimeFeature.java
@@ -0,0 +1,188 @@
+/*
+ * 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.timeseries.timefeature;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/** this is a class to generate time feature by frequency. */
+public final class TimeFeature {
+
+    private static final Map<String, List<BiFunction<NDManager, List<LocalDateTime>, NDArray>>>
+            FEATURES_BY_OFFSETS = init();
+
+    private TimeFeature() {}
+
+    /**
+     * Computes feature by seconds.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray secondOfMinute(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getSecond);
+        return manager.create(data).divi(59f).subi(0.5);
+    }
+
+    /**
+     * Computes feature by minutes.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray minuteOfHour(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getMinute);
+        return manager.create(data).divi(59f).subi(0.5);
+    }
+
+    /**
+     * Computes feature by hours.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray hourOfDay(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getHour);
+        return manager.create(data).divi(23f).subi(0.5);
+    }
+
+    /**
+     * Computes feature by days of the week.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray dayOfWeek(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, a -> a.getDayOfWeek().ordinal());
+        return manager.create(data).divi(6f).subi(0.5);
+    }
+
+    /**
+     * Computes feature by days fo the month.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray dayOfMonth(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getDayOfMonth);
+        return manager.create(data).subi(1f).divi(30f).subi(0.5f);
+    }
+
+    /**
+     * Computes feature by days of the year.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray dayOfYear(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getDayOfYear);
+        return manager.create(data).subi(1f).divi(365f).subi(0.5f);
+    }
+
+    /**
+     * Computes feature by months of the year.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray monthOfYear(NDManager manager, List<LocalDateTime> index) {
+        float[] data = getFeature(index, LocalDateTime::getMonthValue);
+        return manager.create(data).subi(1f).divi(11f).subi(0.5);
+    }
+
+    /**
+     * Computes feature by weeks of the year.
+     *
+     * @param manager default {@link NDManager}.
+     * @param index time data
+     * @return the result feature
+     */
+    public static NDArray weekOfYear(NDManager manager, List<LocalDateTime> index) {
+        throw new UnsupportedOperationException("weekOfYear is not supported yet");
+    }
+
+    private static float[] getFeature(
+            List<LocalDateTime> index, Function<LocalDateTime, Number> function) {
+        float[] data = new float[index.size()];
+        int i = 0;
+        for (LocalDateTime time : index) {
+            data[i++] = function.apply(time).floatValue();
+        }
+        return data;
+    }
+
+    /**
+     * Returns a list of time features that will be appropriate for the given frequency string.
+     *
+     * @param freqStr Frequency string of the form [multiple][granularity] such as "12H", "1D"
+     * @return time features
+     */
+    public static List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeaturesFromFreqStr(
+            String freqStr) {
+        return FEATURES_BY_OFFSETS.get(freqStr);
+    }
+
+    private static Map<String, List<BiFunction<NDManager, List<LocalDateTime>, NDArray>>> init() {
+        Map<String, List<BiFunction<NDManager, List<LocalDateTime>, NDArray>>> map =
+                new ConcurrentHashMap<>();
+        map.put("Y", Collections.emptyList());
+        map.put("Q", Collections.singletonList(TimeFeature::monthOfYear));
+        map.put("M", Collections.singletonList(TimeFeature::monthOfYear));
+        map.put("W", Arrays.asList(TimeFeature::dayOfMonth, TimeFeature::weekOfYear));
+        map.put(
+                "D",
+                Arrays.asList(
+                        TimeFeature::dayOfWeek, TimeFeature::dayOfMonth, TimeFeature::dayOfYear));
+        map.put(
+                "H",
+                Arrays.asList(
+                        TimeFeature::hourOfDay,
+                        TimeFeature::dayOfWeek,
+                        TimeFeature::dayOfMonth,
+                        TimeFeature::dayOfYear));
+        map.put(
+                "T",
+                Arrays.asList(
+                        TimeFeature::minuteOfHour,
+                        TimeFeature::hourOfDay,
+                        TimeFeature::dayOfWeek,
+                        TimeFeature::dayOfMonth,
+                        TimeFeature::dayOfYear));
+        map.put(
+                "S",
+                Arrays.asList(
+                        TimeFeature::secondOfMinute,
+                        TimeFeature::minuteOfHour,
+                        TimeFeature::hourOfDay,
+                        TimeFeature::dayOfWeek,
+                        TimeFeature::dayOfMonth,
+                        TimeFeature::dayOfYear));
+        return map;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/package-info.java
new file mode 100644
index 000000000..18ea0cc8c
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/timefeature/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains utils to get time feature from prediction frequency. */
+package ai.djl.timeseries.timefeature;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/InstanceSampler.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/InstanceSampler.java
new file mode 100644
index 000000000..839fad011
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/InstanceSampler.java
@@ -0,0 +1,66 @@
+/*
+ * 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.timeseries.transform;
+
+import ai.djl.ndarray.NDArray;
+
+import java.util.List;
+
+/**
+ * An InstanceSampler is called with the time series ``ts``, and returns a set of indices at which
+ * training instances will be generated.
+ *
+ * <p>The sampled indices ``i`` satisfy ``a &lt;= i &lt;= b``, where ``a = min_past`` and ``b =
+ * ts.shape[axis] - min_future``.
+ */
+public abstract class InstanceSampler {
+
+    protected int axis;
+    protected int minPast;
+    protected int minFuture;
+
+    /**
+     * Constructs a new instance of {@code InstanceSampler}.
+     *
+     * @param axis the axis of the time series length
+     * @param minPast minimal pastime length
+     * @param minFuture minimal future time length
+     */
+    public InstanceSampler(int axis, int minPast, int minFuture) {
+        this.axis = axis;
+        this.minPast = minPast;
+        this.minFuture = minFuture;
+    }
+
+    /**
+     * Returns the sampled indices bounds.
+     *
+     * @param ts the time series
+     * @return the indices bound
+     */
+    public int[] getBounds(NDArray ts) {
+        int start = this.minPast;
+        int posAxis = this.axis < 0 ? ts.getShape().dimension() + this.axis : this.axis;
+        int end = (int) ts.getShape().get(posAxis) - this.minFuture;
+        return new int[] {start, end};
+    }
+
+    /**
+     * Call the sample process.
+     *
+     * @param ts the time series
+     * @return list of indices
+     */
+    public abstract List<Integer> call(NDArray ts);
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/PredictionSplitSampler.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/PredictionSplitSampler.java
new file mode 100644
index 000000000..3e4907388
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/PredictionSplitSampler.java
@@ -0,0 +1,70 @@
+/*
+ * 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.timeseries.transform;
+
+import ai.djl.ndarray.NDArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Sampler used for prediction. */
+public class PredictionSplitSampler extends InstanceSampler {
+
+    private boolean allowEmptyInterval;
+
+    /**
+     * Constructs a new instance of {@code PredictionSplitSampler}.
+     *
+     * @param axis the axis of the time series length
+     * @param minPast minimal pastime length
+     * @param minFuture minimal future time length
+     * @param allowEmptyInterval whether allow to output an empty {@link NDArray}
+     */
+    public PredictionSplitSampler(
+            int axis, int minPast, int minFuture, boolean allowEmptyInterval) {
+        super(axis, minPast, minFuture);
+        this.allowEmptyInterval = allowEmptyInterval;
+    }
+
+    /** {@inheritDoc} * */
+    @Override
+    public List<Integer> call(NDArray ts) {
+        int[] bound = this.getBounds(ts);
+        List<Integer> ret = new ArrayList<>();
+        if (bound[0] < bound[1]) {
+            ret.add(bound[1]);
+        } else if (!allowEmptyInterval) {
+            throw new IllegalArgumentException("The start >= end while allowEmptyInterval = False");
+        }
+        return ret;
+    }
+
+    /**
+     * Creates a new instance {@code PredictionSplitSampler} for test.
+     *
+     * @return a {@code PredictionSplitSampler}
+     */
+    public static PredictionSplitSampler newTestSplitSampler() {
+        return new PredictionSplitSampler(-1, 0, 0, false);
+    }
+
+    /**
+     * Creates a new instance {@code PredictionSplitSampler} for validation.
+     *
+     * @return a {@link PredictionSplitSampler}
+     */
+    public static PredictionSplitSampler newValidationSplitSampler() {
+        return new PredictionSplitSampler(-1, 0, 0, true);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/TimeSeriesTransform.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/TimeSeriesTransform.java
new file mode 100644
index 000000000..e8d3b2147
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/TimeSeriesTransform.java
@@ -0,0 +1,29 @@
+/*
+ * 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.timeseries.transform;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+
+/** This interface is used for data transformation on the {@link TimeSeriesData}. */
+public interface TimeSeriesTransform {
+
+    /**
+     * Transform process on TimeSeriesData.
+     *
+     * @param manager The default manager for data process
+     * @param data The data to be operated on
+     * @return The result {@link TimeSeriesData}.
+     */
+    TimeSeriesData transform(NDManager manager, TimeSeriesData data);
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/Convert.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/Convert.java
new file mode 100644
index 000000000..2ea9a8807
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/Convert.java
@@ -0,0 +1,75 @@
+/*
+ * 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.timeseries.transform.convert;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDArrays;
+import ai.djl.ndarray.NDList;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+
+/** this is a class use to convert the shape of {@link NDArray} in {@link TimeSeriesData}. */
+public final class Convert {
+
+    private Convert() {}
+
+    /**
+     * Stack fields together using {@link NDArrays#concat(NDList)}. when hStack = false, axis = 0
+     * Otherwise axis = 1.
+     *
+     * @param outputField Field names to use for the output
+     * @param inputFields Fields to stack together
+     * @param dropInputs If set to true the input fields will be dropped
+     * @param hStack To stack horizontally instead of vertically
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void vstackFeatures(
+            FieldName outputField,
+            FieldName[] inputFields,
+            boolean dropInputs,
+            boolean hStack,
+            TimeSeriesData data) {
+        NDList ndList = new NDList();
+        for (FieldName fieldName : inputFields) {
+            NDArray temp = data.get(fieldName);
+            if (temp != null) {
+                ndList.add(data.get(fieldName));
+            }
+        }
+
+        NDArray output = NDArrays.concat(ndList, hStack ? 1 : 0);
+        data.setField(outputField, output);
+        if (dropInputs) {
+            for (FieldName fieldName : inputFields) {
+                if (fieldName != outputField) {
+                    data.remove(fieldName);
+                }
+            }
+        }
+    }
+
+    /**
+     * Stack fields together using {@link NDArrays#concat(NDList)}.
+     *
+     * <p>set hStack = false, dropInputs = true
+     *
+     * @param outputField Field names to use for the output
+     * @param inputFields Fields to stack together
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void vstackFeatures(
+            FieldName outputField, FieldName[] inputFields, TimeSeriesData data) {
+        vstackFeatures(outputField, inputFields, true, false, data);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/VstackFeatures.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/VstackFeatures.java
new file mode 100644
index 000000000..24a1fa0d5
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/VstackFeatures.java
@@ -0,0 +1,61 @@
+/*
+ * 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.timeseries.transform.convert;
+
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/** Use the {@link ai.djl.ndarray.NDArrays#concat(NDList)} to vstack data. */
+public class VstackFeatures implements TimeSeriesTransform {
+
+    private FieldName outputField;
+    private FieldName[] inputFields;
+    private boolean dropInputs;
+    private boolean hStack;
+
+    /**
+     * Constructs a {@link VstackFeatures}.
+     *
+     * @param outputField output field name
+     * @param inputFields input field names
+     * @param dropInputs whether to remove the input fields
+     * @param hStack use hStack
+     */
+    public VstackFeatures(
+            FieldName outputField, FieldName[] inputFields, boolean dropInputs, boolean hStack) {
+        this.outputField = outputField;
+        this.inputFields = inputFields;
+        this.dropInputs = dropInputs;
+        this.hStack = hStack;
+    }
+
+    /**
+     * Constructs a {@link VstackFeatures}.
+     *
+     * @param outputField output field name
+     * @param inputFields input field names
+     */
+    public VstackFeatures(FieldName outputField, FieldName[] inputFields) {
+        this(outputField, inputFields, true, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        Convert.vstackFeatures(outputField, inputFields, dropInputs, hStack, data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/package-info.java
new file mode 100644
index 000000000..dd8cf7cf5
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/convert/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains transform for {@link ai.djl.timeseries.TimeSeriesData} to convert {@link
+ * ai.djl.ndarray.NDArray}.
+ */
+package ai.djl.timeseries.transform.convert;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddAgeFeature.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddAgeFeature.java
new file mode 100644
index 000000000..f8a32f6f5
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddAgeFeature.java
@@ -0,0 +1,61 @@
+/*
+ * 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.timeseries.transform.feature;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/** Add age feature through the prediction length. */
+public class AddAgeFeature implements TimeSeriesTransform {
+
+    private FieldName targetField;
+    private FieldName outputField;
+    private int predictionLength;
+    private boolean logScale;
+
+    /**
+     * Constructs a {@link AddAgeFeature}.
+     *
+     * @param targetField target field name
+     * @param outputField output field name
+     * @param predictionLength time series prediction length
+     */
+    public AddAgeFeature(FieldName targetField, FieldName outputField, int predictionLength) {
+        this(targetField, outputField, predictionLength, true);
+    }
+
+    /**
+     * Constructs a {@link AddAgeFeature}.
+     *
+     * @param targetField target field name
+     * @param outputField output field name
+     * @param predictionLength time series prediction length
+     * @param logScale whether to use log data
+     */
+    public AddAgeFeature(
+            FieldName targetField, FieldName outputField, int predictionLength, boolean logScale) {
+        this.targetField = targetField;
+        this.outputField = outputField;
+        this.predictionLength = predictionLength;
+        this.logScale = logScale;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        return Feature.addAgeFeature(
+                manager, targetField, outputField, predictionLength, logScale, data);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddObservedValuesIndicator.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddObservedValuesIndicator.java
new file mode 100644
index 000000000..108334805
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddObservedValuesIndicator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.timeseries.transform.feature;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/** Add observed value for the target data. */
+public class AddObservedValuesIndicator implements TimeSeriesTransform {
+
+    private FieldName targetField;
+    private FieldName outputField;
+
+    /**
+     * Constructs a {@link AddObservedValuesIndicator}.
+     *
+     * @param targetField target field name to be observed
+     * @param outputField output field name
+     */
+    public AddObservedValuesIndicator(FieldName targetField, FieldName outputField) {
+        this.targetField = targetField;
+        this.outputField = outputField;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        Feature.addObservedValuesIndicator(manager, targetField, outputField, data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddTimeFeature.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddTimeFeature.java
new file mode 100644
index 000000000..7ebabda20
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/AddTimeFeature.java
@@ -0,0 +1,74 @@
+/*
+ * 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.timeseries.transform.feature;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.function.BiFunction;
+
+/** Add time feature by frequency. */
+public class AddTimeFeature implements TimeSeriesTransform {
+
+    private FieldName startField;
+    private FieldName targetField;
+    private FieldName outputField;
+    private List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures;
+    private int predictionLength;
+    String freq;
+
+    /**
+     * Constructs a {@link AddTimeFeature}.
+     *
+     * @param startField start field name containing start time
+     * @param targetField target field name
+     * @param outputField output value field name
+     * @param timeFeatures functions to generate time features
+     * @param predictionLength prediction length
+     * @param freq prediction frequency
+     */
+    public AddTimeFeature(
+            FieldName startField,
+            FieldName targetField,
+            FieldName outputField,
+            List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures,
+            int predictionLength,
+            String freq) {
+        this.startField = startField;
+        this.targetField = targetField;
+        this.outputField = outputField;
+        this.timeFeatures = timeFeatures;
+        this.predictionLength = predictionLength;
+        this.freq = freq;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        Feature.addTimeFeature(
+                manager,
+                startField,
+                targetField,
+                outputField,
+                timeFeatures,
+                predictionLength,
+                freq,
+                data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/Feature.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/Feature.java
new file mode 100644
index 000000000..751a10a09
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/Feature.java
@@ -0,0 +1,179 @@
+/*
+ * 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.timeseries.transform.feature;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDArrays;
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.Period;
+import java.time.temporal.TemporalAmount;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+
+/** this is a class use to add feature in {@link TimeSeriesData}. */
+public final class Feature {
+
+    private Feature() {}
+
+    /**
+     * Replaces missing values in a {@link NDArray} (NaNs) with a dummy value and adds an
+     * "observed"-indicator that is "1" when values are observed and "0" when values are missing.
+     *
+     * @param manager default {@link NDManager}
+     * @param targetField Field for which missing values will be replaced
+     * @param outputField Field name to use for the indicator
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void addObservedValuesIndicator(
+            NDManager manager, FieldName targetField, FieldName outputField, TimeSeriesData data) {
+        NDArray value = data.get(targetField);
+        data.setField(targetField, dummyValueImputation(manager, value, 0f));
+        NDArray nanEntries = value.isNaN();
+        data.setField(outputField, nanEntries.logicalNot().toType(value.getDataType(), false));
+    }
+
+    /**
+     * Adds a set of time features.
+     *
+     * @param manager default {@link NDManager}
+     * @param startField Field with the start time stamp of the time series
+     * @param targetField Field with the array containing the time series values
+     * @param outputField Field name for result
+     * @param timeFeatures list of time features to use
+     * @param predictionLength Prediction length
+     * @param freq Prediction time frequency
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void addTimeFeature(
+            NDManager manager,
+            FieldName startField,
+            FieldName targetField,
+            FieldName outputField,
+            List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures,
+            int predictionLength,
+            String freq,
+            TimeSeriesData data) {
+        if (timeFeatures.isEmpty()) {
+            data.setField(outputField, null);
+        }
+
+        LocalDateTime start = data.getStartTime();
+        int length = targetTransformationLength(data.get(targetField), predictionLength, false);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(freq);
+        if (!freq.matches("\\d+.*")) {
+            sb.insert(0, 1);
+        }
+        sb.insert(0, "P");
+        String formattedFreq = sb.toString();
+
+        TemporalAmount timeFreq;
+        if (freq.endsWith("H") || freq.endsWith("T") || freq.endsWith("S")) {
+            timeFreq = Duration.parse(formattedFreq);
+        } else {
+            timeFreq = Period.parse(formattedFreq);
+        }
+
+        List<LocalDateTime> index = new ArrayList<>();
+        LocalDateTime temp = start;
+        for (int i = 0; i < length; i++) {
+            index.add(temp);
+            temp = temp.plus(timeFreq);
+        }
+
+        NDList outputs = new NDList(timeFeatures.size());
+        for (BiFunction<NDManager, List<LocalDateTime>, NDArray> f : timeFeatures) {
+            outputs.add(f.apply(manager, index));
+        }
+
+        data.setField(outputField, NDArrays.stack(outputs));
+    }
+
+    /**
+     * Adds on 'age' feature to the {@link TimeSeriesData}.
+     *
+     * <p>The age feature starts with a small value at the start of the time series and grows over
+     * time.
+     *
+     * @param manager default {@link NDManager}
+     * @param targetField Field with target values (array) of time series
+     * @param outputField Field name to use for the output
+     * @param predictionLength Prediction length
+     * @param logScale If set to true the age feature grows logarithmically otherwise linearly over
+     *     time.
+     * @param data the {@link TimeSeriesData} to operate on
+     * @return the result {@link TimeSeriesData}
+     */
+    public static TimeSeriesData addAgeFeature(
+            NDManager manager,
+            FieldName targetField,
+            FieldName outputField,
+            int predictionLength,
+            boolean logScale,
+            TimeSeriesData data) {
+
+        NDArray targetData = data.get(targetField);
+        int length = targetTransformationLength(targetData, predictionLength, false);
+
+        NDArray age = manager.arange(0, length, 1, targetData.getDataType());
+        if (logScale) {
+            age = age.add(2f).log10();
+        }
+        age = age.reshape(new Shape(1, length));
+
+        data.setField(outputField, age);
+        return data;
+    }
+
+    /**
+     * Adds on 'age' feature to the {@link TimeSeriesData}, set logScale = ture
+     *
+     * <p>The age feature starts with a small value at the start of the time series and grows over
+     * time.
+     *
+     * @param manager default {@link NDManager}
+     * @param targetField Field with target values (array) of time series
+     * @param outputField Field name to use for the output
+     * @param predictionLength Prediction length
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void addAgeFeature(
+            NDManager manager,
+            FieldName targetField,
+            FieldName outputField,
+            int predictionLength,
+            TimeSeriesData data) {
+        addAgeFeature(manager, targetField, outputField, predictionLength, true, data);
+    }
+
+    private static int targetTransformationLength(
+            NDArray target, int predictionLength, boolean isTrain) {
+        return (int) target.getShape().tail() + (isTrain ? 0 : predictionLength);
+    }
+
+    private static NDArray dummyValueImputation(
+            NDManager manager, NDArray value, float dummyValue) {
+        NDArray dummyArray = manager.full(value.getShape(), dummyValue);
+        return NDArrays.where(value.isNaN(), dummyArray, value);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/package-info.java
new file mode 100644
index 000000000..0cb19f47b
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/feature/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains transform for {@link ai.djl.timeseries.TimeSeriesData} to generate time feature. */
+package ai.djl.timeseries.transform.feature;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/Field.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/Field.java
new file mode 100644
index 000000000..7ee76592b
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/Field.java
@@ -0,0 +1,68 @@
+/*
+ * 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.timeseries.transform.field;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** A utility class that used to operate field name in {@link TimeSeriesData}. */
+public final class Field {
+
+    private Field() {}
+
+    /**
+     * Remove fields names if present.
+     *
+     * @param fieldNames List of names of the fields that will be removed
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void removeFields(List<FieldName> fieldNames, TimeSeriesData data) {
+        for (FieldName k : fieldNames) {
+            data.remove(k);
+        }
+    }
+
+    /**
+     * Sets a field in the dictionary with the given value.
+     *
+     * @param outputField Name of the field that will be set
+     * @param value Value to be set
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void setField(FieldName outputField, NDArray value, TimeSeriesData data) {
+        data.remove(outputField);
+        data.add(outputField, value);
+    }
+
+    /**
+     * Only keep the listed fields.
+     *
+     * @param inputFields List of fields to keep
+     * @param data the {@link TimeSeriesData} to operate on
+     * @return the result {@link TimeSeriesData}
+     */
+    public static TimeSeriesData selectField(String[] inputFields, TimeSeriesData data) {
+        List<String> keys = Arrays.asList(inputFields);
+        List<NDArray> values = new ArrayList<>(keys.size());
+        for (String field : inputFields) {
+            values.add(data.get(field));
+        }
+        return new TimeSeriesData(keys, values);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/RemoveFields.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/RemoveFields.java
new file mode 100644
index 000000000..aaa346636
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/RemoveFields.java
@@ -0,0 +1,42 @@
+/*
+ * 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.timeseries.transform.field;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+import java.util.List;
+
+/** Remove the field names. */
+public class RemoveFields implements TimeSeriesTransform {
+
+    private final List<FieldName> fieldNames;
+
+    /**
+     * Constructs a {@code RemoveFields} instance.
+     *
+     * @param fieldNames field name to be removed
+     */
+    public RemoveFields(List<FieldName> fieldNames) {
+        this.fieldNames = fieldNames;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        Field.removeFields(fieldNames, data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SelectField.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SelectField.java
new file mode 100644
index 000000000..03f39a32d
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SelectField.java
@@ -0,0 +1,38 @@
+/*
+ * 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.timeseries.transform.field;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/** Select preset field names. */
+public class SelectField implements TimeSeriesTransform {
+
+    private String[] inputFields;
+
+    /**
+     * Constructs a {@code SelectField} instance.
+     *
+     * @param inputFields field names to select from
+     */
+    public SelectField(String[] inputFields) {
+        this.inputFields = inputFields;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        return Field.selectField(inputFields, data);
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SetField.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SetField.java
new file mode 100644
index 000000000..28523313a
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/SetField.java
@@ -0,0 +1,45 @@
+/*
+ * 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.timeseries.transform.field;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/** Use the preset value for input field names. */
+public class SetField implements TimeSeriesTransform {
+
+    private final FieldName outputField;
+    private final NDArray value;
+
+    /**
+     * Constructs a {@link SetField}.
+     *
+     * @param outputField output field name to be set
+     * @param value value to be set
+     */
+    public SetField(FieldName outputField, NDArray value) {
+        this.outputField = outputField;
+        this.value = value;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        NDArray copyValue = value.duplicate();
+        Field.setField(outputField, copyValue, data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/package-info.java
new file mode 100644
index 000000000..93db57e2c
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/field/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains transform for {@link ai.djl.timeseries.TimeSeriesData} to CRUD name field. */
+package ai.djl.timeseries.transform.field;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/package-info.java
new file mode 100644
index 000000000..4d58102e1
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains transform classes. */
+package ai.djl.timeseries.transform;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/InstanceSplit.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/InstanceSplit.java
new file mode 100644
index 000000000..f114e8c05
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/InstanceSplit.java
@@ -0,0 +1,135 @@
+/*
+ * 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.timeseries.transform.split;
+
+import ai.djl.ndarray.NDManager;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.InstanceSampler;
+import ai.djl.timeseries.transform.TimeSeriesTransform;
+
+/**
+ * Use the {@link ai.djl.timeseries.transform.InstanceSampler} to split the time series data into
+ * past and future part.
+ */
+public class InstanceSplit implements TimeSeriesTransform {
+
+    private FieldName targetField;
+    private FieldName isPadField;
+    private FieldName startField;
+    private FieldName forecastStartField;
+    private InstanceSampler instanceSampler;
+    private int pastLength;
+    private int futureLength;
+    private int leadTime;
+    private boolean outputNTC;
+    private FieldName[] timeSeriesFields;
+    private float dummyValue;
+
+    /**
+     * Constructs a {@link InstanceSplit}.
+     *
+     * @param targetField target field name
+     * @param isPadField is_pad field name
+     * @param startField start time field name
+     * @param forecastStartField forecast time field name
+     * @param instanceSampler Sampler to generate indices for splitting
+     * @param pastLength past target data length
+     * @param futureLength future target data length
+     * @param leadTime lead time
+     * @param outputNTC whether to lay out as "NTC"
+     * @param timeSeriesFields time series field names to be split
+     * @param dummyValue value for padding
+     */
+    public InstanceSplit(
+            FieldName targetField,
+            FieldName isPadField,
+            FieldName startField,
+            FieldName forecastStartField,
+            InstanceSampler instanceSampler,
+            int pastLength,
+            int futureLength,
+            int leadTime,
+            boolean outputNTC,
+            FieldName[] timeSeriesFields,
+            float dummyValue) {
+        this.targetField = targetField;
+        this.isPadField = isPadField;
+        this.startField = startField;
+        this.forecastStartField = forecastStartField;
+        this.instanceSampler = instanceSampler;
+        this.pastLength = pastLength;
+        this.futureLength = futureLength;
+        this.leadTime = leadTime;
+        this.outputNTC = outputNTC;
+        this.timeSeriesFields = timeSeriesFields;
+        this.dummyValue = dummyValue;
+    }
+
+    /**
+     * Constructs a {@link InstanceSplit}.
+     *
+     * @param targetField target field name
+     * @param isPadField is_pad field name
+     * @param startField start time field name
+     * @param forecastStartField forecast time field name
+     * @param instanceSampler Sampler to generate indices for splitting
+     * @param pastLength past target data length
+     * @param futureLength future target data length
+     * @param timeSeriesFields time series field names to be split
+     * @param dummyValue value for padding
+     */
+    public InstanceSplit(
+            FieldName targetField,
+            FieldName isPadField,
+            FieldName startField,
+            FieldName forecastStartField,
+            InstanceSampler instanceSampler,
+            int pastLength,
+            int futureLength,
+            FieldName[] timeSeriesFields,
+            float dummyValue) {
+        this(
+                targetField,
+                isPadField,
+                startField,
+                forecastStartField,
+                instanceSampler,
+                pastLength,
+                futureLength,
+                0,
+                true,
+                timeSeriesFields,
+                dummyValue);
+    }
+
+    /** {@inheritDoc}. */
+    @Override
+    public TimeSeriesData transform(NDManager manager, TimeSeriesData data) {
+        Split.instanceSplit(
+                manager,
+                targetField,
+                isPadField,
+                startField,
+                forecastStartField,
+                instanceSampler,
+                pastLength,
+                futureLength,
+                leadTime,
+                outputNTC,
+                timeSeriesFields,
+                dummyValue,
+                data);
+        return data;
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/Split.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/Split.java
new file mode 100644
index 000000000..2b0689064
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/Split.java
@@ -0,0 +1,211 @@
+/*
+ * 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.timeseries.transform.split;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.index.NDIndex;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.transform.InstanceSampler;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** this is a class use to split the time series data of {@link TimeSeriesData}. */
+public final class Split {
+
+    private Split() {}
+
+    /**
+     * Selects training instances, by slicing the target and other time series like arrays at random
+     * points in training mode or at the last time point in prediction mode. Assumption is that all
+     * time like arrays start at the same time point.
+     *
+     * <p>The target and each time_series_field is removed and instead two corresponding fields with
+     * prefix `past_` and `future_` are included. E.g.
+     *
+     * <p>If the target array is one-dimensional, the resulting instance has shape (len_target). In
+     * the multi-dimensional case, the instance has shape (dim, len_target).
+     *
+     * <p>target -&gt; past_target and future_target
+     *
+     * <p>The transformation also adds a field 'past_is_pad' that indicates whether values where
+     * padded or not. Convention: time axis is always the last axis.
+     *
+     * @param manager the default {@link NDManager}
+     * @param targetField {@link FieldName} containing the target
+     * @param isPadField output {@link FieldName} indicating whether padding happened
+     * @param startField field containing the start date of the time series
+     * @param forecastStartField output field that will contain the time point where the forecast
+     *     starts
+     * @param instanceSampler {@link InstanceSampler} that provides sampling indices given a
+     *     time-series
+     * @param pastLength length of the target seen before making prediction
+     * @param futureLength length of the target that must be predicted
+     * @param leadTime gap between the past and future windows (default 0)
+     * @param outputNTC whether to have time series output in (time, dimension) or in (dimension,
+     *     time) layout (default True)
+     * @param timeSeriesFields fields that contains time-series, they are split in the same interval
+     *     as the target (default None)
+     * @param dummyValue Value to use for padding (default 0.0)
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void instanceSplit(
+            NDManager manager,
+            FieldName targetField,
+            FieldName isPadField,
+            FieldName startField,
+            FieldName forecastStartField,
+            InstanceSampler instanceSampler,
+            int pastLength,
+            int futureLength,
+            int leadTime,
+            boolean outputNTC,
+            FieldName[] timeSeriesFields,
+            float dummyValue,
+            TimeSeriesData data) {
+
+        List<FieldName> sliceCols = new ArrayList<>(timeSeriesFields.length + 1);
+        sliceCols.addAll(Arrays.asList(timeSeriesFields));
+        sliceCols.add(targetField);
+        NDArray target = data.get(targetField);
+
+        List<Integer> sampledIndices = instanceSampler.call(target);
+
+        // TODO: add yield method
+        for (int i : sampledIndices.subList(0, 1)) {
+            int padLength = Math.max(pastLength - i, 0);
+            for (FieldName tsField : sliceCols) {
+                NDArray pastPiece;
+                NDArray tsData = data.get(tsField);
+                if (i > pastLength) {
+                    pastPiece = tsData.get("..., {}:{}", i - pastLength, i);
+                } else if (i < pastLength) {
+                    Shape shape = tsData.getShape();
+                    int dims = shape.dimension();
+                    shape = shape.slice(0, dims - 1).add(padLength);
+                    NDArray padBlock = manager.full(shape, dummyValue, tsData.getDataType());
+
+                    pastPiece = padBlock.concat(tsData.get("..., :{}", i), -1);
+                } else {
+                    pastPiece = tsData.get("..., :{}", i);
+                }
+                data.setField(past(tsField), pastPiece);
+                NDArray futureData;
+                if (i + leadTime >= (int) tsData.getShape().tail()) {
+                    // Only for the inference. if create the NDArray by slice the tsData, an unknown
+                    // error occur
+                    Shape shape = tsData.getShape();
+                    shape = shape.slice(0, shape.dimension() - 1).add(0);
+                    futureData = manager.create(shape);
+                } else {
+                    futureData =
+                            tsData.get("..., {}:{}", i + leadTime, i + leadTime + futureLength);
+                }
+                data.setField(future(tsField), futureData);
+                data.remove(tsField);
+            }
+
+            NDArray padIndicator = manager.zeros(new Shape(pastLength), target.getDataType());
+            if (padLength > 0) {
+                padIndicator.set(new NDIndex(":{}", padLength), 1);
+            }
+
+            if (outputNTC) {
+                for (FieldName tsField : sliceCols) {
+                    NDArray past = data.get(past(tsField));
+                    data.setField(past(tsField), past.transpose());
+                    NDArray future = data.get(future(tsField));
+                    data.setField(future(tsField), future.transpose());
+                }
+            }
+
+            data.setField(past(isPadField), padIndicator);
+
+            // only for freq "D" now
+            data.setForecastStartTime(data.getStartTime().plusDays(i + leadTime));
+        }
+    }
+
+    /**
+     * Selects training instances, by slicing the target and other time series like arrays at random
+     * points in training mode or at the last time point in prediction mode. Assumption is that all
+     * time like arrays start at the same time point.
+     *
+     * <p>The target and each time_series_field is removed and instead two corresponding fields with
+     * prefix `past_` and `future_` are included. E.g.
+     *
+     * <p>If the target array is one-dimensional, the resulting instance has shape (len_target). In
+     * the multi-dimensional case, the instance has shape (dim, len_target).
+     *
+     * <p>target -&gt; past_target and future_target
+     *
+     * <p>The transformation also adds a field 'past_is_pad' that indicates whether values where
+     * padded or not. Convention: time axis is always the last axis.
+     *
+     * @param manager the default {@link NDManager}
+     * @param targetField {@link FieldName} containing the target
+     * @param isPadField output {@link FieldName} indicating whether padding happened
+     * @param startField field containing the start date of the time series
+     * @param forecastStartField output field that will contain the time point where the forecast
+     *     starts
+     * @param instanceSampler {@link InstanceSampler} that provides sampling indices given a
+     *     time-series
+     * @param pastLength length of the target seen before making prediction
+     * @param futureLength length of the target that must be predicted (time, dimension) or in
+     *     (dimension, time) layout (default True)
+     * @param timeSeriesFields fields that contains time-series, they are split in the same interval
+     *     as the target (default None)
+     * @param dummyValue Value to use for padding (default 0.0)
+     * @param data the {@link TimeSeriesData} to operate on
+     */
+    public static void instanceSplit(
+            NDManager manager,
+            FieldName targetField,
+            FieldName isPadField,
+            FieldName startField,
+            FieldName forecastStartField,
+            InstanceSampler instanceSampler,
+            int pastLength,
+            int futureLength,
+            FieldName[] timeSeriesFields,
+            float dummyValue,
+            TimeSeriesData data) {
+        instanceSplit(
+                manager,
+                targetField,
+                isPadField,
+                startField,
+                forecastStartField,
+                instanceSampler,
+                pastLength,
+                futureLength,
+                0,
+                true,
+                timeSeriesFields,
+                dummyValue,
+                data);
+    }
+
+    private static String past(FieldName name) {
+        return "PAST_" + name.name();
+    }
+
+    private static String future(FieldName name) {
+        return "FUTURE_" + name.name();
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/package-info.java
new file mode 100644
index 000000000..5aa91ba12
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/transform/split/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains transform for {@link ai.djl.timeseries.TimeSeriesData} to split time feature for
+ * inference and train.
+ */
+package ai.djl.timeseries.transform.split;
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/BaseTimeSeriesTranslator.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/BaseTimeSeriesTranslator.java
new file mode 100644
index 000000000..c84e874a3
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/BaseTimeSeriesTranslator.java
@@ -0,0 +1,92 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.translate.ArgumentsUtil;
+import ai.djl.translate.Batchifier;
+import ai.djl.translate.Translator;
+
+import java.util.Map;
+
+/** Built-in {@code Translator} that provides default TimeSeriesTranslator config process. */
+public abstract class BaseTimeSeriesTranslator implements Translator<TimeSeriesData, Forecast> {
+
+    protected int predictionLength;
+    protected int contextLength;
+
+    protected String freq;
+
+    private Batchifier batchifier;
+
+    /**
+     * Constructs a new {@code TimeSeriesTranslator} instance with the provided builder.
+     *
+     * @param builder the data to build with
+     */
+    protected BaseTimeSeriesTranslator(BaseBuilder<?> builder) {
+        this.batchifier = builder.batchifier;
+        this.freq = builder.freq;
+        this.predictionLength = builder.predictionLength;
+        // TODO: for inferring
+        this.contextLength = builder.predictionLength;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Batchifier getBatchifier() {
+        return batchifier;
+    }
+
+    /**
+     * A builder to extend for all classes extend the {@link BaseTimeSeriesTranslator}.
+     *
+     * @param <T> the concrete builder type
+     */
+    public abstract static class BaseBuilder<T extends BaseBuilder<T>> {
+        protected Batchifier batchifier = Batchifier.STACK;
+        protected int predictionLength;
+
+        protected String freq;
+
+        /**
+         * Sets the {@link Batchifier} for the {@link Translator}.
+         *
+         * @param batchifier the {@link Batchifier} to be set
+         * @return this builder
+         */
+        public T optBachifier(Batchifier batchifier) {
+            this.batchifier = batchifier;
+            return self();
+        }
+
+        protected abstract T self();
+
+        protected void validate() {}
+
+        protected void configPreProcess(Map<String, ?> arguments) {
+            this.freq = ArgumentsUtil.stringValue(arguments, "freq", "D");
+            this.predictionLength = ArgumentsUtil.intValue(arguments, "prediction_length");
+            if (predictionLength <= 0) {
+                throw new IllegalArgumentException(
+                        "The value of `prediction_length` should be > 0");
+            }
+            if (arguments.containsKey("batchifier")) {
+                batchifier = Batchifier.fromString((String) arguments.get("batchifier"));
+            }
+        }
+
+        protected void configPostProcess(Map<String, ?> arguments) {}
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslator.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslator.java
new file mode 100644
index 000000000..0b0f8e99b
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslator.java
@@ -0,0 +1,231 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.SampleForecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.timefeature.Lag;
+import ai.djl.timeseries.timefeature.TimeFeature;
+import ai.djl.timeseries.transform.InstanceSampler;
+import ai.djl.timeseries.transform.PredictionSplitSampler;
+import ai.djl.timeseries.transform.convert.Convert;
+import ai.djl.timeseries.transform.feature.Feature;
+import ai.djl.timeseries.transform.field.Field;
+import ai.djl.timeseries.transform.split.Split;
+import ai.djl.translate.ArgumentsUtil;
+import ai.djl.translate.Translator;
+import ai.djl.translate.TranslatorContext;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+/** The {@link Translator} for DeepAR time series forecasting tasks. */
+public class DeepARTranslator extends BaseTimeSeriesTranslator {
+
+    private boolean useFeatDynamicReal;
+    private boolean useFeatStaticReal;
+    private boolean useFeatStaticCat;
+    private int historyLength;
+
+    private static final String[] PRED_INPUT_FIELDS = {
+        FieldName.FEAT_STATIC_CAT.name(),
+        FieldName.FEAT_STATIC_REAL.name(),
+        "PAST_" + FieldName.FEAT_TIME.name(),
+        "PAST_" + FieldName.TARGET.name(),
+        "PAST_" + FieldName.OBSERVED_VALUES.name(),
+        "FUTURE_" + FieldName.FEAT_TIME.name(),
+        "PAST_" + FieldName.IS_PAD.name()
+    };
+    private static final FieldName[] TIME_SERIES_FIELDS = {
+        FieldName.FEAT_TIME, FieldName.OBSERVED_VALUES
+    };
+    private final List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures;
+
+    private final InstanceSampler instanceSampler;
+
+    /**
+     * Constructs a new {@code DeepARTranslator} instance.
+     *
+     * @param builder the data to build with
+     */
+    public DeepARTranslator(Builder builder) {
+        super(builder);
+        this.useFeatDynamicReal = builder.useFeatDynamicReal;
+        this.useFeatStaticReal = builder.useFeatStaticReal;
+        this.useFeatStaticCat = builder.useFeatStaticCat;
+
+        List<Integer> lagsSeq = Lag.getLagsForFreq(freq);
+        this.timeFeatures = TimeFeature.timeFeaturesFromFreqStr(freq);
+        this.historyLength = contextLength + lagsSeq.get(lagsSeq.size() - 1);
+        this.instanceSampler = PredictionSplitSampler.newTestSplitSampler();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Forecast processOutput(TranslatorContext ctx, NDList list) {
+        NDArray outputs = list.singletonOrThrow();
+        TimeSeriesData data = (TimeSeriesData) ctx.getAttachment("input");
+        outputs.attach((NDManager) ctx.getAttachment("manager"));
+        return new SampleForecast(outputs, data.getStartTime(), this.freq);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDList processInput(TranslatorContext ctx, TimeSeriesData input) {
+        NDManager manager = ctx.getNDManager();
+        ctx.setAttachment("input", input);
+        ctx.setAttachment("manager", input.get(FieldName.TARGET).getManager());
+
+        List<FieldName> removeFieldNames = new ArrayList<>();
+        removeFieldNames.add(FieldName.FEAT_DYNAMIC_CAT);
+        if (!useFeatStaticReal) {
+            removeFieldNames.add(FieldName.FEAT_STATIC_REAL);
+        }
+        if (!useFeatDynamicReal) {
+            removeFieldNames.add(FieldName.FEAT_DYNAMIC_REAL);
+        }
+        Field.removeFields(removeFieldNames, input);
+
+        if (!useFeatStaticCat) {
+            Field.setField(FieldName.FEAT_STATIC_CAT, manager.zeros(new Shape(1)), input);
+        }
+
+        if (!useFeatStaticReal) {
+            Field.setField(FieldName.FEAT_STATIC_REAL, manager.zeros(new Shape(1)), input);
+        }
+
+        Feature.addObservedValuesIndicator(
+                manager, FieldName.TARGET, FieldName.OBSERVED_VALUES, input);
+
+        Feature.addTimeFeature(
+                manager,
+                FieldName.START,
+                FieldName.TARGET,
+                FieldName.FEAT_TIME,
+                timeFeatures,
+                predictionLength,
+                freq,
+                input);
+
+        Feature.addAgeFeature(
+                manager, FieldName.TARGET, FieldName.FEAT_AGE, predictionLength, input);
+
+        FieldName[] inputFields;
+        if (useFeatDynamicReal) {
+            inputFields = new FieldName[3];
+            inputFields[2] = FieldName.FEAT_DYNAMIC_REAL;
+        } else {
+            inputFields = new FieldName[2];
+        }
+        inputFields[0] = FieldName.FEAT_TIME;
+        inputFields[1] = FieldName.FEAT_AGE;
+        Convert.vstackFeatures(FieldName.FEAT_TIME, inputFields, input);
+
+        Split.instanceSplit(
+                manager,
+                FieldName.TARGET,
+                FieldName.IS_PAD,
+                FieldName.START,
+                FieldName.FORECAST_START,
+                instanceSampler,
+                historyLength,
+                predictionLength,
+                TIME_SERIES_FIELDS,
+                0,
+                input);
+
+        input = Field.selectField(PRED_INPUT_FIELDS, input);
+
+        return input.toNDList();
+    }
+
+    /**
+     * Creates a builder to build a {@code DeepARTranslator}.
+     *
+     * @return a new builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Creates a builder to build a {@code DeepARTranslator}.
+     *
+     * @param arguments the models' arguments
+     * @return a new builder
+     */
+    public static Builder builder(Map<String, ?> arguments) {
+        Builder builder = new Builder();
+
+        builder.configPreProcess(arguments);
+        builder.configPostProcess(arguments);
+
+        return builder;
+    }
+
+    /** The builder for DeepAR translator. */
+    public static class Builder extends BaseBuilder<Builder> {
+
+        // preProcess args
+        private boolean useFeatDynamicReal;
+        private boolean useFeatStaticReal;
+        private boolean useFeatStaticCat;
+
+        Builder() {}
+
+        @Override
+        protected Builder self() {
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected void configPreProcess(Map<String, ?> arguments) {
+            super.configPreProcess(arguments);
+            useFeatDynamicReal =
+                    ArgumentsUtil.booleanValue(
+                            arguments,
+                            "use_" + FieldName.FEAT_DYNAMIC_REAL.name().toLowerCase(),
+                            false);
+            useFeatStaticCat =
+                    ArgumentsUtil.booleanValue(
+                            arguments,
+                            "use_" + FieldName.FEAT_STATIC_CAT.name().toLowerCase(),
+                            false);
+            useFeatStaticReal =
+                    ArgumentsUtil.booleanValue(
+                            arguments,
+                            "use_" + FieldName.FEAT_STATIC_REAL.name().toLowerCase(),
+                            false);
+        }
+
+        /**
+         * Builds the translator.
+         *
+         * @return the new translator
+         */
+        public DeepARTranslator build() {
+            validate();
+            return new DeepARTranslator(this);
+        }
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslatorFactory.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslatorFactory.java
new file mode 100644
index 000000000..09d19fdf0
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/DeepARTranslatorFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.Model;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.translate.TranslateException;
+import ai.djl.translate.Translator;
+import ai.djl.translate.TranslatorFactory;
+import ai.djl.util.Pair;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/** A {@link TranslatorFactory} that creates a {@link DeepARTranslator} instance. */
+public class DeepARTranslatorFactory implements TranslatorFactory {
+
+    /** {@inheritDoc} */
+    @Override
+    public Set<Pair<Type, Type>> getSupportedTypes() {
+        return Collections.singleton(new Pair<>(TimeSeriesData.class, Forecast.class));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Translator<?, ?> newInstance(
+            Class<?> input, Class<?> output, Model model, Map<String, ?> arguments)
+            throws TranslateException {
+        if (!isSupported(input, output)) {
+            throw new IllegalArgumentException("Unsupported input/output types.");
+        }
+        return DeepARTranslator.builder(arguments).build();
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslator.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslator.java
new file mode 100644
index 000000000..3f1a418f7
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslator.java
@@ -0,0 +1,219 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.SampleForecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.timefeature.Lag;
+import ai.djl.timeseries.timefeature.TimeFeature;
+import ai.djl.timeseries.transform.InstanceSampler;
+import ai.djl.timeseries.transform.PredictionSplitSampler;
+import ai.djl.timeseries.transform.convert.Convert;
+import ai.djl.timeseries.transform.feature.Feature;
+import ai.djl.timeseries.transform.field.Field;
+import ai.djl.timeseries.transform.split.Split;
+import ai.djl.translate.ArgumentsUtil;
+import ai.djl.translate.Translator;
+import ai.djl.translate.TranslatorContext;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+/** The {@link Translator} for Transformer time series forecasting tasks. */
+public class TransformerTranslator extends BaseTimeSeriesTranslator {
+
+    private final boolean useFeatDynamicReal;
+    private final boolean useFeatStaticCat;
+
+    private int historyLength;
+
+    private static final String[] PRED_INPUT_FIELDS = {
+        FieldName.FEAT_STATIC_CAT.name(),
+        "PAST_" + FieldName.FEAT_TIME.name(),
+        "PAST_" + FieldName.TARGET.name(),
+        "PAST_" + FieldName.OBSERVED_VALUES.name(),
+        "FUTURE_" + FieldName.FEAT_TIME.name()
+    };
+    private static final FieldName[] TIME_SERIES_FIELDS = {
+        FieldName.FEAT_TIME, FieldName.OBSERVED_VALUES
+    };
+    private final List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures;
+
+    private final InstanceSampler instanceSampler;
+
+    /**
+     * Constructs a {@link TransformerTranslator} with {@link Builder}.
+     *
+     * @param builder the data to build with
+     */
+    public TransformerTranslator(Builder builder) {
+        super(builder);
+        this.useFeatDynamicReal = builder.useFeatDynamicReal;
+        this.useFeatStaticCat = builder.useFeatStaticCat;
+
+        List<Integer> lagsSeq = Lag.getLagsForFreq(freq);
+        this.timeFeatures = TimeFeature.timeFeaturesFromFreqStr(freq);
+        this.historyLength = contextLength + lagsSeq.get(lagsSeq.size() - 1);
+        this.instanceSampler = PredictionSplitSampler.newTestSplitSampler();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Forecast processOutput(TranslatorContext ctx, NDList list) {
+        NDArray outputs = list.singletonOrThrow();
+        TimeSeriesData data = (TimeSeriesData) ctx.getAttachment("input");
+        outputs.attach((NDManager) ctx.getAttachment("manager"));
+        return new SampleForecast(outputs, data.getStartTime(), this.freq);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public NDList processInput(TranslatorContext ctx, TimeSeriesData input) {
+        NDManager manager = ctx.getNDManager();
+        ctx.setAttachment("input", input);
+        ctx.setAttachment("manager", input.get(FieldName.TARGET).getManager());
+
+        List<FieldName> removeFieldNames = new ArrayList<>();
+        removeFieldNames.add(FieldName.FEAT_DYNAMIC_CAT);
+        removeFieldNames.add(FieldName.FEAT_STATIC_REAL);
+
+        if (!useFeatDynamicReal) {
+            removeFieldNames.add(FieldName.FEAT_DYNAMIC_REAL);
+        }
+        Field.removeFields(removeFieldNames, input);
+
+        if (!useFeatStaticCat) {
+            Field.setField(FieldName.FEAT_STATIC_CAT, manager.zeros(new Shape(1)), input);
+        }
+
+        Feature.addObservedValuesIndicator(
+                manager, FieldName.TARGET, FieldName.OBSERVED_VALUES, input);
+
+        Feature.addTimeFeature(
+                manager,
+                FieldName.START,
+                FieldName.TARGET,
+                FieldName.FEAT_TIME,
+                timeFeatures,
+                predictionLength,
+                freq,
+                input);
+
+        Feature.addAgeFeature(
+                manager, FieldName.TARGET, FieldName.FEAT_AGE, predictionLength, input);
+
+        FieldName[] inputFields;
+        if (useFeatDynamicReal) {
+            inputFields = new FieldName[3];
+            inputFields[2] = FieldName.FEAT_DYNAMIC_REAL;
+        } else {
+            inputFields = new FieldName[2];
+        }
+        inputFields[0] = FieldName.FEAT_TIME;
+        inputFields[1] = FieldName.FEAT_AGE;
+        Convert.vstackFeatures(FieldName.FEAT_TIME, inputFields, input);
+
+        Split.instanceSplit(
+                manager,
+                FieldName.TARGET,
+                FieldName.IS_PAD,
+                FieldName.START,
+                FieldName.FORECAST_START,
+                instanceSampler,
+                historyLength,
+                predictionLength,
+                TIME_SERIES_FIELDS,
+                0,
+                input);
+
+        input = Field.selectField(PRED_INPUT_FIELDS, input);
+
+        return input.toNDList();
+    }
+
+    /**
+     * Creates a builder to build a {@code TransformerTranslator}.
+     *
+     * @return a new builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Creates a builder to build a {@code TransformerTranslator}.
+     *
+     * @param arguments the models' arguments
+     * @return a new builder
+     */
+    public static Builder builder(Map<String, ?> arguments) {
+        Builder builder = new Builder();
+
+        builder.configPreProcess(arguments);
+        builder.configPostProcess(arguments);
+
+        return builder;
+    }
+
+    /** The builder for Transformer translator. */
+    public static class Builder extends BaseBuilder<Builder> {
+
+        // preProcess args
+        private boolean useFeatDynamicReal;
+        private boolean useFeatStaticCat;
+
+        // postProcess args
+
+        Builder() {}
+
+        @Override
+        protected Builder self() {
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected void configPreProcess(Map<String, ?> arguments) {
+            super.configPreProcess(arguments);
+            this.useFeatDynamicReal =
+                    ArgumentsUtil.booleanValue(
+                            arguments,
+                            "use_" + FieldName.FEAT_DYNAMIC_REAL.name().toLowerCase(),
+                            false);
+            this.useFeatStaticCat =
+                    ArgumentsUtil.booleanValue(
+                            arguments,
+                            "use_" + FieldName.FEAT_STATIC_CAT.name().toLowerCase(),
+                            false);
+        }
+
+        /**
+         * Builds the translator.
+         *
+         * @return the new translator
+         */
+        public TransformerTranslator build() {
+            validate();
+            return new TransformerTranslator(this);
+        }
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslatorFactory.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslatorFactory.java
new file mode 100644
index 000000000..e80a8f59b
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/TransformerTranslatorFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.Model;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.translate.TranslateException;
+import ai.djl.translate.Translator;
+import ai.djl.translate.TranslatorFactory;
+import ai.djl.util.Pair;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/** A {@link TranslatorFactory} that creates a {@link DeepARTranslator} instance. */
+public class TransformerTranslatorFactory implements TranslatorFactory {
+
+    /** {@inheritDoc} */
+    @Override
+    public Set<Pair<Type, Type>> getSupportedTypes() {
+        return Collections.singleton(new Pair<>(TimeSeriesData.class, Forecast.class));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Translator<?, ?> newInstance(
+            Class<?> input, Class<?> output, Model model, Map<String, ?> arguments)
+            throws TranslateException {
+        if (!isSupported(input, output)) {
+            throw new IllegalArgumentException("Unsupported input/output types.");
+        }
+        return TransformerTranslator.builder(arguments).build();
+    }
+}
diff --git a/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/package-info.java b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/package-info.java
new file mode 100644
index 000000000..5bf070b3f
--- /dev/null
+++ b/extensions/timeseries/src/main/java/ai/djl/timeseries/translator/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains translators for TimeSeries models inference. */
+package ai.djl.timeseries.translator;
diff --git a/settings.gradle b/settings.gradle
index 7f842d39f..033748949 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -35,6 +35,7 @@ include ':extensions:opencv'
 include ':extensions:sentencepiece'
 include ':extensions:tokenizers'
 include ':extensions:tablesaw'
+include ':extensions:timeseries'
 include ':integration'
 include ':model-zoo'
 include ':testing'
diff --git a/tools/gradle/publish.gradle b/tools/gradle/publish.gradle
index 55853f73c..23afe8041 100644
--- a/tools/gradle/publish.gradle
+++ b/tools/gradle/publish.gradle
@@ -25,6 +25,7 @@ configure([
         project(':extensions:opencv'),
         project(':extensions:sentencepiece'),
         project(':extensions:tablesaw'),
+        project(':extensions:timeseries'),
         project(':extensions:tokenizers'),
         project(':model-zoo')]) {
     apply plugin: "maven-publish"


Test patch:
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/TimeFeatureTest.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/TimeFeatureTest.java
new file mode 100644
index 000000000..3f8789180
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/TimeFeatureTest.java
@@ -0,0 +1,15 @@
+/*
+ * 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.timeseries.timefeature;
+
+public class TimeFeatureTest {}
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/package-info.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/package-info.java
new file mode 100644
index 000000000..df2cb8917
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/timefeature/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains tests for the timeFeature module. */
+package ai.djl.timeseries.timefeature;
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/TransformTest.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/TransformTest.java
new file mode 100644
index 000000000..8e521f048
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/TransformTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.timeseries.transform;
+
+import ai.djl.Device;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.index.NDIndex;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.timeseries.timefeature.TimeFeature;
+import ai.djl.timeseries.transform.convert.Convert;
+import ai.djl.timeseries.transform.feature.Feature;
+import ai.djl.timeseries.transform.field.Field;
+import ai.djl.timeseries.transform.split.Split;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiFunction;
+
+public class TransformTest {
+
+    @Test
+    public void testVstackFeatures() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+            input.setField(FieldName.FEAT_STATIC_REAL, manager.create(new Shape(1, 2, 3)));
+            input.setField(FieldName.FEAT_STATIC_CAT, manager.create(new Shape(2, 2, 3)));
+            FieldName[] inputFields = {FieldName.FEAT_STATIC_REAL, FieldName.FEAT_STATIC_CAT};
+            Convert.vstackFeatures(FieldName.FEAT_TIME, inputFields, input);
+            Assert.assertTrue(input.contains(FieldName.FEAT_TIME.name()));
+            Assert.assertEquals(input.get(FieldName.FEAT_TIME).getShape(), new Shape(3, 2, 3));
+        }
+    }
+
+    @Test
+    public void testAddObservedValuesIndicator() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+            NDArray target = manager.zeros(new Shape(2, 3));
+            target.set(new NDIndex("0, 0"), Float.NaN);
+            input.setField(FieldName.TARGET, target);
+
+            Feature.addObservedValuesIndicator(
+                    manager, FieldName.TARGET, FieldName.FEAT_TIME, input);
+            Assert.assertTrue(input.contains(FieldName.FEAT_TIME.name()));
+            Assert.assertEquals(
+                    input.get(FieldName.TARGET).get("0, 0").toFloatArray()[0], 0.f, 1e-3f);
+            Assert.assertEquals(
+                    input.get(FieldName.FEAT_TIME).get("0, 0").toFloatArray()[0], 0.f, 1e-3f);
+        }
+    }
+
+    @Test
+    public void testAddTimeFeature() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+            List<BiFunction<NDManager, List<LocalDateTime>, NDArray>> timeFeatures =
+                    TimeFeature.timeFeaturesFromFreqStr("D");
+
+            input.setStartTime(LocalDateTime.parse("2011-01-29T00:00"));
+            input.setField(FieldName.TARGET, manager.ones(new Shape(32, 48)));
+            Feature.addTimeFeature(
+                    manager,
+                    FieldName.START,
+                    FieldName.TARGET,
+                    FieldName.FEAT_AGE,
+                    timeFeatures,
+                    28,
+                    "D",
+                    input);
+
+            NDArray array = input.get(FieldName.FEAT_AGE);
+            Assert.assertEquals(array.getShape(), new Shape(3, 76));
+            Assert.assertEquals(array.get("0, 0").toFloatArray()[0], 0.3333f, 1e-4f);
+            Assert.assertEquals(array.get("1, 0").toFloatArray()[0], 0.4333f, 1e-4f);
+            Assert.assertEquals(array.get("2, 0").toFloatArray()[0], -0.4233f, 1e-4f);
+        }
+    }
+
+    @Test
+    public void testAddAgeFeature() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+
+            input.setField(FieldName.TARGET, manager.ones(new Shape(32, 48)));
+            Feature.addAgeFeature(manager, FieldName.TARGET, FieldName.FEAT_AGE, 28, input);
+
+            NDArray array = input.get(FieldName.FEAT_AGE);
+            Assert.assertEquals(array.get("0, 0").toFloatArray()[0], 0.30103f, 1e-5f);
+            Assert.assertEquals(array.getShape(), new Shape(1, 76));
+        }
+    }
+
+    @Test
+    public void testRemoveFields() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+
+            NDArray array = manager.ones(new Shape(2, 3));
+            input.setField(FieldName.TARGET, array);
+            input.setField(FieldName.FEAT_AGE, array);
+            input.setField(FieldName.FEAT_TIME, array);
+
+            List<FieldName> removeFields = Arrays.asList(FieldName.FEAT_AGE, FieldName.FEAT_TIME);
+            Field.removeFields(removeFields, input);
+
+            Assert.assertTrue(input.contains(FieldName.TARGET.name()));
+            Assert.assertFalse(input.contains(FieldName.FEAT_AGE.name()));
+            Assert.assertFalse(input.contains(FieldName.FEAT_TIME.name()));
+        }
+    }
+
+    @Test
+    public void testSetFields() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+
+            NDArray array = manager.ones(new Shape(2, 3));
+            Field.setField(FieldName.TARGET, array, input);
+
+            Assert.assertTrue(input.contains(FieldName.TARGET.name()));
+            Assert.assertEquals(input.get(FieldName.TARGET), array);
+        }
+    }
+
+    @Test
+    public void testSelectFields() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+
+            NDArray array = manager.ones(new Shape(1));
+            NDArray array1 = manager.ones(new Shape(2));
+            NDArray array2 = manager.ones(new Shape(3));
+            input.setField(FieldName.TARGET, array);
+            input.setField(FieldName.FEAT_AGE, array1);
+            input.setField(FieldName.FEAT_TIME, array2);
+
+            String[] fields = {FieldName.FEAT_TIME.name(), FieldName.FEAT_AGE.name()};
+            input = Field.selectField(fields, input);
+
+            Assert.assertEquals(input.size(), 2);
+            Assert.assertEquals(input.valueAt(0).getShape(), new Shape(3));
+            Assert.assertEquals(input.valueAt(1).getShape(), new Shape(2));
+        }
+    }
+
+    @Test
+    public void testInstanceSplit() {
+        try (NDManager manager = NDManager.newBaseManager(Device.cpu())) {
+            TimeSeriesData input = new TimeSeriesData(10);
+
+            NDArray array = manager.ones(new Shape(32, 48));
+            input.setField(FieldName.TARGET, array);
+            input.setField(FieldName.FEAT_TIME, manager.ones(new Shape(32, 700)));
+            input.setField(FieldName.OBSERVED_VALUES, manager.ones(new Shape(32, 400)));
+            input.setStartTime(LocalDateTime.parse("2011-01-29T00:00"));
+
+            Split.instanceSplit(
+                    manager,
+                    FieldName.TARGET,
+                    FieldName.IS_PAD,
+                    FieldName.START,
+                    FieldName.FORECAST_START,
+                    PredictionSplitSampler.newTestSplitSampler(),
+                    30,
+                    28,
+                    new FieldName[] {FieldName.FEAT_TIME, FieldName.OBSERVED_VALUES},
+                    0f,
+                    input);
+
+            Assert.assertTrue(input.contains("PAST_" + FieldName.FEAT_TIME));
+            Assert.assertTrue(input.contains("FUTURE_" + FieldName.FEAT_TIME));
+            Assert.assertTrue(input.contains("PAST_" + FieldName.OBSERVED_VALUES));
+            Assert.assertTrue(input.contains("FUTURE_" + FieldName.OBSERVED_VALUES));
+            Assert.assertTrue(input.contains("PAST_" + FieldName.TARGET));
+            Assert.assertTrue(input.contains("FUTURE_" + FieldName.TARGET));
+
+            Assert.assertEquals(
+                    input.get("PAST_" + FieldName.FEAT_TIME).getShape(), new Shape(30, 32));
+            Assert.assertEquals(
+                    input.get("FUTURE_" + FieldName.FEAT_TIME).getShape(), new Shape(28, 32));
+            Assert.assertEquals(
+                    input.get("PAST_" + FieldName.OBSERVED_VALUES).getShape(), new Shape(30, 32));
+            Assert.assertEquals(
+                    input.get("FUTURE_" + FieldName.OBSERVED_VALUES).getShape(), new Shape(28, 32));
+            Assert.assertEquals(
+                    input.get("PAST_" + FieldName.TARGET).getShape(), new Shape(30, 32));
+            Assert.assertEquals(
+                    input.get("FUTURE_" + FieldName.TARGET).getShape(), new Shape(0, 32));
+            Assert.assertEquals(
+                    input.getForecastStartTime(), LocalDateTime.parse("2011-03-18T00:00"));
+        }
+    }
+}
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/package-info.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/package-info.java
new file mode 100644
index 000000000..905689350
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/transform/package-info.java
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+/** Contains tests for the TimeSeries timeFeature module. */
+package ai.djl.timeseries.transform;
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/DeepARTranslatorTest.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/DeepARTranslatorTest.java
new file mode 100644
index 000000000..8e64746ba
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/DeepARTranslatorTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.ModelException;
+import ai.djl.inference.Predictor;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ZooModel;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.training.util.ProgressBar;
+import ai.djl.translate.TranslateException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DeepARTranslatorTest {
+
+    @Test
+    public void testDeepARTranslator() throws IOException, TranslateException, ModelException {
+        String modelUrl = "https://resources.djl.ai/test-models/mxnet/timeseries/deepar.zip";
+        Map<String, Object> arguments = new ConcurrentHashMap<>();
+        arguments.put("prediction_length", 28);
+        DeepARTranslator.Builder builder = DeepARTranslator.builder(arguments);
+        DeepARTranslator translator = builder.build();
+        Criteria<TimeSeriesData, Forecast> criteria =
+                Criteria.builder()
+                        .setTypes(TimeSeriesData.class, Forecast.class)
+                        .optModelUrls(modelUrl)
+                        .optTranslator(translator)
+                        .optProgress(new ProgressBar())
+                        .build();
+
+        try (NDManager manager = NDManager.newBaseManager()) {
+            manager.getEngine().setRandomSeed(1);
+            NDArray target = manager.randomUniform(0f, 50f, new Shape(1857));
+
+            TimeSeriesData input = new TimeSeriesData(1);
+            input.setStartTime(LocalDateTime.parse("2011-01-29T00:00"));
+            input.setField(FieldName.TARGET, target);
+
+            try (ZooModel<TimeSeriesData, Forecast> model = criteria.loadModel();
+                    Predictor<TimeSeriesData, Forecast> predictor = model.newPredictor()) {
+                Forecast forecast = predictor.predict(input);
+                // TODO: forecast is random???
+                Assert.assertEquals(forecast.mean().toFloatArray().length, 28);
+            }
+        }
+    }
+}
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/TransformerTranslatorTest.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/TransformerTranslatorTest.java
new file mode 100644
index 000000000..e12af5150
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/TransformerTranslatorTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.timeseries.translator;
+
+import ai.djl.ModelException;
+import ai.djl.inference.Predictor;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ZooModel;
+import ai.djl.timeseries.Forecast;
+import ai.djl.timeseries.TimeSeriesData;
+import ai.djl.timeseries.dataset.FieldName;
+import ai.djl.training.util.ProgressBar;
+import ai.djl.translate.TranslateException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class TransformerTranslatorTest {
+
+    @Test
+    public void testTransformerTranslator() throws IOException, TranslateException, ModelException {
+        String modelUrl = "https://resources.djl.ai/test-models/mxnet/timeseries/transformer.zip";
+        Map<String, Object> arguments = new ConcurrentHashMap<>();
+        arguments.put("prediction_length", 28);
+        TransformerTranslator.Builder builder = TransformerTranslator.builder(arguments);
+        TransformerTranslator translator = builder.build();
+        Criteria<TimeSeriesData, Forecast> criteria =
+                Criteria.builder()
+                        .setTypes(TimeSeriesData.class, Forecast.class)
+                        .optModelUrls(modelUrl)
+                        .optTranslator(translator)
+                        .optProgress(new ProgressBar())
+                        .build();
+
+        try (NDManager manager = NDManager.newBaseManager()) {
+            manager.getEngine().setRandomSeed(1);
+            NDArray target = manager.randomUniform(0f, 50f, new Shape(1857));
+            TimeSeriesData input = new TimeSeriesData(1);
+            input.setStartTime(LocalDateTime.parse("2011-01-29T00:00"));
+            input.setField(FieldName.TARGET, target);
+
+            try (ZooModel<TimeSeriesData, Forecast> model = criteria.loadModel();
+                    Predictor<TimeSeriesData, Forecast> predictor = model.newPredictor()) {
+                Forecast forecast = predictor.predict(input);
+                // TODO: forecast is random???
+                Assert.assertEquals(forecast.mean().toFloatArray().length, 28);
+            }
+        }
+    }
+}
diff --git a/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/package-info.java b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/package-info.java
new file mode 100644
index 000000000..78807fb0b
--- /dev/null
+++ b/extensions/timeseries/src/test/java/ai/djl/timeseries/translator/package-info.java
@@ -0,0 +1,13 @@
+/*
+ * 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.timeseries.translator;