| 695 | return self._run_internal_graph(inputs, training=training, mask=mask) |
| 696 | |
| 697 | def compute_output_shape(self, input_shape): |
| 698 | if not self._is_graph_network: |
| 699 | return super(Network, self).compute_output_shape(input_shape) |
| 700 | |
| 701 | # Convert any shapes in tuple format to TensorShapes. |
| 702 | input_shape = tf_utils.convert_shapes(input_shape, to_tuples=False) |
| 703 | |
| 704 | if len(nest.flatten(input_shape)) != len(nest.flatten(self._input_layers)): |
| 705 | raise ValueError('Invalid input_shape argument ' + str(input_shape) + |
| 706 | ': model has ' + str(len(self._input_layers)) + |
| 707 | ' tensor inputs.') |
| 708 | |
| 709 | cache_key = generic_utils.object_list_uid(input_shape) |
| 710 | if cache_key in self._output_shape_cache: |
| 711 | # Cache hit. Return shapes as TensorShapes. |
| 712 | return self._output_shape_cache[cache_key] |
| 713 | |
| 714 | layers_to_output_shapes = {} |
| 715 | for layer, shape in zip(self._input_layers, nest.flatten(input_shape)): |
| 716 | # It's an input layer: then `compute_output_shape` is identity, |
| 717 | # and there is only one node and one tensor.. |
| 718 | shape_key = layer.name + '_0_0' |
| 719 | layers_to_output_shapes[shape_key] = shape |
| 720 | |
| 721 | depth_keys = list(self._nodes_by_depth.keys()) |
| 722 | depth_keys.sort(reverse=True) |
| 723 | # Iterate over nodes, by depth level. |
| 724 | if len(depth_keys) > 1: |
| 725 | for depth in depth_keys: |
| 726 | nodes = self._nodes_by_depth[depth] |
| 727 | for node in nodes: |
| 728 | # This is always a single layer, never a list. |
| 729 | layer = node.outbound_layer |
| 730 | if layer in self._input_layers: |
| 731 | # We've already covered the input layers |
| 732 | # a few lines above. |
| 733 | continue |
| 734 | # Potentially redundant list, |
| 735 | # same size as node.input_tensors. |
| 736 | layer_input_shapes = [] |
| 737 | for inbound_layer, node_id, tensor_id, _ in node.iterate_inbound(): |
| 738 | input_layer_key = inbound_layer.name + '_%s_%s' % (node_id, |
| 739 | tensor_id) |
| 740 | layer_input_shapes.append(layers_to_output_shapes[input_layer_key]) |
| 741 | layer_input_shapes = nest.pack_sequence_as(node.inbound_layers, |
| 742 | layer_input_shapes) |
| 743 | # Layers expect shapes to be tuples for `compute_output_shape`. |
| 744 | layer_input_shapes = tf_utils.convert_shapes( |
| 745 | layer_input_shapes, to_tuples=True) |
| 746 | layer_output_shapes = layer.compute_output_shape(layer_input_shapes) |
| 747 | # Convert back to TensorShapes. |
| 748 | layer_output_shapes = tf_utils.convert_shapes( |
| 749 | layer_output_shapes, to_tuples=False) |
| 750 | |
| 751 | node_index = layer._inbound_nodes.index(node) # pylint: disable=protected-access |
| 752 | for j, shape in enumerate(nest.flatten(layer_output_shapes)): |
| 753 | shape_key = layer.name + '_%s_%s' % (node_index, j) |
| 754 | layers_to_output_shapes[shape_key] = shape |