@@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow | |||||
{ | |||||
public class TypeError : Exception | |||||
{ | |||||
public TypeError() : base() | |||||
{ | |||||
} | |||||
public TypeError(string message) : base(message) | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -3,6 +3,7 @@ using System.Collections.Generic; | |||||
using System.ComponentModel; | using System.ComponentModel; | ||||
using System.Dynamic; | using System.Dynamic; | ||||
using System.IO; | using System.IO; | ||||
using System.Linq; | |||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
using System.Text; | using System.Text; | ||||
using static Tensorflow.OpDef.Types; | using static Tensorflow.OpDef.Types; | ||||
@@ -41,6 +42,7 @@ namespace Tensorflow | |||||
var attrs = new Dictionary<string, object>(); | var attrs = new Dictionary<string, object>(); | ||||
var inputs = new List<Tensor>(); | var inputs = new List<Tensor>(); | ||||
var input_types = new List<TF_DataType>(); | var input_types = new List<TF_DataType>(); | ||||
var base_types = new List<TF_DataType>(); | |||||
Operation op = null; | Operation op = null; | ||||
Python.with<ops.name_scope>(new ops.name_scope(name), scope => | Python.with<ops.name_scope>(new ops.name_scope(name), scope => | ||||
@@ -49,34 +51,67 @@ namespace Tensorflow | |||||
foreach (var input_arg in op_def.InputArg) | foreach (var input_arg in op_def.InputArg) | ||||
{ | { | ||||
var input_name = input_arg.Name; | var input_name = input_arg.Name; | ||||
if (keywords[input_name] is double int_value) | |||||
var values = keywords[input_name]; | |||||
// Goals: | |||||
// * Convert values to Tensors if it contains constants. | |||||
// * Verify that values is a list if that matches the input_arg's | |||||
// type. | |||||
// * If the input_arg's type is determined by attrs, either set | |||||
// those attrs and validate those attr values are legal (if | |||||
// they have not yet been set) or validate the input matches | |||||
// the type indicated by the attrs (if they have already been | |||||
// inferred via an earlier input). | |||||
// * If the input_arg has an explicit type, make sure the input | |||||
// conforms. | |||||
if (_IsListParameter(input_arg)) | |||||
{ | { | ||||
keywords[input_name] = constant_op.constant(int_value, input_name); | |||||
} | |||||
DataType dtype = DataType.DtInvalid; | |||||
DataType default_dtype = DataType.DtInvalid; | |||||
if (keywords[input_name] is Tensor value) | |||||
{ | |||||
if (keywords.ContainsKey(input_name)) | |||||
if (!_IsListValue(values)) | |||||
throw new TypeError($"Expected list for '{input_name}' argument to '{op_type_name}' Op, not {values}."); | |||||
if(input_arg.Type != DataType.DtInvalid) | |||||
{ | { | ||||
inputs.Add(value); | |||||
dtype = input_arg.Type; | |||||
} | } | ||||
if (!String.IsNullOrEmpty(input_arg.TypeAttr)) | |||||
else if (!String.IsNullOrEmpty(input_arg.NumberAttr)) | |||||
{ | { | ||||
attrs[input_arg.TypeAttr] = value.dtype; | |||||
} | } | ||||
if (input_arg.IsRef) | |||||
{ | |||||
if(input_arg.IsRef && dtype != DataType.DtInvalid) | |||||
dtype = dtype.as_base_dtype(); | |||||
values = ops.internal_convert_n_to_tensor(values, name: input_arg.Name, dtype: dtype, preferred_dtype: default_dtype, as_ref: input_arg.IsRef); | |||||
inputs.AddRange(values as Tensor[]); | |||||
} | |||||
else | |||||
{ | |||||
if (!(values is Tensor)) | |||||
{ | |||||
keywords[input_name] = constant_op.constant(values, input_name); | |||||
} | } | ||||
else | |||||
if (keywords[input_name] is Tensor value) | |||||
{ | { | ||||
var base_type = value.dtype.as_base_dtype(); | |||||
if (keywords.ContainsKey(input_name)) | |||||
{ | |||||
inputs.Add(value); | |||||
} | |||||
if (!String.IsNullOrEmpty(input_arg.TypeAttr)) | |||||
{ | |||||
attrs[input_arg.TypeAttr] = value.dtype; | |||||
} | |||||
input_types.Add(base_type); | |||||
values = new Tensor[] { value }; | |||||
} | } | ||||
} | } | ||||
base_types.AddRange((values as Tensor[]).Select(x => x.dtype.as_base_dtype())); | |||||
input_types.AddRange(base_types); | |||||
} | } | ||||
// Process remaining attrs | // Process remaining attrs | ||||
@@ -152,6 +187,27 @@ namespace Tensorflow | |||||
return v.as_base_dtype().as_datatype_enum(); | return v.as_base_dtype().as_datatype_enum(); | ||||
} | } | ||||
private bool _IsListParameter(ArgDef arg) | |||||
{ | |||||
if (!String.IsNullOrEmpty(arg.NumberAttr)) | |||||
return true; | |||||
else if (!String.IsNullOrEmpty(arg.TypeListAttr)) | |||||
return true; | |||||
else | |||||
return false; | |||||
} | |||||
private bool _IsListValue(object v) | |||||
{ | |||||
switch (v) | |||||
{ | |||||
case Tensor[] val: | |||||
return true; | |||||
default: | |||||
return false; | |||||
} | |||||
} | |||||
private Dictionary<string, object> ConvertToDict(dynamic dyn) | private Dictionary<string, object> ConvertToDict(dynamic dyn) | ||||
{ | { | ||||
var dictionary = new Dictionary<string, object>(); | var dictionary = new Dictionary<string, object>(); | ||||
@@ -50,10 +50,10 @@ namespace Tensorflow | |||||
/// Creates a tensor filled with a scalar value. | /// Creates a tensor filled with a scalar value. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="dims">A `Tensor`.</param> | /// <param name="dims">A `Tensor`.</param> | ||||
/// <param name="value">A `Tensor`.</param> | |||||
/// <param name="value">A `Tensor`. 0-D (scalar). Value to fill the returned tensor.</param> | |||||
/// <param name="name">A name for the operation (optional).</param> | /// <param name="name">A name for the operation (optional).</param> | ||||
/// <returns>A `Tensor`. Has the same type as `value`.</returns> | /// <returns>A `Tensor`. Has the same type as `value`.</returns> | ||||
public static Tensor fill(Tensor dims, Tensor value, string name = "") | |||||
public static Tensor fill<T>(Tensor dims, T value, string name = "") | |||||
{ | { | ||||
var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value }); | var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value }); | ||||
@@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow | |||||
{ | |||||
public class gen_data_flow_ops | |||||
{ | |||||
public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | |||||
public static Tensor dynamic_stitch(Tensor[] indices, Tensor[] data, string name = "") | |||||
{ | |||||
var _attr_N = indices.Length; | |||||
var _op = _op_def_lib._apply_op_helper("DynamicStitch", name, new { indices, data }); | |||||
return _op.outputs[0]; | |||||
} | |||||
} | |||||
} |
@@ -20,8 +20,10 @@ namespace Tensorflow | |||||
var input_rank = array_ops.size(input_shape); | var input_rank = array_ops.size(input_shape); | ||||
axes = (axes + input_rank) % input_rank; | axes = (axes + input_rank) % input_rank; | ||||
var axes_shape = array_ops.shape(axes); | var axes_shape = array_ops.shape(axes); | ||||
var a1 = new Tensor[] { input_rank, axes }; | |||||
var a2 = new Tensor[] { input_shape, gen_array_ops.fill(axes_shape, 1) }; | |||||
return null; | |||||
return gen_data_flow_ops.dynamic_stitch(a1, a2); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -83,6 +83,12 @@ namespace Tensorflow | |||||
for (int i = 0; i < t1.Count; i++) | for (int i = 0; i < t1.Count; i++) | ||||
yield return (t1[i], t2[i]); | yield return (t1[i], t2[i]); | ||||
} | } | ||||
public static IEnumerable<(int, T)> enumerate<T>(IList<T> values) | |||||
{ | |||||
for (int i = 0; i < values.Count; i++) | |||||
yield return (i, values[i]); | |||||
} | |||||
} | } | ||||
public interface IPython : IDisposable | public interface IPython : IDisposable | ||||
@@ -46,6 +46,7 @@ namespace Tensorflow | |||||
public void Dispose() | public void Dispose() | ||||
{ | { | ||||
var g = get_default_graph(); | var g = get_default_graph(); | ||||
Console.WriteLine($"name_scope: {g._name_stack} -> {old_stack}"); | |||||
g._name_stack = old_stack; | g._name_stack = old_stack; | ||||
} | } | ||||
@@ -309,5 +309,33 @@ namespace Tensorflow | |||||
return (p1.GetValue(result, null) as Tensor, p2.GetValue(result, null) as Tensor);*/ | return (p1.GetValue(result, null) as Tensor, p2.GetValue(result, null) as Tensor);*/ | ||||
}; | }; | ||||
} | } | ||||
public static T[] internal_convert_n_to_tensor<T>(T[] values, DataType dtype = DataType.DtInvalid, | |||||
string name = "", DataType preferred_dtype = DataType.DtInvalid, | |||||
bool as_ref = false) | |||||
{ | |||||
var ret = new List<T>(); | |||||
foreach((int i, T value) in Python.enumerate(values)) | |||||
{ | |||||
string n = string.IsNullOrEmpty(name) ? "" : $"{name}_{i}"; | |||||
ret.Add(internal_convert_to_tensor(value, dtype: dtype, name: n, as_ref: as_ref, preferred_dtype: preferred_dtype)); | |||||
} | |||||
return ret.ToArray(); | |||||
} | |||||
public static T internal_convert_to_tensor<T>(T value, DataType dtype = DataType.DtInvalid, | |||||
string name = "", DataType preferred_dtype = DataType.DtInvalid, | |||||
bool as_ref = false) | |||||
{ | |||||
switch (typeof(T).Name) | |||||
{ | |||||
case "Tensor": | |||||
return value; | |||||
default: | |||||
throw new NotImplementedException("internal_convert_to_tensor"); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |