(m: GraphModule, fn: ActivationFunction)
| 43 | } |
| 44 | |
| 45 | def wrap_in_activation_function(m: GraphModule, fn: ActivationFunction) -> GraphModule: |
| 46 | # Get output node |
| 47 | output_node: Optional[Node] = None |
| 48 | for n in reversed(m.graph.nodes): |
| 49 | if n.op == "output": |
| 50 | output_node = n |
| 51 | break |
| 52 | assert output_node |
| 53 | |
| 54 | # Get the actual output (the "input" of the output node). This is |
| 55 | # the Node we want to wrap in a user-specified activation function |
| 56 | assert len(output_node.all_input_nodes) == 1 |
| 57 | wrap_node = output_node.all_input_nodes[0] |
| 58 | |
| 59 | # Wrap the actual output in a Proxy |
| 60 | wrap_proxy = Proxy(wrap_node) |
| 61 | |
| 62 | # Get the implementation of the specified activation function and |
| 63 | # symbolically trace it |
| 64 | fn_impl = activation_functions[fn] |
| 65 | fn_impl_traced = symbolic_trace(fn_impl) |
| 66 | |
| 67 | # Call the specified activation function using the Proxy wrapper for |
| 68 | # `output_op`. The result of this call is another Proxy, which we |
| 69 | # can hook into our existing Graph. |
| 70 | with traced.graph.inserting_after(wrap_node): |
| 71 | fn_impl_output_node = fn_impl_traced(wrap_proxy) |
| 72 | new_args = (fn_impl_output_node.node,) |
| 73 | output_node.args = new_args |
| 74 | |
| 75 | m.recompile() |
| 76 | |
| 77 | |
| 78 | # Example call |
no outgoing calls
no test coverage detected