Implementation of rewrite of parallel-for loops. This class takes a DAG or a set of DAGs representing the body of a parallel-for loop, and adds new operations to the graph that implements functionality equivalent to running that loop body for a specified number of iterations. This new set o
| 1053 | |
| 1054 | |
| 1055 | class PFor(object): |
| 1056 | """Implementation of rewrite of parallel-for loops. |
| 1057 | |
| 1058 | This class takes a DAG or a set of DAGs representing the body of a |
| 1059 | parallel-for loop, and adds new operations to the graph that implements |
| 1060 | functionality equivalent to running that loop body for a specified number of |
| 1061 | iterations. This new set of nodes may or may not use a tensorflow loop |
| 1062 | construct. |
| 1063 | |
| 1064 | The process of conversion does not delete or change any existing operations. |
| 1065 | It only adds operations that efficiently implement the equivalent |
| 1066 | functionality. We refer to the added ops as "converted ops". |
| 1067 | |
| 1068 | The conversion process uses a simple greedy heuristic. It walks the loop body |
| 1069 | and tries to express the functionality of running each node in a loop with a |
| 1070 | new set of nodes. When converting an op several cases are possible: |
| 1071 | - The op is not inside the loop body. Hence it can be used as is. |
| 1072 | - The op does not depend on the iteration number and is stateless. In this |
| 1073 | case, it can be used as is. |
| 1074 | - The op is not stateful, and depends on iteration number only through control |
| 1075 | dependencies. In this case, we can create a single op with same inputs and |
| 1076 | attributes, but with "converted" control dependencies. |
| 1077 | - The op is not stateful, and all its inputs are loop invariant. In this |
| 1078 | case, similar to above, we can create a single op with same inputs and |
| 1079 | attributes, but with "converted" control dependencies. |
| 1080 | - The op is stateful or at least one of the inputs is not loop invariant. In |
| 1081 | this case, we run the registered converter for that op to create a set of |
| 1082 | converted ops. All nodes in the set will have converted control dependencies |
| 1083 | corresponding to control dependencies of the original op. If the op returned |
| 1084 | multiple outputs, "converted outputs" could be produced by different ops in |
| 1085 | this set. |
| 1086 | """ |
| 1087 | |
| 1088 | def __init__(self, |
| 1089 | loop_var, |
| 1090 | loop_len, |
| 1091 | pfor_ops, |
| 1092 | all_indices=None, |
| 1093 | all_indices_partitioned=False, |
| 1094 | pfor_config=None): |
| 1095 | """Creates an object to rewrite a parallel-for loop. |
| 1096 | |
| 1097 | Args: |
| 1098 | loop_var: ops.Tensor output of a Placeholder operation. The value should |
| 1099 | be an int32 scalar representing the loop iteration number. |
| 1100 | loop_len: A scalar or scalar Tensor representing the number of iterations |
| 1101 | the loop is run for. |
| 1102 | pfor_ops: List of all ops inside the loop body. |
| 1103 | all_indices: If not None, an int32 vector with size `loop_len` |
| 1104 | representing the iteration ids that are still active. These values |
| 1105 | should be unique and sorted. However they may not be contiguous. This is |
| 1106 | typically the case when inside a control flow construct which has |
| 1107 | partitioned the indices of the iterations that are being converted. |
| 1108 | all_indices_partitioned: If True, this object is being constructed from a |
| 1109 | control flow construct where not all the pfor iterations are guaranteed |
| 1110 | to be active. |
| 1111 | pfor_config: PForConfig object used while constructing the loop body. |
| 1112 | """ |
no outgoing calls
no test coverage detected