Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3e5f277
added eclipse folders to .gitignore file
ebamberg Dec 17, 2020
a9f7143
added eclipse folders to .gitignore file
ebamberg Dec 17, 2020
efc166a
Merge branch 'master' of https://github.com/ebamberg/djl into master
ebamberg Jan 6, 2021
0412cd2
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 7, 2021
5a55059
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 11, 2021
5f6f27b
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 11, 2021
9396d5d
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 14, 2021
bc38adf
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 21, 2021
1f5e926
Merge remote-tracking branch 'upstream/master' into master
ebamberg Jan 22, 2021
08ced42
Merge remote-tracking branch 'upstream/master' into master
ebamberg Feb 1, 2021
449b0fb
Merge remote-tracking branch 'upstream/master' into master
ebamberg Feb 2, 2021
3309895
Merge remote-tracking branch 'upstream/master' into master
ebamberg Feb 11, 2021
e0ad5f0
Merge remote-tracking branch 'upstream/master' into master
ebamberg Feb 23, 2021
df4fe38
Merge remote-tracking branch 'upstream/master' into master
ebamberg Mar 11, 2021
b1c915b
Merge remote-tracking branch 'upstream/master' into master
ebamberg Mar 15, 2021
8558438
Merge remote-tracking branch 'upstream/master' into master
ebamberg Mar 30, 2021
643a80a
Merge remote-tracking branch 'upstream/master' into master
ebamberg Apr 5, 2021
3809207
Merge remote-tracking branch 'upstream/master' into master
ebamberg Apr 16, 2021
2173dbb
Merge remote-tracking branch 'upstream/master' into master
ebamberg Apr 20, 2021
6d1e12f
Merge remote-tracking branch 'upstream/master' into master
ebamberg Apr 28, 2021
dd97db0
Merge remote-tracking branch 'upstream/master' into master
ebamberg May 26, 2021
4d40afd
[api] added MinMaxScaler
ebamberg May 28, 2021
424c485
[api] added MinMaxScaler - fixed some comments
ebamberg May 28, 2021
b53a61a
Minor javaodc changes
frankfliu May 30, 2021
ffa9b0d
[api] added detach-function to minmaxscaler
ebamberg Jun 1, 2021
c13e322
Fix spotbugs warnings.
frankfliu Jun 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions api/src/main/java/ai/djl/training/util/MinMaxScaler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/*
* Copyright 2021 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.training.util;

import ai.djl.ndarray.NDArray;

/**
* Transform arrays by scaling each value to a given range. The desired range of transformed data
* can be set using {@code optRange}. the range defaults to 0...1.
*
* <p>After fitting the scaler the fitted values are attached to the same NDManager as the input
* array.
*
* @author [email protected]
*/
public class MinMaxScaler implements AutoCloseable {

private NDArray fittedMin;
private NDArray fittedMax;
private NDArray fittedRange;
private float minRange;
private float maxRange = 1f;
private boolean detached;

/**
* Computes the minimum and maximum to be used for later scaling.
*
* <p>After fitting the scaler the fitted values are attached to the same NDManager as the input
* array. reusing the minMaxScaler in the context of other NDManager's is possible by {@code
* detach()} the scaler from the NDManager.
*
* @param data used to compute the minimum and maximum used for later scaling
* @param axises minimum maximum computation along this axises
* @return the fitted MinMaxScaler
*/
public MinMaxScaler fit(NDArray data, int[] axises) {
fittedMin = data.min(axises);
fittedMax = data.max(axises);
fittedRange = fittedMax.sub(fittedMin);
if (detached) {
detach();
}
return this;
}

/**
* Computes the minimum and maximum to be used for later scaling.
*
* <p>After fitting the scaler the fitted values are attached to the same NDManager as the input
* array. reusing the minMaxScaler in the context of other NDManager's is possible by {@code
* detach()} the scaler from the NDManager.
*
* @param data used to compute the minimum and maximum used for later scaling
* @return the fitted MinMaxScaler
*/
public MinMaxScaler fit(NDArray data) {
fit(data, new int[] {0});
return this;
}

/**
* Transforms the data using the previous calculated minimum and maximum.
*
* <p>if {@code fit()} is not executed yet, then the minimum/maximum is computer based on the
* input data array and used for later computations. X_std = (X - X.min(axis=0)) /
* (X.max(axis=0) - X.min(axis=0)) X_scaled = X_std * (max - min) + min
*
* @param data to get transformed
* @return the transformed data, the input array is not changed
*/
public NDArray transform(NDArray data) {
if (fittedRange == null) {
fit(data, new int[] {0});
}
NDArray std = data.sub(fittedMin).divi(fittedRange);
return scale(std);
}

/**
* Transforms the data in-place using the previous calculated minimum and maximum.
*
* <p>if {@code fit()} is not called before then the minimum/maximum is computer based on the
* input data array and used for later computations. X_std = (X - X.min(axis=0)) /
* (X.max(axis=0) - X.min(axis=0)) X_scaled = X_std * (max - min) + min
*
* @param data to get transformed
* @return the transformed data (reference to the input data) the input array is changed
* in-place by this operation
*/
public NDArray transformi(NDArray data) {
if (fittedRange == null) {
fit(data, new int[] {0});
}
NDArray std = data.subi(fittedMin).divi(fittedRange);
return scale(std);
}

/**
* Scales array from std if range is not default range otherwise return the unchanged array.
*
* <p>this is an in-place operation.
*
* @param std input array to scale
* @return scaled array
*/
private NDArray scale(NDArray std) {
// we don't have to scale by custom range when range is default 0..1
if (maxRange != 1f || minRange != 0f) {
return std.muli(maxRange - minRange).addi(minRange);
}
return std;
}

/**
* Inverses scale array from std if range is not default range otherwise return the unchanged
* array as a duplicate.
*
* @param std input array to scale
* @return re-scaled array
*/
private NDArray inverseScale(NDArray std) {
// we don't have to scale by custom range when range is default 0..1
if (maxRange != 1f || minRange != 0f) {
return std.sub(minRange).divi(maxRange - minRange);
}
return std.duplicate();
}

/**
* Inverses scale array from std if range is not default range otherwise return the array
* itself.
*
* <p>this is an in-place operation.
*
* @param std input array to scale in-place
* @return re-scaled array
*/
private NDArray inverseScalei(NDArray std) {
// we don't have to scale by custom range when range is default 0..1
if (maxRange != 1f || minRange != 0f) {
return std.subi(minRange).divi(maxRange - minRange);
}
return std;
}

/**
* Undoes the transformation of X according to feature_range.
*
* @param data to get transformed
* @return the transformed array
*/
public NDArray inverseTransform(NDArray data) {
throwsIllegalStateWhenNotFitted();
NDArray result = inverseScale(data);
return result.muli(fittedRange).addi(fittedMin);
}

/**
* Undoes the transformation of X according to feature_range as an in-place operation.
*
* @param data to get transformed, the data get changed in-place
* @return the transformed array
*/
public NDArray inverseTransformi(NDArray data) {
throwsIllegalStateWhenNotFitted();
NDArray result = inverseScalei(data);
return result.muli(fittedRange).addi(fittedMin);
}

/**
* Checks if this MinMaxScaler is already fitted and throws exception otherwise.
*
* @throws IllegalStateException when not Fitted
*/
private void throwsIllegalStateWhenNotFitted() {
if (fittedRange == null) {
throw new IllegalStateException("Min Max Scaler is not fitted");
}
}

/**
* Detaches this MinMaxScaler fitted value from current NDManager's lifecycle.
*
* <p>this becomes un-managed and it is the user's responsibility to close this. Failure to
* close the resource might cause your machine to run out of native memory.
*
* <p>After fitting the scaler the fitted values are attached to the same NDManager as the input
* array.
*
* <p>Re-fitting the scaler after detaching doesn't re-attach the scaler to any NDManager.
*
* @return the detached MinMaxScaler (itself) - to use as a fluent API
*/
public MinMaxScaler detach() {
detached = true;
if (fittedMin != null) {
fittedMin.detach();
}
if (fittedMax != null) {
fittedMax.detach();
}
if (fittedRange != null) {
fittedRange.detach();
}
return this;
}

/**
* Sets desired range of transformed data.
*
* @param minRange min value for desired range
* @param maxRange max value for desired range
* @return the configured MinMaxScaler
*/
public MinMaxScaler optRange(float minRange, float maxRange) {
this.minRange = minRange;
this.maxRange = maxRange;
return this;
}

/**
* Returns the value of fittedMin.
*
* @return the fittedMin value
*/
public NDArray getMin() {
throwsIllegalStateWhenNotFitted();
return fittedMin;
}

/**
* Returns the value of fittedMax.
*
* @return the fittedMax value
*/
public NDArray getMax() {
throwsIllegalStateWhenNotFitted();
return fittedMax;
}

/** {@inheritDoc} */
@Override
public void close() {
if (fittedMin != null) {
fittedMin.close();
}
if (fittedMax != null) {
fittedMax.close();
}
if (fittedRange != null) {
fittedRange.close();
}
}
}
Loading