From 5f73a6fb6213b6a699d81b735edf1e6677e4c932 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 8 May 2020 17:20:59 -0400 Subject: [PATCH 1/3] add deprecation warnings for strict variants --- tfjs-core/src/ops/binary_ops.ts | 44 ++++++++++++++++++++++++++++++++ tfjs-core/src/ops/compare.ts | 22 ++++++++++++++++ tfjs-core/src/tensor.ts | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/tfjs-core/src/ops/binary_ops.ts b/tfjs-core/src/ops/binary_ops.ts index 56db8d840f2..e0c30c6a0cc 100644 --- a/tfjs-core/src/ops/binary_ops.ts +++ b/tfjs-core/src/ops/binary_ops.ts @@ -16,6 +16,7 @@ */ import {ENGINE} from '../engine'; +import {deprecationWarn} from '../globals'; import {Tensor} from '../tensor'; import {makeTypesMatch} from '../tensor_util'; import {convertToTensor} from '../tensor_util_env'; @@ -29,6 +30,7 @@ import {scalar, zerosLike} from './tensor_ops'; import {neg} from './unary_ops'; /** + * @deprecated * Adds two `tf.Tensor`s element-wise, A + B. * * Inputs must be the same shape. For broadcasting support, use add() instead. @@ -37,6 +39,9 @@ import {neg} from './unary_ops'; * @param b The second Tensor to add element-wise. */ function addStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'addStrict'); const $b = convertToTensor(b, 'b', 'addStrict'); util.assertShapesMatch($a.shape, $b.shape, 'Error in addStrict: '); @@ -44,6 +49,7 @@ function addStrict_(a: T|TensorLike, b: T|TensorLike): T { } /** + * @deprecated * Subtracts two `tf.Tensor`s element-wise, A - B. Inputs must * be the same shape. * @@ -53,6 +59,10 @@ function addStrict_(a: T|TensorLike, b: T|TensorLike): T { * @param b The second Tensor to subtract element-wise. */ function subStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'subStrict'); const $b = convertToTensor(b, 'b', 'subStrict'); util.assertShapesMatch($a.shape, $b.shape, 'Error in subStrict: '); @@ -129,6 +139,7 @@ function pow_( } /** + * @deprecated * Computes the power of one `tf.Tensor` to another. Inputs must * be the same shape. * @@ -138,6 +149,10 @@ function pow_( * @param exp The exponent tensor to pow element-wise. */ function powStrict_(base: T, exp: Tensor): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + util.assertShapesMatch(base.shape, exp.shape, 'Error in powStrict: '); return base.pow(exp); } @@ -202,6 +217,7 @@ function mul_(a: Tensor|TensorLike, b: Tensor|TensorLike): T { } /** + * @deprecated * Multiplies two `tf.Tensor`s element-wise, A * B. * * Inputs must be the same shape. For broadcasting support, use `tf.mul`. @@ -211,6 +227,10 @@ function mul_(a: Tensor|TensorLike, b: Tensor|TensorLike): T { * dtype as `a`. */ function mulStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'mul'); const $b = convertToTensor(b, 'b', 'mul'); util.assertShapesMatch($a.shape, $b.shape, 'Error in multiplyStrict: '); @@ -279,6 +299,7 @@ function floorDiv_( } /** + * @deprecated * Divides two `tf.Tensor`s element-wise, A / B. Inputs must * be the same shape. * @@ -286,6 +307,10 @@ function floorDiv_( * @param b The second tensor as the denominator for element-wise division. */ function divStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'div'); const $b = convertToTensor(b, 'b', 'div'); util.assertShapesMatch($a.shape, $b.shape, 'Error in divideStrict: '); @@ -353,6 +378,7 @@ function mod_(a: Tensor|TensorLike, b: Tensor|TensorLike): T { } /** + * @deprecated * Returns the mod of a and b (`a < b ? a : b`) element-wise. Inputs must * be the same shape. For broadcasting support, use mod(). * @@ -360,6 +386,10 @@ function mod_(a: Tensor|TensorLike, b: Tensor|TensorLike): T { * @param b The second tensor. Must have the same dtype as `a`. */ function modStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'modStrict'); const $b = convertToTensor(b, 'b', 'modStrict'); util.assertShapesMatch($a.shape, $b.shape, 'Error in modStrict: '); @@ -418,6 +448,7 @@ function minimum_( } /** + * @deprecated * Returns the min of a and b (`a < b ? a : b`) element-wise. Inputs must * be the same shape. For broadcasting support, use minimum(). * @@ -425,6 +456,10 @@ function minimum_( * @param b The second tensor. Must have the same dtype as `a`. */ function minimumStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'minimumStrict'); const $b = convertToTensor(b, 'b', 'minimumStrict'); util.assertShapesMatch($a.shape, $b.shape, 'Error in minimumStrict: '); @@ -483,6 +518,7 @@ function maximum_( } /** + * @deprecated * Returns the max of a and b (`a > b ? a : b`) element-wise. Inputs must * be the same shape. For broadcasting support, use maximum(). * @@ -490,6 +526,10 @@ function maximum_( * @param b The second tensor. Must have the same dtype as `a`. */ function maximumStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); + const $a = convertToTensor(a, 'a', 'maximumStrict'); const $b = convertToTensor(b, 'b', 'maximumStrict'); util.assertShapesMatch($a.shape, $b.shape, 'Error in maximumStrict: '); @@ -497,6 +537,7 @@ function maximumStrict_(a: T|TensorLike, b: T|TensorLike): T { } /** + * @deprecated * Returns (a - b) * (a - b) element-wise. * * Inputs must be the same shape. For broadcasting support, use @@ -507,6 +548,9 @@ function maximumStrict_(a: T|TensorLike, b: T|TensorLike): T { */ function squaredDifferenceStrict_( a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'squaredDifferenceStrict'); const $b = convertToTensor(b, 'b', 'squaredDifferenceStrict'); util.assertShapesMatch( diff --git a/tfjs-core/src/ops/compare.ts b/tfjs-core/src/ops/compare.ts index 58ed9ee201b..d1f2fc752c0 100644 --- a/tfjs-core/src/ops/compare.ts +++ b/tfjs-core/src/ops/compare.ts @@ -14,13 +14,16 @@ * limitations under the License. * ============================================================================= */ +import {deprecationWarn} from '../globals'; import {Tensor} from '../tensor'; import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import {assertShapesMatch} from '../util'; + import {op} from './operation'; /** + * @deprecated * Strict version of `tf.notEqual` that forces `a` and `b` to be of the same * shape. * @@ -30,6 +33,9 @@ import {op} from './operation'; */ function notEqualStrict_( a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'notEqualStrict'); const $b = convertToTensor(b, 'b', 'notEqualStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in notEqualStrict: '); @@ -37,6 +43,7 @@ function notEqualStrict_( } /** + * @deprecated * Strict version of `tf.less` that forces `a` and `b` to be of the same * shape. * @@ -45,6 +52,9 @@ function notEqualStrict_( * `a`. */ function lessStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'lessStrict'); const $b = convertToTensor(b, 'b', 'lessStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in lessStrict: '); @@ -52,6 +62,9 @@ function lessStrict_(a: T|TensorLike, b: T|TensorLike): T { } function equalStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'equalStrict'); const $b = convertToTensor(b, 'b', 'equalStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in equalStrict: '); @@ -60,6 +73,9 @@ function equalStrict_(a: T|TensorLike, b: T|TensorLike): T { function lessEqualStrict_( a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'lessEqualStrict'); const $b = convertToTensor(b, 'b', 'lessEqualStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in lessEqualStrict: '); @@ -67,6 +83,9 @@ function lessEqualStrict_( } function greaterStrict_(a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'greaterStrict'); const $b = convertToTensor(b, 'b', 'greaterStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in greaterStrict: '); @@ -75,6 +94,9 @@ function greaterStrict_(a: T|TensorLike, b: T|TensorLike): T { function greaterEqualStrict_( a: T|TensorLike, b: T|TensorLike): T { + deprecationWarn( + 'strict variants of ops have been deprecated ' + + 'and will be removed in future'); const $a = convertToTensor(a, 'a', 'greaterEqualStrict'); const $b = convertToTensor(b, 'b', 'greaterEqualStrict'); assertShapesMatch($a.shape, $b.shape, 'Error in greaterEqualStrict: '); diff --git a/tfjs-core/src/tensor.ts b/tfjs-core/src/tensor.ts index 095df29d2ab..1df1994bf40 100644 --- a/tfjs-core/src/tensor.ts +++ b/tfjs-core/src/tensor.ts @@ -825,6 +825,9 @@ export class Tensor { } // Binary ops. + /** + * @deprecated strict variants of ops have been deprecated + */ addStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.addStrict(this, x); @@ -833,6 +836,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.atan2(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ subStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.subStrict(this, x); @@ -841,6 +847,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.pow(this, exp); } + /** + * @deprecated strict variants of ops have been deprecated + */ powStrict(exp: Tensor|TensorLike): Tensor { this.throwIfDisposed(); return opHandler.powStrict(this, exp); @@ -849,6 +858,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.mul(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ mulStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.mulStrict(this, x); @@ -857,6 +869,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.floorDiv(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ divStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.divStrict(this, x); @@ -865,6 +880,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.minimum(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ minimumStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.minimumStrict(this, x); @@ -873,6 +891,9 @@ export class Tensor { this.throwIfDisposed(); return opHandler.maximum(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ maximumStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.maximumStrict(this, x); @@ -881,36 +902,60 @@ export class Tensor { this.throwIfDisposed(); return opHandler.mod(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ modStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.modStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ squaredDifferenceStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.squaredDifferenceStrict(this, x); } // Compare ops. + /** + * @deprecated strict variants of ops have been deprecated + */ notEqualStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.notEqualStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ lessStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.lessStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ equalStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.equalStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ lessEqualStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.lessEqualStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ greaterStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.greaterStrict(this, x); } + /** + * @deprecated strict variants of ops have been deprecated + */ greaterEqualStrict(this: T, x: T|TensorLike): T { this.throwIfDisposed(); return opHandler.greaterEqualStrict(this, x); From 38f5d99612da90caaebf23abcd86db2c817af37e Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 8 May 2020 18:59:49 -0400 Subject: [PATCH 2/3] remove internal usage of strict methods --- tfjs-core/src/globals_test.ts | 22 ++++++------ tfjs-core/src/ops/add.ts | 2 -- tfjs-core/src/ops/equal.ts | 3 -- tfjs-core/src/ops/linalg_ops.ts | 2 +- tfjs-core/src/ops/lstm.ts | 6 ++-- tfjs-core/src/ops/not_equal.ts | 3 -- tfjs-core/src/ops/relu_ops.ts | 8 +++-- tfjs-core/src/ops/softmax_test.ts | 2 +- tfjs-core/src/ops/squared_difference.ts | 4 --- tfjs-core/src/ops/sub.ts | 3 -- tfjs-core/src/ops/unary_ops.ts | 39 +++++++++++++++++----- tfjs-core/src/optimizers/optimizer_test.ts | 18 ++++++---- tfjs-layers/src/backend/tfjs_backend.ts | 2 +- tfjs-layers/src/constraints.ts | 2 +- tfjs-layers/src/engine/training_test.ts | 6 ++-- tfjs-layers/src/layers/merge.ts | 4 +-- tfjs-layers/src/layers/recurrent.ts | 7 ++-- tfjs-layers/src/utils/math_utils.ts | 20 +++++------ 18 files changed, 83 insertions(+), 70 deletions(-) diff --git a/tfjs-core/src/globals_test.ts b/tfjs-core/src/globals_test.ts index 967dd2e7f78..a2441711615 100644 --- a/tfjs-core/src/globals_test.ts +++ b/tfjs-core/src/globals_test.ts @@ -86,9 +86,9 @@ describeWithFlags('tidy', ALL_ENVS, () => { expect(tf.memory().numTensors).toBe(2); tf.tidy(() => { const result = tf.tidy(() => { - b = tf.addStrict(a, b); - b = tf.addStrict(a, b); - b = tf.addStrict(a, b); + b = tf.add(a, b); + b = tf.add(a, b); + b = tf.add(a, b); return tf.add(a, b); }); @@ -167,9 +167,9 @@ describeWithFlags('tidy', ALL_ENVS, () => { expect(tf.memory().numTensors).toBe(2); tf.tidy(() => { - b = tf.addStrict(a, b); - b = tf.addStrict(a, b); - b = tf.addStrict(a, b); + b = tf.add(a, b); + b = tf.add(a, b); + b = tf.add(a, b); tf.add(a, b); }); @@ -185,25 +185,25 @@ describeWithFlags('tidy', ALL_ENVS, () => { tf.tidy(() => { const result = tf.tidy(() => { - b = tf.addStrict(a, b); + b = tf.add(a, b); b = tf.tidy(() => { b = tf.tidy(() => { - return tf.addStrict(a, b); + return tf.add(a, b); }); // original a, b, and two intermediates. expect(tf.memory().numTensors).toBe(4); tf.tidy(() => { - tf.addStrict(a, b); + tf.add(a, b); }); // All the intermediates should be cleaned up. expect(tf.memory().numTensors).toBe(4); - return tf.addStrict(a, b); + return tf.add(a, b); }); expect(tf.memory().numTensors).toBe(4); - return tf.addStrict(a, b); + return tf.add(a, b); }); expect(tf.memory().numTensors).toBe(3); diff --git a/tfjs-core/src/ops/add.ts b/tfjs-core/src/ops/add.ts index b96b7ca1abb..ec23b961bc7 100644 --- a/tfjs-core/src/ops/add.ts +++ b/tfjs-core/src/ops/add.ts @@ -27,8 +27,6 @@ import {op} from './operation'; /** * Adds two `tf.Tensor`s element-wise, A + B. Supports broadcasting. * - * We also expose `tf.addStrict` which has the same signature as this op and - * asserts that `a` and `b` are the same shape (does not broadcast). * * ```js * const a = tf.tensor1d([1, 2, 3, 4]); diff --git a/tfjs-core/src/ops/equal.ts b/tfjs-core/src/ops/equal.ts index dcf0c54a4cd..9423ae19053 100644 --- a/tfjs-core/src/ops/equal.ts +++ b/tfjs-core/src/ops/equal.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a == b) element-wise. Supports broadcasting. * - * We also expose `tf.equalStrict` which has the same signature as this op - * and asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([2, 2, 2]); diff --git a/tfjs-core/src/ops/linalg_ops.ts b/tfjs-core/src/ops/linalg_ops.ts index cb00fa80657..4f10e56fb33 100644 --- a/tfjs-core/src/ops/linalg_ops.ts +++ b/tfjs-core/src/ops/linalg_ops.ts @@ -193,7 +193,7 @@ function gramSchmidt_(xs: Tensor1D[]|Tensor2D): Tensor1D[]|Tensor2D { let x = xs1d[i]; if (i > 0) { for (let j = 0; j < i; ++j) { - const proj = sum(ys[j].mulStrict(x)).mul(ys[j]); + const proj = sum(ys[j].mul(x)).mul(ys[j]); x = x.sub(proj); } } diff --git a/tfjs-core/src/ops/lstm.ts b/tfjs-core/src/ops/lstm.ts index 476e340505e..7f43c500100 100644 --- a/tfjs-core/src/ops/lstm.ts +++ b/tfjs-core/src/ops/lstm.ts @@ -108,9 +108,9 @@ function basicLSTMCell_( const f = res.slice([0, sliceCols * 2], sliceSize); const o = res.slice([0, sliceCols * 3], sliceSize); - const newC = i.sigmoid().mulStrict(j.tanh()).addStrict( - $c.mulStrict($forgetBias.add(f).sigmoid() as Tensor2D)); - const newH = newC.tanh().mulStrict(o.sigmoid()); + const newC: Tensor2D = i.sigmoid().mul(j.tanh()).add( + $c.mul($forgetBias.add(f).sigmoid() as Tensor2D)); + const newH: Tensor2D = newC.tanh().mul(o.sigmoid()); return [newC, newH]; } diff --git a/tfjs-core/src/ops/not_equal.ts b/tfjs-core/src/ops/not_equal.ts index f210da73492..fd018fc6dc6 100644 --- a/tfjs-core/src/ops/not_equal.ts +++ b/tfjs-core/src/ops/not_equal.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a != b) element-wise. Supports broadcasting. * - * We also expose `tf.notEqualStrict` which has the same signature as this op - * and asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([0, 2, 3]); diff --git a/tfjs-core/src/ops/relu_ops.ts b/tfjs-core/src/ops/relu_ops.ts index 7bbe791202c..031bb3edd89 100644 --- a/tfjs-core/src/ops/relu_ops.ts +++ b/tfjs-core/src/ops/relu_ops.ts @@ -19,7 +19,7 @@ import {ENGINE} from '../engine'; import {Tensor} from '../tensor'; import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; -import {maximum} from './binary_ops'; +import {maximum, mul} from './binary_ops'; import {getReductionAxes} from './broadcast_util'; import {where} from './logical_ops'; import {op} from './operation'; @@ -46,7 +46,8 @@ function relu_(x: T|TensorLike): T { } const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; - return {x: () => dy.mulStrict($x.step().toFloat() as T)}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {x: () => mul(dy, $x.step().toFloat()) as T}; }; return ENGINE.runKernelFunc((backend, save) => { const res = backend.relu($x); @@ -76,7 +77,8 @@ function relu6_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; const mask = $x.lessEqual(6).mul($x.step()); - return {x: () => dy.mulStrict(mask.toFloat() as T)}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {x: () => mul(dy, mask.toFloat()) as T}; }; return ENGINE.runKernelFunc((backend, save) => { const res = backend.relu6($x); diff --git a/tfjs-core/src/ops/softmax_test.ts b/tfjs-core/src/ops/softmax_test.ts index e18397bb0a0..64336caeec8 100644 --- a/tfjs-core/src/ops/softmax_test.ts +++ b/tfjs-core/src/ops/softmax_test.ts @@ -109,7 +109,7 @@ describeWithFlags('softmax', ALL_ENVS, () => { const dx = tf.grad((x) => x.softmax())(x, dy); const axis = -1; - const totalSum: tf.Tensor1D = tf.sum(tf.mulStrict(dy, y), axis); + const totalSum: tf.Tensor1D = tf.sum(tf.mul(dy, y), axis); const dyVals = await dy.array(); const sumVals = await totalSum.array(); diff --git a/tfjs-core/src/ops/squared_difference.ts b/tfjs-core/src/ops/squared_difference.ts index 23abbe633a8..32fa26a5f02 100644 --- a/tfjs-core/src/ops/squared_difference.ts +++ b/tfjs-core/src/ops/squared_difference.ts @@ -30,10 +30,6 @@ import {op} from './operation'; * Returns (a - b) * (a - b) element-wise. * Supports broadcasting. * - * We also expose `tf.squaredDifferenceStrict` which has the same signature as - * this op and asserts that `a` and `b` are the same shape (does not - * broadcast). - * * ```js * const a = tf.tensor1d([1, 4, 3, 16]); * const b = tf.tensor1d([1, 2, 9, 4]); diff --git a/tfjs-core/src/ops/sub.ts b/tfjs-core/src/ops/sub.ts index 74bbcf20323..0ba04db5a56 100644 --- a/tfjs-core/src/ops/sub.ts +++ b/tfjs-core/src/ops/sub.ts @@ -27,9 +27,6 @@ import {op} from './operation'; /** * Subtracts two `tf.Tensor`s element-wise, A - B. Supports broadcasting. * - * We also expose `tf.subStrict` which has the same signature as this op and - * asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([10, 20, 30, 40]); * const b = tf.tensor1d([1, 2, 3, 4]); diff --git a/tfjs-core/src/ops/unary_ops.ts b/tfjs-core/src/ops/unary_ops.ts index 1c50420490e..97ecfbee54c 100644 --- a/tfjs-core/src/ops/unary_ops.ts +++ b/tfjs-core/src/ops/unary_ops.ts @@ -22,6 +22,7 @@ import {TensorLike} from '../types'; import * as util from '../util'; import {op} from './operation'; +import {div, mul} from './ops'; import {scalar, zerosLike} from './tensor_ops'; /** @@ -216,7 +217,8 @@ function exp_(x: T|TensorLike): T { const $x = convertToTensor(x, 'x', 'exp'); const bck = (dy: T, saved: Tensor[]) => { - return {x: () => dy.mulStrict(saved[0] as T)}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {x: () => mul(dy, saved[0]) as T}; }; const attrs = {}; const inputsToSave: Tensor[] = []; @@ -624,7 +626,8 @@ function asin_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; return { - $x: () => dy.divStrict(scalar(1).sub($x.toFloat().square()).sqrt() as T) + // tslint:disable-next-line: no-unnecessary-type-assertion + $x: () => div(dy, scalar(1).sub($x.toFloat().square()).sqrt()) as T }; }; return ENGINE.runKernelFunc((backend, save) => { @@ -651,8 +654,13 @@ function acos_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; return { - $x: () => - dy.divStrict(scalar(1).sub($x.toFloat().square()).sqrt() as T).neg() + $x: () => { + const a = $x.toFloat().square(); + const b = scalar(1).sub(a).sqrt(); + // tslint:disable-next-line: no-unnecessary-type-assertion + return (dy.div(b) as T).neg(); + } + }; }; return ENGINE.runKernelFunc((backend, save) => { @@ -703,7 +711,8 @@ function sinh_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; - return {$x: () => $x.toFloat().cosh().mulStrict(dy) as T}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {$x: () => $x.toFloat().cosh().mul(dy) as T}; }; return ENGINE.runKernelFunc((backend, save) => { const res = backend.sinh($x); @@ -728,7 +737,8 @@ function cosh_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; - return {$x: () => $x.toFloat().sinh().mulStrict(dy) as T}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {$x: () => $x.toFloat().sinh().mul(dy) as T}; }; return ENGINE.runKernelFunc((backend, save) => { const res = backend.cosh($x); @@ -753,7 +763,8 @@ function tanh_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [y] = saved; - return {x: () => scalar(1).sub(y.square()).mulStrict(dy) as T}; + // tslint:disable-next-line: no-unnecessary-type-assertion + return {x: () => scalar(1).sub(y.square()).mul(dy) as T}; }; const outputsToSave = [true]; return ENGINE.runKernelFunc( @@ -784,7 +795,11 @@ function asinh_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; return { - $x: () => dy.divStrict(scalar(1).add($x.toFloat().square()).sqrt() as T) + $x: () => { + const a = scalar(1).add($x.toFloat().square()).sqrt(); + // tslint:disable-next-line: no-unnecessary-type-assertion + return dy.div(a) as T; + } }; }; return ENGINE.runKernelFunc((backend, save) => { @@ -811,7 +826,13 @@ function acosh_(x: T|TensorLike): T { const grad = (dy: T, saved: Tensor[]) => { const [$x] = saved; - return {$x: () => dy.divStrict($x.toFloat().square().sub(1).sqrt() as T)}; + return { + $x: () => { + const a = $x.toFloat().square().sub(1).sqrt(); + // tslint:disable-next-line: no-unnecessary-type-assertion + return dy.div(a) as T; + } + }; }; return ENGINE.runKernelFunc((backend, save) => { const res = backend.acosh($x); diff --git a/tfjs-core/src/optimizers/optimizer_test.ts b/tfjs-core/src/optimizers/optimizer_test.ts index add269a72c7..98477d16a67 100644 --- a/tfjs-core/src/optimizers/optimizer_test.ts +++ b/tfjs-core/src/optimizers/optimizer_test.ts @@ -34,7 +34,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { let numTensors = tf.memory().numTensors; - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; let cost = optimizer.minimize(f, /* returnCost */ true); @@ -83,7 +84,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { const strayVariable = tf.scalar(-1).variable(); const varList = [x, bias]; - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; let cost = optimizer.minimize(f, /* returnCost */ true, varList); @@ -118,7 +120,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { tf.scalar(-1).variable(); const varList: Variable[] = []; - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; expect(() => optimizer.minimize(f, /* returnCost */ true, varList)) .toThrowError(); @@ -133,7 +136,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { const strayVariable = tf.scalar(-1).variable(); const varList = [x]; - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; let cost = optimizer.minimize(f, /* returnCost */ true, varList); @@ -166,7 +170,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { const bias = tf.scalar(1).variable(); const strayVariable = tf.scalar(-1).variable(); - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; let cost = optimizer.minimize(f, /* returnCost */ true); @@ -201,7 +206,8 @@ describeWithFlags('optimizer', ALL_ENVS, () => { tf.scalar(-1).variable(); const varList = [x]; - const f = () => x.square().addStrict(bias); + // tslint:disable-next-line: no-unnecessary-type-assertion + const f = () => x.square().add(bias) as tf.Scalar; expect(() => optimizer.minimize(f, /* returnCost */ true, varList)) .toThrowError(); diff --git a/tfjs-layers/src/backend/tfjs_backend.ts b/tfjs-layers/src/backend/tfjs_backend.ts index f16351189c9..175dc1c617c 100644 --- a/tfjs-layers/src/backend/tfjs_backend.ts +++ b/tfjs-layers/src/backend/tfjs_backend.ts @@ -531,7 +531,7 @@ export function gather( * @return element-wise x^2 */ export function square(x: Tensor): Tensor { - return tfc.mulStrict(x, x); + return tfc.mul(x, x); } /** diff --git a/tfjs-layers/src/constraints.ts b/tfjs-layers/src/constraints.ts index 4d51513b9ee..486a5314cf8 100644 --- a/tfjs-layers/src/constraints.ts +++ b/tfjs-layers/src/constraints.ts @@ -19,7 +19,7 @@ import {deserializeKerasObject, serializeKerasObject} from './utils/generic_util * Helper function used by many of the Constraints to find the L2Norms. */ function calcL2Norms(w: Tensor, axis: number): Tensor { - return tidy(() => tfc.sqrt(tfc.sum(tfc.mulStrict(w, w), axis, true))); + return tidy(() => tfc.sqrt(tfc.sum(tfc.mul(w, w), axis, true))); } /** diff --git a/tfjs-layers/src/engine/training_test.ts b/tfjs-layers/src/engine/training_test.ts index 756ede7ce76..84b8f82c9cb 100644 --- a/tfjs-layers/src/engine/training_test.ts +++ b/tfjs-layers/src/engine/training_test.ts @@ -1069,7 +1069,7 @@ describeMathCPUAndGPU('LayersModel.fit', () => { // be updated in every training epoch. // TODO(cais): Use `expectArraysNotClose()` when available. expect(tensor1d(layer2KernelValues[epoch]) - .subStrict(tensor1d(layer2KernelValues[epoch - 1])) + .sub(tensor1d(layer2KernelValues[epoch - 1])) .abs() .max() .dataSync()[0]) @@ -1081,14 +1081,14 @@ describeMathCPUAndGPU('LayersModel.fit', () => { // === 2. if (epoch === 2) { expect(tensor1d(layer1KernelValues[epoch]) - .subStrict(tensor1d(layer1KernelValues[epoch - 1])) + .sub(tensor1d(layer1KernelValues[epoch - 1])) .abs() .max() .dataSync()[0]) .toEqual(0); } else if (epoch > 0) { expect(tensor1d(layer1KernelValues[epoch]) - .subStrict(tensor1d(layer1KernelValues[epoch - 1])) + .sub(tensor1d(layer1KernelValues[epoch - 1])) .abs() .max() .dataSync()[0]) diff --git a/tfjs-layers/src/layers/merge.ts b/tfjs-layers/src/layers/merge.ts index abeddb14c12..733c168b1f9 100644 --- a/tfjs-layers/src/layers/merge.ts +++ b/tfjs-layers/src/layers/merge.ts @@ -926,9 +926,9 @@ function batchDot(x: Tensor, y: Tensor, axes: number|[number, number]): Tensor { let out: Tensor; if (x.shape.length === 2 && y.shape.length === 2) { if (axesArray[0] === axesArray[1]) { - out = x.mulStrict(y).sum(axesArray[0]); + out = x.mul(y).sum(axesArray[0]); } else { - out = x.transpose([1, 0]).mulStrict(y).sum(axesArray[1]); + out = x.transpose([1, 0]).mul(y).sum(axesArray[1]); } } else { const adjX = axesArray[0] !== x.shape.length - 1; diff --git a/tfjs-layers/src/layers/recurrent.ts b/tfjs-layers/src/layers/recurrent.ts index 508f3303d51..c368582a6bf 100644 --- a/tfjs-layers/src/layers/recurrent.ts +++ b/tfjs-layers/src/layers/recurrent.ts @@ -213,11 +213,10 @@ export function rnn( const stepMask = perStepMasks[t]; const negStepMask = tfc.onesLike(stepMask).sub(stepMask); // TODO(cais): Would tfc.where() be better for performance? - const output = stepOutputs[0].mul(stepMask).addStrict( - states[0].mul(negStepMask)); + const output = + stepOutputs[0].mul(stepMask).add(states[0].mul(negStepMask)); const newStates = states.map((state, i) => { - return stepOutputs[1][i].mul(stepMask).addStrict( - state.mul(negStepMask)); + return stepOutputs[1][i].mul(stepMask).add(state.mul(negStepMask)); }); return {output, newStates}; }); diff --git a/tfjs-layers/src/utils/math_utils.ts b/tfjs-layers/src/utils/math_utils.ts index 4f2d3dde6b5..459b1d63de1 100644 --- a/tfjs-layers/src/utils/math_utils.ts +++ b/tfjs-layers/src/utils/math_utils.ts @@ -23,7 +23,7 @@ import * as tfc from '@tensorflow/tfjs-core'; import {scalar, Tensor1D, tensor1d} from '@tensorflow/tfjs-core'; import {ValueError} from '../errors'; -export type ArrayTypes = Uint8Array | Int32Array | Float32Array; +export type ArrayTypes = Uint8Array|Int32Array|Float32Array; /** * Determine if a number is an integer. @@ -40,7 +40,7 @@ export function isInteger(x: number): boolean { * @return The product. */ export function arrayProd( - array: number[] | ArrayTypes, begin?: number, end?: number): number { + array: number[]|ArrayTypes, begin?: number, end?: number): number { if (begin == null) { begin = 0; } @@ -60,7 +60,7 @@ export function arrayProd( * so the return value can be fed directly into various TF.js Core functions. * @param array */ -function toArray1D(array: number[] | Float32Array): Tensor1D { +function toArray1D(array: number[]|Float32Array): Tensor1D { array = Array.isArray(array) ? new Float32Array(array) : array; return tensor1d(array); } @@ -70,7 +70,7 @@ function toArray1D(array: number[] | Float32Array): Tensor1D { * @param array * @return minimum value. */ -export function min(array: number[] | Float32Array): number { +export function min(array: number[]|Float32Array): number { return tfc.min(toArray1D(array)).dataSync()[0]; } @@ -79,7 +79,7 @@ export function min(array: number[] | Float32Array): number { * @param array * @return maximum value */ -export function max(array: number[] | Float32Array): number { +export function max(array: number[]|Float32Array): number { return tfc.max(toArray1D(array)).dataSync()[0]; } @@ -88,7 +88,7 @@ export function max(array: number[] | Float32Array): number { * @param array * @return The sum. */ -export function sum(array: number[] | Float32Array): number { +export function sum(array: number[]|Float32Array): number { return tfc.sum(toArray1D(array)).dataSync()[0]; } @@ -97,7 +97,7 @@ export function sum(array: number[] | Float32Array): number { * @param array * @return The mean. */ -export function mean(array: number[] | Float32Array): number { +export function mean(array: number[]|Float32Array): number { return sum(array) / array.length; } @@ -106,9 +106,9 @@ export function mean(array: number[] | Float32Array): number { * @param array * @return The variance. */ -export function variance(array: number[] | Float32Array): number { +export function variance(array: number[]|Float32Array): number { const demeaned = tfc.sub(toArray1D(array), scalar(mean(array))); - const sumSquare = tfc.sum(tfc.mulStrict(demeaned, demeaned)).dataSync()[0]; + const sumSquare = tfc.sum(tfc.mul(demeaned, demeaned)).dataSync()[0]; return sumSquare / array.length; } @@ -117,7 +117,7 @@ export function variance(array: number[] | Float32Array): number { * @param array * @return The median value. */ -export function median(array: number[] | Float32Array): number { +export function median(array: number[]|Float32Array): number { const arraySorted = array.slice().sort((a, b) => a - b); const lowIdx = Math.floor((arraySorted.length - 1) / 2); const highIdx = Math.ceil((arraySorted.length - 1) / 2); From 0934d22b1d0ed5788f797470c3bb72b4f431a833 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 8 May 2020 19:21:42 -0400 Subject: [PATCH 3/3] save --- tfjs-core/src/ops/div.ts | 3 --- tfjs-core/src/ops/div_no_nan.ts | 2 -- tfjs-core/src/ops/greater.ts | 3 --- tfjs-core/src/ops/greater_equal.ts | 3 --- tfjs-core/src/ops/less.ts | 3 --- tfjs-core/src/ops/less_equal.ts | 3 --- tfjs-core/src/ops/unary_ops.ts | 6 ++---- 7 files changed, 2 insertions(+), 21 deletions(-) diff --git a/tfjs-core/src/ops/div.ts b/tfjs-core/src/ops/div.ts index 54364f18f05..20ab1d24b94 100644 --- a/tfjs-core/src/ops/div.ts +++ b/tfjs-core/src/ops/div.ts @@ -29,9 +29,6 @@ import {op} from './operation'; /** * Divides two `tf.Tensor`s element-wise, A / B. Supports broadcasting. * - * We also expose `tf.divStrict` which has the same signature as this op and - * asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 4, 9, 16]); * const b = tf.tensor1d([1, 2, 3, 4]); diff --git a/tfjs-core/src/ops/div_no_nan.ts b/tfjs-core/src/ops/div_no_nan.ts index b9737316cad..7b4fc3330ee 100644 --- a/tfjs-core/src/ops/div_no_nan.ts +++ b/tfjs-core/src/ops/div_no_nan.ts @@ -29,8 +29,6 @@ import {zerosLike} from './tensor_ops'; * Divides two `tf.Tensor`s element-wise, A / B. Supports broadcasting. Return 0 * if denominator is 0. * - * We also expose `tf.divStrict` which has the same signature as this op and - * asserts that `a` and `b` are the same shape (does not broadcast). * * ```js * const a = tf.tensor1d([1, 4, 9, 16]); diff --git a/tfjs-core/src/ops/greater.ts b/tfjs-core/src/ops/greater.ts index c6e19ba5287..5ed863dbd29 100644 --- a/tfjs-core/src/ops/greater.ts +++ b/tfjs-core/src/ops/greater.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a > b) element-wise. Supports broadcasting. * - * We also expose `tf.greaterStrict` which has the same signature as this - * op and asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([2, 2, 2]); diff --git a/tfjs-core/src/ops/greater_equal.ts b/tfjs-core/src/ops/greater_equal.ts index 4f8090a4e82..5530e92b5c6 100644 --- a/tfjs-core/src/ops/greater_equal.ts +++ b/tfjs-core/src/ops/greater_equal.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a >= b) element-wise. Supports broadcasting. * - * We also expose `tf.greaterEqualStrict` which has the same signature as this - * op and asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([2, 2, 2]); diff --git a/tfjs-core/src/ops/less.ts b/tfjs-core/src/ops/less.ts index 41445651d00..1a123dd5735 100644 --- a/tfjs-core/src/ops/less.ts +++ b/tfjs-core/src/ops/less.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a < b) element-wise. Supports broadcasting. * - * We also expose `tf.lessStrict` which has the same signature as this op and - * asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([2, 2, 2]); diff --git a/tfjs-core/src/ops/less_equal.ts b/tfjs-core/src/ops/less_equal.ts index 93dd68206ce..211cbdca448 100644 --- a/tfjs-core/src/ops/less_equal.ts +++ b/tfjs-core/src/ops/less_equal.ts @@ -28,9 +28,6 @@ import {op} from './operation'; /** * Returns the truth value of (a <= b) element-wise. Supports broadcasting. * - * We also expose `tf.lessEqualStrict` which has the same signature as this op - * and asserts that `a` and `b` are the same shape (does not broadcast). - * * ```js * const a = tf.tensor1d([1, 2, 3]); * const b = tf.tensor1d([2, 2, 2]); diff --git a/tfjs-core/src/ops/unary_ops.ts b/tfjs-core/src/ops/unary_ops.ts index 97ecfbee54c..e31bfb20d28 100644 --- a/tfjs-core/src/ops/unary_ops.ts +++ b/tfjs-core/src/ops/unary_ops.ts @@ -20,9 +20,7 @@ import {Tensor} from '../tensor'; import {convertToTensor} from '../tensor_util_env'; import {TensorLike} from '../types'; import * as util from '../util'; - import {op} from './operation'; -import {div, mul} from './ops'; import {scalar, zerosLike} from './tensor_ops'; /** @@ -218,7 +216,7 @@ function exp_(x: T|TensorLike): T { const bck = (dy: T, saved: Tensor[]) => { // tslint:disable-next-line: no-unnecessary-type-assertion - return {x: () => mul(dy, saved[0]) as T}; + return {x: () => dy.mul(saved[0]) as T}; }; const attrs = {}; const inputsToSave: Tensor[] = []; @@ -627,7 +625,7 @@ function asin_(x: T|TensorLike): T { const [$x] = saved; return { // tslint:disable-next-line: no-unnecessary-type-assertion - $x: () => div(dy, scalar(1).sub($x.toFloat().square()).sqrt()) as T + $x: () => dy.div(scalar(1).sub($x.toFloat().square()).sqrt()) as T }; }; return ENGINE.runKernelFunc((backend, save) => {