Parallel map on the list of tensors unpacked from `elems` on dimension 0. This method works similar to tf.map_fn but is optimized to run much faster, possibly with a much larger memory footprint. The speedups are obtained by vectorization (see https://arxiv.org/pdf/1903.04243.pdf). The idea
(fn, elems)
| 307 | |
| 308 | @tf_export("vectorized_map") |
| 309 | def vectorized_map(fn, elems): |
| 310 | """Parallel map on the list of tensors unpacked from `elems` on dimension 0. |
| 311 | |
| 312 | |
| 313 | This method works similar to tf.map_fn but is optimized to run much faster, |
| 314 | possibly with a much larger memory footprint. The speedups are obtained by |
| 315 | vectorization (see https://arxiv.org/pdf/1903.04243.pdf). The idea behind |
| 316 | vectorization is to semantically launch all the invocations of `fn` in |
| 317 | parallel and fuse corresponding operations across all these invocations. This |
| 318 | fusion is done statically at graph generation time and the generated code is |
| 319 | often similar in performance to a manually fused version. |
| 320 | |
| 321 | Because `tf.vectorized_map` fully parallelizes the batch, this method will |
| 322 | generally be significantly faster than using `tf.map_fn`, especially in eager |
| 323 | mode. However this is an experimental feature and currently has a lot of |
| 324 | limitations: |
| 325 | - There should be no data dependency between the different semantic |
| 326 | invocations of `fn`, i.e. it should be safe to map the elements of the |
| 327 | inputs in any order. |
| 328 | - Stateful kernels may mostly not be supported since these often imply a |
| 329 | data dependency. We do support a limited set of such stateful kernels |
| 330 | though (like RandomFoo, Variable operations like reads, etc). |
| 331 | - `fn` has limited support for control flow operations. `tf.cond` in |
| 332 | particular is not supported. |
| 333 | - `fn` should return nested structure of Tensors or Operations. However |
| 334 | if an Operation is returned, it should have zero outputs. |
| 335 | - The shape and dtype of any intermediate or output tensors in the |
| 336 | computation of `fn` should not depend on the input to `fn`. |
| 337 | |
| 338 | Args: |
| 339 | fn: The callable to be performed. It accepts one argument, which will have |
| 340 | the same (possibly nested) structure as `elems`, and returns a possibly |
| 341 | nested structure of Tensors and Operations, which may be different than |
| 342 | the structure of `elems`. |
| 343 | elems: A tensor or (possibly nested) sequence of tensors, each of which will |
| 344 | be unpacked along their first dimension. The nested sequence of the |
| 345 | resulting slices will be mapped over by `fn`. |
| 346 | |
| 347 | Returns: |
| 348 | A tensor or (possibly nested) sequence of tensors. Each tensor packs the |
| 349 | results of applying fn to tensors unpacked from elems along the first |
| 350 | dimension, from first to last. |
| 351 | |
| 352 | Examples: |
| 353 | ```python |
| 354 | def outer_product(a): |
| 355 | return tf.tensordot(a, a, 0) |
| 356 | |
| 357 | batch_size = 100 |
| 358 | a = tf.ones((batch_size, 32, 32)) |
| 359 | c = tf.vectorized_map(outer_product, a) |
| 360 | assert c.shape == (batch_size, 32, 32, 32, 32) |
| 361 | ``` |
| 362 | |
| 363 | ```python |
| 364 | # Computing per-example gradients |
| 365 | |
| 366 | batch_size = 10 |