@@ -56,7 +56,9 @@ namespace Tensorflow.Keras.Layers | |||
protected override void build(TensorShape input_shape) | |||
{ | |||
int channel_axis = data_format == "channels_first" ? 1 : -1; | |||
int input_dim = input_shape.Dimensions[input_shape.NDim - 1]; | |||
int input_dim = channel_axis < 0 ? | |||
input_shape.Dimensions[input_shape.NDim + channel_axis] : | |||
input_shape.Dimensions[channel_axis]; | |||
var kernel_shape = new int[] { kernel_size[0], kernel_size[1], input_dim, filters }; | |||
kernel = add_weight(name: "kernel", | |||
shape: kernel_shape, | |||
@@ -102,7 +104,7 @@ namespace Tensorflow.Keras.Layers | |||
} | |||
else | |||
{ | |||
outputs = nn_ops.bias_add(outputs, bias._AsTensor(), data_format: "NHWC"); | |||
outputs = nn_ops.bias_add(outputs, bias, data_format: "NHWC"); | |||
} | |||
} | |||
@@ -206,12 +206,14 @@ namespace Tensorflow.Keras.Layers | |||
_updates.AddRange(updates_op); | |||
} | |||
// Determine layer name (non-unique). | |||
protected virtual void _init_set_name(string name, bool zero_based = true) | |||
{ | |||
var base_name = name; | |||
_name = name; | |||
if (name == null) | |||
_name = base_layer_utils.unique_layer_name(generic_utils.to_snake_case(this.GetType().Name), zero_based: zero_based); | |||
else | |||
_name = name; | |||
(_name, base_name) = _make_unique_name(); | |||
_base_name = base_name; | |||
} | |||
protected virtual (string, string) _make_unique_name() | |||
@@ -67,13 +67,6 @@ namespace Tensorflow.Layers | |||
return outputs; | |||
} | |||
protected override void _init_set_name(string name, bool zero_based = true) | |||
{ | |||
// Determine layer name (non-unique). | |||
base._init_set_name(name, zero_based: zero_based); | |||
_base_name = this.name; | |||
} | |||
protected virtual void _add_elements_to_collection(Operation[] elements, string[] collection_list) | |||
{ | |||
foreach(var name in collection_list) | |||
@@ -0,0 +1,53 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace Tensorflow.Operations | |||
{ | |||
public class Conv2dParams | |||
{ | |||
public string Name { get; set; } | |||
/// <summary> | |||
/// An optional `string` from: `"NHWC", "NCHW"`. Defaults to `"NHWC"`. | |||
/// Specify the data format of the input and output data. With the | |||
/// default format "NHWC", the data is stored in the order of: | |||
/// [batch, height, width, channels]. | |||
/// </summary> | |||
public string DataFormat { get; set; } = "NHWC"; | |||
/// <summary> | |||
/// Must be one of the following types: `half`, `bfloat16`, `float32`, `float64`. | |||
/// A 4-D tensor. The dimension order is interpreted according to the value | |||
/// </summary> | |||
public Tensor Input { get; set; } | |||
/// <summary> | |||
/// A 4-D tensor of shape | |||
/// </summary> | |||
public Tensor Filter { get; set; } | |||
/// <summary> | |||
/// The stride of the sliding window for each | |||
/// dimension of `input`. The dimension order is determined by the value of | |||
/// `data_format`, see below for details. | |||
/// </summary> | |||
public int[] Strides { get; set; } | |||
/// <summary> | |||
/// A `string` from: `"SAME", "VALID", "EXPLICIT"`. | |||
/// </summary> | |||
public string Padding { get; set; } | |||
public int[] ExplicitPaddings { get; set; } = new int[0]; | |||
public bool UseCudnnOnGpu { get; set; } = true; | |||
public int[] Dilations { get; set; } = new [] { 1, 1, 1, 1 }; | |||
public Conv2dParams() | |||
{ | |||
} | |||
} | |||
} |
@@ -11,7 +11,7 @@ namespace Tensorflow.Operations | |||
public string name; | |||
public int[] strides; | |||
public string data_format; | |||
private Func<object, Tensor> conv_op; | |||
private Func<Conv2dParams, Tensor> conv_op; | |||
public _NonAtrousConvolution(TensorShape input_shape, | |||
TensorShape filter_shape, | |||
@@ -55,14 +55,14 @@ namespace Tensorflow.Operations | |||
public Tensor __call__(Tensor inp, RefVariable filter) | |||
{ | |||
return conv_op(new | |||
return conv_op(new Conv2dParams | |||
{ | |||
input = inp, | |||
filter, | |||
strides, | |||
padding, | |||
data_format, | |||
name | |||
Input = inp, | |||
Filter = filter, | |||
Strides = strides, | |||
Padding = padding, | |||
DataFormat = data_format, | |||
Name = name | |||
}); | |||
} | |||
} | |||
@@ -10,28 +10,36 @@ namespace Tensorflow.Operations | |||
{ | |||
public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | |||
public static Tensor conv2d(object parameters) | |||
/// <summary> | |||
/// Computes a 2-D convolution given 4-D `input` and `filter` tensors. | |||
/// | |||
/// Given an input tensor of shape `[batch, in_height, in_width, in_channels]` | |||
/// and a filter / kernel tensor of shape | |||
/// `[filter_height, filter_width, in_channels, out_channels]`, this op | |||
/// performs the following: | |||
/// | |||
/// 1. Flattens the filter to a 2-D matrix with shape | |||
/// `[filter_height * filter_width * in_channels, output_channels]`. | |||
/// 2. Extracts image patches from the input tensor to form a *virtual* | |||
/// tensor of shape `[batch, out_height, out_width, | |||
/// filter_height * filter_width * in_channels]`. | |||
/// 3. For each patch, right-multiplies the filter matrix and the image patch | |||
/// vector. | |||
/// </summary> | |||
/// <param name="parameters"></param> | |||
/// <returns></returns> | |||
public static Tensor conv2d(Conv2dParams parameters) | |||
{ | |||
var args = Python.ConvertToDict(parameters); | |||
var input = args["input"]; | |||
var filter = args["filter"]; | |||
var strides = args["strides"]; | |||
var padding = args["padding"]; | |||
var name = args["name"]; | |||
var data_format = args.ContainsKey("data_format") ? args["data_format"] : "NHWC"; | |||
var use_cudnn_on_gpu = args.ContainsKey("use_cudnn_on_gpu") ? args["use_cudnn_on_gpu"] : true; | |||
var dilations = args.ContainsKey("dilations") ? args["dilations"] : new int[] { 1, 1, 1, 1 }; | |||
var _op = _op_def_lib._apply_op_helper("Conv2D", name: name?.ToString(), args: new | |||
var _op = _op_def_lib._apply_op_helper("Conv2D", name: parameters.Name, args: new | |||
{ | |||
input, | |||
filter, | |||
strides, | |||
padding, | |||
use_cudnn_on_gpu, | |||
data_format, | |||
dilations | |||
input = parameters.Input, | |||
filter = parameters.Filter, | |||
strides = parameters.Strides, | |||
padding = parameters.Padding, | |||
use_cudnn_on_gpu = parameters.UseCudnnOnGpu, | |||
explicit_paddings = parameters.ExplicitPaddings, | |||
data_format = parameters.DataFormat, | |||
dilations = parameters.Dilations | |||
}); | |||
return _op.outputs[0]; | |||
@@ -37,6 +37,7 @@ namespace Tensorflow | |||
{ | |||
return Python.with(ops.name_scope(name, "BiasAdd", new { value, bias }), scope => | |||
{ | |||
name = scope; | |||
value = ops.convert_to_tensor(value, name: "input"); | |||
var bias_tensor = ops.convert_to_tensor(bias, dtype: value.dtype, name: "bias"); | |||
return gen_nn_ops.bias_add(value, bias_tensor, data_format: data_format, name: name); | |||
@@ -188,7 +188,7 @@ namespace Tensorflow | |||
public Tensor _as_graph_element() => _variable; | |||
public Tensor _TensorConversionFunction(bool as_ref = false) | |||
public Tensor _TensorConversionFunction(TF_DataType dtype = TF_DataType.DtInvalid, string name = null, bool as_ref = false) | |||
{ | |||
if (as_ref) | |||
return _ref(); | |||
@@ -40,7 +40,7 @@ namespace Tensorflow | |||
VariableSynchronization synchronization = VariableSynchronization.Auto, | |||
VariableAggregation aggregation= VariableAggregation.None) | |||
{ | |||
string full_name = !string.IsNullOrEmpty(this._name) ? this._name + "/" + name : name; | |||
string full_name = !string.IsNullOrEmpty(this.name) ? this.name + "/" + name : name; | |||
return with(ops.name_scope(null), scope => | |||
{ | |||
if (dtype == TF_DataType.DtInvalid) | |||
@@ -473,7 +473,7 @@ namespace Tensorflow | |||
case Tensor[] tensors: | |||
return array_ops._autopacking_helper(tensors, dtype, name == null ? "packed" : name); | |||
case RefVariable varVal: | |||
return varVal._TensorConversionFunction(as_ref: as_ref); | |||
return varVal._TensorConversionFunction(dtype: dtype, name: name, as_ref: as_ref); | |||
case ResourceVariable varVal: | |||
return null; | |||
case object[] objects: | |||