Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tf.unsortedSegmentSum does not aggregate all indices? #8174

Open
wangjia184 opened this issue Feb 9, 2024 · 4 comments
Open

tf.unsortedSegmentSum does not aggregate all indices? #8174

wangjia184 opened this issue Feb 9, 2024 · 4 comments

Comments

@wangjia184
Copy link

wangjia184 commented Feb 9, 2024

  • Tensorflow JS : version 4.16.0
  • Backend : webgpu
        // https://js.tensorflow.org/api/4.17.0/#unsortedSegmentSum
        const onesTensor = tf.ones([size * size], 'float32');
        const countTensor = tf.unsortedSegmentSum(onesTensor, indexTensor, size * size);
        console.log("onesTensor shape =", onesTensor.shape, "; dtype =", onesTensor.dtype);
        console.log("indexTensor shape =", indexTensor.shape, "; dtype =", indexTensor.dtype);
        console.log("countTensor shape =", countTensor.shape, "; dtype =", countTensor.dtype);
        console.log("size * size =", size * size);
        const indexBuffer = indexTensor.arraySync();
        console.log("indexBuffer valid element number ="
            , indexBuffer.map((v) => (v >= 0 && v < size * size) ? 1 : 0).reduce((a, b) => a + b)
        );
        const data = countTensor.arraySync();
        console.log("total =", data.reduce((a, b) => a + b));

I have the above code using tf.unsortedSegmentSum to calculate the sum of the ones based on the indices in indexTensor.
Here is output from console.

onesTensor shape = [88804] ; dtype = float32
indexTensor shape = [1000000] ; dtype = int32
countTensor shape = [88804] ; dtype = float32
size * size = 88804
indexBuffer valid element number = 1000000
total = 88804

As you can see, there are 1000000 indices in indexBuffer but there are only 88804 indices aggregated. Actually those 88804 indices are aggregated correctly, I can see duplicates are counted, I can see the graph if I draw in heatmap. But there are 1000000 valid indices and total should be 1000000. Why only 88804 elements are counted?

@wangjia184
Copy link
Author

wangjia184 commented Feb 10, 2024

I am overcoming this issue by using following code. The actual distinct segment number is just size*size, but I have to supply a larger buffer to solve it.

        const ONES_TENSOR = tf.ones([indexTensor.size], 'float32');
        // using tf.unsortedSegmentSum to calculate the sum of the ones based on the indices in indexTensor
        const countTensor = tf.unsortedSegmentSum(ONES_TENSOR, indexTensor, indexTensor.size);
        indexTensor.dispose();

        // Possible bug in TensorflowJS : https://github.com/tensorflow/tfjs/issues/8174
        const slicedTensor = tf.slice(countTensor, 0, size * size);
        countTensor.dispose();

@gaikwadrahul8
Copy link
Contributor

gaikwadrahul8 commented Feb 13, 2024

Hi, @wangjia184

I apologize for the delayed response, Good to hear that your issue has been resolved by supplying larger buffer size. I was trying to replicate the same behavior from my end with webgpu backend in Tensorflow.js api page itself and I'm getting below output at the moment I'm not sure what values you are passing so I tried with size=1000 & indexTensor is equal to const indexTensor = tf.ones([size * size], 'int32');

If I have missed something here please let me know. Thank you.

image

@wangjia184
Copy link
Author

Thanks @gaikwadrahul8 , please find Pen.io here: https://codepen.io/wangjia184/pen/NWJoXdq and watch console output

<html>
  <head>
     <!-- Import @tensorflow/tfjs or @tensorflow/tfjs-core -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"> </script>

<!-- Add the WebGPU backend to the global backend registry -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgpu/dist/tf-backend-webgpu.js"></script>

  </head>
  <body onload="init()">
    <script>
      function init() {
        // Set the backend to WebGPU and wait for the module to be ready
        tf.setBackend('webgpu').then( async () => {
          console.log('WebGPU is ready');
          
          const TOTAL_SAMPLES = 1000000;
          const shape = [TOTAL_SAMPLES];

          // generate noises
          const guassianTensor = tf.randomNormal(shape, 0/*mean*/, 1/*stddev*/, 'float32');
          console.log("guassianTensor shape =", guassianTensor.shape, "; dtype =", guassianTensor.dtype);
          guassianTensor.print();
          
          
          const segmentNums = 256*256;
          const increment = 2 / (segmentNums - 1.0); // range from [-1, +1]
          const edges = Array.from({ length: segmentNums - 2 }, (_, idx) => -1 + (idx + 1) * increment); 
          const seqTensor = tf.tensor(edges);
          
          console.log("seqTensor shape =", seqTensor.shape, "; dtype =", seqTensor.dtype);
          seqTensor.print();
          
          const discretizedTensor = tf.lowerBound(seqTensor, guassianTensor); 
          seqTensor.dispose();
          guassianTensor.dispose();
          const indexTensor = discretizedTensor.reshape([TOTAL_SAMPLES]);
          discretizedTensor.dispose();
          
          console.log("indexTensor shape =", indexTensor.shape, "; dtype =", indexTensor.dtype);
          indexTensor.print();
          
          const indexBuffer = await indexTensor.array();
          console.log("indexBuffer valid element number ="
            , indexBuffer.map((v) => (v >= 0 && v < segmentNums) ? 1 : 0).reduce((a, b) => a + b)
          );
          const onesTensor = tf.ones([segmentNums], 'float32');
          console.log("onesTensor shape =", onesTensor.shape, "; dtype =", onesTensor.dtype);
          
          const countTensor = tf.unsortedSegmentSum(onesTensor, indexTensor, segmentNums);
          console.log("countTensor shape =", countTensor.shape, "; dtype =", countTensor.dtype);
          
          const data = await countTensor.array();
          console.log("total =", data.reduce((a, b) => a + b));
          console.log(data); 
          
          indexTensor.dispose();
          onesTensor.dispose();
          countTensor.dispose();
          
        });
        
      }
    </script>
  </body>
</html>
image

@gaikwadrahul8
Copy link
Contributor

Hi, @wangjia184

I apologize for the delayed response and I tried to replicate the same behaviour from my end and I'm also getting the same result which you mentioned in your above comment so we'll have to dig more into this, thank you for bringing this issue to our attention

For reference I have added output log below :

image

Thank you for your understanding and patience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants