Generates gradient Do operator, given forward Do op and a list of gradient blobs corresponding to forward op's outputs Returns a gradient op and a list of blobs corresponding to input gradients
(op, g_output)
| 9 | |
| 10 | |
| 11 | def gen_do_gradient(op, g_output): |
| 12 | """ |
| 13 | Generates gradient Do operator, given forward Do op and a list |
| 14 | of gradient blobs corresponding to forward op's outputs |
| 15 | Returns a gradient op and a list of blobs corresponding to input gradients |
| 16 | """ |
| 17 | from caffe2.python.core import BlobReference |
| 18 | subnet, outer_to_inner_map, inner_to_outer_map, workspace_blob_name = \ |
| 19 | _do_op_sanity_check_and_process(op) |
| 20 | |
| 21 | assert len(g_output) == len(op.output), \ |
| 22 | "Different number of gradient blobs and Do op outputs" |
| 23 | |
| 24 | grad_ops, deduped_g_output = dedupe_g_output(op, g_output) |
| 25 | g_output = deduped_g_output |
| 26 | |
| 27 | # From the outer net point of view: |
| 28 | # Do is an operator that has some number of inputs and outputs; |
| 29 | # we have to generate a gradient operator that writes into |
| 30 | # corresponding input gradient blobs and has access to inputs, outputs |
| 31 | # and gradient output blobs |
| 32 | # From the inner net point of view: |
| 33 | # Do is an operator with a subnet and blob bindings, |
| 34 | # we need to forward Do's output blob gradients into inner workspace, |
| 35 | # use them to run backward pass generation and forward Do's input blob |
| 36 | # gradients back into outer workspace |
| 37 | |
| 38 | op_output = [str(o) for o in op.output] |
| 39 | op_output = op_output[:-1] # remove workspace pointer blob |
| 40 | op_input = [str(i) for i in op.input] |
| 41 | op_input = op_input[:-1] # remove workspace pointer blob |
| 42 | |
| 43 | ordered_inner_output_blob_names = [outer_to_inner_map[o] for o in op_output] |
| 44 | |
| 45 | backward_pass_initial_grad_map = {} |
| 46 | initial_grad_map = {} |
| 47 | for inner_output_name, outer_grad_output_name in \ |
| 48 | zip(ordered_inner_output_blob_names, g_output): |
| 49 | # link inner_output_name to corresponding inner_grad_output_name for |
| 50 | # backward pass generation; |
| 51 | if outer_grad_output_name: |
| 52 | inner_grad_output_name = inner_output_name + "/_DO_OPERATOR_INNER_GRAD_" |
| 53 | backward_pass_initial_grad_map[BlobReference(inner_output_name)] = \ |
| 54 | BlobReference(inner_grad_output_name) |
| 55 | initial_grad_map[inner_grad_output_name] = str(outer_grad_output_name) |
| 56 | assert len(initial_grad_map) > 0, "Empty initial gradient map for Do op" |
| 57 | |
| 58 | inner_grad_ops, inner_grad_names_map = _gen_subgradient_pass( |
| 59 | subnet, backward_pass_initial_grad_map) |
| 60 | |
| 61 | if len(inner_grad_ops) == 0: |
| 62 | return [], [] |
| 63 | |
| 64 | grad_copy_ops = [] |
| 65 | g_input = [] |
| 66 | new_op_outputs = [] |
| 67 | new_blob_bindings = {} |
| 68 | for outer_input_name in op_input: |
nothing calls this directly
no test coverage detected
searching dependent graphs…