/// <summary> /// Creates a TF_Operation. /// </summary> /// <param name="graph">a `Graph`.</param> /// <param name="node_def">`node_def_pb2.NodeDef` for the operation to create.</param> /// <param name="inputs"> /// A list of `Tensor`s (corresponding to scalar inputs) and lists of /// `Tensor`s (corresponding to sequence inputs, e.g. "int64 * N", /// "list(int64)"). The length of the list should be equal to the number of /// inputs specified by this operation's op def. /// </param> /// <param name="control_inputs">A list of `Operation`s to set as control dependencies.</param> /// <returns>A wrapped TF_Operation*.</returns> public static (IntPtr, OperationDescription) _create_c_op(Graph graph, NodeDef node_def, Tensor[] inputs, Operation[] control_inputs, OpDef op_def = null) { if (op_def == null) { op_def = graph.GetOpDef(node_def.Op); } var input_tensors = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); lock (Locks.ProcessWide) { var op_desc = graph.NewOperation(node_def.Op, node_def.Name); if (!string.IsNullOrEmpty(node_def.Device)) { c_api.TF_SetDevice(op_desc, node_def.Device); } // Add inputs foreach (var op_input in input_tensors) { if (op_input.IsList) { c_api.TF_AddInputList(op_desc, op_input.Select(x => x._as_tf_output()).ToArray(), op_input.Count()); } else if (op_input.Count() == 1) { c_api.TF_AddInput(op_desc, op_input[0]._as_tf_output()); } } var status = tf.Status; // Add control inputs foreach (var control_input in control_inputs) { c_api.TF_AddControlInput(op_desc, control_input); } // Add attrs foreach (var attr in node_def.Attr) { var bytes = attr.Value.ToByteArray(); //TODO: we can use attr.Value.WriteTo with a memory stream. var protoHandle = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, protoHandle, bytes.Length); uint len = (uint)bytes.Length; c_api.TF_SetAttrValueProto(op_desc, attr.Key, protoHandle, proto_len: len, status: status.Handle); status.Check(true); Marshal.FreeHGlobal(protoHandle); } var c_op = c_api.TF_FinishOperation(op_desc, status.Handle); status.Check(true); return(c_op, op_desc); } }
/// <summary> /// Creates an `Operation`. /// </summary> /// <param name="node_def">`node_def_pb2.NodeDef`. `NodeDef` for the `Operation`.</param> /// <param name="g">`Graph`. The parent graph.</param> /// <param name="inputs">list of `Tensor` objects. The inputs to this `Operation`.</param> /// <param name="output_types">list of `DType` objects.</param> /// <param name="control_inputs"> /// list of operations or tensors from which to have a /// control dependency. /// </param> /// <param name="input_types"> /// List of `DType` objects representing the /// types of the tensors accepted by the `Operation`. By default /// uses `[x.dtype.base_dtype for x in inputs]`. Operations that expect /// reference-typed inputs must specify these explicitly. /// </param> /// <param name="original_op"></param> /// <param name="op_def"></param> public Operation(NodeDef node_def, Graph g, Tensor[] inputs = null, TF_DataType[] output_types = null, ITensorOrOperation[] control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) { _graph = g; // Build the list of control inputs. var control_input_ops = new List <Operation>(); if (control_inputs != null) { foreach (var c in control_inputs) { switch (c) { case Operation c1: control_input_ops.Add(c1); break; default: throw new NotImplementedException($"Control input must be an Operation, a Tensor, or IndexedSlices: {c}"); } } } // Dict mapping op name to file and line information for op colocation // context managers. _control_flow_context = graph._get_control_flow_context(); // This will be set by self.inputs. if (op_def == null) { op_def = g.GetOpDef(node_def.Op); } var grouped_inputs = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); _handle = ops._create_c_op(g, node_def, grouped_inputs, control_input_ops.ToArray()); // Initialize self._outputs. output_types = new TF_DataType[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { output_types[i] = OutputType(i); } _outputs = new Tensor[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { _outputs[i] = new Tensor(this, i, OutputType(i)); } graph._add_op(this); if (_handle != IntPtr.Zero) { _control_flow_post_processing(); } }
/// <summary> /// Creates an `Operation`. /// </summary> /// <param name="node_def">`node_def_pb2.NodeDef`. `NodeDef` for the `Operation`.</param> /// <param name="g">`Graph`. The parent graph.</param> /// <param name="inputs">list of `Tensor` objects. The inputs to this `Operation`.</param> /// <param name="output_types">list of `DType` objects.</param> /// <param name="control_inputs"> /// list of operations or tensors from which to have a /// control dependency. /// </param> /// <param name="input_types"> /// List of `DType` objects representing the /// types of the tensors accepted by the `Operation`. By default /// uses `[x.dtype.base_dtype for x in inputs]`. Operations that expect /// reference-typed inputs must specify these explicitly. /// </param> /// <param name="original_op"></param> /// <param name="op_def"></param> public Operation(NodeDef node_def, Graph g, List <Tensor> inputs = null, TF_DataType[] output_types = null, Operation[] control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) { Graph = g; // Build the list of control inputs. var control_input_ops = new List <Operation>(); if (control_inputs != null) { foreach (var c in control_inputs) { switch (c) { case Operation c1: control_input_ops.Add(c1); break; default: throw new NotImplementedException($"Control input must be an Operation, a Tensor, or IndexedSlices: {c}"); } } } // This will be set by self.inputs. _id_value = Graph._next_id(); if (op_def == null) { op_def = g.GetOpDef(node_def.Op); } _handle = ops._create_c_op(g, node_def, inputs, control_input_ops.ToArray()); // Initialize self._outputs. output_types = new TF_DataType[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { output_types[i] = OutputType(i); } _outputs = new Tensor[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { _outputs[i] = new Tensor(this, i, OutputType(i)); } Graph._add_op(this); if (_handle != IntPtr.Zero) { _control_flow_post_processing(); } }
/// <summary> /// Creates a TF_Operation. /// </summary> /// <param name="graph">a `Graph`.</param> /// <param name="node_def">`node_def_pb2.NodeDef` for the operation to create.</param> /// <param name="inputs"> /// A list of `Tensor`s (corresponding to scalar inputs) and lists of /// `Tensor`s (corresponding to sequence inputs, e.g. "int64 * N", /// "list(int64)"). The length of the list should be equal to the number of /// inputs specified by this operation's op def. /// </param> /// <param name="control_inputs">A list of `Operation`s to set as control dependencies.</param> /// <returns>A wrapped TF_Operation*.</returns> public static (IntPtr, OperationDescription) _create_c_op(Graph graph, NodeDef node_def, Tensor[] inputs, Operation[] control_inputs, OpDef op_def = null) { if (op_def == null) { op_def = graph.GetOpDef(node_def.Op); } var input_tensors = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); var op_desc = graph.NewOperation(node_def.Op, node_def.Name); if (!string.IsNullOrEmpty(node_def.Device)) { c_api.TF_SetDevice(op_desc, node_def.Device); } // Add inputs foreach (var op_input in input_tensors) { if (op_input.IsList) { c_api.TF_AddInputList(op_desc, op_input.Select(x => x._as_tf_output()).ToArray(), op_input.Count()); } else if (op_input.Count() == 1) { c_api.TF_AddInput(op_desc, op_input[0]._as_tf_output()); } } var status = tf.Status; // Add control inputs foreach (var control_input in control_inputs) { c_api.TF_AddControlInput(op_desc, control_input); } // Add attrs foreach (var attr in node_def.Attr) { var bytes = attr.Value.ToByteArray(); c_api.TF_SetAttrValueProto(op_desc, attr.Key, bytes, proto_len: bytes.Length, status: status.Handle); status.Check(true); } var c_op = op_desc.FinishOperation(status); status.Check(true); return(c_op, op_desc); }
public Operation(NodeDef node_def, Graph g, List <Tensor> inputs = null, TF_DataType[] output_types = null, object control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) { Graph = g; _id_value = Graph._next_id(); if (op_def == null) { op_def = g.GetOpDef(node_def.Op); } _handle = ops._create_c_op(g, node_def, inputs); output_types = new TF_DataType[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { output_types[i] = OutputType(i); } Graph._add_op(this); }
public static OpDef _get_op_def(Graph graph, string type) { return(graph.GetOpDef(type)); }
/*public Operation(Graph g, string opType, string oper_name) * { * _graph = g; * * var _operDesc = c_api.TF_NewOperation(g, opType, oper_name); * c_api.TF_SetAttrType(_operDesc, "dtype", TF_DataType.TF_INT32); * lock (Locks.ProcessWide) * using (var status = new Status()) * { * _handle = c_api.TF_FinishOperation(_operDesc, status); * status.Check(true); * } * * // Dict mapping op name to file and line information for op colocation * // context managers. * _control_flow_context = graph._get_control_flow_context(); * }*/ /// <summary> /// Creates an `Operation`. /// </summary> /// <param name="node_def">`node_def_pb2.NodeDef`. `NodeDef` for the `Operation`.</param> /// <param name="g">`Graph`. The parent graph.</param> /// <param name="inputs">list of `Tensor` objects. The inputs to this `Operation`.</param> /// <param name="output_types">list of `DType` objects.</param> /// <param name="control_inputs"> /// list of operations or tensors from which to have a /// control dependency. /// </param> /// <param name="input_types"> /// List of `DType` objects representing the /// types of the tensors accepted by the `Operation`. By default /// uses `[x.dtype.base_dtype for x in inputs]`. Operations that expect /// reference-typed inputs must specify these explicitly. /// </param> /// <param name="original_op"></param> /// <param name="op_def"></param> public Operation(NodeDef node_def, Graph g, Tensor[] inputs = null, TF_DataType[] output_types = null, ITensorOrOperation[] control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) { _graph = g; // Build the list of control inputs. var control_input_ops = new List <Operation>(); if (control_inputs != null) { foreach (var c in control_inputs) { switch (c) { case Operation c1: control_input_ops.Add(c1); break; case Tensor tensor: control_input_ops.Add(tensor.op); break; // TODO: IndexedSlices don't yet exist, but once they do, this needs to be uncommented //case IndexedSlices islices: // control_input_ops.Add(islices.op); // break; default: throw new NotImplementedException($"Control input must be an Operation, a Tensor, or IndexedSlices: {c}"); } } } _id_value = _graph._next_id(); // Dict mapping op name to file and line information for op colocation // context managers. _control_flow_context = graph._get_control_flow_context(); // This will be set by self.inputs. if (op_def == null) { op_def = g.GetOpDef(node_def.Op); } (_handle, OpDesc) = ops._create_c_op(g, node_def, inputs, control_input_ops.ToArray()); _is_stateful = op_def.IsStateful; // Initialize self._outputs. output_types = new TF_DataType[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { output_types[i] = OutputType(i); } _outputs = new Tensor[NumOutputs]; for (int i = 0; i < NumOutputs; i++) { _outputs[i] = new Tensor(this, i, output_types[i]); } graph._add_op(this); if (_handle != IntPtr.Zero) { _control_flow_post_processing(); } }