0.11.6
Safari Version 11.1 (13605.1.33.1.4)
maximum and minimum leads to Fatal ErrorRunning
await tf.toPixels(
tf.tensor2d([[0, 1], [3, 4]])
.maximum(tf.scalar(0))
.minimum(tf.scalar(1))
)
leads to
An error occured
Tensor values for a float32 Tensor must be in the range [0 - 1] but got range [-0.000004730089131044224 - 1.000494122505188].
in Safari.
Accompanied by WebGL: INVALID_ENUM: readPixels: invalid type. Is the floating imprecision a general limitation of Safari because readPixels doesn't work?
I think maximum and minimum should be precise, even if it comes at a cost. A graceful toPixels could be a workaround but probably leads to similar errors in other places.
Just in case you weren't aware:
const x = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
const [a, b] = tf.split(x, 2, 1);
a.print();
b.print();
Example Safari Output
Tensor
[[1.0004941, 1.9997916],
[5.0000868, 5.9993935]]
Tensor
[[3.0002904, 3.9995973],
[6.9998927, 8.000391 ]]
Chrome Output
Tensor
[[1, 2],
[5, 6]]
Tensor
[[3, 4],
[7, 8]]
Affects most arithmetic, slicing, padding and joining ops.
Just adding some info here for us that clipByValue also does the same in safari.
const res2 = tf.tensor2d([[0, 1], [3, 4]])
.clipByValue(0, 1)
res2.print()
@tpreusse I'm not sure if this applies in your actual code but a potential workaround if you know your data are integers is to declare the tensor with an int32 dtype. e.g.
const res = tf.tensor2d([[0, 1], [3, 4]], undefined, 'int32')
.maximum(tf.scalar(0, 'int32'))
.minimum(tf.scalar(1, 'int32'))
res.print()
// Or using clipByValue
const res2 = tf.tensor2d([[0, 1], [3, 4]], undefined,'int32')
.clipByValue(0, 1)
res2.print()
This will be fixed when https://github.com/tensorflow/tfjs-core/pull/978 lands, which means safari desktop gives perfect precision (iOS will use half float).
I will get it in before EOW, but needed to refactor testing infrastructure before I could get it in.
Awesome. Thank you.
@tafsiri thanks for the workaround! Did the job.
Complete workaround, including mul(255), for toPixels:
const t = tf.tensor2d([[0, 1], [3, 4]])
await tf.toPixels(
t.clipByValue(0, 1)
.mul(tf.scalar(255)) // floats automatically are multiplied by toPixels
.cast('int32')
)
Closing since tensorflow/tfjs-core#978 has been merged.