Do a backward graph walk and return all the visited ops. Args: seed_ops: an iterable of operations from which the backward graph walk starts. If a list of tensors is given instead, the seed_ops are set to be the generators of those tensors. inclusive: if True the given seed_op
(seed_ops,
inclusive=True,
within_ops=None,
within_ops_fn=None,
stop_at_ts=(),
control_inputs=False,
only_differentiable=False)
| 235 | |
| 236 | |
| 237 | def get_backward_walk_ops(seed_ops, |
| 238 | inclusive=True, |
| 239 | within_ops=None, |
| 240 | within_ops_fn=None, |
| 241 | stop_at_ts=(), |
| 242 | control_inputs=False, |
| 243 | only_differentiable=False): |
| 244 | """Do a backward graph walk and return all the visited ops. |
| 245 | |
| 246 | Args: |
| 247 | seed_ops: an iterable of operations from which the backward graph |
| 248 | walk starts. If a list of tensors is given instead, the seed_ops are set |
| 249 | to be the generators of those tensors. |
| 250 | inclusive: if True the given seed_ops are also part of the resulting set. |
| 251 | within_ops: an iterable of `tf.Operation` within which the search is |
| 252 | restricted. If `within_ops` is `None`, the search is performed within |
| 253 | the whole graph. |
| 254 | within_ops_fn: if provided, a function on ops that should return True iff |
| 255 | the op is within the graph traversal. This can be used along within_ops, |
| 256 | in which case an op is within if it is also in within_ops. |
| 257 | stop_at_ts: an iterable of tensors at which the graph walk stops. |
| 258 | control_inputs: if True, control inputs will be used while moving backward. |
| 259 | only_differentiable: if True, only traverse ops which are differentiable. |
| 260 | This includes natively differentiable ops, or ops with custom gradients. |
| 261 | Returns: |
| 262 | A Python set of all the `tf.Operation` behind `seed_ops`. |
| 263 | Raises: |
| 264 | TypeError: if `seed_ops` or `within_ops` cannot be converted to a list of |
| 265 | `tf.Operation`. |
| 266 | """ |
| 267 | control_inputs = control_inputs and (not only_differentiable) |
| 268 | |
| 269 | if not is_iterable(seed_ops): |
| 270 | seed_ops = [seed_ops] |
| 271 | if not seed_ops: |
| 272 | return [] |
| 273 | if isinstance(seed_ops[0], ops.Tensor): |
| 274 | ts = make_list_of_t(seed_ops, allow_graph=False) |
| 275 | seed_ops = get_generating_ops(ts) |
| 276 | else: |
| 277 | seed_ops = make_list_of_op(seed_ops, allow_graph=False) |
| 278 | |
| 279 | stop_at_ts = object_identity.ObjectIdentitySet(make_list_of_t(stop_at_ts)) |
| 280 | seed_ops = object_identity.ObjectIdentitySet(make_list_of_op(seed_ops)) |
| 281 | if within_ops: |
| 282 | within_ops = make_list_of_op(within_ops, allow_graph=False) |
| 283 | within_ops = object_identity.ObjectIdentitySet(within_ops) |
| 284 | seed_ops &= within_ops |
| 285 | |
| 286 | def is_within(op): |
| 287 | return (within_ops is None or op in within_ops) and ( |
| 288 | within_ops_fn is None or within_ops_fn(op)) |
| 289 | |
| 290 | result = list(seed_ops) |
| 291 | wave = set(seed_ops) |
| 292 | while wave: |
| 293 | new_wave = set() |
| 294 | for op in wave: |
nothing calls this directly
no test coverage detected