Returns the next input from the iterator for all replicas.
(self, name=None)
| 277 | raise StopIteration |
| 278 | |
| 279 | def get_next(self, name=None): |
| 280 | """Returns the next input from the iterator for all replicas.""" |
| 281 | if not self._enable_get_next_as_optional: |
| 282 | replicas = [] |
| 283 | for i, worker in enumerate(self._input_workers.worker_devices): |
| 284 | if name is not None: |
| 285 | d = tf_device.DeviceSpec.from_string(worker) |
| 286 | new_name = "%s_%s_%d" % (name, d.job, d.task) |
| 287 | else: |
| 288 | new_name = None |
| 289 | with ops.device(worker): |
| 290 | # Make `replicas` a flat list of values across all replicas. |
| 291 | replicas.extend( |
| 292 | self._iterators[i].get_next_as_list_deprecated(new_name)) |
| 293 | return values.regroup(self._input_workers.device_map, replicas) |
| 294 | |
| 295 | out_of_range_replicas = [] |
| 296 | def out_of_range_fn(worker_index, device): |
| 297 | """This function will throw an OutOfRange error.""" |
| 298 | # As this will be only called when there is no data left, so calling |
| 299 | # get_next() will trigger an OutOfRange error. |
| 300 | data = self._iterators[worker_index].get_next(device) |
| 301 | out_of_range_replicas.append(data) |
| 302 | return data |
| 303 | |
| 304 | global_has_value, replicas = _get_next_as_optional(self, self._strategy) |
| 305 | results = [] |
| 306 | for i, worker in enumerate(self._input_workers.worker_devices): |
| 307 | with ops.device(worker): |
| 308 | devices = self._input_workers.compute_devices_for_worker(i) |
| 309 | for j, device in enumerate(devices): |
| 310 | with ops.device(device): |
| 311 | # pylint: disable=undefined-loop-variable |
| 312 | # pylint: disable=cell-var-from-loop |
| 313 | # It is fine for the lambda to capture variables from the loop as |
| 314 | # the lambda is executed in the loop as well. |
| 315 | result = control_flow_ops.cond(global_has_value, |
| 316 | lambda: replicas[i][j], |
| 317 | lambda: out_of_range_fn(i, device)) |
| 318 | # pylint: enable=cell-var-from-loop |
| 319 | # pylint: enable=undefined-loop-variable |
| 320 | results.append(result) |
| 321 | replicas = results |
| 322 | |
| 323 | # Some dimensions in `replicas` will become unknown after we conditionally |
| 324 | # return the real tensors or the dummy tensors. We fix the input shapes by |
| 325 | # using the shapes from `out_of_range_replicas` because it is calling |
| 326 | # get_next() inside. |
| 327 | flattened_replicas = nest.flatten(replicas) |
| 328 | for i, replica_data in enumerate(nest.flatten(out_of_range_replicas)): |
| 329 | flattened_replicas[i].set_shape(replica_data.get_shape()) |
| 330 | replicas = nest.pack_sequence_as(replicas, flattened_replicas) |
| 331 | |
| 332 | return values.regroup(self._input_workers.device_map, replicas) |
| 333 | |
| 334 | # We need a private initializer method for re-initializing multidevice |
| 335 | # iterators when used with Keras training loops. If we don't reinitialize the |