Tfjs: Floating Imprecision in Safari leads to exceeded `maximum` and undermined `minimum`

Created on 11 Jun 2018  路  4Comments  路  Source: tensorflow/tfjs

TensorFlow.js version

0.11.6

Browser version

Safari Version 11.1 (13605.1.33.1.4)

Floating Imprecision in maximum and minimum leads to Fatal Error

Running

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.

Other Examples of the Floating Imprecision

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.

core bug

All 4 comments

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.

Was this page helpful?
0 / 5 - 0 ratings