From 1e3d17c3e9aa16a93f6ba7ee86dbd88b49140d3f Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 10 Jul 2020 20:48:33 -0400 Subject: [PATCH 1/5] modularize zerosLike, onesLike --- tfjs-core/src/gradients/ArgMax_grad.ts | 2 +- tfjs-core/src/gradients/ArgMin_grad.ts | 2 +- tfjs-core/src/gradients/Ceil_grad.ts | 2 +- tfjs-core/src/gradients/Floor_grad.ts | 2 +- tfjs-core/src/gradients/GreaterEqual_grad.ts | 2 +- tfjs-core/src/gradients/OnesLike_grad.ts | 28 +++++++++ tfjs-core/src/gradients/Pow_grad.ts | 3 +- tfjs-core/src/gradients/Prelu_grad.ts | 2 +- tfjs-core/src/gradients/SelectV2_grad.ts | 2 +- tfjs-core/src/gradients/Sign_grad.ts | 2 +- tfjs-core/src/gradients/Tile_grad.ts | 2 +- .../src/gradients/UnsortedSegmentSum_grad.ts | 3 +- tfjs-core/src/gradients/ZerosLike_grad.ts | 28 +++++++++ tfjs-core/src/kernel_names.ts | 6 ++ tfjs-core/src/ops/div_no_nan.ts | 2 +- tfjs-core/src/ops/ones_like.ts | 61 ++++++++++++++++++ tfjs-core/src/ops/ops.ts | 2 + tfjs-core/src/ops/tensor_ops.ts | 62 +++++-------------- tfjs-core/src/ops/unary_ops.ts | 3 +- tfjs-core/src/ops/zeros_like.ts | 46 ++++++++++++++ tfjs-core/src/register_all_gradients.ts | 7 ++- 21 files changed, 206 insertions(+), 63 deletions(-) create mode 100644 tfjs-core/src/gradients/OnesLike_grad.ts create mode 100644 tfjs-core/src/gradients/ZerosLike_grad.ts create mode 100644 tfjs-core/src/ops/ones_like.ts create mode 100644 tfjs-core/src/ops/zeros_like.ts diff --git a/tfjs-core/src/gradients/ArgMax_grad.ts b/tfjs-core/src/gradients/ArgMax_grad.ts index 12ed1094f8f..109523c4164 100644 --- a/tfjs-core/src/gradients/ArgMax_grad.ts +++ b/tfjs-core/src/gradients/ArgMax_grad.ts @@ -17,7 +17,7 @@ import {ArgMax} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const argMaxGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/ArgMin_grad.ts b/tfjs-core/src/gradients/ArgMin_grad.ts index 7b9611b99d3..063b6e63178 100644 --- a/tfjs-core/src/gradients/ArgMin_grad.ts +++ b/tfjs-core/src/gradients/ArgMin_grad.ts @@ -17,7 +17,7 @@ import {ArgMin} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const argMinGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Ceil_grad.ts b/tfjs-core/src/gradients/Ceil_grad.ts index e3e08144ab8..3b3ebabbcc4 100644 --- a/tfjs-core/src/gradients/Ceil_grad.ts +++ b/tfjs-core/src/gradients/Ceil_grad.ts @@ -17,7 +17,7 @@ import {Ceil} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const ceilGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Floor_grad.ts b/tfjs-core/src/gradients/Floor_grad.ts index 30771c454d5..454a8967c4c 100644 --- a/tfjs-core/src/gradients/Floor_grad.ts +++ b/tfjs-core/src/gradients/Floor_grad.ts @@ -17,7 +17,7 @@ import {Floor} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const floorGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/GreaterEqual_grad.ts b/tfjs-core/src/gradients/GreaterEqual_grad.ts index 6e9e542abae..abb512efd17 100644 --- a/tfjs-core/src/gradients/GreaterEqual_grad.ts +++ b/tfjs-core/src/gradients/GreaterEqual_grad.ts @@ -16,7 +16,7 @@ */ import {GreaterEqual} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const greaterEqualGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/OnesLike_grad.ts b/tfjs-core/src/gradients/OnesLike_grad.ts new file mode 100644 index 00000000000..96bfcfceba6 --- /dev/null +++ b/tfjs-core/src/gradients/OnesLike_grad.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2020 Google LLC. 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. + * ============================================================================= + */ + +import {OnesLike} from '../kernel_names'; +import {GradConfig} from '../kernel_registry'; +import {zerosLike} from '../ops/zeros_like'; +import {Tensor} from '../tensor'; + +export const onesLikeGradConfig: GradConfig = { + kernelName: OnesLike, + gradFunc: (dy: Tensor) => { + return {x: () => zerosLike(dy)}; + } +}; diff --git a/tfjs-core/src/gradients/Pow_grad.ts b/tfjs-core/src/gradients/Pow_grad.ts index e0422e65f33..e8130cdad4c 100644 --- a/tfjs-core/src/gradients/Pow_grad.ts +++ b/tfjs-core/src/gradients/Pow_grad.ts @@ -24,9 +24,10 @@ import {pow} from '../ops/pow'; import {reshape} from '../ops/reshape'; import {sub} from '../ops/sub'; import {sum} from '../ops/sum'; -import {scalar, zerosLike} from '../ops/tensor_ops'; +import {scalar} from '../ops/tensor_ops'; import {log} from '../ops/unary_ops'; import {where} from '../ops/where'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const powGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Prelu_grad.ts b/tfjs-core/src/gradients/Prelu_grad.ts index d9fe69a197a..2eb18ce53ca 100644 --- a/tfjs-core/src/gradients/Prelu_grad.ts +++ b/tfjs-core/src/gradients/Prelu_grad.ts @@ -21,8 +21,8 @@ import {greater} from '../ops/greater'; import {mul} from '../ops/mul'; import {reshape} from '../ops/reshape'; import {sum} from '../ops/sum'; -import {zerosLike} from '../ops/tensor_ops'; import {where} from '../ops/where'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const preluGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/SelectV2_grad.ts b/tfjs-core/src/gradients/SelectV2_grad.ts index c49b17c774f..294397a9120 100644 --- a/tfjs-core/src/gradients/SelectV2_grad.ts +++ b/tfjs-core/src/gradients/SelectV2_grad.ts @@ -20,7 +20,7 @@ import {GradConfig} from '../kernel_registry'; import {cast} from '../ops/array_ops'; import {logicalNot} from '../ops/logical_not'; import {mul} from '../ops/mul'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const selectV2PoolGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Sign_grad.ts b/tfjs-core/src/gradients/Sign_grad.ts index f6ac46229ba..79400762425 100644 --- a/tfjs-core/src/gradients/Sign_grad.ts +++ b/tfjs-core/src/gradients/Sign_grad.ts @@ -17,7 +17,7 @@ import {Sign} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const signGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Tile_grad.ts b/tfjs-core/src/gradients/Tile_grad.ts index c3b80ce5e3b..4f090be2198 100644 --- a/tfjs-core/src/gradients/Tile_grad.ts +++ b/tfjs-core/src/gradients/Tile_grad.ts @@ -19,7 +19,7 @@ import {Tile, TileAttrs} from '../kernel_names'; import {GradConfig, NamedAttrMap} from '../kernel_registry'; import {add} from '../ops/add'; import {slice} from '../ops/slice'; -import {zerosLike} from '../ops/tensor_ops'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const tileGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts b/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts index 982194417a5..a676770caae 100644 --- a/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts +++ b/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts @@ -22,8 +22,9 @@ import {gather} from '../ops/gather'; import {greaterEqual} from '../ops/greater_equal'; import {logicalAnd} from '../ops/logical_and'; import {maximum} from '../ops/maximum'; -import {ones, scalar, zerosLike} from '../ops/tensor_ops'; +import {ones, scalar} from '../ops/tensor_ops'; import {where} from '../ops/where'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor, Tensor1D} from '../tensor'; export const unsortedSegmentSumGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/ZerosLike_grad.ts b/tfjs-core/src/gradients/ZerosLike_grad.ts new file mode 100644 index 00000000000..688ad14bca4 --- /dev/null +++ b/tfjs-core/src/gradients/ZerosLike_grad.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2020 Google LLC. 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. + * ============================================================================= + */ + +import {ZerosLike} from '../kernel_names'; +import {GradConfig} from '../kernel_registry'; +import {zerosLike} from '../ops/zeros_like'; +import {Tensor} from '../tensor'; + +export const zerosLikeGradConfig: GradConfig = { + kernelName: ZerosLike, + gradFunc: (dy: Tensor) => { + return {x: () => zerosLike(dy)}; + } +}; diff --git a/tfjs-core/src/kernel_names.ts b/tfjs-core/src/kernel_names.ts index 70cf4cb01fa..419f9fb45bc 100644 --- a/tfjs-core/src/kernel_names.ts +++ b/tfjs-core/src/kernel_names.ts @@ -468,6 +468,9 @@ export interface NonMaxSuppressionV5Attrs { softNmsSigma: number; } +export const OnesLike = 'OnesLike'; +export type OnesLikeInputs = UnaryInputs; + export const OneHot = 'OneHot'; export type OneHotInputs = Pick; export interface OneHotAttrs { @@ -631,6 +634,9 @@ export interface UnsortedSegmentSumAttrs { numSegments: number; } +export const ZerosLike = 'ZerosLike'; +export type ZerosLikeInputs = UnaryInputs; + /** * TensorFlow.js-only kernels */ diff --git a/tfjs-core/src/ops/div_no_nan.ts b/tfjs-core/src/ops/div_no_nan.ts index 48a96a59e20..a5b6f327a73 100644 --- a/tfjs-core/src/ops/div_no_nan.ts +++ b/tfjs-core/src/ops/div_no_nan.ts @@ -22,8 +22,8 @@ import {TensorLike} from '../types'; import {div} from './div'; import {op} from './operation'; -import {zerosLike} from './tensor_ops'; import {where} from './where'; +import {zerosLike} from './zeros_like'; /** * Divides two `tf.Tensor`s element-wise, A / B. Supports broadcasting. Return 0 diff --git a/tfjs-core/src/ops/ones_like.ts b/tfjs-core/src/ops/ones_like.ts new file mode 100644 index 00000000000..a338963b549 --- /dev/null +++ b/tfjs-core/src/ops/ones_like.ts @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE, ForwardFunc} from '../engine'; +import {OnesLike, OnesLikeInputs} from '../kernel_names'; +import {Tensor} from '../tensor'; +import {NamedTensorMap} from '../tensor_types'; +import {convertToTensor} from '../tensor_util_env'; +import {TensorLike} from '../types'; + +import {complex} from './complex'; +import {imag} from './imag'; +import {op} from './operation'; +import {real} from './real'; +import {zerosLike} from './zeros_like'; + +/** + * Creates a `tf.Tensor` with all elements set to 1 with the same shape as the + * given tensor. + * + * ```js + * const x = tf.tensor([1, 2]); + * tf.onesLike(x).print(); + * ``` + * @param x A tensor. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +function onesLike_(x: T|TensorLike): T { + const $x = convertToTensor(x, 'x', 'onesLike'); + + const forward: ForwardFunc = (backend, save) => { + if ($x.dtype === 'complex64') { + const r = onesLike(real($x)); + const i = zerosLike(imag($x)); + return complex(r, i); + } + + return backend.onesLike($x); + }; + + const inputs: OnesLikeInputs = {x: $x}; + return ENGINE.runKernelFunc( + forward, inputs as {} as NamedTensorMap, null /* grad */, + OnesLike) as T; +} + +export const onesLike = op({onesLike_}); diff --git a/tfjs-core/src/ops/ops.ts b/tfjs-core/src/ops/ops.ts index 378658b52ca..7e93487b0e9 100644 --- a/tfjs-core/src/ops/ops.ts +++ b/tfjs-core/src/ops/ops.ts @@ -99,6 +99,7 @@ export {multinomial} from './multinomial'; export {neg} from './neg'; export {notEqual} from './not_equal'; export {oneHot} from './one_hot'; +export {onesLike} from './ones_like'; export {outerProduct} from './outer_product'; export {pad} from './pad'; export {pad1d} from './pad1d'; @@ -148,6 +149,7 @@ export {unsortedSegmentSum} from './unsorted_segment_sum'; export {unstack} from './unstack'; export {where} from './where'; export {whereAsync} from './where_async'; +export {zerosLike} from './zeros_like'; export * from './boolean_mask'; export * from './unary_ops'; diff --git a/tfjs-core/src/ops/tensor_ops.ts b/tfjs-core/src/ops/tensor_ops.ts index 6248a96c7f0..ff3d2ed6c1a 100644 --- a/tfjs-core/src/ops/tensor_ops.ts +++ b/tfjs-core/src/ops/tensor_ops.ts @@ -17,15 +17,12 @@ import {ENGINE} from '../engine'; import {Scalar, Tensor, Tensor1D, Tensor2D, Tensor3D, Tensor4D, Tensor5D, Tensor6D, Variable} from '../tensor'; -import {convertToTensor, inferShape} from '../tensor_util_env'; +import {inferShape} from '../tensor_util_env'; import {TensorLike, TensorLike1D, TensorLike2D, TensorLike3D, TensorLike4D, TensorLike5D, TensorLike6D, TypedArray} from '../types'; import {DataType, Rank, ShapeMap} from '../types'; import {assert, assertNonNegativeIntegerDimensions, assertNonNull, flatten, inferDtype, isTypedArray, makeOnesTypedArray, makeZerosTypedArray, sizeFromShape, toTypedArray} from '../util'; import {complex} from './complex'; -import {imag} from './imag'; -import {op} from './operation'; -import {real} from './real'; /** * Creates a `tf.Tensor` with the provided values, shape and dtype. @@ -455,48 +452,6 @@ function zeros( return ENGINE.makeTensor(values, shape, dtype) as Tensor; } -/** - * Creates a `tf.Tensor` with all elements set to 1 with the same shape as the - * given tensor. - * - * ```js - * const x = tf.tensor([1, 2]); - * tf.onesLike(x).print(); - * ``` - * @param x A tensor. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function onesLike_(x: T|TensorLike): T { - const $x = convertToTensor(x, 'x', 'onesLike'); - if ($x.dtype === 'complex64') { - const r = onesLike(real($x)); - const i = zerosLike(imag($x)); - return complex(r, i); - } - const der = (dy: T, saved: Tensor[]) => ({x: () => zerosLike(dy)}); - return ENGINE.runKernelFunc( - backend => backend.onesLike($x), {x: $x}, der, 'OnesLike') as T; -} - -/** - * Creates a `tf.Tensor` with all elements set to 0 with the same shape as the - * given tensor. - * - * ```js - * const x = tf.tensor([1, 2]); - * tf.zerosLike(x).print(); - * ``` - * - * @param x The tensor of required shape. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function zerosLike_(x: T|TensorLike): T { - const $x = convertToTensor(x, 'x', 'zerosLike'); - const der = (dy: T, saved: Tensor[]) => ({x: () => zerosLike(dy)}); - return ENGINE.runKernelFunc( - backend => backend.zerosLike($x), {x: $x}, der, 'ZerosLike') as T; -} - /** * Return an evenly spaced sequence of numbers over the given interval. * @@ -582,5 +537,16 @@ export { zeros }; -export const onesLike = op({onesLike_}); -export const zerosLike = op({zerosLike_}); +// export const linspace = op(linspace_); +// export const ones = op(ones_); +// export const range = op(range_); +// export const scalar = op(scalar_); +// export const tensor = op(tensor_); +// export const tensor1d = op(tensor1d_); +// export const tensor2d = op(tensor2d_); +// export const tensor3d = op(tensor3d_); +// export const tensor4d = op(tensor4d_); +// export const tensor5d = op(tensor5d_); +// export const tensor6d = op(tensor6d_); +// export const variable = op(variable_); +// export const zeros = op(zeros_); diff --git a/tfjs-core/src/ops/unary_ops.ts b/tfjs-core/src/ops/unary_ops.ts index 13fb7f66a25..606aa236fd6 100644 --- a/tfjs-core/src/ops/unary_ops.ts +++ b/tfjs-core/src/ops/unary_ops.ts @@ -21,7 +21,8 @@ import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import * as util from '../util'; import {op} from './operation'; -import {scalar, zerosLike} from './tensor_ops'; +import {scalar} from './tensor_ops'; +import {zerosLike} from './zeros_like'; /** * RReturns which elements of x are NaN. diff --git a/tfjs-core/src/ops/zeros_like.ts b/tfjs-core/src/ops/zeros_like.ts new file mode 100644 index 00000000000..6958a2ceec4 --- /dev/null +++ b/tfjs-core/src/ops/zeros_like.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {ZerosLike, ZerosLikeInputs} from '../kernel_names'; +import {Tensor} from '../tensor'; +import {NamedTensorMap} from '../tensor_types'; +import {convertToTensor} from '../tensor_util_env'; +import {TensorLike} from '../types'; + +import {op} from './operation'; + +/** + * Creates a `tf.Tensor` with all elements set to 0 with the same shape as the + * given tensor. + * + * ```js + * const x = tf.tensor([1, 2]); + * tf.zerosLike(x).print(); + * ``` + * + * @param x The tensor of required shape. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +function zerosLike_(x: T|TensorLike): T { + const $x = convertToTensor(x, 'x', 'zerosLike'); + const inputs: ZerosLikeInputs = {x: $x}; + return ENGINE.runKernelFunc( + backend => backend.zerosLike($x), inputs as {} as NamedTensorMap, + null /* grad */, ZerosLike) as T; +} +export const zerosLike = op({zerosLike_}); diff --git a/tfjs-core/src/register_all_gradients.ts b/tfjs-core/src/register_all_gradients.ts index 5aea486a509..4f965919979 100644 --- a/tfjs-core/src/register_all_gradients.ts +++ b/tfjs-core/src/register_all_gradients.ts @@ -60,6 +60,7 @@ import {modGradConfig} from './gradients/Mod_grad'; import {multiplyGradConfig} from './gradients/Multiply_grad'; import {negateGradConfig} from './gradients/Negate_grad'; import {oneHotGradConfig} from './gradients/OneHot_grad'; +import {onesLikeGradConfig} from './gradients/OnesLike_grad'; import {padV2GradConfig} from './gradients/PadV2_grad'; import {powGradConfig} from './gradients/Pow_grad'; import {preluGradConfig} from './gradients/Prelu_grad'; @@ -87,6 +88,7 @@ import {tileGradConfig} from './gradients/Tile_grad'; import {transposeGradConfig} from './gradients/Transpose_grad'; import {unpackGradConfig} from './gradients/Unpack_grad'; import {unsortedSegmentSumGradConfig} from './gradients/UnsortedSegmentSum_grad'; +import {zerosLikeGradConfig} from './gradients/ZerosLike_grad'; import {GradConfig} from './kernel_registry'; import {registerGradient} from './kernel_registry'; @@ -139,7 +141,7 @@ const gradConfigs: GradConfig[] = [ multiplyGradConfig, negateGradConfig, oneHotGradConfig, - oneHotGradConfig, + onesLikeGradConfig, padV2GradConfig, padV2GradConfig, powGradConfig, @@ -169,7 +171,8 @@ const gradConfigs: GradConfig[] = [ tileGradConfig, transposeGradConfig, unpackGradConfig, - unsortedSegmentSumGradConfig + unsortedSegmentSumGradConfig, + zerosLikeGradConfig ]; for (const gradientConfig of gradConfigs) { From ce1a223bfe9877c758504be96c7bc13bb50f0f6b Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 10 Jul 2020 21:08:57 -0400 Subject: [PATCH 2/5] range, linspace --- tfjs-core/src/kernel_names.ts | 15 +++++++ tfjs-core/src/ops/linspace.ts | 47 ++++++++++++++++++++ tfjs-core/src/ops/ops.ts | 2 + tfjs-core/src/ops/range.ts | 83 +++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 tfjs-core/src/ops/linspace.ts create mode 100644 tfjs-core/src/ops/range.ts diff --git a/tfjs-core/src/kernel_names.ts b/tfjs-core/src/kernel_names.ts index 419f9fb45bc..272875225a9 100644 --- a/tfjs-core/src/kernel_names.ts +++ b/tfjs-core/src/kernel_names.ts @@ -333,6 +333,13 @@ export type LessInputs = BinaryInputs; export const LessEqual = 'LessEqual'; export type LessEqualInputs = BinaryInputs; +export const LinSpace = 'LinSpace'; +export interface LinSpaceAttrs { + start: number; + stop: number; + num: number; +} + export const LogicalAnd = 'LogicalAnd'; export type LogicalAndInputs = BinaryInputs; @@ -502,6 +509,14 @@ export interface ProdAttrs { keepDims: boolean; } +export const Range = 'Range'; +export interface RangeAttrs { + start: number; + stop: number; + step: number; + dtype: 'float32'|'int32'; +} + export const Real = 'Real'; export type RealInputs = Pick; diff --git a/tfjs-core/src/ops/linspace.ts b/tfjs-core/src/ops/linspace.ts new file mode 100644 index 00000000000..bea802bad0a --- /dev/null +++ b/tfjs-core/src/ops/linspace.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {LinSpace, LinSpaceAttrs} from '../kernel_names'; +import {NamedAttrMap} from '../kernel_registry'; +import {Tensor1D} from '../tensor'; + +import {op} from './operation'; + +/** + * Return an evenly spaced sequence of numbers over the given interval. + * + * ```js + * tf.linspace(0, 9, 10).print(); + * ``` + * @param start The start value of the sequence. + * @param stop The end value of the sequence. + * @param num The number of values to generate. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +function linspace_(start: number, stop: number, num: number): Tensor1D { + if (num <= 0) { + throw new Error('The number of values should be positive.'); + } + + const attrs: LinSpaceAttrs = {start, stop, num}; + return ENGINE.runKernelFunc( + backend => backend.linspace(start, stop, num), {} /* inputs */, + null /* grad */, LinSpace, attrs as {} as NamedAttrMap); +} + +export const linspace = op({linspace_}); diff --git a/tfjs-core/src/ops/ops.ts b/tfjs-core/src/ops/ops.ts index 7e93487b0e9..4f09aafdcbd 100644 --- a/tfjs-core/src/ops/ops.ts +++ b/tfjs-core/src/ops/ops.ts @@ -76,6 +76,7 @@ export {imag} from './imag'; export {leakyRelu} from './leaky_relu'; export {less} from './less'; export {lessEqual} from './less_equal'; +export {linspace} from './linspace'; export {localResponseNormalization} from './local_response_normalization'; export {logSumExp} from './log_sum_exp'; export {logicalAnd} from './logical_and'; @@ -114,6 +115,7 @@ export {rand} from './rand'; export {randomGamma} from './random_gamma'; export {randomNormal} from './random_normal'; export {randomUniform} from './random_uniform'; +export {range} from './range'; export {real} from './real'; export {relu} from './relu'; export {relu6} from './relu6'; diff --git a/tfjs-core/src/ops/range.ts b/tfjs-core/src/ops/range.ts new file mode 100644 index 00000000000..705126cf299 --- /dev/null +++ b/tfjs-core/src/ops/range.ts @@ -0,0 +1,83 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE, ForwardFunc} from '../engine'; +import {Range, RangeAttrs} from '../kernel_names'; +import {NamedAttrMap} from '../kernel_registry'; +import {Tensor, Tensor1D} from '../tensor'; +import {makeZerosTypedArray} from '../util'; + +import {tensor1d, zeros} from './tensor_ops'; + +/** + * Creates a new `tf.Tensor1D` filled with the numbers in the range provided. + * + * The tensor is a is half-open interval meaning it includes start, but + * excludes stop. Decrementing ranges and negative step values are also + * supported.sv + * + * + * ```js + * tf.range(0, 9, 2).print(); + * ``` + * + * @param start An integer start value + * @param stop An integer stop value + * @param step An integer increment (will default to 1 or -1) + * @param dtype The data type of the output tensor. Defaults to 'float32'. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function range( + start: number, stop: number, step = 1, + dtype: 'float32'|'int32' = 'float32'): Tensor1D { + if (step === 0) { + throw new Error('Cannot have a step of zero'); + } + + const forward: ForwardFunc = () => { + const sameStartStop = start === stop; + const increasingRangeNegativeStep = start < stop && step < 0; + const decreasingRangePositiveStep = stop < start && step > 1; + + if (sameStartStop || increasingRangeNegativeStep || + decreasingRangePositiveStep) { + return zeros([0], dtype); + } + + const numElements = Math.abs(Math.ceil((stop - start) / step)); + const values = makeZerosTypedArray(numElements, dtype); + + if (stop < start && step === 1) { + // Auto adjust the step's sign if it hasn't been set + // (or was set to 1) + step = -1; + } + + values[0] = start; + for (let i = 1; i < values.length; i++) { + values[i] = values[i - 1] + step; + } + + return tensor1d(values, dtype); + }; + + const attrs: RangeAttrs = {start, stop, step, dtype}; + + return ENGINE.runKernelFunc( + forward, {} /* inputs */, null /* grad */, Range, + attrs as {} as NamedAttrMap) as Tensor1D; +} From ae54ef6d67e64c1eca8ded2555ba7e89f4c482af Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 10 Jul 2020 21:09:33 -0400 Subject: [PATCH 3/5] save --- tfjs-core/src/ops/linspace.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tfjs-core/src/ops/linspace.ts b/tfjs-core/src/ops/linspace.ts index bea802bad0a..203b0f900e7 100644 --- a/tfjs-core/src/ops/linspace.ts +++ b/tfjs-core/src/ops/linspace.ts @@ -33,7 +33,7 @@ import {op} from './operation'; * @param num The number of values to generate. */ /** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function linspace_(start: number, stop: number, num: number): Tensor1D { +export function linspace(start: number, stop: number, num: number): Tensor1D { if (num <= 0) { throw new Error('The number of values should be positive.'); } @@ -43,5 +43,3 @@ function linspace_(start: number, stop: number, num: number): Tensor1D { backend => backend.linspace(start, stop, num), {} /* inputs */, null /* grad */, LinSpace, attrs as {} as NamedAttrMap); } - -export const linspace = op({linspace_}); From f0652798d7439a5867d3dd2f2893b4b810fa0ffa Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 10 Jul 2020 21:31:17 -0400 Subject: [PATCH 4/5] modularize tensor ops --- tfjs-core/src/backends/backend_util.ts | 4 +- .../src/backends/non_max_suppression_impl.ts | 3 +- tfjs-core/src/backends/topk_impl.ts | 2 +- tfjs-core/src/gradients/Acos_grad.ts | 2 +- tfjs-core/src/gradients/Asin_grad.ts | 2 +- tfjs-core/src/gradients/Asinh_grad.ts | 2 +- tfjs-core/src/gradients/Atanh_grad.ts | 2 +- .../src/gradients/FusedBatchNorm_grad.ts | 2 +- tfjs-core/src/gradients/OneHot_grad.ts | 2 +- tfjs-core/src/gradients/Pow_grad.ts | 2 +- tfjs-core/src/gradients/Selu_grad.ts | 2 +- .../src/gradients/SquaredDifference_grad.ts | 2 +- tfjs-core/src/gradients/Sum_grad.ts | 2 +- tfjs-core/src/gradients/Tanh_grad.ts | 2 +- .../src/gradients/UnsortedSegmentSum_grad.ts | 3 +- tfjs-core/src/io/io_utils.ts | 29 +- tfjs-core/src/ops/band_part.ts | 4 +- tfjs-core/src/ops/browser.ts | 2 +- tfjs-core/src/ops/compute_weighted_loss.ts | 3 +- tfjs-core/src/ops/concat.ts | 2 +- tfjs-core/src/ops/cosine_distance.ts | 2 +- tfjs-core/src/ops/dropout_test.ts | 2 +- tfjs-core/src/ops/frame.ts | 2 +- tfjs-core/src/ops/gather_nd_test.ts | 2 +- tfjs-core/src/ops/hinge_loss.ts | 3 +- tfjs-core/src/ops/huber_loss.ts | 2 +- tfjs-core/src/ops/in_top_k.ts | 2 +- tfjs-core/src/ops/in_top_k_test.ts | 2 +- tfjs-core/src/ops/leaky_relu.ts | 2 +- tfjs-core/src/ops/linspace.ts | 2 - tfjs-core/src/ops/log_loss.ts | 2 +- tfjs-core/src/ops/mean.ts | 3 +- tfjs-core/src/ops/moving_average.ts | 2 +- tfjs-core/src/ops/norm.ts | 2 +- tfjs-core/src/ops/ones.ts | 47 ++ tfjs-core/src/ops/ops.ts | 12 +- tfjs-core/src/ops/qr.ts | 2 +- tfjs-core/src/ops/range.ts | 3 +- tfjs-core/src/ops/scalar.ts | 54 ++ tfjs-core/src/ops/sigmoid_cross_entropy.ts | 2 +- tfjs-core/src/ops/signal_ops_util.ts | 2 +- tfjs-core/src/ops/softmax_cross_entropy.ts | 2 +- tfjs-core/src/ops/spectral_ops.ts | 3 +- tfjs-core/src/ops/tensor.ts | 56 ++ tfjs-core/src/ops/tensor1d.ts | 48 ++ tfjs-core/src/ops/tensor2d.ts | 65 +++ tfjs-core/src/ops/tensor3d.ts | 65 +++ tfjs-core/src/ops/tensor4d.ts | 65 +++ tfjs-core/src/ops/tensor5d.ts | 66 +++ tfjs-core/src/ops/tensor6d.ts | 69 +++ tfjs-core/src/ops/tensor_ops.ts | 552 ------------------ tfjs-core/src/ops/tensor_ops_util.ts | 76 +++ tfjs-core/src/ops/topk_test.ts | 5 +- tfjs-core/src/ops/unary_ops.ts | 2 +- tfjs-core/src/ops/variable.ts | 42 ++ tfjs-core/src/ops/zeros.ts | 46 ++ 56 files changed, 777 insertions(+), 611 deletions(-) create mode 100644 tfjs-core/src/ops/ones.ts create mode 100644 tfjs-core/src/ops/scalar.ts create mode 100644 tfjs-core/src/ops/tensor.ts create mode 100644 tfjs-core/src/ops/tensor1d.ts create mode 100644 tfjs-core/src/ops/tensor2d.ts create mode 100644 tfjs-core/src/ops/tensor3d.ts create mode 100644 tfjs-core/src/ops/tensor4d.ts create mode 100644 tfjs-core/src/ops/tensor5d.ts create mode 100644 tfjs-core/src/ops/tensor6d.ts delete mode 100644 tfjs-core/src/ops/tensor_ops.ts create mode 100644 tfjs-core/src/ops/tensor_ops_util.ts create mode 100644 tfjs-core/src/ops/variable.ts create mode 100644 tfjs-core/src/ops/zeros.ts diff --git a/tfjs-core/src/backends/backend_util.ts b/tfjs-core/src/backends/backend_util.ts index c188bf9289a..ba1e0db78ca 100644 --- a/tfjs-core/src/backends/backend_util.ts +++ b/tfjs-core/src/backends/backend_util.ts @@ -16,7 +16,9 @@ */ import {ENGINE} from '../engine'; -import {scalar, tensor1d, zeros} from '../ops/tensor_ops'; +import {scalar} from '../ops/scalar'; +import {tensor1d} from '../ops/tensor1d'; +import {zeros} from '../ops/zeros'; import {Tensor} from '../tensor'; import {Rank} from '../types'; import {DataType, ShapeMap} from '../types'; diff --git a/tfjs-core/src/backends/non_max_suppression_impl.ts b/tfjs-core/src/backends/non_max_suppression_impl.ts index dab7f92caa9..9acea57483b 100644 --- a/tfjs-core/src/backends/non_max_suppression_impl.ts +++ b/tfjs-core/src/backends/non_max_suppression_impl.ts @@ -19,7 +19,8 @@ * Implementation of the NonMaxSuppression kernel shared between webgl and cpu. */ -import {scalar, tensor1d} from '../ops/tensor_ops'; +import {scalar} from '../ops/scalar'; +import {tensor1d} from '../ops/tensor1d'; import {Tensor1D} from '../tensor'; import {NamedTensorMap} from '../tensor_types'; import {TypedArray} from '../types'; diff --git a/tfjs-core/src/backends/topk_impl.ts b/tfjs-core/src/backends/topk_impl.ts index 4b46288eb01..98628dbfede 100644 --- a/tfjs-core/src/backends/topk_impl.ts +++ b/tfjs-core/src/backends/topk_impl.ts @@ -17,7 +17,7 @@ /** An implementation of the TopK kernel shared between webgl and cpu. */ -import {tensor} from '../ops/tensor_ops'; +import {tensor} from '../ops/tensor'; import {Tensor} from '../tensor'; import {NumericDataType, TypedArray} from '../types'; import {getTypedArrayFromDType} from '../util'; diff --git a/tfjs-core/src/gradients/Acos_grad.ts b/tfjs-core/src/gradients/Acos_grad.ts index 208e7dc4473..d51c87cf5fe 100644 --- a/tfjs-core/src/gradients/Acos_grad.ts +++ b/tfjs-core/src/gradients/Acos_grad.ts @@ -20,9 +20,9 @@ import {GradConfig} from '../kernel_registry'; import {cast} from '../ops/array_ops'; import {div} from '../ops/div'; import {neg} from '../ops/neg'; +import {scalar} from '../ops/scalar'; import {square} from '../ops/square'; import {sub} from '../ops/sub'; -import {scalar} from '../ops/tensor_ops'; import {sqrt} from '../ops/unary_ops'; import {Tensor} from '../tensor'; diff --git a/tfjs-core/src/gradients/Asin_grad.ts b/tfjs-core/src/gradients/Asin_grad.ts index 290cd3ecb4f..fa5713a055c 100644 --- a/tfjs-core/src/gradients/Asin_grad.ts +++ b/tfjs-core/src/gradients/Asin_grad.ts @@ -19,9 +19,9 @@ import {Asin} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; import {cast} from '../ops/array_ops'; import {div} from '../ops/div'; +import {scalar} from '../ops/scalar'; import {square} from '../ops/square'; import {sub} from '../ops/sub'; -import {scalar} from '../ops/tensor_ops'; import {sqrt} from '../ops/unary_ops'; import {Tensor} from '../tensor'; diff --git a/tfjs-core/src/gradients/Asinh_grad.ts b/tfjs-core/src/gradients/Asinh_grad.ts index 8916f012aa1..f2f360ef3eb 100644 --- a/tfjs-core/src/gradients/Asinh_grad.ts +++ b/tfjs-core/src/gradients/Asinh_grad.ts @@ -20,8 +20,8 @@ import {GradConfig} from '../kernel_registry'; import {add} from '../ops/add'; import {cast} from '../ops/array_ops'; import {div} from '../ops/div'; +import {scalar} from '../ops/scalar'; import {square} from '../ops/square'; -import {scalar} from '../ops/tensor_ops'; import {sqrt} from '../ops/unary_ops'; import {Tensor} from '../tensor'; diff --git a/tfjs-core/src/gradients/Atanh_grad.ts b/tfjs-core/src/gradients/Atanh_grad.ts index 67d1aae4685..9e92ea1beed 100644 --- a/tfjs-core/src/gradients/Atanh_grad.ts +++ b/tfjs-core/src/gradients/Atanh_grad.ts @@ -21,7 +21,7 @@ import {cast} from '../ops/array_ops'; import {div} from '../ops/div'; import {square} from '../ops/square'; import {sub} from '../ops/sub'; -import {scalar} from '../ops/tensor_ops'; +import {scalar} from '../ops/scalar'; import {Tensor} from '../tensor'; export const atanhGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/FusedBatchNorm_grad.ts b/tfjs-core/src/gradients/FusedBatchNorm_grad.ts index 9ab2726bfe1..e5f516974fe 100644 --- a/tfjs-core/src/gradients/FusedBatchNorm_grad.ts +++ b/tfjs-core/src/gradients/FusedBatchNorm_grad.ts @@ -20,9 +20,9 @@ import {add} from '../ops/add'; import {getReductionAxes} from '../ops/broadcast_util'; import {mul} from '../ops/mul'; import {reshape} from '../ops/reshape'; +import {scalar} from '../ops/scalar'; import {sub} from '../ops/sub'; import {sum} from '../ops/sum'; -import {scalar} from '../ops/tensor_ops'; import {tile} from '../ops/tile'; import {rsqrt} from '../ops/unary_ops'; import {Tensor} from '../tensor'; diff --git a/tfjs-core/src/gradients/OneHot_grad.ts b/tfjs-core/src/gradients/OneHot_grad.ts index d24dcfd50b5..4db5271e849 100644 --- a/tfjs-core/src/gradients/OneHot_grad.ts +++ b/tfjs-core/src/gradients/OneHot_grad.ts @@ -17,7 +17,7 @@ import {OneHot} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; -import {zeros} from '../ops/tensor_ops'; +import {zeros} from '../ops/zeros'; import {Tensor} from '../tensor'; export const oneHotGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Pow_grad.ts b/tfjs-core/src/gradients/Pow_grad.ts index e8130cdad4c..df4201a11c4 100644 --- a/tfjs-core/src/gradients/Pow_grad.ts +++ b/tfjs-core/src/gradients/Pow_grad.ts @@ -22,9 +22,9 @@ import {greater} from '../ops/greater'; import {mul} from '../ops/mul'; import {pow} from '../ops/pow'; import {reshape} from '../ops/reshape'; +import {scalar} from '../ops/scalar'; import {sub} from '../ops/sub'; import {sum} from '../ops/sum'; -import {scalar} from '../ops/tensor_ops'; import {log} from '../ops/unary_ops'; import {where} from '../ops/where'; import {zerosLike} from '../ops/zeros_like'; diff --git a/tfjs-core/src/gradients/Selu_grad.ts b/tfjs-core/src/gradients/Selu_grad.ts index 59177669fa2..5d7d63bcad9 100644 --- a/tfjs-core/src/gradients/Selu_grad.ts +++ b/tfjs-core/src/gradients/Selu_grad.ts @@ -19,8 +19,8 @@ import {GradConfig} from '../kernel_registry'; import {cast} from '../ops/array_ops'; import {greater} from '../ops/greater'; import {mul} from '../ops/mul'; +import {scalar} from '../ops/scalar'; import {SELU_SCALE, SELU_SCALEALPHA} from '../ops/selu_util'; -import {scalar} from '../ops/tensor_ops'; import {exp} from '../ops/unary_ops'; import {where} from '../ops/where'; import {Tensor} from '../tensor'; diff --git a/tfjs-core/src/gradients/SquaredDifference_grad.ts b/tfjs-core/src/gradients/SquaredDifference_grad.ts index 46e7a40ccc7..8e0cccd6041 100644 --- a/tfjs-core/src/gradients/SquaredDifference_grad.ts +++ b/tfjs-core/src/gradients/SquaredDifference_grad.ts @@ -18,8 +18,8 @@ import {SquaredDifference} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; import {mul} from '../ops/mul'; +import {scalar} from '../ops/scalar'; import {sub} from '../ops/sub'; -import {scalar} from '../ops/tensor_ops'; import {Tensor} from '../tensor'; export const squaredDifferenceGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Sum_grad.ts b/tfjs-core/src/gradients/Sum_grad.ts index de3a0a41b14..b4f15d0cd49 100644 --- a/tfjs-core/src/gradients/Sum_grad.ts +++ b/tfjs-core/src/gradients/Sum_grad.ts @@ -18,8 +18,8 @@ import {Sum, SumAttrs} from '../kernel_names'; import {GradConfig, NamedAttrMap} from '../kernel_registry'; import {mul} from '../ops/mul'; +import {ones} from '../ops/ones'; import {reshape} from '../ops/reshape'; -import {ones} from '../ops/tensor_ops'; import {Tensor} from '../tensor'; import {parseAxisParam} from '../util'; diff --git a/tfjs-core/src/gradients/Tanh_grad.ts b/tfjs-core/src/gradients/Tanh_grad.ts index e2e1096c370..ccae78f2f68 100644 --- a/tfjs-core/src/gradients/Tanh_grad.ts +++ b/tfjs-core/src/gradients/Tanh_grad.ts @@ -18,9 +18,9 @@ import {Tanh} from '../kernel_names'; import {GradConfig} from '../kernel_registry'; import {mul} from '../ops/mul'; +import {scalar} from '../ops/scalar'; import {square} from '../ops/square'; import {sub} from '../ops/sub'; -import {scalar} from '../ops/tensor_ops'; import {Tensor} from '../tensor'; export const tanhGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts b/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts index a676770caae..a6bff2ed25e 100644 --- a/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts +++ b/tfjs-core/src/gradients/UnsortedSegmentSum_grad.ts @@ -22,7 +22,8 @@ import {gather} from '../ops/gather'; import {greaterEqual} from '../ops/greater_equal'; import {logicalAnd} from '../ops/logical_and'; import {maximum} from '../ops/maximum'; -import {ones, scalar} from '../ops/tensor_ops'; +import {ones} from '../ops/ones'; +import {scalar} from '../ops/scalar'; import {where} from '../ops/where'; import {zerosLike} from '../ops/zeros_like'; import {Tensor, Tensor1D} from '../tensor'; diff --git a/tfjs-core/src/io/io_utils.ts b/tfjs-core/src/io/io_utils.ts index d83d4e3646b..9a341a411a2 100644 --- a/tfjs-core/src/io/io_utils.ts +++ b/tfjs-core/src/io/io_utils.ts @@ -17,7 +17,7 @@ import {complex} from '../ops/complex'; -import {tensor} from '../ops/tensor_ops'; +import {tensor} from '../ops/tensor'; import {NamedTensor, NamedTensorMap} from '../tensor_types'; import {TypedArray} from '../types'; import {sizeFromShape} from '../util'; @@ -128,16 +128,14 @@ export function decodeWeights( if (quantization.dtype === 'uint8' || quantization.dtype === 'uint16') { if (!('min' in quantization && 'scale' in quantization)) { throw new Error( - `Weight ${spec.name} with quantization ${quantization.dtype} ` + - `doesn't have corresponding metadata min and scale.` - ); + `Weight ${spec.name} with quantization ${quantization.dtype} ` + + `doesn't have corresponding metadata min and scale.`); } } else if (quantization.dtype === 'float16') { if (dtype !== 'float32') { throw new Error( - `Weight ${spec.name} is quantized with ${quantization.dtype} ` + - `which only supports weights of type float32 not ${dtype}.` - ); + `Weight ${spec.name} is quantized with ${quantization.dtype} ` + + `which only supports weights of type float32 not ${dtype}.`); } } else { throw new Error( @@ -166,16 +164,14 @@ export function decodeWeights( values = float16Decode(quantizedArray as Uint16Array); } else { throw new Error( - `Unsupported quantization type ${quantization.dtype} ` + - `for weight type float32.` - ); + `Unsupported quantization type ${quantization.dtype} ` + + `for weight type float32.`); } } else if (dtype === 'int32') { if (quantization.dtype !== 'uint8' && quantization.dtype !== 'uint16') { throw new Error( - `Unsupported quantization type ${quantization.dtype} ` + - `for weight type int32.` - ); + `Unsupported quantization type ${quantization.dtype} ` + + `for weight type int32.`); } values = new Int32Array(quantizedArray.length); for (let i = 0; i < quantizedArray.length; i++) { @@ -480,7 +476,8 @@ function computeFloat16OffsetTable(): Uint32Array { * the Uint16Array of Float16 bytes to a Float32Array. */ export function getFloat16Decoder(): (buffer: Uint16Array) => Float32Array { - // Algorithm is based off of http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf + // Algorithm is based off of + // http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf // Cache lookup tables const mantisaTable = computeFloat16MantisaTable(); @@ -493,8 +490,8 @@ export function getFloat16Decoder(): (buffer: Uint16Array) => Float32Array { for (let index = 0; index < quantizedArray.length; index++) { const float16Bits = quantizedArray[index]; const float32Bits = - mantisaTable[offsetTable[float16Bits >> 10] + (float16Bits & 0x3ff)] + - exponentTable[float16Bits >> 10]; + mantisaTable[offsetTable[float16Bits >> 10] + (float16Bits & 0x3ff)] + + exponentTable[float16Bits >> 10]; bufferUint32View[index] = float32Bits; } return new Float32Array(buffer); diff --git a/tfjs-core/src/ops/band_part.ts b/tfjs-core/src/ops/band_part.ts index 16f50e59ae6..3c896085e3a 100644 --- a/tfjs-core/src/ops/band_part.ts +++ b/tfjs-core/src/ops/band_part.ts @@ -24,12 +24,14 @@ import {greaterEqual} from './greater_equal'; import {lessEqual} from './less_equal'; import {logicalAnd} from './logical_and'; import {op} from './operation'; +import {range} from './range'; import {reshape} from './reshape'; +import {scalar} from './scalar'; import {stack} from './stack'; import {sub} from './sub'; -import {range, scalar, zeros} from './tensor_ops'; import {unstack} from './unstack'; import {where} from './where'; +import {zeros} from './zeros'; /** * Copy a tensor setting everything outside a central band in each innermost diff --git a/tfjs-core/src/ops/browser.ts b/tfjs-core/src/ops/browser.ts index 8ac28e6f1d7..22aba683829 100644 --- a/tfjs-core/src/ops/browser.ts +++ b/tfjs-core/src/ops/browser.ts @@ -24,7 +24,7 @@ import {convertToTensor} from '../tensor_util_env'; import {PixelData, TensorLike} from '../types'; import {op} from './operation'; -import {tensor3d} from './tensor_ops'; +import {tensor3d} from './tensor3d'; let fromPixels2DContext: CanvasRenderingContext2D; diff --git a/tfjs-core/src/ops/compute_weighted_loss.ts b/tfjs-core/src/ops/compute_weighted_loss.ts index e7fc099b61a..4789f1d58aa 100644 --- a/tfjs-core/src/ops/compute_weighted_loss.ts +++ b/tfjs-core/src/ops/compute_weighted_loss.ts @@ -24,9 +24,10 @@ import {Reduction} from './loss_ops_utils'; import {mean} from './mean'; import {mul} from './mul'; import {notEqual} from './not_equal'; +import {ones} from './ones'; import {op} from './operation'; +import {scalar} from './scalar'; import {sum} from './sum'; -import {ones, scalar} from './tensor_ops'; /** * Computes the weighted loss between two tensors. diff --git a/tfjs-core/src/ops/concat.ts b/tfjs-core/src/ops/concat.ts index ed35ced5dc5..57a6605958d 100644 --- a/tfjs-core/src/ops/concat.ts +++ b/tfjs-core/src/ops/concat.ts @@ -25,7 +25,7 @@ import {assert, parseAxisParam, sizeFromShape} from '../util'; import {assertParamsConsistent, computeOutShape} from './concat_util'; import {op} from './operation'; -import {tensor} from './tensor_ops'; +import {tensor} from './tensor'; /** * Concatenates a list of `tf.Tensor`s along a given axis. diff --git a/tfjs-core/src/ops/cosine_distance.ts b/tfjs-core/src/ops/cosine_distance.ts index 88ca1beda65..1684ffed135 100644 --- a/tfjs-core/src/ops/cosine_distance.ts +++ b/tfjs-core/src/ops/cosine_distance.ts @@ -23,9 +23,9 @@ import {computeWeightedLoss} from './compute_weighted_loss'; import {Reduction} from './loss_ops_utils'; import {mul} from './mul'; import {op} from './operation'; +import {scalar} from './scalar'; import {sub} from './sub'; import {sum} from './sum'; -import {scalar} from './tensor_ops'; /** * Computes the cosine distance loss between two tensors. diff --git a/tfjs-core/src/ops/dropout_test.ts b/tfjs-core/src/ops/dropout_test.ts index 88e2223b3ba..75e8d4f3609 100644 --- a/tfjs-core/src/ops/dropout_test.ts +++ b/tfjs-core/src/ops/dropout_test.ts @@ -19,7 +19,7 @@ import * as tf from '../index'; import {ALL_ENVS, describeWithFlags} from '../jasmine_util'; import {expectArraysClose} from '../test_util'; -import {tensor1d, tensor2d} from './tensor_ops'; +import {tensor1d, tensor2d} from './ops'; describeWithFlags('dropout', ALL_ENVS, () => { it('x 1d array, rate 0', async () => { diff --git a/tfjs-core/src/ops/frame.ts b/tfjs-core/src/ops/frame.ts index 7070c720c35..933b81f0b08 100644 --- a/tfjs-core/src/ops/frame.ts +++ b/tfjs-core/src/ops/frame.ts @@ -22,7 +22,7 @@ import {concat} from './concat'; import {fill} from './fill'; import {reshape} from './reshape'; import {slice} from './slice'; -import {tensor2d} from './tensor_ops'; +import {tensor2d} from './tensor2d'; /** * Expands input into frames of frameLength. diff --git a/tfjs-core/src/ops/gather_nd_test.ts b/tfjs-core/src/ops/gather_nd_test.ts index 7bf38754cab..87b01dc0193 100644 --- a/tfjs-core/src/ops/gather_nd_test.ts +++ b/tfjs-core/src/ops/gather_nd_test.ts @@ -19,7 +19,7 @@ import {ALL_ENVS, describeWithFlags} from '../jasmine_util'; import {expectArraysClose} from '../test_util'; import {gatherND} from './gather_nd'; -import {scalar, tensor1d, tensor2d, tensor3d} from './tensor_ops'; +import {scalar, tensor1d, tensor2d, tensor3d} from './ops'; describeWithFlags('gatherND', ALL_ENVS, () => { it('should work for simple slice', async () => { diff --git a/tfjs-core/src/ops/hinge_loss.ts b/tfjs-core/src/ops/hinge_loss.ts index b2afd269a4d..2e5633c03cf 100644 --- a/tfjs-core/src/ops/hinge_loss.ts +++ b/tfjs-core/src/ops/hinge_loss.ts @@ -18,13 +18,14 @@ import {Tensor} from '../tensor'; import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import {assertShapesMatch} from '../util'; + import {computeWeightedLoss} from './compute_weighted_loss'; import {Reduction} from './loss_ops_utils'; import {mul} from './mul'; import {op} from './operation'; import {relu} from './relu'; +import {scalar} from './scalar'; import {sub} from './sub'; -import {scalar} from './tensor_ops'; /** * Computes the Hinge loss between two tensors. diff --git a/tfjs-core/src/ops/huber_loss.ts b/tfjs-core/src/ops/huber_loss.ts index 9ee27b0c9d4..ba25e7f0941 100644 --- a/tfjs-core/src/ops/huber_loss.ts +++ b/tfjs-core/src/ops/huber_loss.ts @@ -27,9 +27,9 @@ import {Reduction} from './loss_ops_utils'; import {minimum} from './minimum'; import {mul} from './mul'; import {op} from './operation'; +import {scalar} from './scalar'; import {square} from './square'; import {sub} from './sub'; -import {scalar} from './tensor_ops'; /** * Computes the huber loss between two tensors. diff --git a/tfjs-core/src/ops/in_top_k.ts b/tfjs-core/src/ops/in_top_k.ts index d3d390f0bc3..b31e00809c6 100644 --- a/tfjs-core/src/ops/in_top_k.ts +++ b/tfjs-core/src/ops/in_top_k.ts @@ -19,7 +19,7 @@ import {Tensor} from '../tensor'; import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import {assert, assertShapesMatch, getTypedArrayFromDType} from '../util'; -import {tensor} from './tensor_ops'; +import {tensor} from './tensor'; /** * Returns whether the targets are in the top K predictions. diff --git a/tfjs-core/src/ops/in_top_k_test.ts b/tfjs-core/src/ops/in_top_k_test.ts index ac06f149be0..b23f338be87 100644 --- a/tfjs-core/src/ops/in_top_k_test.ts +++ b/tfjs-core/src/ops/in_top_k_test.ts @@ -19,7 +19,7 @@ import * as tf from '../index'; import {ALL_ENVS, describeWithFlags} from '../jasmine_util'; import {expectArraysClose} from '../test_util'; -import {tensor1d, tensor2d, tensor3d} from './tensor_ops'; +import {tensor1d, tensor2d, tensor3d} from './ops'; describeWithFlags('inTopKAsync', ALL_ENVS, async () => { it('predictions 2d array, targets 1d array, with default k', async () => { diff --git a/tfjs-core/src/ops/leaky_relu.ts b/tfjs-core/src/ops/leaky_relu.ts index 7f90d9b5c1e..bee32448c0e 100644 --- a/tfjs-core/src/ops/leaky_relu.ts +++ b/tfjs-core/src/ops/leaky_relu.ts @@ -22,7 +22,7 @@ import {TensorLike} from '../types'; import {maximum} from './maximum'; import {mul} from './mul'; import {op} from './operation'; -import {scalar} from './tensor_ops'; +import {scalar} from './scalar'; /** * Computes leaky rectified linear element-wise. diff --git a/tfjs-core/src/ops/linspace.ts b/tfjs-core/src/ops/linspace.ts index 203b0f900e7..e098724f7a1 100644 --- a/tfjs-core/src/ops/linspace.ts +++ b/tfjs-core/src/ops/linspace.ts @@ -20,8 +20,6 @@ import {LinSpace, LinSpaceAttrs} from '../kernel_names'; import {NamedAttrMap} from '../kernel_registry'; import {Tensor1D} from '../tensor'; -import {op} from './operation'; - /** * Return an evenly spaced sequence of numbers over the given interval. * diff --git a/tfjs-core/src/ops/log_loss.ts b/tfjs-core/src/ops/log_loss.ts index 0543646c578..cb5d5d3de81 100644 --- a/tfjs-core/src/ops/log_loss.ts +++ b/tfjs-core/src/ops/log_loss.ts @@ -26,8 +26,8 @@ import {Reduction} from './loss_ops_utils'; import {mul} from './mul'; import {neg} from './neg'; import {op} from './operation'; +import {scalar} from './scalar'; import {sub} from './sub'; -import {scalar} from './tensor_ops'; import {log} from './unary_ops'; /** diff --git a/tfjs-core/src/ops/mean.ts b/tfjs-core/src/ops/mean.ts index 9ef7737b56a..be6e6f68a06 100644 --- a/tfjs-core/src/ops/mean.ts +++ b/tfjs-core/src/ops/mean.ts @@ -24,10 +24,11 @@ import {cast} from './array_ops'; import {computeOutAndReduceShapes} from './axis_util'; import {div} from './div'; import {mul} from './mul'; +import {ones} from './ones'; import {op} from './operation'; import {reshape} from './reshape'; +import {scalar} from './scalar'; import {sum} from './sum'; -import {ones, scalar} from './tensor_ops'; /** * Computes the mean of elements across dimensions of a `tf.Tensor`. diff --git a/tfjs-core/src/ops/moving_average.ts b/tfjs-core/src/ops/moving_average.ts index d695f58e4c4..0858922d783 100644 --- a/tfjs-core/src/ops/moving_average.ts +++ b/tfjs-core/src/ops/moving_average.ts @@ -26,8 +26,8 @@ import {div} from './div'; import {mul} from './mul'; import {op} from './operation'; import {pow} from './pow'; +import {scalar} from './scalar'; import {sub} from './sub'; -import {scalar} from './tensor_ops'; /** * Compute the moving average of a variable. diff --git a/tfjs-core/src/ops/norm.ts b/tfjs-core/src/ops/norm.ts index 8a68364045f..be8364b2493 100644 --- a/tfjs-core/src/ops/norm.ts +++ b/tfjs-core/src/ops/norm.ts @@ -27,9 +27,9 @@ import {min} from './min'; import {op} from './operation'; import {pow} from './pow'; import {reshape} from './reshape'; +import {scalar} from './scalar'; import {square} from './square'; import {sum} from './sum'; -import {scalar} from './tensor_ops'; import {sqrt} from './unary_ops'; /** diff --git a/tfjs-core/src/ops/ones.ts b/tfjs-core/src/ops/ones.ts new file mode 100644 index 00000000000..5d8b23b23cd --- /dev/null +++ b/tfjs-core/src/ops/ones.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {Tensor} from '../tensor'; +import {DataType, Rank, ShapeMap} from '../types'; +import {makeOnesTypedArray, sizeFromShape} from '../util'; + +import {complex} from './complex'; +import {zeros} from './zeros'; + +/** + * Creates a `tf.Tensor` with all elements set to 1. + * + * ```js + * tf.ones([2, 2]).print(); + * ``` + * + * @param shape An array of integers defining the output tensor shape. + * @param dtype The type of an element in the resulting tensor. Defaults to + * 'float'. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function ones( + shape: ShapeMap[R], dtype: DataType = 'float32'): Tensor { + if (dtype === 'complex64') { + const real = ones(shape, 'float32'); + const imag = zeros(shape, 'float32'); + return complex(real, imag); + } + const values = makeOnesTypedArray(sizeFromShape(shape), dtype); + return ENGINE.makeTensor(values, shape, dtype) as Tensor; +} diff --git a/tfjs-core/src/ops/ops.ts b/tfjs-core/src/ops/ops.ts index 4f09aafdcbd..38d934b6d53 100644 --- a/tfjs-core/src/ops/ops.ts +++ b/tfjs-core/src/ops/ops.ts @@ -100,6 +100,7 @@ export {multinomial} from './multinomial'; export {neg} from './neg'; export {notEqual} from './not_equal'; export {oneHot} from './one_hot'; +export {ones} from './ones'; export {onesLike} from './ones_like'; export {outerProduct} from './outer_product'; export {pad} from './pad'; @@ -125,6 +126,7 @@ export {reverse1d} from './reverse_1d'; export {reverse2d} from './reverse_2d'; export {reverse3d} from './reverse_3d'; export {reverse4d} from './reverse_4d'; +export {scalar} from './scalar'; export {selu} from './selu'; export {separableConv2d} from './separable_conv2d'; export {sign} from './sign'; @@ -145,12 +147,21 @@ export {sub} from './sub'; export {sum} from './sum'; export {tan} from './tan'; export {tanh} from './tanh'; +export {tensor} from './tensor'; +export {tensor1d} from './tensor1d'; +export {tensor2d} from './tensor2d'; +export {tensor3d} from './tensor3d'; +export {tensor4d} from './tensor4d'; +export {tensor5d} from './tensor5d'; +export {tensor6d} from './tensor6d'; export {tile} from './tile'; export {truncatedNormal} from './truncated_normal'; export {unsortedSegmentSum} from './unsorted_segment_sum'; export {unstack} from './unstack'; +export {variable} from './variable'; export {where} from './where'; export {whereAsync} from './where_async'; +export {zeros} from './zeros'; export {zerosLike} from './zeros_like'; export * from './boolean_mask'; @@ -158,7 +169,6 @@ export * from './unary_ops'; export * from './compare'; export * from './binary_ops'; export * from './array_ops'; -export * from './tensor_ops'; export * from './transpose'; export * from './softmax'; export * from './norm'; diff --git a/tfjs-core/src/ops/qr.ts b/tfjs-core/src/ops/qr.ts index 31dd3573936..2e82a8e7f13 100644 --- a/tfjs-core/src/ops/qr.ts +++ b/tfjs-core/src/ops/qr.ts @@ -33,7 +33,7 @@ import {reshape} from './reshape'; import {slice} from './slice'; import {stack} from './stack'; import {sub} from './sub'; -import {tensor2d} from './tensor_ops'; +import {tensor2d} from './tensor2d'; import {transpose} from './transpose'; import {unstack} from './unstack'; import {where} from './where'; diff --git a/tfjs-core/src/ops/range.ts b/tfjs-core/src/ops/range.ts index 705126cf299..7ef29976b96 100644 --- a/tfjs-core/src/ops/range.ts +++ b/tfjs-core/src/ops/range.ts @@ -21,7 +21,8 @@ import {NamedAttrMap} from '../kernel_registry'; import {Tensor, Tensor1D} from '../tensor'; import {makeZerosTypedArray} from '../util'; -import {tensor1d, zeros} from './tensor_ops'; +import {tensor1d} from './tensor1d'; +import {zeros} from './zeros'; /** * Creates a new `tf.Tensor1D` filled with the numbers in the range provided. diff --git a/tfjs-core/src/ops/scalar.ts b/tfjs-core/src/ops/scalar.ts new file mode 100644 index 00000000000..df6a83956c8 --- /dev/null +++ b/tfjs-core/src/ops/scalar.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Scalar} from '../tensor'; +import {DataType} from '../types'; +import {isTypedArray} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-0 `tf.Tensor` (scalar) with the provided value and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.scalar` as it makes the code more readable. + * + * ```js + * tf.scalar(3.14).print(); + * ``` + * + * @param value The value of the scalar. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function scalar( + value: number|boolean|string|Uint8Array, dtype?: DataType): Scalar { + if (((isTypedArray(value) && dtype !== 'string') || Array.isArray(value)) && + dtype !== 'complex64') { + throw new Error( + 'Error creating a new Scalar: value must be a primitive ' + + '(number|boolean|string)'); + } + if (dtype === 'string' && isTypedArray(value) && + !(value instanceof Uint8Array)) { + throw new Error( + 'When making a scalar from encoded string, ' + + 'the value must be `Uint8Array`.'); + } + const shape: number[] = []; + const inferredShape: number[] = []; + return makeTensor(value, shape, inferredShape, dtype) as Scalar; +} diff --git a/tfjs-core/src/ops/sigmoid_cross_entropy.ts b/tfjs-core/src/ops/sigmoid_cross_entropy.ts index 7316002b2da..a2d17b9bfd1 100644 --- a/tfjs-core/src/ops/sigmoid_cross_entropy.ts +++ b/tfjs-core/src/ops/sigmoid_cross_entropy.ts @@ -28,8 +28,8 @@ import {mul} from './mul'; import {neg} from './neg'; import {op} from './operation'; import {relu} from './relu'; +import {scalar} from './scalar'; import {sub} from './sub'; -import {scalar} from './tensor_ops'; import {exp, log1p} from './unary_ops'; function sigmoidCrossEntropyWithLogits_( diff --git a/tfjs-core/src/ops/signal_ops_util.ts b/tfjs-core/src/ops/signal_ops_util.ts index f930187e4dc..15f5a278316 100644 --- a/tfjs-core/src/ops/signal_ops_util.ts +++ b/tfjs-core/src/ops/signal_ops_util.ts @@ -16,7 +16,7 @@ */ import {Tensor1D} from '../tensor'; -import {tensor1d} from './tensor_ops'; +import {tensor1d} from './tensor1d'; export function enclosingPowerOfTwo(value: number) { // Return 2**N for integer N such that 2**N >= value. diff --git a/tfjs-core/src/ops/softmax_cross_entropy.ts b/tfjs-core/src/ops/softmax_cross_entropy.ts index b86f01f1db9..d8a25244459 100644 --- a/tfjs-core/src/ops/softmax_cross_entropy.ts +++ b/tfjs-core/src/ops/softmax_cross_entropy.ts @@ -32,9 +32,9 @@ import {mul} from './mul'; import {neg} from './neg'; import {op} from './operation'; import {reshape} from './reshape'; +import {scalar} from './scalar'; import {sub} from './sub'; import {sum} from './sum'; -import {scalar} from './tensor_ops'; import {exp} from './unary_ops'; /** diff --git a/tfjs-core/src/ops/spectral_ops.ts b/tfjs-core/src/ops/spectral_ops.ts index 839e7f49939..b6f12959e95 100644 --- a/tfjs-core/src/ops/spectral_ops.ts +++ b/tfjs-core/src/ops/spectral_ops.ts @@ -23,7 +23,8 @@ import {real} from '../ops/real'; import {Tensor, Tensor2D} from '../tensor'; import {assert} from '../util'; -import {scalar, zeros} from './tensor_ops'; +import {scalar} from './scalar'; +import {zeros} from './zeros'; /** * Fast Fourier transform. diff --git a/tfjs-core/src/ops/tensor.ts b/tfjs-core/src/ops/tensor.ts new file mode 100644 index 00000000000..3a6a00b2e05 --- /dev/null +++ b/tfjs-core/src/ops/tensor.ts @@ -0,0 +1,56 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike} from '../types'; +import {DataType, Rank, ShapeMap} from '../types'; + +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates a `tf.Tensor` with the provided values, shape and dtype. + * + * ```js + * // Pass an array of values to create a vector. + * tf.tensor([1, 2, 3, 4]).print(); + * ``` + * + * ```js + * // Pass a nested array of values to make a matrix or a higher + * // dimensional tensor. + * tf.tensor([[1, 2], [3, 4]]).print(); + * ``` + * + * ```js + * // Pass a flat array and specify a shape yourself. + * tf.tensor([1, 2, 3, 4], [2, 2]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. If the values are strings, + * they will be encoded as utf-8 and kept as `Uint8Array[]`. + * @param shape The shape of the tensor. Optional. If not provided, + * it is inferred from `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor( + values: TensorLike, shape?: ShapeMap[R], dtype?: DataType): Tensor { + const inferredShape = inferShape(values, dtype); + return makeTensor(values, shape, inferredShape, dtype) as Tensor; +} diff --git a/tfjs-core/src/ops/tensor1d.ts b/tfjs-core/src/ops/tensor1d.ts new file mode 100644 index 00000000000..3f08a500d5e --- /dev/null +++ b/tfjs-core/src/ops/tensor1d.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor1D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike1D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-1 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor1d` as it makes the code more readable. + * + * ```js + * tf.tensor1d([1, 2, 3]).print(); + * ``` + * + * @param values The values of the tensor. Can be array of numbers, + * or a `TypedArray`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor1d(values: TensorLike1D, dtype?: DataType): Tensor1D { + assertNonNull(values); + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 1) { + throw new Error('tensor1d() requires values to be a flat/TypedArray'); + } + const shape: number[] = null; + return makeTensor(values, shape, inferredShape, dtype) as Tensor1D; +} diff --git a/tfjs-core/src/ops/tensor2d.ts b/tfjs-core/src/ops/tensor2d.ts new file mode 100644 index 00000000000..571ecd25914 --- /dev/null +++ b/tfjs-core/src/ops/tensor2d.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor2D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike2D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-2 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor2d` as it makes the code more readable. + * + * ```js + * // Pass a nested array. + * tf.tensor2d([[1, 2], [3, 4]]).print(); + * ``` + * ```js + * // Pass a flat array and specify a shape. + * tf.tensor2d([1, 2, 3, 4], [2, 2]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. + * @param shape The shape of the tensor. If not provided, it is inferred from + * `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor2d( + values: TensorLike2D, shape?: [number, number], + dtype?: DataType): Tensor2D { + assertNonNull(values); + if (shape != null && shape.length !== 2) { + throw new Error('tensor2d() requires shape to have two numbers'); + } + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 2 && inferredShape.length !== 1) { + throw new Error( + 'tensor2d() requires values to be number[][] or flat/TypedArray'); + } + if (inferredShape.length === 1 && shape == null) { + throw new Error( + 'tensor2d() requires shape to be provided when `values` ' + + 'are a flat/TypedArray'); + } + return makeTensor(values, shape, inferredShape, dtype) as Tensor2D; +} diff --git a/tfjs-core/src/ops/tensor3d.ts b/tfjs-core/src/ops/tensor3d.ts new file mode 100644 index 00000000000..a0d38b36067 --- /dev/null +++ b/tfjs-core/src/ops/tensor3d.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor3D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike3D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-3 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor3d` as it makes the code more readable. + * + * ```js + * // Pass a nested array. + * tf.tensor3d([[[1], [2]], [[3], [4]]]).print(); + * ``` + * ```js + * // Pass a flat array and specify a shape. + * tf.tensor3d([1, 2, 3, 4], [2, 2, 1]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. + * @param shape The shape of the tensor. If not provided, it is inferred from + * `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor3d( + values: TensorLike3D, shape?: [number, number, number], + dtype?: DataType): Tensor3D { + assertNonNull(values); + if (shape != null && shape.length !== 3) { + throw new Error('tensor3d() requires shape to have three numbers'); + } + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 3 && inferredShape.length !== 1) { + throw new Error( + 'tensor3d() requires values to be number[][][] or flat/TypedArray'); + } + if (inferredShape.length === 1 && shape == null) { + throw new Error( + 'tensor3d() requires shape to be provided when `values` ' + + 'are a flat array'); + } + return makeTensor(values, shape, inferredShape, dtype) as Tensor3D; +} diff --git a/tfjs-core/src/ops/tensor4d.ts b/tfjs-core/src/ops/tensor4d.ts new file mode 100644 index 00000000000..b96b6ac8845 --- /dev/null +++ b/tfjs-core/src/ops/tensor4d.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor4D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike4D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-4 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor4d` as it makes the code more readable. + * + * ```js + * // Pass a nested array. + * tf.tensor4d([[[[1], [2]], [[3], [4]]]]).print(); + * ``` + * ```js + * // Pass a flat array and specify a shape. + * tf.tensor4d([1, 2, 3, 4], [1, 2, 2, 1]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. + * @param shape The shape of the tensor. Optional. If not provided, + * it is inferred from `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor4d( + values: TensorLike4D, shape?: [number, number, number, number], + dtype?: DataType): Tensor4D { + assertNonNull(values); + if (shape != null && shape.length !== 4) { + throw new Error('tensor4d() requires shape to have four numbers'); + } + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 4 && inferredShape.length !== 1) { + throw new Error( + 'tensor4d() requires values to be number[][][][] or flat/TypedArray'); + } + if (inferredShape.length === 1 && shape == null) { + throw new Error( + 'tensor4d() requires shape to be provided when `values` ' + + 'are a flat array'); + } + return makeTensor(values, shape, inferredShape, dtype) as Tensor4D; +} diff --git a/tfjs-core/src/ops/tensor5d.ts b/tfjs-core/src/ops/tensor5d.ts new file mode 100644 index 00000000000..00d369b12bf --- /dev/null +++ b/tfjs-core/src/ops/tensor5d.ts @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor5D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike5D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-5 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor5d` as it makes the code more readable. + * + * ```js + * // Pass a nested array. + * tf.tensor5d([[[[[1], [2]], [[3], [4]]]]]).print(); + * ``` + * ```js + * // Pass a flat array and specify a shape. + * tf.tensor5d([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 2, 2, 1]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. + * @param shape The shape of the tensor. Optional. If not provided, + * it is inferred from `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor5d( + values: TensorLike5D, shape?: [number, number, number, number, number], + dtype?: DataType): Tensor5D { + assertNonNull(values); + if (shape != null && shape.length !== 5) { + throw new Error('tensor5d() requires shape to have five numbers'); + } + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 5 && inferredShape.length !== 1) { + throw new Error( + 'tensor5d() requires values to be ' + + 'number[][][][][] or flat/TypedArray'); + } + if (inferredShape.length === 1 && shape == null) { + throw new Error( + 'tensor5d() requires shape to be provided when `values` ' + + 'are a flat array'); + } + return makeTensor(values, shape, inferredShape, dtype) as Tensor5D; +} diff --git a/tfjs-core/src/ops/tensor6d.ts b/tfjs-core/src/ops/tensor6d.ts new file mode 100644 index 00000000000..ab3d6b9c018 --- /dev/null +++ b/tfjs-core/src/ops/tensor6d.ts @@ -0,0 +1,69 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {Tensor6D} from '../tensor'; +import {inferShape} from '../tensor_util_env'; +import {TensorLike6D} from '../types'; +import {DataType} from '../types'; +import {assertNonNull} from '../util'; +import {makeTensor} from './tensor_ops_util'; + +/** + * Creates rank-6 `tf.Tensor` with the provided values, shape and dtype. + * + * The same functionality can be achieved with `tf.tensor`, but in general + * we recommend using `tf.tensor6d` as it makes the code more readable. + * + * ```js + * // Pass a nested array. + * tf.tensor6d([[[[[[1],[2]],[[3],[4]]],[[[5],[6]],[[7],[8]]]]]]).print(); + * ``` + * ```js + * // Pass a flat array and specify a shape. + * tf.tensor6d([1, 2, 3, 4, 5, 6, 7, 8], [1, 1, 2, 2, 2, 1]).print(); + * ``` + * + * @param values The values of the tensor. Can be nested array of numbers, + * or a flat array, or a `TypedArray`. + * @param shape The shape of the tensor. Optional. If not provided, + * it is inferred from `values`. + * @param dtype The data type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function tensor6d( + values: TensorLike6D, + shape?: [number, number, number, number, number, number], + dtype?: DataType): Tensor6D { + assertNonNull(values); + if (shape != null && shape.length !== 6) { + throw new Error('tensor6d() requires shape to have six numbers'); + } + const inferredShape = inferShape(values, dtype); + if (inferredShape.length !== 6 && inferredShape.length !== 1) { + throw new Error( + 'tensor6d() requires values to be number[][][][][][] or ' + + 'flat/TypedArray'); + } + if (inferredShape.length === 1 && shape == null) { + throw new Error( + 'tensor6d() requires shape to be provided when `values` ' + + 'are a flat array'); + } + shape = shape || + inferredShape as [number, number, number, number, number, number]; + return makeTensor(values, shape, inferredShape, dtype) as Tensor6D; +} diff --git a/tfjs-core/src/ops/tensor_ops.ts b/tfjs-core/src/ops/tensor_ops.ts deleted file mode 100644 index ff3d2ed6c1a..00000000000 --- a/tfjs-core/src/ops/tensor_ops.ts +++ /dev/null @@ -1,552 +0,0 @@ -/** - * @license - * Copyright 2018 Google LLC. 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. - * ============================================================================= - */ - -import {ENGINE} from '../engine'; -import {Scalar, Tensor, Tensor1D, Tensor2D, Tensor3D, Tensor4D, Tensor5D, Tensor6D, Variable} from '../tensor'; -import {inferShape} from '../tensor_util_env'; -import {TensorLike, TensorLike1D, TensorLike2D, TensorLike3D, TensorLike4D, TensorLike5D, TensorLike6D, TypedArray} from '../types'; -import {DataType, Rank, ShapeMap} from '../types'; -import {assert, assertNonNegativeIntegerDimensions, assertNonNull, flatten, inferDtype, isTypedArray, makeOnesTypedArray, makeZerosTypedArray, sizeFromShape, toTypedArray} from '../util'; - -import {complex} from './complex'; - -/** - * Creates a `tf.Tensor` with the provided values, shape and dtype. - * - * ```js - * // Pass an array of values to create a vector. - * tf.tensor([1, 2, 3, 4]).print(); - * ``` - * - * ```js - * // Pass a nested array of values to make a matrix or a higher - * // dimensional tensor. - * tf.tensor([[1, 2], [3, 4]]).print(); - * ``` - * - * ```js - * // Pass a flat array and specify a shape yourself. - * tf.tensor([1, 2, 3, 4], [2, 2]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. If the values are strings, - * they will be encoded as utf-8 and kept as `Uint8Array[]`. - * @param shape The shape of the tensor. Optional. If not provided, - * it is inferred from `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor( - values: TensorLike, shape?: ShapeMap[R], dtype?: DataType): Tensor { - const inferredShape = inferShape(values, dtype); - return makeTensor(values, shape, inferredShape, dtype) as Tensor; -} - -/** This is shared code across all tensor creation methods. */ -function makeTensor( - values: TensorLike, shape: number[], inferredShape: number[], - dtype?: DataType): Tensor { - if (dtype == null) { - dtype = inferDtype(values); - } - if (dtype === 'complex64') { - throw new Error( - `Cannot construct a complex64 tensor directly. ` + - `Please use tf.complex(real, imag).`); - } - if (!isTypedArray(values) && !Array.isArray(values) && - typeof values !== 'number' && typeof values !== 'boolean' && - typeof values !== 'string') { - throw new Error( - 'values passed to tensor(values) must be a number/boolean/string or ' + - 'an array of numbers/booleans/strings, or a TypedArray'); - } - if (shape != null) { - assertNonNegativeIntegerDimensions(shape); - - const providedSize = sizeFromShape(shape); - const inferredSize = sizeFromShape(inferredShape); - assert( - providedSize === inferredSize, - () => - `Based on the provided shape, [${shape}], the tensor should have ` + - `${providedSize} values but has ${inferredSize}`); - - for (let i = 0; i < inferredShape.length; ++i) { - const inferred = inferredShape[i]; - const flatDimsDontMatch = i === inferredShape.length - 1 ? - inferred !== sizeFromShape(shape.slice(i)) : - true; - assert( - inferredShape[i] === shape[i] || !flatDimsDontMatch, - () => `Error creating a new Tensor. Inferred shape ` + - `(${inferredShape}) does not match the provided ` + - `shape (${shape}). `); - } - } - - if (!isTypedArray(values) && !Array.isArray(values)) { - values = [values] as number[]; - } - - shape = shape || inferredShape; - values = dtype !== 'string' ? - toTypedArray(values, dtype) : - flatten(values as string[], [], true) as string[]; - return ENGINE.makeTensor(values as TypedArray, shape, dtype); -} - -/** - * Creates rank-0 `tf.Tensor` (scalar) with the provided value and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.scalar` as it makes the code more readable. - * - * ```js - * tf.scalar(3.14).print(); - * ``` - * - * @param value The value of the scalar. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function scalar( - value: number|boolean|string|Uint8Array, dtype?: DataType): Scalar { - if (((isTypedArray(value) && dtype !== 'string') || Array.isArray(value)) && - dtype !== 'complex64') { - throw new Error( - 'Error creating a new Scalar: value must be a primitive ' + - '(number|boolean|string)'); - } - if (dtype === 'string' && isTypedArray(value) && - !(value instanceof Uint8Array)) { - throw new Error( - 'When making a scalar from encoded string, ' + - 'the value must be `Uint8Array`.'); - } - const shape: number[] = []; - const inferredShape: number[] = []; - return makeTensor(value, shape, inferredShape, dtype) as Scalar; -} - -/** - * Creates rank-1 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor1d` as it makes the code more readable. - * - * ```js - * tf.tensor1d([1, 2, 3]).print(); - * ``` - * - * @param values The values of the tensor. Can be array of numbers, - * or a `TypedArray`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor1d(values: TensorLike1D, dtype?: DataType): Tensor1D { - assertNonNull(values); - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 1) { - throw new Error('tensor1d() requires values to be a flat/TypedArray'); - } - const shape: number[] = null; - return makeTensor(values, shape, inferredShape, dtype) as Tensor1D; -} - -/** - * Creates rank-2 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor2d` as it makes the code more readable. - * - * ```js - * // Pass a nested array. - * tf.tensor2d([[1, 2], [3, 4]]).print(); - * ``` - * ```js - * // Pass a flat array and specify a shape. - * tf.tensor2d([1, 2, 3, 4], [2, 2]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. - * @param shape The shape of the tensor. If not provided, it is inferred from - * `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor2d( - values: TensorLike2D, shape?: [number, number], - dtype?: DataType): Tensor2D { - assertNonNull(values); - if (shape != null && shape.length !== 2) { - throw new Error('tensor2d() requires shape to have two numbers'); - } - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 2 && inferredShape.length !== 1) { - throw new Error( - 'tensor2d() requires values to be number[][] or flat/TypedArray'); - } - if (inferredShape.length === 1 && shape == null) { - throw new Error( - 'tensor2d() requires shape to be provided when `values` ' + - 'are a flat/TypedArray'); - } - return makeTensor(values, shape, inferredShape, dtype) as Tensor2D; -} - -/** - * Creates rank-3 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor3d` as it makes the code more readable. - * - * ```js - * // Pass a nested array. - * tf.tensor3d([[[1], [2]], [[3], [4]]]).print(); - * ``` - * ```js - * // Pass a flat array and specify a shape. - * tf.tensor3d([1, 2, 3, 4], [2, 2, 1]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. - * @param shape The shape of the tensor. If not provided, it is inferred from - * `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor3d( - values: TensorLike3D, shape?: [number, number, number], - dtype?: DataType): Tensor3D { - assertNonNull(values); - if (shape != null && shape.length !== 3) { - throw new Error('tensor3d() requires shape to have three numbers'); - } - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 3 && inferredShape.length !== 1) { - throw new Error( - 'tensor3d() requires values to be number[][][] or flat/TypedArray'); - } - if (inferredShape.length === 1 && shape == null) { - throw new Error( - 'tensor3d() requires shape to be provided when `values` ' + - 'are a flat array'); - } - return makeTensor(values, shape, inferredShape, dtype) as Tensor3D; -} - -/** - * Creates rank-4 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor4d` as it makes the code more readable. - * - * ```js - * // Pass a nested array. - * tf.tensor4d([[[[1], [2]], [[3], [4]]]]).print(); - * ``` - * ```js - * // Pass a flat array and specify a shape. - * tf.tensor4d([1, 2, 3, 4], [1, 2, 2, 1]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. - * @param shape The shape of the tensor. Optional. If not provided, - * it is inferred from `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor4d( - values: TensorLike4D, shape?: [number, number, number, number], - dtype?: DataType): Tensor4D { - assertNonNull(values); - if (shape != null && shape.length !== 4) { - throw new Error('tensor4d() requires shape to have four numbers'); - } - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 4 && inferredShape.length !== 1) { - throw new Error( - 'tensor4d() requires values to be number[][][][] or flat/TypedArray'); - } - if (inferredShape.length === 1 && shape == null) { - throw new Error( - 'tensor4d() requires shape to be provided when `values` ' + - 'are a flat array'); - } - return makeTensor(values, shape, inferredShape, dtype) as Tensor4D; -} - -/** - * Creates rank-5 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor5d` as it makes the code more readable. - * - * ```js - * // Pass a nested array. - * tf.tensor5d([[[[[1], [2]], [[3], [4]]]]]).print(); - * ``` - * ```js - * // Pass a flat array and specify a shape. - * tf.tensor5d([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 2, 2, 1]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. - * @param shape The shape of the tensor. Optional. If not provided, - * it is inferred from `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor5d( - values: TensorLike5D, shape?: [number, number, number, number, number], - dtype?: DataType): Tensor5D { - assertNonNull(values); - if (shape != null && shape.length !== 5) { - throw new Error('tensor5d() requires shape to have five numbers'); - } - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 5 && inferredShape.length !== 1) { - throw new Error( - 'tensor5d() requires values to be ' + - 'number[][][][][] or flat/TypedArray'); - } - if (inferredShape.length === 1 && shape == null) { - throw new Error( - 'tensor5d() requires shape to be provided when `values` ' + - 'are a flat array'); - } - return makeTensor(values, shape, inferredShape, dtype) as Tensor5D; -} - -/** - * Creates rank-6 `tf.Tensor` with the provided values, shape and dtype. - * - * The same functionality can be achieved with `tf.tensor`, but in general - * we recommend using `tf.tensor6d` as it makes the code more readable. - * - * ```js - * // Pass a nested array. - * tf.tensor6d([[[[[[1],[2]],[[3],[4]]],[[[5],[6]],[[7],[8]]]]]]).print(); - * ``` - * ```js - * // Pass a flat array and specify a shape. - * tf.tensor6d([1, 2, 3, 4, 5, 6, 7, 8], [1, 1, 2, 2, 2, 1]).print(); - * ``` - * - * @param values The values of the tensor. Can be nested array of numbers, - * or a flat array, or a `TypedArray`. - * @param shape The shape of the tensor. Optional. If not provided, - * it is inferred from `values`. - * @param dtype The data type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function tensor6d( - values: TensorLike6D, - shape?: [number, number, number, number, number, number], - dtype?: DataType): Tensor6D { - assertNonNull(values); - if (shape != null && shape.length !== 6) { - throw new Error('tensor6d() requires shape to have six numbers'); - } - const inferredShape = inferShape(values, dtype); - if (inferredShape.length !== 6 && inferredShape.length !== 1) { - throw new Error( - 'tensor6d() requires values to be number[][][][][][] or ' + - 'flat/TypedArray'); - } - if (inferredShape.length === 1 && shape == null) { - throw new Error( - 'tensor6d() requires shape to be provided when `values` ' + - 'are a flat array'); - } - shape = shape || - inferredShape as [number, number, number, number, number, number]; - return makeTensor(values, shape, inferredShape, dtype) as Tensor6D; -} - -/** - * Creates a new variable with the provided initial value. - * ```js - * const x = tf.variable(tf.tensor([1, 2, 3])); - * x.assign(tf.tensor([4, 5, 6])); - * - * x.print(); - * ``` - * - * @param initialValue Initial value for the tensor. - * @param trainable If true, optimizers are allowed to update it. - * @param name Name of the variable. Defaults to a unique id. - * @param dtype If set, initialValue will be converted to the given type. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function variable( - initialValue: Tensor, trainable = true, name?: string, - dtype?: DataType): Variable { - return ENGINE.makeVariable(initialValue, trainable, name, dtype) as - Variable; -} - -/** - * Creates a `tf.Tensor` with all elements set to 1. - * - * ```js - * tf.ones([2, 2]).print(); - * ``` - * - * @param shape An array of integers defining the output tensor shape. - * @param dtype The type of an element in the resulting tensor. Defaults to - * 'float'. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function ones( - shape: ShapeMap[R], dtype: DataType = 'float32'): Tensor { - if (dtype === 'complex64') { - const real = ones(shape, 'float32'); - const imag = zeros(shape, 'float32'); - return complex(real, imag); - } - const values = makeOnesTypedArray(sizeFromShape(shape), dtype); - return ENGINE.makeTensor(values, shape, dtype) as Tensor; -} - -/** - * Creates a `tf.Tensor` with all elements set to 0. - * - * ```js - * tf.zeros([2, 2]).print(); - * ``` - * - * @param shape An array of integers defining the output tensor shape. - * @param dtype The type of an element in the resulting tensor. Can - * be 'float32', 'int32' or 'bool'. Defaults to 'float'. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function zeros( - shape: ShapeMap[R], dtype: DataType = 'float32'): Tensor { - if (dtype === 'complex64') { - const real = zeros(shape, 'float32'); - const imag = zeros(shape, 'float32'); - return complex(real, imag); - } - const values = makeZerosTypedArray(sizeFromShape(shape), dtype); - return ENGINE.makeTensor(values, shape, dtype) as Tensor; -} - -/** - * Return an evenly spaced sequence of numbers over the given interval. - * - * ```js - * tf.linspace(0, 9, 10).print(); - * ``` - * @param start The start value of the sequence. - * @param stop The end value of the sequence. - * @param num The number of values to generate. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function linspace(start: number, stop: number, num: number): Tensor1D { - if (num <= 0) { - throw new Error('The number of values should be positive.'); - } - return ENGINE.runKernelFunc( - backend => backend.linspace(start, stop, num), {}); -} - -/** - * Creates a new `tf.Tensor1D` filled with the numbers in the range provided. - * - * The tensor is a is half-open interval meaning it includes start, but - * excludes stop. Decrementing ranges and negative step values are also - * supported. - * - * ```js - * tf.range(0, 9, 2).print(); - * ``` - * - * @param start An integer start value - * @param stop An integer stop value - * @param step An integer increment (will default to 1 or -1) - * @param dtype The data type of the output tensor. Defaults to 'float32'. - */ -/** @doc {heading: 'Tensors', subheading: 'Creation'} */ -function range( - start: number, stop: number, step = 1, - dtype: 'float32'|'int32' = 'float32'): Tensor1D { - if (step === 0) { - throw new Error('Cannot have a step of zero'); - } - - const sameStartStop = start === stop; - const increasingRangeNegativeStep = start < stop && step < 0; - const decreasingRangePositiveStep = stop < start && step > 1; - - if (sameStartStop || increasingRangeNegativeStep || - decreasingRangePositiveStep) { - return zeros([0], dtype); - } - - const numElements = Math.abs(Math.ceil((stop - start) / step)); - const values = makeZerosTypedArray(numElements, dtype); - - if (stop < start && step === 1) { - // Auto adjust the step's sign if it hasn't been set - // (or was set to 1) - step = -1; - } - - values[0] = start; - for (let i = 1; i < values.length; i++) { - values[i] = values[i - 1] + step; - } - - return tensor1d(values, dtype); -} - -export { - linspace, - ones, - range, - scalar, - tensor, - tensor1d, - tensor2d, - tensor3d, - tensor4d, - tensor5d, - tensor6d, - variable, - zeros -}; - -// export const linspace = op(linspace_); -// export const ones = op(ones_); -// export const range = op(range_); -// export const scalar = op(scalar_); -// export const tensor = op(tensor_); -// export const tensor1d = op(tensor1d_); -// export const tensor2d = op(tensor2d_); -// export const tensor3d = op(tensor3d_); -// export const tensor4d = op(tensor4d_); -// export const tensor5d = op(tensor5d_); -// export const tensor6d = op(tensor6d_); -// export const variable = op(variable_); -// export const zeros = op(zeros_); diff --git a/tfjs-core/src/ops/tensor_ops_util.ts b/tfjs-core/src/ops/tensor_ops_util.ts new file mode 100644 index 00000000000..9fee47fa0c1 --- /dev/null +++ b/tfjs-core/src/ops/tensor_ops_util.ts @@ -0,0 +1,76 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {Tensor} from '../tensor'; +import {TensorLike, TypedArray} from '../types'; +import {DataType} from '../types'; +import {assert, assertNonNegativeIntegerDimensions, flatten, inferDtype, isTypedArray, sizeFromShape, toTypedArray} from '../util'; + +/** This is shared code across all tensor creation methods. */ +export function makeTensor( + values: TensorLike, shape: number[], inferredShape: number[], + dtype?: DataType): Tensor { + if (dtype == null) { + dtype = inferDtype(values); + } + if (dtype === 'complex64') { + throw new Error( + `Cannot construct a complex64 tensor directly. ` + + `Please use tf.complex(real, imag).`); + } + if (!isTypedArray(values) && !Array.isArray(values) && + typeof values !== 'number' && typeof values !== 'boolean' && + typeof values !== 'string') { + throw new Error( + 'values passed to tensor(values) must be a number/boolean/string or ' + + 'an array of numbers/booleans/strings, or a TypedArray'); + } + if (shape != null) { + assertNonNegativeIntegerDimensions(shape); + + const providedSize = sizeFromShape(shape); + const inferredSize = sizeFromShape(inferredShape); + assert( + providedSize === inferredSize, + () => + `Based on the provided shape, [${shape}], the tensor should have ` + + `${providedSize} values but has ${inferredSize}`); + + for (let i = 0; i < inferredShape.length; ++i) { + const inferred = inferredShape[i]; + const flatDimsDontMatch = i === inferredShape.length - 1 ? + inferred !== sizeFromShape(shape.slice(i)) : + true; + assert( + inferredShape[i] === shape[i] || !flatDimsDontMatch, + () => `Error creating a new Tensor. Inferred shape ` + + `(${inferredShape}) does not match the provided ` + + `shape (${shape}). `); + } + } + + if (!isTypedArray(values) && !Array.isArray(values)) { + values = [values] as number[]; + } + + shape = shape || inferredShape; + values = dtype !== 'string' ? + toTypedArray(values, dtype) : + flatten(values as string[], [], true) as string[]; + return ENGINE.makeTensor(values as TypedArray, shape, dtype); +} diff --git a/tfjs-core/src/ops/topk_test.ts b/tfjs-core/src/ops/topk_test.ts index 2ff85ed32b5..9cec90a4cc9 100644 --- a/tfjs-core/src/ops/topk_test.ts +++ b/tfjs-core/src/ops/topk_test.ts @@ -19,7 +19,10 @@ import * as tf from '../index'; import {ALL_ENVS, describeWithFlags} from '../jasmine_util'; import {expectArraysClose} from '../test_util'; -import {scalar, tensor1d, tensor2d, tensor3d} from './tensor_ops'; +import {scalar} from './scalar'; +import {tensor1d} from './tensor1d'; +import {tensor2d} from './tensor2d'; +import {tensor3d} from './tensor3d'; describeWithFlags('topk', ALL_ENVS, () => { it('1d array with default k', async () => { diff --git a/tfjs-core/src/ops/unary_ops.ts b/tfjs-core/src/ops/unary_ops.ts index 606aa236fd6..aae89a167f1 100644 --- a/tfjs-core/src/ops/unary_ops.ts +++ b/tfjs-core/src/ops/unary_ops.ts @@ -21,7 +21,7 @@ import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import * as util from '../util'; import {op} from './operation'; -import {scalar} from './tensor_ops'; +import {scalar} from './scalar'; import {zerosLike} from './zeros_like'; /** diff --git a/tfjs-core/src/ops/variable.ts b/tfjs-core/src/ops/variable.ts new file mode 100644 index 00000000000..25c4525afa2 --- /dev/null +++ b/tfjs-core/src/ops/variable.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {Tensor, Variable} from '../tensor'; +import {DataType, Rank} from '../types'; + +/** + * Creates a new variable with the provided initial value. + * ```js + * const x = tf.variable(tf.tensor([1, 2, 3])); + * x.assign(tf.tensor([4, 5, 6])); + * + * x.print(); + * ``` + * + * @param initialValue Initial value for the tensor. + * @param trainable If true, optimizers are allowed to update it. + * @param name Name of the variable. Defaults to a unique id. + * @param dtype If set, initialValue will be converted to the given type. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function variable( + initialValue: Tensor, trainable = true, name?: string, + dtype?: DataType): Variable { + return ENGINE.makeVariable(initialValue, trainable, name, dtype) as + Variable; +} diff --git a/tfjs-core/src/ops/zeros.ts b/tfjs-core/src/ops/zeros.ts new file mode 100644 index 00000000000..5cd18a1bbd1 --- /dev/null +++ b/tfjs-core/src/ops/zeros.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright 2018 Google LLC. 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. + * ============================================================================= + */ + +import {ENGINE} from '../engine'; +import {Tensor} from '../tensor'; +import {DataType, Rank, ShapeMap} from '../types'; +import {makeZerosTypedArray, sizeFromShape} from '../util'; + +import {complex} from './complex'; + +/** + * Creates a `tf.Tensor` with all elements set to 0. + * + * ```js + * tf.zeros([2, 2]).print(); + * ``` + * + * @param shape An array of integers defining the output tensor shape. + * @param dtype The type of an element in the resulting tensor. Can + * be 'float32', 'int32' or 'bool'. Defaults to 'float'. + */ +/** @doc {heading: 'Tensors', subheading: 'Creation'} */ +export function zeros( + shape: ShapeMap[R], dtype: DataType = 'float32'): Tensor { + if (dtype === 'complex64') { + const real = zeros(shape, 'float32'); + const imag = zeros(shape, 'float32'); + return complex(real, imag); + } + const values = makeZerosTypedArray(sizeFromShape(shape), dtype); + return ENGINE.makeTensor(values, shape, dtype) as Tensor; +} From 209f0b31569890b88e894a1b7c0d4e4e3b451f1d Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Mon, 13 Jul 2020 11:26:37 -0400 Subject: [PATCH 5/5] fix imports --- tfjs-core/src/gradients/ClipByValue_grad.ts | 2 +- tfjs-core/src/gradients/Pow_grad.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tfjs-core/src/gradients/ClipByValue_grad.ts b/tfjs-core/src/gradients/ClipByValue_grad.ts index b13b2a7c77a..1467fd7ba65 100644 --- a/tfjs-core/src/gradients/ClipByValue_grad.ts +++ b/tfjs-core/src/gradients/ClipByValue_grad.ts @@ -20,8 +20,8 @@ import {GradConfig, NamedAttrMap} from '../kernel_registry'; import {greaterEqual} from '../ops/greater_equal'; import {lessEqual} from '../ops/less_equal'; import {logicalAnd} from '../ops/logical_and'; -import {zerosLike} from '../ops/tensor_ops'; import {where} from '../ops/where'; +import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor'; export const clipByValueGradConfig: GradConfig = { diff --git a/tfjs-core/src/gradients/Pow_grad.ts b/tfjs-core/src/gradients/Pow_grad.ts index 90514bfa5a6..90fddcd5c8d 100644 --- a/tfjs-core/src/gradients/Pow_grad.ts +++ b/tfjs-core/src/gradients/Pow_grad.ts @@ -26,7 +26,6 @@ import {reshape} from '../ops/reshape'; import {scalar} from '../ops/scalar'; import {sub} from '../ops/sub'; import {sum} from '../ops/sum'; -import {scalar, zerosLike} from '../ops/tensor_ops'; import {where} from '../ops/where'; import {zerosLike} from '../ops/zeros_like'; import {Tensor} from '../tensor';