| @@ -52,17 +52,24 @@ namespace Tensorflow.Clustering | |||||
| _num_data = math_ops.add_n(_inputs.Select(i => array_ops.shape(i)[0]).ToArray()); | _num_data = math_ops.add_n(_inputs.Select(i => array_ops.shape(i)[0]).ToArray()); | ||||
| } | } | ||||
| private Operation[] _initialize() | |||||
| private Tensor[] _initialize() | |||||
| { | { | ||||
| with(ops.control_dependencies(new Operation[] | |||||
| return with(ops.control_dependencies(new Operation[] | |||||
| { | { | ||||
| check_ops.assert_positive(_num_remaining) | check_ops.assert_positive(_num_remaining) | ||||
| }), delegate | }), delegate | ||||
| { | { | ||||
| // var num_now_remaining = _add_new_centers(); | |||||
| var num_now_remaining = _add_new_centers(); | |||||
| return control_flow_ops.cond(math_ops.equal(num_now_remaining, 0), | |||||
| () => | |||||
| { | |||||
| return new Tensor[] { state_ops.assign(_cluster_centers_initialized, true) }; | |||||
| }, | |||||
| () => | |||||
| { | |||||
| return new Tensor[] { control_flow_ops.no_op().output[0] }; | |||||
| }); | |||||
| }); | }); | ||||
| throw new NotImplementedException("_InitializeClustersOpFactory _initialize"); | |||||
| } | } | ||||
| public Tensor[] op() | public Tensor[] op() | ||||
| @@ -71,14 +78,49 @@ namespace Tensorflow.Clustering | |||||
| () => | () => | ||||
| { | { | ||||
| var op = check_ops.assert_equal(_cluster_centers_initialized, true); | var op = check_ops.assert_equal(_cluster_centers_initialized, true); | ||||
| return new Operation[] { op }; | |||||
| return new Tensor[] { op.output[0] }; | |||||
| }, | }, | ||||
| _initialize); | _initialize); | ||||
| } | } | ||||
| /*private int _add_new_centers() | |||||
| private Tensor _add_new_centers() | |||||
| { | { | ||||
| // Adds some centers and returns the number of centers remaining. | |||||
| var new_centers = _choose_initial_centers(); | var new_centers = _choose_initial_centers(); | ||||
| }*/ | |||||
| if (_distance_metric == KMeans.COSINE_DISTANCE) | |||||
| new_centers = nn_impl.l2_normalize(new_centers[0], axis: 1); | |||||
| // If cluster_centers is empty, it doesn't have the right shape for concat. | |||||
| var all_centers = control_flow_ops.cond(math_ops.equal(_num_selected, 0), | |||||
| () => new Tensor[] { new_centers }, | |||||
| () => new Tensor[] { gen_array_ops.concat(new Tensor[] { _cluster_centers, new_centers }, 0) }); | |||||
| var a = state_ops.assign(_cluster_centers, all_centers, validate_shape: false); | |||||
| return _num_clusters - array_ops.shape(a)[0]; | |||||
| } | |||||
| private Tensor _choose_initial_centers() | |||||
| { | |||||
| return _greedy_batch_sampler()[0]; | |||||
| } | |||||
| private Tensor[] _greedy_batch_sampler() | |||||
| { | |||||
| return control_flow_ops.cond(_num_data <= _num_remaining, | |||||
| () => | |||||
| { | |||||
| return new Tensor[] { gen_array_ops.concat(_inputs, 0) }; | |||||
| }, | |||||
| () => | |||||
| { | |||||
| return new Tensor[] { _random() }; | |||||
| }); | |||||
| } | |||||
| private Tensor _random() | |||||
| { | |||||
| throw new NotImplementedException(""); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -75,6 +75,8 @@ namespace Tensorflow.Operations | |||||
| { | { | ||||
| case Tensor[] results: | case Tensor[] results: | ||||
| return (original_result, results); | return (original_result, results); | ||||
| case Operation[] results: | |||||
| return (original_result, new Tensor[] { _BuildCondTensor (results) }); | |||||
| case float[] fv: | case float[] fv: | ||||
| var result = ops.convert_to_tensor(fv[0]); | var result = ops.convert_to_tensor(fv[0]); | ||||
| return (original_result, new Tensor[] { result }); | return (original_result, new Tensor[] { result }); | ||||
| @@ -82,5 +84,11 @@ namespace Tensorflow.Operations | |||||
| return (original_result, new Tensor[0]); | return (original_result, new Tensor[0]); | ||||
| } | } | ||||
| } | } | ||||
| private Tensor _BuildCondTensor(Operation[] v) | |||||
| { | |||||
| // Use pivot as the proxy for this op. | |||||
| return control_flow_ops.with_dependencies(v, _pivot); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -64,6 +64,14 @@ namespace Tensorflow | |||||
| }); | }); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Does nothing. Only useful as a placeholder for control edges. | |||||
| /// </summary> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| public static Operation no_op(string name = null) | |||||
| => gen_control_flow_ops.no_op(name: name); | |||||
| private static Operation _GroupControlDeps(string dev, Operation[] deps, string name = null) | private static Operation _GroupControlDeps(string dev, Operation[] deps, string name = null) | ||||
| { | { | ||||
| return with(ops.control_dependencies(deps), ctl => | return with(ops.control_dependencies(deps), ctl => | ||||
| @@ -12,6 +12,13 @@ namespace Tensorflow | |||||
| public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | ||||
| public static Execute _execute = new Execute(); | public static Execute _execute = new Execute(); | ||||
| public static Tensor concat(Tensor[] values, int axis, string name = null) | |||||
| { | |||||
| var _op = _op_def_lib._apply_op_helper("ConcatV2", name: name, args: new { values, axis }); | |||||
| return _op.outputs[0]; | |||||
| } | |||||
| public static Tensor expand_dims(Tensor input, int axis, string name = null) | public static Tensor expand_dims(Tensor input, int axis, string name = null) | ||||
| { | { | ||||
| var _op = _op_def_lib._apply_op_helper("ExpandDims", name: name, args: new { input, dim = axis }); | var _op = _op_def_lib._apply_op_helper("ExpandDims", name: name, args: new { input, dim = axis }); | ||||
| @@ -428,5 +428,18 @@ namespace Tensorflow | |||||
| return _op.outputs[0]; | return _op.outputs[0]; | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Computes reciprocal of square root of x element-wise. | |||||
| /// </summary> | |||||
| /// <param name="x"></param> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| public static Tensor rsqrt(Tensor x, string name = null) | |||||
| { | |||||
| var _op = _op_def_lib._apply_op_helper("Rsqrt", name, new { x }); | |||||
| return _op.outputs[0]; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -63,6 +63,13 @@ namespace Tensorflow | |||||
| return x; | return x; | ||||
| }); | }); | ||||
| } | } | ||||
| public static Tensor equal<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
| => gen_math_ops.equal(x, y, name: name); | |||||
| public static Tensor multiply(Tensor x, Tensor y, string name = null) | |||||
| => gen_math_ops.mul(x, y, name: name); | |||||
| /// <summary> | /// <summary> | ||||
| /// Computes the mean of elements across dimensions of a tensor. | /// Computes the mean of elements across dimensions of a tensor. | ||||
| /// Reduces `input_tensor` along the dimensions given in `axis`. | /// Reduces `input_tensor` along the dimensions given in `axis`. | ||||
| @@ -327,7 +334,15 @@ namespace Tensorflow | |||||
| return range(0, rank, 1); | return range(0, rank, 1); | ||||
| } | } | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Computes reciprocal of square root of x element-wise. | |||||
| /// </summary> | |||||
| /// <param name="x"></param> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| public static Tensor rsqrt(Tensor x, string name = null) | |||||
| => gen_math_ops.rsqrt(x, name: name); | |||||
| public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range" ) | public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range" ) | ||||
| { | { | ||||
| @@ -373,6 +388,9 @@ namespace Tensorflow | |||||
| }); | }); | ||||
| } | } | ||||
| public static Tensor maximum<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
| => gen_math_ops.maximum(x, y, name: name); | |||||
| public static Tensor matmul(Tensor a, Tensor b, | public static Tensor matmul(Tensor a, Tensor b, | ||||
| bool transpose_a = false, bool transpose_b = false, | bool transpose_a = false, bool transpose_b = false, | ||||
| bool adjoint_a = false, bool adjoint_b = false, | bool adjoint_a = false, bool adjoint_b = false, | ||||
| @@ -7,6 +7,28 @@ namespace Tensorflow | |||||
| { | { | ||||
| public class nn_impl : Python | public class nn_impl : Python | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Normalizes along dimension `axis` using an L2 norm. | |||||
| /// </summary> | |||||
| /// <param name="x"></param> | |||||
| /// <param name="axis"></param> | |||||
| /// <param name="epsilon"></param> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| public static Tensor l2_normalize(Tensor x, | |||||
| int axis = 0, | |||||
| float epsilon = 1e-12f, | |||||
| string name = null) | |||||
| { | |||||
| return with(ops.name_scope(name, "", new { x }), scope => | |||||
| { | |||||
| x = ops.convert_to_tensor(x, name: "x"); | |||||
| var square_sum = math_ops.reduce_sum(math_ops.square(x), axis, keepdims: true); | |||||
| var x_inv_norm = math_ops.rsqrt(math_ops.maximum(square_sum, epsilon)); | |||||
| return math_ops.multiply(x, x_inv_norm, name: name); | |||||
| }); | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Calculate the mean and variance of `x` | /// Calculate the mean and variance of `x` | ||||
| /// </summary> | /// </summary> | ||||
| @@ -28,9 +28,11 @@ namespace Tensorflow | |||||
| public static Tensor operator %(Tensor x, Tensor y) => BinaryOpWrapper("mod", x, y); | public static Tensor operator %(Tensor x, Tensor y) => BinaryOpWrapper("mod", x, y); | ||||
| public static Tensor operator >(Tensor x, int y) => gen_math_ops.greater(x, y); | public static Tensor operator >(Tensor x, int y) => gen_math_ops.greater(x, y); | ||||
| public static Tensor operator >=(Tensor x, Tensor y) => gen_math_ops.greater_equal(x, y); | |||||
| public static Tensor operator >(Tensor x, float y) => gen_math_ops.greater(x, y); | public static Tensor operator >(Tensor x, float y) => gen_math_ops.greater(x, y); | ||||
| public static Tensor operator >(Tensor x, double y) => gen_math_ops.greater(x, y); | public static Tensor operator >(Tensor x, double y) => gen_math_ops.greater(x, y); | ||||
| public static Tensor operator <(Tensor x, int y) => gen_math_ops.less(x, y); | public static Tensor operator <(Tensor x, int y) => gen_math_ops.less(x, y); | ||||
| public static Tensor operator <=(Tensor x, Tensor y) => gen_math_ops.less_equal(x, y); | |||||
| public static Tensor operator <(Tensor x, float y) => gen_math_ops.less(x, y); | public static Tensor operator <(Tensor x, float y) => gen_math_ops.less(x, y); | ||||
| public static Tensor operator <(Tensor x, double y) => gen_math_ops.less(x, y); | public static Tensor operator <(Tensor x, double y) => gen_math_ops.less(x, y); | ||||
| @@ -134,5 +134,10 @@ namespace Tensorflow | |||||
| { | { | ||||
| return type == TF_DataType.TF_HALF || type == TF_DataType.TF_FLOAT || type == TF_DataType.TF_DOUBLE; | return type == TF_DataType.TF_HALF || type == TF_DataType.TF_FLOAT || type == TF_DataType.TF_DOUBLE; | ||||
| } | } | ||||
| public static bool is_ref_dtype(this TF_DataType type) | |||||
| { | |||||
| return (int)type > 100; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -47,12 +47,12 @@ namespace Tensorflow | |||||
| /// <param name="validate_shape"></param> | /// <param name="validate_shape"></param> | ||||
| /// <param name="use_locking"></param> | /// <param name="use_locking"></param> | ||||
| /// <param name="name"></param> | /// <param name="name"></param> | ||||
| public static Tensor assign(Tensor tensor, object value, | |||||
| public static Tensor assign(Tensor @ref, object value, | |||||
| bool validate_shape = true, | bool validate_shape = true, | ||||
| bool use_locking = true, | bool use_locking = true, | ||||
| string name = null) | string name = null) | ||||
| { | { | ||||
| var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref = tensor, value, validate_shape, use_locking }); | |||||
| var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref, value, validate_shape, use_locking }); | |||||
| var _result = _op.outputs; | var _result = _op.outputs; | ||||
| var _inputs_flat = _op.inputs; | var _inputs_flat = _op.inputs; | ||||
| @@ -19,12 +19,27 @@ namespace Tensorflow | |||||
| TF_DataType dtype, | TF_DataType dtype, | ||||
| string name = "Variable", | string name = "Variable", | ||||
| string container = "", | string container = "", | ||||
| string shared_name = "") => gen_state_ops.variable_v2(shape, | |||||
| dtype, | |||||
| name: name, | |||||
| container: container, | |||||
| string shared_name = "") => gen_state_ops.variable_v2(shape, | |||||
| dtype, | |||||
| name: name, | |||||
| container: container, | |||||
| shared_name: shared_name); | shared_name: shared_name); | ||||
| public static Tensor assign(Tensor @ref, object value, | |||||
| bool validate_shape = true, | |||||
| bool use_locking = true, | |||||
| string name = null) | |||||
| { | |||||
| if (@ref.dtype.is_ref_dtype()) | |||||
| return gen_state_ops.assign(@ref, | |||||
| value, | |||||
| validate_shape: validate_shape, | |||||
| use_locking: use_locking, | |||||
| name: name); | |||||
| else | |||||
| throw new NotImplementedException("state_ops.assign"); | |||||
| } | |||||
| public static Tensor assign_sub(RefVariable @ref, | public static Tensor assign_sub(RefVariable @ref, | ||||
| Tensor value, | Tensor value, | ||||
| bool use_locking = false, | bool use_locking = false, | ||||