This is an automated email from the ASF dual-hosted git repository.

jrmccluskey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new 2940f8fc6a0 Added Criteo TFT fill_in_missing helper (#39011)
2940f8fc6a0 is described below

commit 2940f8fc6a03d1c01bfe2f85e420c944bde71dc6
Author: Lalit Yadav <[email protected]>
AuthorDate: Mon Jul 6 09:23:49 2026 -0500

    Added Criteo TFT fill_in_missing helper (#39011)
    
    * Added Criteo TFT fill_in_missing helper
    
    * Fix Criteo sparse tensor shape tracing
    
    * Lint fixed
    
    * updated the helper to use the old code verbatim
---
 .../benchmarks/cloudml/criteo_tft/criteo.py        | 30 ++++---
 .../benchmarks/cloudml/criteo_tft/criteo_test.py   | 93 ++++++++++++++++++++++
 2 files changed, 110 insertions(+), 13 deletions(-)

diff --git 
a/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo.py 
b/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo.py
index d2a0b652ca6..3390bdf3f3a 100644
--- a/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo.py
+++ b/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo.py
@@ -38,6 +38,21 @@ def 
get_transformed_categorical_column_name(column_name_or_id):
   return column_name + '_id'
 
 
+def fill_in_missing(feature, default_value):
+  """Fills missing values in a rank 2 SparseTensor.
+
+  Args:
+    feature: A rank 2 SparseTensor with at most one value per row.
+    default_value: The value to fill in for missing entries.
+
+  Returns:
+    A rank 1 Tensor with missing entries filled in.
+  """
+  feature = tft.sparse_tensor_to_dense_with_shape(
+      feature, [None, 1], default_value=default_value)
+  return tf.squeeze(feature, axis=1)
+
+
 _INTEGER_COLUMN_NAMES = [
     'int-feature-{}'.format(column_idx) for column_idx in range(1, 14)
 ]
@@ -132,23 +147,12 @@ def make_preprocessing_fn(frequency_threshold):
     result = {'clicked': inputs['clicked']}
     for name in _INTEGER_COLUMN_NAMES:
       feature = inputs[name]
-      # TODO(https://github.com/apache/beam/issues/24902):
-      #  Replace this boilerplate with a helper function.
-      # This is a SparseTensor because it is optional. Here we fill in a
-      # default value when it is missing.
-      feature = tft.sparse_tensor_to_dense_with_shape(
-          feature, [None, 1], default_value=-1)
-      # Reshaping from a batch of vectors of size 1 to a batch of scalars and
-      # adding a bucketized version.
-      feature = tf.squeeze(feature, axis=1)
+      feature = fill_in_missing(feature, -1)
       result[name] = feature
       result[name + '_bucketized'] = tft.bucketize(feature, _NUM_BUCKETS)
     for name in _CATEGORICAL_COLUMN_NAMES:
       feature = inputs[name]
-      # Similar to for integer columns, but use '' as default.
-      feature = tft.sparse_tensor_to_dense_with_shape(
-          feature, [None, 1], default_value='')
-      feature = tf.squeeze(feature, axis=1)
+      feature = fill_in_missing(feature, '')
       result[get_transformed_categorical_column_name(
           name)] = tft.compute_and_apply_vocabulary(
               feature, frequency_threshold=frequency_threshold)
diff --git 
a/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo_test.py 
b/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo_test.py
new file mode 100644
index 00000000000..ce2dd2593d0
--- /dev/null
+++ 
b/sdks/python/apache_beam/testing/benchmarks/cloudml/criteo_tft/criteo_test.py
@@ -0,0 +1,93 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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 unittest
+
+try:
+  import tensorflow as tf
+
+  from apache_beam.testing.benchmarks.cloudml.criteo_tft import criteo
+except ImportError:
+  raise unittest.SkipTest('Dependencies are not installed')
+
+
+class CriteoTest(tf.test.TestCase):
+  def test_fill_in_missing_int_feature(self):
+    feature = tf.SparseTensor(
+        indices=[[0, 0], [2, 0]],
+        values=tf.constant([10, 30], dtype=tf.int64),
+        dense_shape=[3, 1])
+
+    result = criteo.fill_in_missing(feature, -1)
+
+    self.assertAllEqual(result, [10, -1, 30])
+    self.assertEqual(result.shape.rank, 1)
+
+  def test_fill_in_missing_int_feature_traces_with_dynamic_shape(self):
+    @tf.function(
+        input_signature=[
+            tf.SparseTensorSpec(shape=[None, None], dtype=tf.int64)
+        ])
+    def fill_in_missing(feature):
+      return criteo.fill_in_missing(feature, -1)
+
+    feature = tf.SparseTensor(
+        indices=[[0, 0], [2, 0]],
+        values=tf.constant([10, 30], dtype=tf.int64),
+        dense_shape=[3, 1])
+
+    result = fill_in_missing(feature)
+
+    self.assertAllEqual(result, [10, -1, 30])
+    self.assertEqual(result.shape.rank, 1)
+
+  def test_fill_in_missing_all_missing_int_feature(self):
+    feature = tf.SparseTensor(
+        indices=tf.zeros([0, 2], dtype=tf.int64),
+        values=tf.constant([], dtype=tf.int64),
+        dense_shape=[3, 0])
+
+    result = criteo.fill_in_missing(feature, -1)
+
+    self.assertAllEqual(result, [-1, -1, -1])
+    self.assertEqual(result.shape.rank, 1)
+
+  def test_fill_in_missing_string_feature(self):
+    feature = tf.SparseTensor(
+        indices=[[0, 0], [2, 0]],
+        values=tf.constant(['a', 'c'], dtype=tf.string),
+        dense_shape=[3, 1])
+
+    result = criteo.fill_in_missing(feature, '')
+
+    self.assertAllEqual(result, [b'a', b'', b'c'])
+    self.assertEqual(result.shape.rank, 1)
+
+  def test_fill_in_missing_all_missing_string_feature(self):
+    feature = tf.SparseTensor(
+        indices=tf.zeros([0, 2], dtype=tf.int64),
+        values=tf.constant([], dtype=tf.string),
+        dense_shape=[3, 0])
+
+    result = criteo.fill_in_missing(feature, '')
+
+    self.assertAllEqual(result, [b'', b'', b''])
+    self.assertEqual(result.shape.rank, 1)
+
+
+if __name__ == '__main__':
+  unittest.main()

Reply via email to