diff --git a/tensorflow-core/tensorflow-core-api/src/bazel/op_generator/java_defs.h b/tensorflow-core/tensorflow-core-api/src/bazel/op_generator/java_defs.h index ee1b88ca5f3..e41dc2dd9df 100644 --- a/tensorflow-core/tensorflow-core-api/src/bazel/op_generator/java_defs.h +++ b/tensorflow-core/tensorflow-core-api/src/bazel/op_generator/java_defs.h @@ -110,8 +110,12 @@ class Type { return Class("TFloat32", "org.tensorflow.types"); case DataType::DT_DOUBLE: return Class("TFloat64", "org.tensorflow.types"); + case DataType::DT_HALF: + return Class("TFloat16", "org.tensorflow.types"); + case DataType::DT_BFLOAT16: + return Class("TBfloat16", "org.tensorflow.types"); case DataType::DT_UINT8: - return Class("TUInt8", "org.tensorflow.types"); + return Class("TUint8", "org.tensorflow.types"); case DataType::DT_INT32: return Class("TInt32", "org.tensorflow.types"); case DataType::DT_INT64: diff --git a/tensorflow-core/tensorflow-core-api/src/gen/annotations/org/tensorflow/op/ImageOps.java b/tensorflow-core/tensorflow-core-api/src/gen/annotations/org/tensorflow/op/ImageOps.java index 2fb80f519ba..a91c8017ce2 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/annotations/org/tensorflow/op/ImageOps.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/annotations/org/tensorflow/op/ImageOps.java @@ -38,7 +38,7 @@ import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TNumber; import org.tensorflow.types.family.TType; @@ -184,6 +184,18 @@ public RandomCrop randomCrop(Operand image, Operand decodePng(Operand contents, DecodePng.Options... options) { + return DecodePng.create(scope, contents, options); + } + /** * Builds an {@link DecodeAndCropJpeg} operation * @@ -296,19 +308,6 @@ public CombinedNonMaxSuppression combinedNonMaxSuppression(Operand box return CombinedNonMaxSuppression.create(scope, boxes, scores, maxOutputSizePerClass, maxTotalSize, iouThreshold, scoreThreshold, options); } - /** - * Builds an {@link EncodeJpegVariableQuality} operation - * - * @param images Images to adjust. At least 3-D. - * @param quality An int quality to encode to. - * @return a new instance of EncodeJpegVariableQuality - * @see org.tensorflow.op.image.EncodeJpegVariableQuality - */ - public EncodeJpegVariableQuality encodeJpegVariableQuality(Operand images, - Operand quality) { - return EncodeJpegVariableQuality.create(scope, images, quality); - } - /** * Builds an {@link CropAndResizeGradBoxes} operation * @@ -352,6 +351,19 @@ public EncodePng encodePng(Operand image, EncodePng.Optio return EncodePng.create(scope, image, options); } + /** + * Builds an {@link EncodeJpegVariableQuality} operation + * + * @param images Images to adjust. At least 3-D. + * @param quality An int quality to encode to. + * @return a new instance of EncodeJpegVariableQuality + * @see org.tensorflow.op.image.EncodeJpegVariableQuality + */ + public EncodeJpegVariableQuality encodeJpegVariableQuality(Operand images, + Operand quality) { + return EncodeJpegVariableQuality.create(scope, images, quality); + } + /** * Builds an {@link ScaleAndTranslate} operation * @@ -383,18 +395,6 @@ public DrawBoundingBoxes drawBoundingBoxes(Operand ima return DrawBoundingBoxes.create(scope, images, boxes, colors); } - /** - * Builds an {@link DecodePng} operation - * - * @param contents 0-D. The PNG-encoded image. - * @param options carries optional attributes values - * @return a new instance of DecodePng - * @see org.tensorflow.op.image.DecodePng - */ - public DecodePng decodePng(Operand contents, DecodePng.Options... options) { - return DecodePng.create(scope, contents, options); - } - /** * Builds an {@link ResizeNearestNeighbor} operation * @@ -467,18 +467,6 @@ public CropAndResizeGradImage cropAndResizeGradImage( return CropAndResizeGradImage.create(scope, grads, boxes, boxInd, imageSize, T, options); } - /** - * Builds an {@link EncodeJpeg} operation - * - * @param image 3-D with shape `[height, width, channels]`. - * @param options carries optional attributes values - * @return a new instance of EncodeJpeg - * @see org.tensorflow.op.image.EncodeJpeg - */ - public EncodeJpeg encodeJpeg(Operand image, EncodeJpeg.Options... options) { - return EncodeJpeg.create(scope, image, options); - } - /** * Builds an {@link DecodeJpeg} operation * @@ -491,6 +479,18 @@ public DecodeJpeg decodeJpeg(Operand contents, DecodeJpeg.Options... op return DecodeJpeg.create(scope, contents, options); } + /** + * Builds an {@link EncodeJpeg} operation + * + * @param image 3-D with shape `[height, width, channels]`. + * @param options carries optional attributes values + * @return a new instance of EncodeJpeg + * @see org.tensorflow.op.image.EncodeJpeg + */ + public EncodeJpeg encodeJpeg(Operand image, EncodeJpeg.Options... options) { + return EncodeJpeg.create(scope, image, options); + } + /** * Builds an {@link ExtractGlimpse} operation * diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/core/Fingerprint.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/core/Fingerprint.java index 848c1c4e422..4b98a65076c 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/core/Fingerprint.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/core/Fingerprint.java @@ -25,7 +25,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TType; /** @@ -61,7 +61,7 @@ * Fingerprint(ReduceJoin(data))` in general. */ @Operator -public final class Fingerprint extends PrimitiveOp implements Operand { +public final class Fingerprint extends PrimitiveOp implements Operand { /** * Factory method to create a class wrapping a new Fingerprint operation. @@ -85,16 +85,16 @@ public static Fingerprint create(Scope scope, Operand data, * `data`'s first dimension, and the second dimension size depends on the * fingerprint algorithm. */ - public Output fingerprint() { + public Output fingerprint() { return fingerprint; } @Override - public Output asOutput() { + public Output asOutput() { return fingerprint; } - private Output fingerprint; + private Output fingerprint; private Fingerprint(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeAndCropJpeg.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeAndCropJpeg.java index 8f8ecec8052..6bc533ff7c9 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeAndCropJpeg.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeAndCropJpeg.java @@ -26,7 +26,7 @@ import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TInt32; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * Decode and Crop a JPEG-encoded image to a uint8 tensor. @@ -57,7 +57,7 @@ * decoding partial jpeg image. */ @Operator(group = "image") -public final class DecodeAndCropJpeg extends PrimitiveOp implements Operand { +public final class DecodeAndCropJpeg extends PrimitiveOp implements Operand { /** * Optional attributes for {@link org.tensorflow.op.image.DecodeAndCropJpeg} @@ -221,16 +221,16 @@ public static Options dctMethod(String dctMethod) { /** * 3-D with shape `[height, width, channels]`.. */ - public Output image() { + public Output image() { return image; } @Override - public Output asOutput() { + public Output asOutput() { return image; } - private Output image; + private Output image; private DecodeAndCropJpeg(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeBmp.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeBmp.java index 18b16ffcf7f..2cfd11c868f 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeBmp.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeBmp.java @@ -25,7 +25,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * Decode the first frame of a BMP-encoded image to a uint8 tensor. @@ -45,7 +45,7 @@ * 4: output an RGBA image. */ @Operator(group = "image") -public final class DecodeBmp extends PrimitiveOp implements Operand { +public final class DecodeBmp extends PrimitiveOp implements Operand { /** * Optional attributes for {@link org.tensorflow.op.image.DecodeBmp} @@ -98,16 +98,16 @@ public static Options channels(Long channels) { /** * 3-D with shape `[height, width, channels]`. RGB order */ - public Output image() { + public Output image() { return image; } @Override - public Output asOutput() { + public Output asOutput() { return image; } - private Output image; + private Output image; private DecodeBmp(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeGif.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeGif.java index 0042ffeac39..2d06b3f3404 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeGif.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeGif.java @@ -25,7 +25,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * Decode the frame(s) of a GIF-encoded image to a uint8 tensor. @@ -40,7 +40,7 @@ * `tf.image.decode_image`. */ @Operator(group = "image") -public final class DecodeGif extends PrimitiveOp implements Operand { +public final class DecodeGif extends PrimitiveOp implements Operand { /** * Factory method to create a class wrapping a new DecodeGif operation. @@ -59,16 +59,16 @@ public static DecodeGif create(Scope scope, Operand contents) { /** * 4-D with shape `[num_frames, height, width, 3]`. RGB channel order. */ - public Output image() { + public Output image() { return image; } @Override - public Output asOutput() { + public Output asOutput() { return image; } - private Output image; + private Output image; private DecodeGif(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeJpeg.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeJpeg.java index b0ff7c262f5..2aff38ebef7 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeJpeg.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodeJpeg.java @@ -25,7 +25,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * Decode a JPEG-encoded image to a uint8 tensor. @@ -56,7 +56,7 @@ * the same, though it is cleaner to use `tf.image.decode_image`. */ @Operator(group = "image") -public final class DecodeJpeg extends PrimitiveOp implements Operand { +public final class DecodeJpeg extends PrimitiveOp implements Operand { /** * Optional attributes for {@link org.tensorflow.op.image.DecodeJpeg} @@ -218,16 +218,16 @@ public static Options dctMethod(String dctMethod) { /** * 3-D with shape `[height, width, channels]`.. */ - public Output image() { + public Output image() { return image; } @Override - public Output asOutput() { + public Output asOutput() { return image; } - private Output image; + private Output image; private DecodeJpeg(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodePng.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodePng.java index 4fec82ea5ec..b340ca12016 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodePng.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/DecodePng.java @@ -26,7 +26,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TNumber; import org.tensorflow.types.family.TType; @@ -113,8 +113,8 @@ public static DecodePng create(Scope scope, Operand create(Scope scope, Operand contents, Options... options) { - return create(scope, contents, TUInt8.DTYPE, options); + public static DecodePng create(Scope scope, Operand contents, Options... options) { + return create(scope, contents, TUint8.DTYPE, options); } /** diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpeg.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpeg.java index 2063a7a10b2..cddf6a02066 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpeg.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpeg.java @@ -25,7 +25,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * JPEG-encode an image. @@ -159,7 +159,7 @@ private Options() { * @param options carries optional attributes values * @return a new instance of EncodeJpeg */ - public static EncodeJpeg create(Scope scope, Operand image, Options... options) { + public static EncodeJpeg create(Scope scope, Operand image, Options... options) { OperationBuilder opBuilder = scope.env().opBuilder("EncodeJpeg", scope.makeOpName("EncodeJpeg")); opBuilder.addInput(image.asOutput()); opBuilder = scope.applyControlDependencies(opBuilder); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpegVariableQuality.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpegVariableQuality.java index 2a26b0e765b..d00872692bb 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpegVariableQuality.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/image/EncodeJpegVariableQuality.java @@ -26,7 +26,7 @@ import org.tensorflow.op.annotation.Operator; import org.tensorflow.types.TInt32; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * JPEG encode input image with provided compression quality. @@ -46,7 +46,7 @@ public final class EncodeJpegVariableQuality extends PrimitiveOp implements Oper * @param quality An int quality to encode to. * @return a new instance of EncodeJpegVariableQuality */ - public static EncodeJpegVariableQuality create(Scope scope, Operand images, Operand quality) { + public static EncodeJpegVariableQuality create(Scope scope, Operand images, Operand quality) { OperationBuilder opBuilder = scope.env().opBuilder("EncodeJpegVariableQuality", scope.makeOpName("EncodeJpegVariableQuality")); opBuilder.addInput(images.asOutput()); opBuilder.addInput(quality.asOutput()); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/CompareAndBitpack.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/CompareAndBitpack.java index cb7ba0145ce..c3dc0ab1025 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/CompareAndBitpack.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/CompareAndBitpack.java @@ -24,7 +24,7 @@ import org.tensorflow.op.PrimitiveOp; import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TType; /** @@ -53,7 +53,7 @@ * a `uint8` tensor shaped `[s0, s1, ..., s_n / 8]`. */ @Operator(group = "math") -public final class CompareAndBitpack extends PrimitiveOp implements Operand { +public final class CompareAndBitpack extends PrimitiveOp implements Operand { /** * Factory method to create a class wrapping a new CompareAndBitpack operation. @@ -74,16 +74,16 @@ public static CompareAndBitpack create(Scope scope, Operand /** * The bitpacked comparisons. */ - public Output output() { + public Output output() { return output; } @Override - public Output asOutput() { + public Output asOutput() { return output; } - private Output output; + private Output output; private CompareAndBitpack(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/PopulationCount.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/PopulationCount.java index f270cfaab08..9a901d5b550 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/PopulationCount.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/math/PopulationCount.java @@ -24,7 +24,7 @@ import org.tensorflow.op.PrimitiveOp; import org.tensorflow.op.Scope; import org.tensorflow.op.annotation.Operator; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TNumber; import org.tensorflow.types.family.TType; @@ -39,7 +39,7 @@ * 8- or 16-bit inputs and then aggregate the resulting counts. */ @Operator(group = "math") -public final class PopulationCount extends PrimitiveOp implements Operand { +public final class PopulationCount extends PrimitiveOp implements Operand { /** * Factory method to create a class wrapping a new PopulationCount operation. @@ -57,16 +57,16 @@ public static PopulationCount create(Scope scope, Operand /** */ - public Output y() { + public Output y() { return y; } @Override - public Output asOutput() { + public Output asOutput() { return y; } - private Output y; + private Output y; private PopulationCount(Operation operation) { super(operation); diff --git a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/summary/WriteImageSummary.java b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/summary/WriteImageSummary.java index cc2d95a719d..a9952a6dbbe 100644 --- a/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/summary/WriteImageSummary.java +++ b/tensorflow-core/tensorflow-core-api/src/gen/java/org/tensorflow/op/summary/WriteImageSummary.java @@ -24,7 +24,7 @@ import org.tensorflow.op.Scope; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TNumber; import org.tensorflow.types.family.TType; @@ -63,7 +63,7 @@ private Options() { * @param options carries optional attributes values * @return a new instance of WriteImageSummary */ - public static WriteImageSummary create(Scope scope, Operand writer, Operand step, Operand tag, Operand tensor, Operand badColor, Options... options) { + public static WriteImageSummary create(Scope scope, Operand writer, Operand step, Operand tag, Operand tensor, Operand badColor, Options... options) { OperationBuilder opBuilder = scope.env().opBuilder("WriteImageSummary", scope.makeOpName("WriteImageSummary")); opBuilder.addInput(writer.asOutput()); opBuilder.addInput(step.asOutput()); diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/DataTypes.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/DataTypes.java index fbaecc6d34c..1e2ad6ec427 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/DataTypes.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/DataTypes.java @@ -19,13 +19,15 @@ import java.util.HashMap; import java.util.Map; +import org.tensorflow.types.TBfloat16; import org.tensorflow.types.TBool; import org.tensorflow.types.TFloat64; import org.tensorflow.types.TFloat32; +import org.tensorflow.types.TFloat16; import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** * Utility class for working with {@link DataType} objects. @@ -56,10 +58,12 @@ static DataType fromNativeCode(int nativeCode) { register(TBool.DTYPE); register(TFloat64.DTYPE); register(TFloat32.DTYPE); + register(TFloat16.DTYPE); register(TInt32.DTYPE); register(TInt64.DTYPE); register(TString.DTYPE); - register(TUInt8.DTYPE); + register(TUint8.DTYPE); + register(TBfloat16.DTYPE); } // TODO (karllessard): Right now this method is private but we might want to expose it diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Operand.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Operand.java index 06977891956..39151afb870 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Operand.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Operand.java @@ -24,16 +24,16 @@ * *
{@code
  * // The "decodeJpeg" operation can be used as an operand to the "cast" operation
- * Operand decodeJpeg = ops.image().decodeJpeg(...);
- * ops.math().cast(decodeJpeg, DataType.FLOAT);
+ * Operand decodeJpeg = ops.image.decodeJpeg(...);
+ * ops.dtypes.cast(decodeJpeg, TFloat32.DTYPE);
  *
  * // The output "y" of the "unique" operation can be used as an operand to the "cast" operation
- * Output y = ops.array().unique(...).y();
- * ops.math().cast(y, Float.class);
+ * Output y = ops.unique(...).y();
+ * ops.dtypes.cast(y, TFloat32.DTYPE);
  *
  * // The "split" operation can be used as operand list to the "concat" operation
- * Iterable> split = ops.array().split(...);
- * ops.array().concat(0, split);
+ * Iterable> split = ops.split(...);
+ * ops.concat(split, ops.constant(0));
  * }
*/ public interface Operand { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java index 518b5ec794a..265adbe0567 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/Tensor.java @@ -35,7 +35,7 @@ import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TType; /** @@ -771,7 +771,7 @@ private static boolean objectCompatWithType(Object obj, DataType dtype) { if (dto.equals(dtype)) { return true; } - if (dto == TString.DTYPE && dtype == TUInt8.DTYPE) { + if (dto == TString.DTYPE && dtype == TUint8.DTYPE) { return true; } return false; diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorBuffers.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorBuffers.java index 823bf120ba6..8c663c9d248 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorBuffers.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorBuffers.java @@ -31,7 +31,8 @@ import org.tensorflow.tools.buffer.FloatDataBuffer; import org.tensorflow.tools.buffer.IntDataBuffer; import org.tensorflow.tools.buffer.LongDataBuffer; -import org.tensorflow.tools.buffer.layout.BooleanDataLayout; +import org.tensorflow.tools.buffer.ShortDataBuffer; +import org.tensorflow.tools.buffer.layout.DataLayouts; public final class TensorBuffers { @@ -75,6 +76,14 @@ public static DoubleDataBuffer toDoubles(TF_Tensor nativeTensor) { return DataBuffers.from(tensorMemory.asByteBuffer().asDoubleBuffer()); } + public static ShortDataBuffer toShorts(TF_Tensor nativeTensor) { + Pointer tensorMemory = tensorMemory(nativeTensor); + if (TensorRawDataBufferFactory.canBeUsed()) { + return TensorRawDataBufferFactory.mapTensorToShorts(tensorMemory); + } + return DataBuffers.from(tensorMemory.asByteBuffer().asShortBuffer()); + } + public static BooleanDataBuffer toBooleans(TF_Tensor nativeTensor) { Pointer tensorMemory = tensorMemory(nativeTensor); if (TensorRawDataBufferFactory.canBeUsed()) { @@ -82,7 +91,7 @@ public static BooleanDataBuffer toBooleans(TF_Tensor nativeTensor) { } // There is no boolean buffers in Java NIO, so apply a layout that converts booleans // from/to bytes when raw memory mapping is not available. - return BOOLEAN_LAYOUT.applyTo(DataBuffers.from(tensorMemory.asByteBuffer())); + return DataLayouts.BOOL.applyTo(DataBuffers.from(tensorMemory.asByteBuffer())); } public static StringTensorBuffer toStrings(TF_Tensor nativeTensor, long numElements) { @@ -108,20 +117,4 @@ public static StringTensorBuffer toStrings(TF_Tensor nativeTensor, long numEleme private static Pointer tensorMemory(TF_Tensor nativeTensor) { return TF_TensorData(nativeTensor).capacity(TF_TensorByteSize(nativeTensor)); } - - /** - * Basic data layout that converts booleans from/to bytes. - */ - private static final BooleanDataLayout BOOLEAN_LAYOUT = new BooleanDataLayout() { - - @Override - public void writeBoolean(ByteDataBuffer buffer, boolean value, long index) { - buffer.setByte((byte)(value ? 0x1 : 0x0), index); - } - - @Override - public boolean readBoolean(ByteDataBuffer buffer, long index) { - return buffer.getByte(index) > 0x0; - } - }; } diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorRawDataBufferFactory.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorRawDataBufferFactory.java index 03ecf38fe47..a45fcd2dda8 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorRawDataBufferFactory.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/internal/buffer/TensorRawDataBufferFactory.java @@ -24,6 +24,7 @@ import org.tensorflow.tools.buffer.FloatDataBuffer; import org.tensorflow.tools.buffer.IntDataBuffer; import org.tensorflow.tools.buffer.LongDataBuffer; +import org.tensorflow.tools.buffer.ShortDataBuffer; import org.tensorflow.tools.buffer.impl.raw.RawDataBufferFactory; class TensorRawDataBufferFactory extends RawDataBufferFactory { @@ -48,6 +49,10 @@ static DoubleDataBuffer mapTensorToDoubles(Pointer tensorMemory) { return mapNativeDoubles(tensorMemory.address(), tensorMemory.capacity(), false); } + static ShortDataBuffer mapTensorToShorts(Pointer tensorMemory) { + return mapNativeShorts(tensorMemory.address(), tensorMemory.capacity(), false); + } + static BooleanDataBuffer mapTensorToBooleans(Pointer tensorMemory) { return mapNativeBooleans(tensorMemory.address(), tensorMemory.capacity(), false); } diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBfloat16.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBfloat16.java new file mode 100644 index 00000000000..969e7e8aaba --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBfloat16.java @@ -0,0 +1,126 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.types; + +import org.tensorflow.DataType; +import org.tensorflow.Tensor; +import org.tensorflow.internal.buffer.TensorBuffers; +import org.tensorflow.internal.c_api.TF_Tensor; +import org.tensorflow.tools.Shape; +import org.tensorflow.tools.buffer.FloatDataBuffer; +import org.tensorflow.tools.buffer.layout.DataLayouts; +import org.tensorflow.tools.ndarray.FloatNdArray; +import org.tensorflow.tools.ndarray.NdArray; +import org.tensorflow.tools.ndarray.impl.dense.FloatDenseNdArray; +import org.tensorflow.types.family.TNumber; + +/** + * Brain 16-bit float tensor type. + * + *

This type differs from {@link TFloat16} as it truncates the mantissa of a 32-bit float and + * preserve all exponent bits for faster conversion, while the latter shrink the exponent and have + * a longer mantissa for more precision. + * + *

Since there is no floating-point type that fits in 16 bits in Java, a conversion (with potentially + * a precision loss) is required for each 32 bits value written or read on a tensor of this type from + * the JVM. Therefore, if a lot of I/O operations are to be expected on a tensor, performances will be + * improved by working with {@link TFloat32} or {@link TFloat64} data types whenever possible. + * + *

Note that some CPUs support the bfloat16 format natively, which can result in faster computation + * compared to {@link TFloat16} when GPUs are not used. + */ +public interface TBfloat16 extends FloatNdArray, TNumber { + + /** Type metadata */ + DataType DTYPE = DataType.create("BFLOAT16", 14, 2, TBfloat16Impl::mapTensor); + + /** + * Allocates a new tensor for storing a single float value. + * + * @param value float to store in the new tensor + * @return the new tensor + */ + static Tensor scalarOf(float value) { + Tensor t = ofShape(); + t.data().setFloat(value); + return t; + } + + /** + * Allocates a new tensor for storing a vector of floats. + * + * @param values floats to store in the new tensor + * @return the new tensor + */ + static Tensor vectorOf(float... values) { + Tensor t = ofShape(values.length); + t.data().write(values); + return t; + } + + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(Shape shape) { + return Tensor.allocate(DTYPE, shape); + } + + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(long... dimensionSizes) { + return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); + } + + /** + * Allocates a new tensor which is a copy of a given array of floats. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ + static Tensor copyOf(NdArray src) { + Tensor t = Tensor.allocate(DTYPE, src.shape()); + src.copyTo(t.data()); + return t; + } +} + +/** + * Hidden implementation of a {@code TBfloat16} + */ +class TBfloat16Impl extends FloatDenseNdArray implements TBfloat16 { + + static TBfloat16 mapTensor(TF_Tensor nativeTensor, Shape shape) { + return new TBfloat16Impl(DataLayouts.BFLOAT16.applyTo(TensorBuffers.toShorts(nativeTensor)), shape); + } + + private TBfloat16Impl(FloatDataBuffer buffer, Shape shape) { + super(buffer, shape); + } +} + diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBool.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBool.java index 6ca4be216dd..b63bb9a47fd 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBool.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TBool.java @@ -28,30 +28,73 @@ import org.tensorflow.tools.ndarray.impl.dense.BooleanDenseNdArray; import org.tensorflow.types.family.TType; +/** + * Boolean tensor type. + * + *

If direct memory mapping is not available in the JVM, tensors of this type might require an + * explicit mapping between Java boolean values and byte buffers using the + * {@link org.tensorflow.tools.buffer.layout.DataLayouts#BOOL BOOL} layout, which may impact I/O + * performances. + */ public interface TBool extends BooleanNdArray, TType { + /** Type metadata */ DataType DTYPE = DataType.create("BOOL", 10, 1, TBoolImpl::mapTensor); + /** + * Allocates a new tensor for storing a single boolean value. + * + * @param value boolean to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(boolean value) { Tensor t = ofShape(); t.data().setBoolean(value); return t; } + /** + * Allocates a new tensor for storing a vector of booleans. + * + * @param values booleans to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(boolean... values) { Tensor t = ofShape(values.length); t.data().write(values); return t; } + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(Shape shape) { return Tensor.allocate(DTYPE, shape); } + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(long... dimensionSizes) { return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); } + /** + * Allocates a new tensor which is a copy of a given array of booleans. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { Tensor t = Tensor.allocate(DTYPE, src.shape()); src.copyTo(t.data()); @@ -59,6 +102,9 @@ static Tensor copyOf(NdArray src) { } } +/** + * Hidden implementation of a {@code TBool} + */ class TBoolImpl extends BooleanDenseNdArray implements TBool { static TBool mapTensor(TF_Tensor nativeTensor, Shape shape) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat16.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat16.java new file mode 100644 index 00000000000..c3655995979 --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat16.java @@ -0,0 +1,123 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.types; + +import org.tensorflow.DataType; +import org.tensorflow.Tensor; +import org.tensorflow.internal.buffer.TensorBuffers; +import org.tensorflow.internal.c_api.TF_Tensor; +import org.tensorflow.tools.Shape; +import org.tensorflow.tools.buffer.FloatDataBuffer; +import org.tensorflow.tools.buffer.layout.DataLayouts; +import org.tensorflow.tools.ndarray.FloatNdArray; +import org.tensorflow.tools.ndarray.NdArray; +import org.tensorflow.tools.ndarray.impl.dense.FloatDenseNdArray; +import org.tensorflow.types.family.TNumber; + +/** + * IEEE-754 half-precision 16-bit float tensor type. + * + *

Since there is no floating-point type that fits in 16 bits in Java, a conversion (with potentially + * a precision loss) is required for each 32 bits value written or read on a tensor of this type from + * the JVM. Therefore, if a lot of I/O operations are to be expected on a tensor, performances will be + * improved by working with {@link TFloat32} or {@link TFloat64} data types whenever possible. + * + *

Also, {@code TFloat16} tensors normally perform better if they are located in GPU memory since most + * CPUs do not support this format natively. For CPU computation on 16-bit floats, the {@link TBfloat16} + * tensor type might be a better option. + */ +public interface TFloat16 extends FloatNdArray, TNumber { + + /** Type metadata */ + DataType DTYPE = DataType.create("FLOAT16", 19, 2, TFloat16Impl::mapTensor); + + /** + * Allocates a new tensor for storing a single float value. + * + * @param value float to store in the new tensor + * @return the new tensor + */ + static Tensor scalarOf(float value) { + Tensor t = ofShape(); + t.data().setFloat(value); + return t; + } + + /** + * Allocates a new tensor for storing a vector of floats. + * + * @param values floats to store in the new tensor + * @return the new tensor + */ + static Tensor vectorOf(float... values) { + Tensor t = ofShape(values.length); + t.data().write(values); + return t; + } + + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(Shape shape) { + return Tensor.allocate(DTYPE, shape); + } + + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(long... dimensionSizes) { + return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); + } + + /** + * Allocates a new tensor which is a copy of a given array of floats. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ + static Tensor copyOf(NdArray src) { + Tensor t = Tensor.allocate(DTYPE, src.shape()); + src.copyTo(t.data()); + return t; + } +} + +/** + * Hidden implementation of a {@code TFloat16} + */ +class TFloat16Impl extends FloatDenseNdArray implements TFloat16 { + + static TFloat16 mapTensor(TF_Tensor nativeTensor, Shape shape) { + return new TFloat16Impl(DataLayouts.FLOAT16.applyTo(TensorBuffers.toShorts(nativeTensor)), shape); + } + + private TFloat16Impl(FloatDataBuffer buffer, Shape shape) { + super(buffer, shape); + } +} + diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat32.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat32.java index 76650f31853..a9d57e5f5e9 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat32.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat32.java @@ -28,30 +28,68 @@ import org.tensorflow.tools.ndarray.impl.dense.FloatDenseNdArray; import org.tensorflow.types.family.TNumber; +/** + * IEEE-754 single-precision 32-bit float tensor type. + */ public interface TFloat32 extends FloatNdArray, TNumber { + /** Type metadata */ DataType DTYPE = DataType.create("FLOAT", 1, 4, TFloat32Impl::mapTensor); + /** + * Allocates a new tensor for storing a single float value. + * + * @param value float to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(float value) { Tensor t = ofShape(); t.data().setFloat(value); return t; } + /** + * Allocates a new tensor for storing a vector of floats. + * + * @param values floats to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(float... values) { Tensor t = ofShape(values.length); t.data().write(values); return t; } + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(Shape shape) { return Tensor.allocate(DTYPE, shape); } + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(long... dimensionSizes) { return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); } + /** + * Allocates a new tensor which is a copy of a given array of floats. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { Tensor t = Tensor.allocate(DTYPE, src.shape()); src.copyTo(t.data()); @@ -59,6 +97,9 @@ static Tensor copyOf(NdArray src) { } } +/** + * Hidden implementation of a {@code TFloat32} + */ class TFloat32Impl extends FloatDenseNdArray implements TFloat32 { static TFloat32 mapTensor(TF_Tensor nativeTensor, Shape shape) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat64.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat64.java index d84a6ba942c..e62a72162c8 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat64.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TFloat64.java @@ -28,30 +28,68 @@ import org.tensorflow.tools.ndarray.impl.dense.DoubleDenseNdArray; import org.tensorflow.types.family.TNumber; +/** + * IEEE-754 double-precision 64-bit float tensor type. + */ public interface TFloat64 extends DoubleNdArray, TNumber { + /** Type metadata */ DataType DTYPE = DataType.create("DOUBLE", 2, 8, TFloat64Impl::mapTensor); + /** + * Allocates a new tensor for storing a single double value. + * + * @param value double to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(double value) { Tensor t = ofShape(); t.data().setDouble(value); return t; } + /** + * Allocates a new tensor for storing a vector of doubles. + * + * @param values doubles to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(double... values) { Tensor t = ofShape(values.length); t.data().write(values); return t; } + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(Shape shape) { return Tensor.allocate(DTYPE, shape); } + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(long... dimensionSizes) { return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); } + /** + * Allocates a new tensor which is a copy of a given array of doubles. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { Tensor t = Tensor.allocate(DTYPE, src.shape()); src.copyTo(t.data()); @@ -59,6 +97,9 @@ static Tensor copyOf(NdArray src) { } } +/** + * Hidden implementation of a {@code TFloat64} + */ class TFloat64Impl extends DoubleDenseNdArray implements TFloat64 { static TFloat64 mapTensor(TF_Tensor nativeTensor, Shape shape) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt32.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt32.java index 5bb33929114..b24137a4135 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt32.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt32.java @@ -28,30 +28,68 @@ import org.tensorflow.tools.ndarray.impl.dense.IntDenseNdArray; import org.tensorflow.types.family.TNumber; +/** + * 32-bit signed integer tensor type. + */ public interface TInt32 extends IntNdArray, TNumber { + /** Type metadata */ DataType DTYPE = DataType.create("INT32", 3, 4, TInt32Impl::mapTensor); + /** + * Allocates a new tensor for storing a single int value. + * + * @param value int to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(int value) { Tensor t = ofShape(); t.data().setInt(value); return t; } + /** + * Allocates a new tensor for storing a vector of ints. + * + * @param values ints to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(int... values) { Tensor t = ofShape(values.length); t.data().write(values); return t; } + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(Shape shape) { return Tensor.allocate(DTYPE, shape); } + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(long... dimensionSizes) { return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); } + /** + * Allocates a new tensor which is a copy of a given array of ints. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { Tensor t = Tensor.allocate(DTYPE, src.shape()); src.copyTo(t.data()); @@ -59,6 +97,9 @@ static Tensor copyOf(NdArray src) { } } +/** + * Hidden implementation of a {@code TInt32} + */ class TInt32Impl extends IntDenseNdArray implements TInt32 { static TInt32 mapTensor(TF_Tensor nativeTensor, Shape shape) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt64.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt64.java index a75545b81b2..d511e54a9cc 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt64.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TInt64.java @@ -28,30 +28,68 @@ import org.tensorflow.tools.ndarray.impl.dense.LongDenseNdArray; import org.tensorflow.types.family.TNumber; +/** + * 64-bit signed integer tensor type. + */ public interface TInt64 extends LongNdArray, TNumber { + /** Type metadata */ DataType DTYPE = DataType.create("INT64", 9, 8, TInt64Impl::mapTensor); + /** + * Allocates a new tensor for storing a single long value. + * + * @param value long to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(long value) { Tensor t = ofShape(); t.data().setLong(value); return t; } + /** + * Allocates a new tensor for storing a vector of longs. + * + * @param values longs to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(long... values) { Tensor t = ofShape(values.length); t.data().write(values); return t; } + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(Shape shape) { return Tensor.allocate(DTYPE, shape); } + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ static Tensor ofShape(long... dimensionSizes) { return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); } + /** + * Allocates a new tensor which is a copy of a given array of longs. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { Tensor t = Tensor.allocate(DTYPE, src.shape()); src.copyTo(t.data()); @@ -59,6 +97,9 @@ static Tensor copyOf(NdArray src) { } } +/** + * Hidden implementation of a {@code TInt64} + */ class TInt64Impl extends LongDenseNdArray implements TInt64 { static TInt64 mapTensor(TF_Tensor nativeTensor, Shape shape) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TString.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TString.java index be1bbf4dd24..fa0d6f3e453 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TString.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TString.java @@ -30,23 +30,50 @@ import org.tensorflow.tools.ndarray.impl.dense.DenseNdArray; import org.tensorflow.types.family.TType; +/** + * String tensor type. + */ public interface TString extends NdArray, TType { + /** Type metadata */ DataType DTYPE = DataType.create("STRING", 7, -1, TStringImpl::mapTensor); + /** + * Allocates a new tensor for storing a single string value. + * + * @param value string to store in the new tensor + * @return the new tensor + */ static Tensor scalarOf(String value) { return copyOf(NdArrays.ofObjects(String.class, Shape.scalar()).setObject(value)); } + /** + * Allocates a new tensor for storing a vector of strings. + * + * @param values strings to store in the new tensor + * @return the new tensor + */ static Tensor vectorOf(String... values) { return copyOf(NdArrays.ofObjects(String.class, Shape.make(values.length)).write(values)); } + /** + * Allocates a new tensor which is a copy of a given array of strings. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ static Tensor copyOf(NdArray src) { return TStringImpl.createTensor(src); } } +/** + * Hidden implementation of a {@code TString} + */ class TStringImpl extends DenseNdArray implements TString { static Tensor createTensor(NdArray src) { diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUInt8.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUInt8.java deleted file mode 100644 index 33913a96612..00000000000 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUInt8.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2019 The TensorFlow Authors. 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License 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 org.tensorflow.types; - -import org.tensorflow.DataType; -import org.tensorflow.Tensor; -import org.tensorflow.internal.buffer.TensorBuffers; -import org.tensorflow.internal.c_api.TF_Tensor; -import org.tensorflow.tools.Shape; -import org.tensorflow.tools.buffer.ByteDataBuffer; -import org.tensorflow.tools.ndarray.ByteNdArray; -import org.tensorflow.tools.ndarray.NdArray; -import org.tensorflow.tools.ndarray.impl.dense.ByteDenseNdArray; -import org.tensorflow.types.family.TNumber; - -public interface TUInt8 extends ByteNdArray, TNumber { - - DataType DTYPE = DataType.create("UINT8", 4, 1, TUInt8Impl::mapTensor); - - static Tensor scalarOf(byte value) { - Tensor t = ofShape(); - t.data().setByte(value); - return t; - } - - static Tensor vectorOf(byte... values) { - Tensor t = ofShape(values.length); - t.data().write(values); - return t; - } - - static Tensor ofShape(Shape shape) { - return Tensor.allocate(DTYPE, shape); - } - - static Tensor ofShape(long... dimensionSizes) { - return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); - } - - static Tensor copyOf(NdArray src) { - Tensor t = Tensor.allocate(DTYPE, src.shape()); - src.copyTo(t.data()); - return t; - } -} - -class TUInt8Impl extends ByteDenseNdArray implements TUInt8 { - - static TUInt8 mapTensor(TF_Tensor nativeTensor, Shape shape) { - return new TUInt8Impl(TensorBuffers.toBytes(nativeTensor), shape); - } - - private TUInt8Impl(ByteDataBuffer buffer, Shape shape) { - super(buffer, shape); - } -} diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUint8.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUint8.java new file mode 100644 index 00000000000..33b73dc72f8 --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/TUint8.java @@ -0,0 +1,112 @@ +/* + * Copyright 2019 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.types; + +import org.tensorflow.DataType; +import org.tensorflow.Tensor; +import org.tensorflow.internal.buffer.TensorBuffers; +import org.tensorflow.internal.c_api.TF_Tensor; +import org.tensorflow.tools.Shape; +import org.tensorflow.tools.buffer.ByteDataBuffer; +import org.tensorflow.tools.ndarray.ByteNdArray; +import org.tensorflow.tools.ndarray.NdArray; +import org.tensorflow.tools.ndarray.impl.dense.ByteDenseNdArray; +import org.tensorflow.types.family.TNumber; + +/** + * 8-bit unsigned integer tensor type. + */ +public interface TUint8 extends ByteNdArray, TNumber { + + /** Type metadata */ + DataType DTYPE = DataType.create("UINT8", 4, 1, TUint8Impl::mapTensor); + + /** + * Allocates a new tensor for storing a single byte value. + * + * @param value byte to store in the new tensor + * @return the new tensor + */ + static Tensor scalarOf(byte value) { + Tensor t = ofShape(); + t.data().setByte(value); + return t; + } + + /** + * Allocates a new tensor for storing a vector of bytes. + * + * @param values bytes to store in the new tensor + * @return the new tensor + */ + static Tensor vectorOf(byte... values) { + Tensor t = ofShape(values.length); + t.data().write(values); + return t; + } + + /** + * Allocates a new tensor of the given shape. + * + * @param shape shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(Shape shape) { + return Tensor.allocate(DTYPE, shape); + } + + /** + * Allocates a new tensor of the given shape. + * + *

Invoking {@code ofShape(x, y, z)} is equivalent to {@code ofShape(Shape.make(x, y, z))} + * + * @param dimensionSizes dimension sizes that defines the shape of the tensor to allocate + * @return the new tensor + */ + static Tensor ofShape(long... dimensionSizes) { + return Tensor.allocate(DTYPE, Shape.make(dimensionSizes)); + } + + /** + * Allocates a new tensor which is a copy of a given array of bytes. + * + *

The tensor will have the same shape as the source array and its data will be copied. + * + * @param src the source array giving the shape and data to the new tensor + * @return the new tensor + */ + static Tensor copyOf(NdArray src) { + Tensor t = Tensor.allocate(DTYPE, src.shape()); + src.copyTo(t.data()); + return t; + } +} + +/** + * Hidden implementation of a {@code TUint8} + */ +class TUint8Impl extends ByteDenseNdArray implements TUint8 { + + static TUint8 mapTensor(TF_Tensor nativeTensor, Shape shape) { + return new TUint8Impl(TensorBuffers.toBytes(nativeTensor), shape); + } + + private TUint8Impl(ByteDataBuffer buffer, Shape shape) { + super(buffer, shape); + } +} diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TNumber.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TNumber.java index 7e9f0487529..97ee59af095 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TNumber.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TNumber.java @@ -17,6 +17,19 @@ package org.tensorflow.types.family; -public interface TNumber extends TType { - -} +/** + * Marker interface for numeric tensor types. + * + *

Operations that only accepts numeric values as some of their operands enforce that the tensor + * types for these operands to be bound to this interface. For example: + * + *

{@code
+ * TFloat32 tensor1 = TFloat32.vectorOf(1, 2, 3);
+ * TBool tensor2 = TBool.vectorOf(true, false, true);
+ *
+ * Ops tf = Ops.create();
+ * tf.nn.softmax(tf.constant(tensor1));  // OK
+ * tf.nn.softmax(tf.constant(tensor2));  // Compilation failure
+ * }
+ */ +public interface TNumber extends TType {} diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java index ca0290d4097..8f3451b9a68 100644 --- a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/TType.java @@ -17,4 +17,21 @@ package org.tensorflow.types.family; +/** + * Marker interface for all tensor types. + * + *

Tensor types are carried as a generic parameter of the {@link org.tensorflow.Tensor Tensor} + * class bound by the {@code TType} interface. This generic parameter ensure type-compatibility + * between operands of a computation at compile-time. For example: + * + *

{@code
+ * Tensor tensor1 = TFloat32.ofShape(2, 3, 2);
+ * Tensor tensor2 = TFloat32.ofShape(2, 3, 2);
+ * Tensor tensor3 = TInt32.ofShape(2, 3, 2);
+ *
+ * Ops tf = Ops.create();
+ * tf.math.add(tf.constant(tensor1), tf.constant(tensor2));  // OK
+ * tf.math.add(tf.constant(tensor1), tf.constant(tensor3));  // Compilation failure
+ * }
+ */ public interface TType {} diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/package-info.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/package-info.java new file mode 100644 index 00000000000..fcf1f554133 --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/family/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * ======================================================================= + */ + +/** + * Interfaces used to group tensor types in families that define a particular domain of data. + * + *

Some operations enforces that only operands of a type from a given family can be passed + * in argument. For example, if an operation only allows numeric operands, such operands must be + * bound to the {@link org.tensorflow.types.family.TNumber TNumber} interface. + * + *

All tensor types is bound to {@link org.tensorflow.types.family.TType TType}, which lays at + * the root of the family hierarchy. + */ +package org.tensorflow.types.family; diff --git a/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/package-info.java b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/package-info.java new file mode 100644 index 00000000000..bdce85453e3 --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/main/java/org/tensorflow/types/package-info.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + * ======================================================================= + */ + +/** + * Defines classes that represent TensorFlow tensor types. For each possible data type that can be + * used in a tensor, there is a corresponding interface that is used to represent it and its hidden + * implementation. For example, the TensorFlow int32 type is represented by the tensor type interface + * {@link org.tensorflow.types.TInt32 TInt32}, where the {@code T} prefix stands for "Tensor of". + * + *

To support compile-time checking of tensor element types, each interface in this package must be + * bound to one of the marker interface found in {@link org.tensorflow.types.family}, according + * to the nature of the data. + * + *

Each tensor type must provide a static instance of {@link org.tensorflow.DataType} + * carrying type metadata that should be used for allocating a tensor of this type or to pass + * this type as an operation argument. For example, metadata about TensorFlow int32 type is + * found in {@link org.tensorflow.types.TInt32#DTYPE TInt32.DTYPE}. + * + *

Instances of tensor types must also implement the {@link org.tensorflow.tools.ndarray.NdArray NdArray} + * interface so a user can access directly the tensor data in a n-dimensional space by invoking + * {@link org.tensorflow.Tensor#data() Tensor.data()}. + * + *

Note that while it is always possible to allocate a tensor using the + * {@link org.tensorflow.Tensor#allocate(org.tensorflow.DataType, org.tensorflow.tools.Shape) Tensor.allocate(...)} + * method, most tensor types expose factory methods that simplify the creation process, like + * {@code scalarOf(...)}, {@code vectorOf(...)}, {@code ofShape(...)}, etc. + */ +package org.tensorflow.types; diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java index 0c3b1a7e24f..cfce21718ea 100644 --- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/TensorTest.java @@ -38,7 +38,7 @@ import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; /** Unit tests for {@link org.tensorflow.Tensor}. */ @RunWith(JUnit4.class) @@ -423,10 +423,10 @@ public void testNDimensionalStringTensor() { } @Test - public void testUInt8Tensor() { + public void testUint8Tensor() { byte[] vector = new byte[] {1, 2, 3, 4}; - try (Tensor t = Tensor.create(vector, TUInt8.DTYPE)) { - assertEquals(TUInt8.DTYPE, t.dataType()); + try (Tensor t = Tensor.create(vector, TUint8.DTYPE)) { + assertEquals(TUint8.DTYPE, t.dataType()); assertEquals(1, t.shape().numDimensions()); assertEquals(4, t.shape().size(0)); diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/ScopeTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/ScopeTest.java index ecd3d2e2171..98fb709b77a 100644 --- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/ScopeTest.java +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/ScopeTest.java @@ -36,7 +36,7 @@ import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; import org.tensorflow.types.family.TType; /** Unit tests for {@link org.tensorflow.op.Scope}. */ @@ -293,7 +293,7 @@ public static Object zeroValue(DataType type) { zeros.put(TFloat32.DTYPE, 0.0f); zeros.put(TFloat64.DTYPE, 0.0); zeros.put(TInt32.DTYPE, 0); - zeros.put(TUInt8.DTYPE, (byte) 0); + zeros.put(TUint8.DTYPE, (byte) 0); zeros.put(TInt64.DTYPE, 0L); zeros.put(TBool.DTYPE, false); zeros.put(TString.DTYPE, null); // no zero value diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/core/ZerosTest.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/core/ZerosTest.java index e5ccd6bef4b..5a9584e3142 100644 --- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/core/ZerosTest.java +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/op/core/ZerosTest.java @@ -32,7 +32,7 @@ import org.tensorflow.types.TInt32; import org.tensorflow.types.TInt64; import org.tensorflow.types.TString; -import org.tensorflow.types.TUInt8; +import org.tensorflow.types.TUint8; @RunWith(JUnit4.class) public class ZerosTest { @@ -129,14 +129,14 @@ public void createBooleanZeros() { } @Test - public void createUInt8Zeros() { + public void createUint8Zeros() { try (Graph g = new Graph(); Session sess = new Session(g)) { Scope scope = new Scope(g); long[] shape = {2, 2}; - Zeros op = Zeros.create(scope, Constant.create(scope, shape), TUInt8.DTYPE); + Zeros op = Zeros.create(scope, Constant.create(scope, shape), TUint8.DTYPE); try (Tensor result = sess.runner().fetch(op.asOutput()).run().get(0)) { - byte[][] actual = result.expect(TUInt8.DTYPE).copyTo(new byte[(int)shape[0]][(int)shape[1]]); + byte[][] actual = result.expect(TUint8.DTYPE).copyTo(new byte[(int)shape[0]][(int)shape[1]]); result.copyTo(actual); for (int i = 0; i < actual.length; ++i) { for (int j = 0; j < actual[i].length; ++j) { diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TBfloat16Test.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TBfloat16Test.java new file mode 100644 index 00000000000..89f8d03524f --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TBfloat16Test.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.types; + +import org.tensorflow.Tensor; +import org.tensorflow.tools.Shape; + +public class TBfloat16Test extends NumericTypesTestBase { + + @Override + Tensor allocateTensor(Shape shape) { + return TBfloat16.ofShape(shape); + } + + @Override + Float valueOf(Integer value) { + return value.floatValue(); + } +} diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TFloat16Test.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TFloat16Test.java new file mode 100644 index 00000000000..bbd341d50fd --- /dev/null +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TFloat16Test.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.types; + +import org.tensorflow.Tensor; +import org.tensorflow.tools.Shape; + +public class TFloat16Test extends NumericTypesTestBase { + + @Override + Tensor allocateTensor(Shape shape) { + return TFloat16.ofShape(shape); + } + + @Override + Float valueOf(Integer value) { + return value.floatValue(); + } +} diff --git a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUInt8Test.java b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUint8Test.java similarity index 86% rename from tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUInt8Test.java rename to tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUint8Test.java index 52deec08a6d..95c27a7e881 100644 --- a/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUInt8Test.java +++ b/tensorflow-core/tensorflow-core-api/src/test/java/org/tensorflow/types/TUint8Test.java @@ -20,11 +20,11 @@ import org.tensorflow.Tensor; import org.tensorflow.tools.Shape; -public class TUInt8Test extends NumericTypesTestBase { +public class TUint8Test extends NumericTypesTestBase { @Override - Tensor allocateTensor(Shape shape) { - return TUInt8.ofShape(shape); + Tensor allocateTensor(Shape shape) { + return TUint8.ofShape(shape); } @Override diff --git a/tensorflow-tools/pom.xml b/tensorflow-tools/pom.xml index 9f8d64a8b6b..0c85719bf9a 100644 --- a/tensorflow-tools/pom.xml +++ b/tensorflow-tools/pom.xml @@ -27,10 +27,11 @@ tensorflow-tools jar - TensorFlow Utility Library + TensorFlow Tools Library - Library of utilities that do not depend on the TensorFlow runtime and can be used by other - projects outside the TensorFlow organization. + Utility library used by TensorFlow Java language bindings. This library does not depend on + the TensorFlow runtime and therefore can be included by any other projects outside the TensorFlow + organization. diff --git a/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16Layout.java b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16Layout.java new file mode 100644 index 00000000000..6b0b954d795 --- /dev/null +++ b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16Layout.java @@ -0,0 +1,54 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import org.tensorflow.tools.buffer.ShortDataBuffer; +import org.tensorflow.tools.buffer.layout.FloatDataLayout; + +/** + * Data layout that converts 32-bit floats from/to 16-bit, truncating their mantissa to 7 bits but + * preserving the 8-bit exponent with the same bias. + */ +public final class Bfloat16Layout implements FloatDataLayout { + + @Override + public void writeFloat(ShortDataBuffer buffer, float value, long index) { + buffer.setShort(float32to16(value), index); + } + + @Override + public float readFloat(ShortDataBuffer buffer, long index) { + return float16to32(buffer.getShort(index)); + } + + // + // FLOAT 32-bit to/from BFLOAT 16-bit conversions + // + // We simply shift the value from 32-bit to 16-bit and vice-versa. NaN special case is ignored. + // + + // VisibleForTesting + static short float32to16(float f32) { + return (short)(Float.floatToIntBits(f32) >>> 16); + } + + // Visible for testing + static float float16to32(short i16) { + return Float.intBitsToFloat((int)i16 << 16); + } +} diff --git a/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/BoolLayout.java b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/BoolLayout.java new file mode 100644 index 00000000000..3ee701eaf12 --- /dev/null +++ b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/BoolLayout.java @@ -0,0 +1,47 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import org.tensorflow.tools.buffer.ByteDataBuffer; +import org.tensorflow.tools.buffer.layout.BooleanDataLayout; + +/** + * Data layout that converts booleans from/to bytes. + */ +public final class BoolLayout implements BooleanDataLayout { + + @Override + public void writeBoolean(ByteDataBuffer buffer, boolean value, long index) { + buffer.setByte(booleanToByte(value), index); + } + + @Override + public boolean readBoolean(ByteDataBuffer buffer, long index) { + return byteToBoolean(buffer.getByte(index)); + } + + // Visible for testing + static byte booleanToByte(boolean b) { + return (byte)(b ? 0x1 : 0x0); + } + + // Visible for testing + static boolean byteToBoolean(byte b) { + return b != 0x0; + } +} diff --git a/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Float16Layout.java b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Float16Layout.java new file mode 100644 index 00000000000..9f8bd69fa50 --- /dev/null +++ b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/impl/layout/Float16Layout.java @@ -0,0 +1,119 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import org.tensorflow.tools.buffer.ShortDataBuffer; +import org.tensorflow.tools.buffer.layout.FloatDataLayout; + +/** + * Data layout that converts 32-bit floats from/to 16-bit, accordingly to the IEEE-754 half-precision + * floating point specification. + */ +public final class Float16Layout implements FloatDataLayout { + + @Override + public void writeFloat(ShortDataBuffer buffer, float value, long index) { + buffer.setShort(float32to16(value), index); + } + + @Override + public float readFloat(ShortDataBuffer buffer, long index) { + return float16to32(buffer.getShort(index)); + } + + // + // FLOAT 32-bit to/from 16-bit conversions + // + // The following conversion algorithms are issued from the C++ implementation found in the + // Eigen library used by TensorFlow native library. + // See https://eigen.tuxfamily.org/dox-devel/Half_8h_source.html for more details. + // + + // VisibleForTesting + static short float32to16(float f32) { + int i16; + int i32 = Float.floatToIntBits(f32); + short sign16 = (short) ((i32 >>> 16) & 0x8000); + i32 &= 0x7FFFFFFF; // remove sign + + if (i32 >= (E32BIAS + E16MAX + 1) << E32SHIFT) { + // float32 value is higher than float16 max value (max16 -> 2^15 * 2 -> 2^16) + // - if float32 value is higher than infinite (i.e. s32 > 0), then it is NaN and should also + // be NaN in float16 (0x7e00) + // - else, float16 value is forced to infinite (0x7c00) + i16 = i32 > E32MASK ? 0x7E00 : 0x7C00; + + } else if (i32 < (E32BIAS + E16MIN) << E32SHIFT){ + // float32 abs value is smaller than float16 min abs value (min16 = 2^-14), could also be 0 + // - apply magic number to align significand 10 bits at the bottom on the float and subtract bias + i16 = Float.floatToIntBits(Float.intBitsToFloat(i32) + MAGIC_32_16_FLOAT) - MAGIC_32_16; + + } else { + // float32 value can be rounded up to a normalized float16 value (i.e. exp32 = [113(-14), 142(15)]) + // - rebase exponent to float16 + // - round up significand to the 13nd bit if s16 is even, on the 12nd bit if it is odd + int round = 0xFFF + ((i32 >>> 13) & 0x1); + i16 = (i32 + ((E16BIAS - E32BIAS) << E32SHIFT) + round) >>> 13; + } + return (short)(i16 | sign16); + } + + // Visible for testing + static float float16to32(short i16) { + int i32 = (i16 & 0x7FFF) << (S32BITS - S16BITS); // remove sign and align in float32 + i32 += (E32BIAS - E16BIAS) << E32SHIFT; // rebase exponent to float32 + + // Handle float16 exponent special cases + switch (i16 & E16MASK) { + case E16MASK: + // float16 value is infinite or NaN + // - adjust float32 exponent one more time + i32 += (E32BIAS - E16BIAS) << E32SHIFT; + break; + case 0x0: + // float16 value is zero or subnormal + // - adjust float32 exponent + // - renormalize using magic number + i32 = Float.floatToIntBits(Float.intBitsToFloat(i32 + (1 << E32SHIFT)) - MAGIC_16_32_FLOAT); + break; + default: + break; + } + return Float.intBitsToFloat(i32 | ((i16 & 0x8000) << 16)); // reapply sign + } + + // float32 format + private static final int E32SHIFT = 23; // position of the exponent in float32 + private static final int E32MASK = 0xFF << E32SHIFT; // mask for float32 exponent (== Infinity) + private static final int E32BIAS = 127; // exponent bias for float32 + private static final int S32BITS = 23; // number of bits in float32 significand + + // float16 format + private static final int E16SHIFT = 10; // position of the exponent in float16 + private static final int E16MASK = 0x1F << E16SHIFT; // mask for float16 exponent (== Infinity) + private static final int E16BIAS = 15; // exponent bias for float16 + private static final int E16MAX = 15; // max value for float16 exponent + private static final int E16MIN = -14; // min value for float16 exponent + private static final int S16BITS = 10; // number of bits in float16 significand + + // magic numbers used when converting denormalized values + private static final int MAGIC_32_16 = ((E32BIAS - E16BIAS) + (S32BITS - S16BITS) + 1) << E32SHIFT; + private static final float MAGIC_32_16_FLOAT = Float.intBitsToFloat(MAGIC_32_16); + private static final int MAGIC_16_32 = (E32BIAS - E16BIAS + 1) << E32SHIFT; + private static final float MAGIC_16_32_FLOAT = Float.intBitsToFloat(MAGIC_16_32); +} diff --git a/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/layout/DataLayouts.java b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/layout/DataLayouts.java new file mode 100644 index 00000000000..0639e6a984a --- /dev/null +++ b/tensorflow-tools/src/main/java/org/tensorflow/tools/buffer/layout/DataLayouts.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.layout; + +import org.tensorflow.tools.buffer.ByteDataBuffer; +import org.tensorflow.tools.buffer.ShortDataBuffer; +import org.tensorflow.tools.buffer.impl.layout.Bfloat16Layout; +import org.tensorflow.tools.buffer.impl.layout.BoolLayout; +import org.tensorflow.tools.buffer.impl.layout.Float16Layout; + +/** + * Exposes {@link DataLayout} instances of data formats frequently used in linear algebra computation. + * + *

Example of usage: + *

{@code
+ * // Storing boolean values in a ByteDataBuffer
+ * BooleanDataBuffer boolBuffer = DataLayouts.BOOL.applyTo(byteDataBuffer);
+ *
+ * // Allocating a new buffer of 256 half floats
+ * FloatDataBuffer halfBuffer = DataLayouts.FLOAT16.applyTo(bufferOfShorts(256 * DataLayouts.FLOAT16.scale());
+ * }
+ */ +public final class DataLayouts { + + /** + * Data layout for converting 16-bit bfloats to/from short values. + * + *

This format used to be specific to TensorFlow but has now been adopted more broadly in the + * machine learning field. It is optimized for fast conversion with single-precision 32-bit + * floating points by simply shifting their value and truncating the mantissa to only 7 bits. + * + *

Therefore, this is a lost of precision in the fraction part compared to the IEEE-754 + * half-precision floating point specification (see {@link #FLOAT16} but it has a larger range of + * possible values in the whole part as it preserves the 8-bit exponent and uses the same bias, + * (i.e. an absolute range above 0 of approximately [10-40, 3.39 × 1038] + * + *

Some CPUs support the bfloat16 format natively for better performances. + */ + public static final FloatDataLayout BFLOAT16 = new Bfloat16Layout(); + + /** + * Data layout for converting 16-bit half floats to/from short values. + * + *

Half floats are stored in memory accordingly to the IEEE-754 half-precision floating point + * specification, and are converted to/from 32-bit floats in the user space. + * + *

There is a potential loss of precision when converting a single float (32-bit) to a half + * float (16-bit). Absolute range of values above 0 for a half float is approximately + * [5.96 × 10-8, 6.55 × 104] and their decimal part is rounded up to a 10 bits mantissa. + * + *

In general, half float computation perform better on GPUs since, in general, CPUs do not + * support this format natively.

+ */ + public static final FloatDataLayout FLOAT16 = new Float16Layout(); + + /** + * Data layout for converting booleans to/from byte values. + * + *

Since there is no Java NIO boolean buffer, this layout is particularly useful for mapping + * booleans values to standard byte buffers. The conversion between a boolean and a byte requires + * explicit type casting. + */ + public static final BooleanDataLayout BOOL = new BoolLayout(); +} diff --git a/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16LayoutTest.java b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16LayoutTest.java new file mode 100644 index 00000000000..860ceab35bb --- /dev/null +++ b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Bfloat16LayoutTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class Bfloat16LayoutTest { + + @Test + public void testFloat32to16() { + + // Zero and subnormals + assertEquals((short)0x0000, Bfloat16Layout.float32to16(0.0f)); + assertEquals((short)0x8000, Bfloat16Layout.float32to16(-0.0f)); + assertEquals((short)0x0001, Bfloat16Layout.float32to16(1e-40f)); + assertEquals((short)0xC000, Bfloat16Layout.float32to16(-2.0f)); + assertEquals((short)0x0000, Bfloat16Layout.float32to16(4.59e-41f)); + + // Infinite and NaN + assertEquals((short)0x7F80, Bfloat16Layout.float32to16(Float.POSITIVE_INFINITY)); + assertEquals((short)0xFF80, Bfloat16Layout.float32to16(Float.NEGATIVE_INFINITY)); + assertEquals((short)0x7FC0, Bfloat16Layout.float32to16(Float.NaN)); + assertEquals((short)0x7FC0, Bfloat16Layout.float32to16(Float.intBitsToFloat(0xFFFFFFFF))); + + // Normalized + assertEquals((short)0x3F80, Bfloat16Layout.float32to16(1.0f)); + assertEquals((short)0xBF80, Bfloat16Layout.float32to16(-1.0f)); + assertEquals((short)0x42C8, Bfloat16Layout.float32to16(100.0f)); + assertEquals((short)0xC2CA, Bfloat16Layout.float32to16(-101.0f)); + assertEquals((short)0x3F8F, Bfloat16Layout.float32to16(1.1171875f)); + assertEquals((short)0x4800, Bfloat16Layout.float32to16(131072f)); + assertEquals((short)0x7F7F, Bfloat16Layout.float32to16(3.3895314e38f)); + assertEquals((short)0xFF7F, Bfloat16Layout.float32to16(-3.3895314e38f)); + + // Rounding up + assertEquals((short)0x3FCF, Bfloat16Layout.float32to16(1.6191406f)); // 1.6171875 + assertEquals((short)0x4780, Bfloat16Layout.float32to16(65600.0f)); // 65536.0 + } + + @Test + public void testFloat16to32() { + + // Zero and subnormals + assertEquals(0.0f, Bfloat16Layout.float16to32((short)0x0000), 0); + assertEquals(-0.0f, Bfloat16Layout.float16to32((short)0x8000), 0); + assertEquals(9.18355E-41f, Bfloat16Layout.float16to32((short)0x0001), 1e-8f); + assertEquals(-9.403955E-38, Bfloat16Layout.float16to32((short)0x8200), 1e-8f); + + // Infinite and NaN + assertEquals(Float.POSITIVE_INFINITY, Bfloat16Layout.float16to32((short)0x7F80), 0); + assertEquals(Float.NEGATIVE_INFINITY, Bfloat16Layout.float16to32((short)0xFF80), 0); + assertEquals(Float.NaN, Bfloat16Layout.float16to32((short)0x7FC0), 0); + assertEquals(Float.intBitsToFloat(0xFFFFFFFF), Bfloat16Layout.float16to32((short)0x7FC0), 0); + + // Normalized + assertEquals(1.0f, Bfloat16Layout.float16to32((short)0x3F80), 0); + assertEquals(-1.0f, Bfloat16Layout.float16to32((short)0xBF80), 0); + assertEquals(100.0f, Bfloat16Layout.float16to32((short)0x42C8), 0); + assertEquals(-101.0f, Bfloat16Layout.float16to32((short)0xC2CA), 0); + assertEquals(1.1171875f, Bfloat16Layout.float16to32((short)0x3F8F), 0); + assertEquals(131072f, Bfloat16Layout.float16to32((short)0x4800), 0); + assertEquals(3.3895314e38f, Bfloat16Layout.float16to32((short)0x7F7F), 0); + assertEquals(-3.3895314e38f, Bfloat16Layout.float16to32((short)0xFF7F), 0); + assertEquals(1.6171875f, Bfloat16Layout.float16to32((short)0x3FCF), 0); + assertEquals(65536.0, Bfloat16Layout.float16to32((short)0x4780), 0); + } +} diff --git a/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/BoolLayoutTest.java b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/BoolLayoutTest.java new file mode 100644 index 00000000000..b277624208d --- /dev/null +++ b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/BoolLayoutTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class BoolLayoutTest { + + @Test + public void booleanToByteTest() { + assertEquals((byte)1, BoolLayout.booleanToByte(true)); + assertEquals((byte)0, BoolLayout.booleanToByte(false)); + } + + @Test + public void byteToBooleanTest() { + assertTrue(BoolLayout.byteToBoolean((byte)1)); + assertTrue(BoolLayout.byteToBoolean((byte)127)); + assertTrue(BoolLayout.byteToBoolean((byte)-128)); + assertTrue(BoolLayout.byteToBoolean((byte)255)); + assertFalse(BoolLayout.byteToBoolean((byte)0)); + } +} diff --git a/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Float16LayoutTest.java b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Float16LayoutTest.java new file mode 100644 index 00000000000..2fb06bbc7c8 --- /dev/null +++ b/tensorflow-tools/src/test/java/org/tensorflow/tools/buffer/impl/layout/Float16LayoutTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2020 The TensorFlow Authors. 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.tensorflow.tools.buffer.impl.layout; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class Float16LayoutTest { + + @Test + public void testFloat32to16() { + + // Zero and subnormals + assertEquals((short)0x0000, Float16Layout.float32to16(0.0f)); + assertEquals((short)0x8000, Float16Layout.float32to16(-0.0f)); + assertEquals((short)0x0001, Float16Layout.float32to16(6e-8f)); + assertEquals((short)0x8200, Float16Layout.float32to16(-3.052e-5f)); + assertEquals((short)0x0000, Float16Layout.float32to16(6e-9f)); + + // Infinite and NaN + assertEquals((short)0x7C00, Float16Layout.float32to16(Float.POSITIVE_INFINITY)); + assertEquals((short)0xFC00, Float16Layout.float32to16(Float.NEGATIVE_INFINITY)); + assertEquals((short)0x7C00, Float16Layout.float32to16(65520.0f)); + assertEquals((short)0x7C00, Float16Layout.float32to16(165536.0f)); + assertEquals((short)0xFC00, Float16Layout.float32to16(-65520.0f)); + assertEquals((short)0x7E00, Float16Layout.float32to16(Float.NaN)); + assertEquals((short)0x7E00, Float16Layout.float32to16(Float.intBitsToFloat(0xFFFFFFFF))); + + // Normalized + assertEquals((short)0x7BFF, Float16Layout.float32to16(65519.0f)); + assertEquals((short)0x3C00, Float16Layout.float32to16(1.0f)); + assertEquals((short)0xBC00, Float16Layout.float32to16(-1.0f)); + assertEquals((short)0x5640, Float16Layout.float32to16(100.0f)); + assertEquals((short)0xD650, Float16Layout.float32to16(-101.0f)); + assertEquals((short)0x3C7E, Float16Layout.float32to16(1.123f)); + + // Rounding up + assertEquals((short)0x3C7E, Float16Layout.float32to16(1.1235f)); // 1.123 + assertEquals((short)0x3C7F, Float16Layout.float32to16(1.1236f)); // 1.124 + assertEquals((short)0x4000, Float16Layout.float32to16(2.0009f)); // 2.0 + assertEquals((short)0x4001, Float16Layout.float32to16(2.001f)); // 2.002 + assertEquals((short)0x5C00, Float16Layout.float32to16(256.125f)); // 256.0 + assertEquals((short)0x5C01, Float16Layout.float32to16(256.126f)); // 256.3 + assertEquals((short)0x5C01, Float16Layout.float32to16(256.30f)); // 256.3 + assertEquals((short)0x5C01, Float16Layout.float32to16(256.374f)); // 256.3 + assertEquals((short)0x5C02, Float16Layout.float32to16(256.375f)); // 256.5 + assertEquals((short)0x5C02, Float16Layout.float32to16(256.51f)); // 256.5 + } + + @Test + public void testFloat16to32() { + + // Zero and subnormals + assertEquals(0.0f, Float16Layout.float16to32((short)0x0000), 0); + assertEquals(-0.0f, Float16Layout.float16to32((short)0x8000), 0); + assertEquals(6e-8f, Float16Layout.float16to32((short)0x0001), 1e-8f); + assertEquals(-3.052e-5f, Float16Layout.float16to32((short)0x8200), 1e-8f); + + // Infinite and NaN + assertEquals(Float.POSITIVE_INFINITY, Float16Layout.float16to32((short)0x7C00), 0); + assertEquals(Float.NEGATIVE_INFINITY, Float16Layout.float16to32((short)0xFC00), 0); + assertEquals(Float.NaN, Float16Layout.float16to32((short)0x7E00), 0); + assertEquals(Float.intBitsToFloat(0xFFFFFFFF), Float16Layout.float16to32((short)0x7E00), 0); + + // Normalized + assertEquals(1.0f, Float16Layout.float16to32((short)0x3C00), 1e-1f); + assertEquals(-1.0f, Float16Layout.float16to32((short)0xBC00), 1e-1f); + assertEquals(100.0f, Float16Layout.float16to32((short)0x5640), 1e-1f); + assertEquals(-101.0f, Float16Layout.float16to32((short)0xD650), 1e-1f); + assertEquals(1.123f, Float16Layout.float16to32((short)0x3C7E), 1e-3f); + assertEquals(1.123f, Float16Layout.float16to32((short)0x3C7E), 1e-3f); + assertEquals(-62.34f, Float16Layout.float16to32((short)0xD3CB), 1e-2f); + } +}