Add the added_variables as an inputs to the Save op. We change the inputs of the SaveV2 op to include the names of the added variables. We also add the variables as inputs to the save op.
| 183 | // We change the inputs of the SaveV2 op to include the names of the added |
| 184 | // variables. We also add the variables as inputs to the save op. |
| 185 | Status ConnectVariablesToSaveOp(Graph* graph, Node* save_op, |
| 186 | const std::vector<const Edge*>& in_edges, |
| 187 | const std::vector<Node*>& added_variables) { |
| 188 | Node* tensor_names_op = in_edges[1]->src(); |
| 189 | Node* shape_and_slices_op = in_edges[2]->src(); |
| 190 | |
| 191 | // Get the tensor_names and shape_and_slices tensors from the const op. |
| 192 | Tensor tensor_names; |
| 193 | Tensor shape_and_slices; |
| 194 | TF_RETURN_IF_ERROR( |
| 195 | GetNodeAttr(tensor_names_op->attrs(), "value", &tensor_names)); |
| 196 | TF_RETURN_IF_ERROR( |
| 197 | GetNodeAttr(shape_and_slices_op->attrs(), "value", &shape_and_slices)); |
| 198 | |
| 199 | int tn_size = tensor_names.NumElements(); |
| 200 | int var_size = added_variables.size(); |
| 201 | |
| 202 | // Create a new save_op that has inputs to all the new variables. |
| 203 | NodeBuilder save_op_builder = |
| 204 | NodeBuilder(save_op->name(), save_op->type_string()); |
| 205 | // The first three inputs are prefix, tensor_names, and shapes_and_slices. |
| 206 | for (int i = 0; i < 3; i++) { |
| 207 | save_op_builder = save_op_builder.Input(in_edges[i]->src()); |
| 208 | } |
| 209 | std::vector<NodeBuilder::NodeOut> var_nodeouts; |
| 210 | var_nodeouts.reserve(tn_size + var_size); |
| 211 | // The rest of the inputs need to be used the construct the tensor list arg. |
| 212 | for (int i = 3; i < in_edges.size(); i++) { |
| 213 | var_nodeouts.emplace_back(in_edges[i]->src()); |
| 214 | } |
| 215 | |
| 216 | // Add the new values to the tensors and the op input. |
| 217 | Tensor new_tensor_names(DT_STRING, TensorShape({tn_size + var_size})); |
| 218 | Tensor new_shape_and_slices(DT_STRING, TensorShape({tn_size + var_size})); |
| 219 | FillStringTensor(&new_tensor_names, tensor_names); |
| 220 | FillStringTensor(&new_shape_and_slices, shape_and_slices); |
| 221 | for (int i = 0; i < var_size; i++) { |
| 222 | Node* var = added_variables[i]; |
| 223 | new_tensor_names.flat<tstring>()(tn_size + i) = var->name(); |
| 224 | new_shape_and_slices.flat<tstring>()(tn_size + i) = ""; |
| 225 | var_nodeouts.emplace_back(var); |
| 226 | } |
| 227 | save_op_builder = save_op_builder.Input(var_nodeouts); |
| 228 | |
| 229 | // Update the attrs. |
| 230 | tensor_names_op->AddAttr("value", new_tensor_names); |
| 231 | shape_and_slices_op->AddAttr("value", new_shape_and_slices); |
| 232 | |
| 233 | // Remove the old save_op and add the new one. |
| 234 | Node* new_save_op; |
| 235 | TF_RETURN_IF_ERROR(save_op_builder.Finalize(graph, &new_save_op)); |
| 236 | // Add outputs to the new_save_op, all outputs are control edges. |
| 237 | for (const Edge* edge : save_op->out_edges()) { |
| 238 | graph->AddControlEdge(new_save_op, edge->dst()); |
| 239 | } |
| 240 | graph->RemoveNode(save_op); |
| 241 | |
| 242 | return Status::OK(); |
no test coverage detected