|
14 | 14 |
|
15 | 15 | from collections.abc import Mapping |
16 | 16 | import pathlib |
| 17 | +import re |
17 | 18 | from typing import Any |
18 | 19 |
|
19 | 20 | import jax |
@@ -166,6 +167,114 @@ def add(x: jax.Array) -> jax.Array: |
166 | 167 | ('cpu', 'tpu'), |
167 | 168 | ) |
168 | 169 |
|
| 170 | + def test_prepare_with_polymorphic_shapes(self): |
| 171 | + def add(x: jax.Array) -> jax.Array: |
| 172 | + return x + 1.0 |
| 173 | + |
| 174 | + processor = jax_data_processor.JaxDataProcessor(add, name='add') |
| 175 | + processor.prepare( |
| 176 | + jax.ShapeDtypeStruct(('b', 3), jnp.float32), |
| 177 | + ) |
| 178 | + |
| 179 | + self.assertIsNotNone(processor.obm_function) |
| 180 | + self.assertIsNotNone(processor.input_signature) |
| 181 | + self.assertIsNotNone(processor.output_signature) |
| 182 | + |
| 183 | + def test_prepare_with_polymorphic_shapes_signatures(self): |
| 184 | + def add(x: jax.Array) -> jax.Array: |
| 185 | + return x + 1.0 |
| 186 | + |
| 187 | + processor = jax_data_processor.JaxDataProcessor(add, name='add') |
| 188 | + processor.prepare( |
| 189 | + jax.ShapeDtypeStruct(('b', 3), jnp.float32), |
| 190 | + ) |
| 191 | + |
| 192 | + self.assertEqual( |
| 193 | + processor.input_signature, jax.ShapeDtypeStruct(('b', 3), jnp.float32) |
| 194 | + ) |
| 195 | + |
| 196 | + # Note: The underlying OBM Function signature uses None for dynamic |
| 197 | + # dimensions, regardless of the symbolic string provided by the user. |
| 198 | + out_spec = processor.output_signature |
| 199 | + self.assertEqual(list(out_spec.shape), [None, 3]) # pytype: disable=attribute-error |
| 200 | + |
| 201 | + def test_prepare_with_polymorphic_shapes_none(self): |
| 202 | + def add(x: jax.Array) -> jax.Array: |
| 203 | + return x + 1.0 |
| 204 | + |
| 205 | + processor = jax_data_processor.JaxDataProcessor(add, name='add') |
| 206 | + processor.prepare( |
| 207 | + jax.ShapeDtypeStruct((None, 3), jnp.float32), |
| 208 | + ) |
| 209 | + |
| 210 | + self.assertEqual( |
| 211 | + processor.input_signature, jax.ShapeDtypeStruct((None, 3), jnp.float32) |
| 212 | + ) |
| 213 | + |
| 214 | + out_spec = processor.output_signature |
| 215 | + self.assertEqual(list(out_spec.shape), [None, 3]) # pytype: disable=attribute-error |
| 216 | + |
| 217 | + |
| 218 | +class JaxShapeSpecGeneratorTest(parameterized.TestCase): |
| 219 | + |
| 220 | + @parameterized.named_parameters( |
| 221 | + dict(testcase_name='empty_shape', shape=(), expected='()'), |
| 222 | + dict(testcase_name='one_dim_none', shape=(None,), expected='(b,)'), |
| 223 | + dict(testcase_name='one_dim_int', shape=(4,), expected='(4,)'), |
| 224 | + dict( |
| 225 | + testcase_name='multi_dim_first_none', |
| 226 | + shape=(None, 4), |
| 227 | + expected='(b, 4)', |
| 228 | + ), |
| 229 | + dict( |
| 230 | + testcase_name='multi_dim_second_none', |
| 231 | + shape=(4, None), |
| 232 | + expected='(4, d_0)', |
| 233 | + ), |
| 234 | + dict( |
| 235 | + testcase_name='multi_dim_both_none', |
| 236 | + shape=(None, None), |
| 237 | + expected='(b, d_0)', |
| 238 | + ), |
| 239 | + dict( |
| 240 | + testcase_name='multi_dim_all_none', |
| 241 | + shape=(None, None, None, 256), |
| 242 | + expected='(b, d_0, d_1, 256)', |
| 243 | + ), |
| 244 | + dict(testcase_name='string_dims', shape=('foo', 4), expected='(foo, 4)'), |
| 245 | + dict( |
| 246 | + testcase_name='string_and_none', |
| 247 | + shape=('foo', None), |
| 248 | + expected='(foo, d_0)', |
| 249 | + ), |
| 250 | + ) |
| 251 | + def test_jax_shape_spec_generator(self, expected, shape=None): |
| 252 | + spec = jax.ShapeDtypeStruct(shape, jnp.float32) |
| 253 | + generator = jax_data_processor._JaxShapeSpecGenerator() |
| 254 | + self.assertEqual(generator(spec), expected) |
| 255 | + |
| 256 | + def test_jax_shape_spec_generator_unsupported_type(self): |
| 257 | + spec = object() |
| 258 | + generator = jax_data_processor._JaxShapeSpecGenerator() |
| 259 | + with self.assertRaisesRegex( |
| 260 | + ValueError, f'Unsupported spec type: {re.escape(str(type(spec)))}' |
| 261 | + ): |
| 262 | + generator(spec) |
| 263 | + |
| 264 | + def test_jax_shape_spec_generator_multiple_calls(self): |
| 265 | + spec1 = jax.ShapeDtypeStruct((None, None), jnp.float32) |
| 266 | + spec2 = jax.ShapeDtypeStruct((None, None, 256), jnp.float32) |
| 267 | + generator = jax_data_processor._JaxShapeSpecGenerator() |
| 268 | + self.assertEqual(generator(spec1), '(b, d_0)') |
| 269 | + self.assertEqual(generator(spec2), '(b, d_1, 256)') |
| 270 | + |
| 271 | + def test_jax_shape_spec_generator_uniterable_shape(self): |
| 272 | + class UniterableShape: |
| 273 | + shape = None |
| 274 | + |
| 275 | + generator = jax_data_processor._JaxShapeSpecGenerator() |
| 276 | + self.assertEqual(generator(UniterableShape()), '...') |
| 277 | + |
169 | 278 |
|
170 | 279 | if __name__ == '__main__': |
171 | 280 | googletest.main() |
0 commit comments