Skip to content

Commit 616b62b

Browse files
Implemented Conv1D and unit tests.
1 parent 2a42bcd commit 616b62b

File tree

8 files changed

+362
-14
lines changed

8 files changed

+362
-14
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Tensorflow.Keras.ArgsDefinition
2+
{
3+
public class Conv1DArgs : ConvolutionalArgs
4+
{
5+
6+
}
7+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*****************************************************************************
2+
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
******************************************************************************/
16+
17+
namespace Tensorflow.Operations
18+
{
19+
public class Conv1dParams
20+
{
21+
public string Name { get; set; }
22+
23+
/// <summary>
24+
/// An optional `string` from: `"NHWC", "NCHW"`. Defaults to `"NHWC"`.
25+
/// Specify the data format of the input and output data. With the
26+
/// default format "NHWC", the data is stored in the order of:
27+
/// [batch, height, width, channels].
28+
/// </summary>
29+
public string DataFormat { get; set; } = "NHWC";
30+
31+
/// <summary>
32+
/// Must be one of the following types: `half`, `bfloat16`, `float32`, `float64`.
33+
/// A 4-D tensor. The dimension order is interpreted according to the value
34+
/// </summary>
35+
public Tensor Input { get; set; }
36+
37+
/// <summary>
38+
/// An integer vector representing the shape of `input`
39+
/// </summary>
40+
public Tensor InputSizes { get; set; }
41+
42+
/// <summary>
43+
/// A 4-D tensor of shape
44+
/// </summary>
45+
public IVariableV1 Filter { get; set; }
46+
47+
/// <summary>
48+
/// An integer vector representing the tensor shape of `filter`
49+
/// </summary>
50+
public Tensor FilterSizes { get; set; }
51+
52+
/// <summary>
53+
/// A `Tensor`. Must have the same type as `filter`.
54+
/// 4-D with shape `[batch, out_height, out_width, out_channels]`.
55+
/// </summary>
56+
public Tensor OutBackProp { get; set; }
57+
58+
/// <summary>
59+
/// The stride of the sliding window for each
60+
/// dimension of `input`. The dimension order is determined by the value of
61+
/// `data_format`, see below for details.
62+
/// </summary>
63+
public int[] Strides { get; set; }
64+
65+
/// <summary>
66+
/// A `string` from: `"SAME", "VALID", "EXPLICIT"`.
67+
/// </summary>
68+
public string Padding { get; set; }
69+
70+
public int[] ExplicitPaddings { get; set; } = new int[0];
71+
72+
public bool UseCudnnOnGpu { get; set; } = true;
73+
74+
public int[] Dilations { get; set; } = new int[] { 1, 1, 1 };
75+
76+
public Conv1dParams()
77+
{
78+
79+
}
80+
}
81+
}

src/TensorFlowNET.Core/Operations/NnOps/ConvolutionInternal.cs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,32 @@ public Tensor Apply(Tensors input, IVariableV1 filters)
4141
var filters_rank = filters.shape.rank;
4242
var inputs_rank = input.shape.rank;
4343
var num_spatial_dims = args.NumSpatialDims;
44-
if (num_spatial_dims == Unknown)
44+
if (args.Rank == 1)
45+
{
46+
// Special case: Conv1D
47+
num_spatial_dims = 1;
48+
}
49+
else if (num_spatial_dims == Unknown)
50+
{
4551
num_spatial_dims = filters_rank - 2;
52+
}
4653

4754
// Channel dimension.
4855
var num_batch_dims = inputs_rank - num_spatial_dims - 1;
4956
if (!new[] { 1, 2, 3 }.Contains(num_spatial_dims))
5057
throw new ValueError($"num_spatial_dims (input.shape.ndims - num_batch_dims - 1) must be one " +
5158
$"of 1, 2 or 3 but saw {num_spatial_dims}. num_batch_dims: {num_batch_dims}.");
5259

53-
var channel_index = num_batch_dims + num_spatial_dims;
54-
var dilations = _get_sequence(args.DilationRate, num_spatial_dims, channel_index);
55-
var strides = _get_sequence(args.Strides, num_spatial_dims, channel_index);
56-
5760
Tensor result = null;
5861
tf_with(ops.name_scope(name, default_name: null), scope =>
5962
{
6063
name = scope;
6164
if (num_spatial_dims == 2)
6265
{
66+
var channel_index = num_batch_dims + num_spatial_dims;
67+
var dilations = _get_sequence(args.DilationRate, num_spatial_dims, channel_index).ToArray();
68+
var strides = _get_sequence(args.Strides, num_spatial_dims, channel_index).ToArray();
69+
6370
result = gen_nn_ops.conv2d(new Conv2dParams
6471
{
6572
Input = input,
@@ -72,13 +79,37 @@ public Tensor Apply(Tensors input, IVariableV1 filters)
7279
});
7380
}
7481
else
75-
throw new NotImplementedException("");
82+
{
83+
var channel_first = data_format == "NCW";
84+
var spatial_start_dim = channel_first ? -2 : -3;
85+
86+
var channel_index = channel_first ? 1 : 2;
87+
var dilations = _get_sequence(args.DilationRate, 1, channel_index);
88+
var strides = _get_sequence(args.Strides, 1, channel_index);
89+
90+
strides.Insert(0, 1);
91+
dilations.Insert(0, 1);
92+
93+
var expanded = tf.expand_dims(input, spatial_start_dim);
94+
95+
result = gen_nn_ops.conv2d(new Conv2dParams
96+
{
97+
Input = expanded,
98+
Filter = filters,
99+
Strides = strides.ToArray(),
100+
Padding = padding,
101+
DataFormat = channel_first ? "NCHW" : "NHWC",
102+
Dilations = dilations.ToArray(),
103+
Name = name
104+
});
105+
result = tf.squeeze(result, squeeze_dims: spatial_start_dim);
106+
}
76107
});
77108

78109
return result;
79110
}
80111

81-
int[] _get_sequence(int[] value, int n, int channel_index)
112+
IList<int> _get_sequence(int[] value, int n, int channel_index)
82113
{
83114
var seq = new List<int>();
84115

@@ -95,7 +126,7 @@ int[] _get_sequence(int[] value, int n, int channel_index)
95126
seq.Add(1);
96127
}
97128

98-
return seq.ToArray();
129+
return seq;
99130
}
100131
}
101132
}

src/TensorFlowNET.Core/Operations/nn_ops.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ public class nn_ops
2727
public static ConvolutionInternal convolution_internal(string padding,
2828
int[] strides,
2929
int[] dilation_rate,
30+
int rank,
3031
string name = null,
3132
string data_format = null) => new ConvolutionInternal(new ConvolutionalArgs
3233
{
34+
Rank = rank,
3335
Padding = padding,
3436
Strides = strides,
3537
DilationRate = dilation_rate,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*****************************************************************************
2+
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
******************************************************************************/
16+
17+
using Tensorflow.Keras.ArgsDefinition;
18+
19+
namespace Tensorflow.Keras.Layers
20+
{
21+
public class Conv1D : Convolutional
22+
{
23+
public Conv1D(Conv1DArgs args) : base(args)
24+
{
25+
26+
}
27+
}
28+
}

src/TensorFlowNET.Keras/Layers/Convolution/Convolutional.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ protected override void build(Tensors inputs)
9393
_convolution_op = nn_ops.convolution_internal(tf_padding,
9494
strides,
9595
dilation_rate,
96+
rank,
9697
data_format: _tf_data_format,
9798
name: tf_op_name);
9899

src/TensorFlowNET.Keras/Layers/LayersApi.cs

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,113 @@ public BatchNormalization BatchNormalization(int axis = -1,
6767
Name = name
6868
});
6969

70+
/// <summary>
71+
/// 1D convolution layer (e.g. temporal convolution).
72+
/// This layer creates a convolution kernel that is convolved with the layer input over a single spatial(or temporal) dimension to produce a tensor of outputs.If use_bias is True, a bias vector is created and added to the outputs.Finally, if activation is not None, it is applied to the outputs as well.
73+
/// </summary>
74+
/// <param name="filters">Integer, the dimensionality of the output space (i.e. the number of output filters in the convolution)</param>
75+
/// <param name="kernel_size">An integer specifying the width of the 1D convolution window.</param>
76+
/// <param name="strides">An integer specifying the stride of the convolution window . Specifying any stride value != 1 is incompatible with specifying any dilation_rate value != 1.</param>
77+
/// <param name="padding">one of "valid" or "same" (case-insensitive). "valid" means no padding. "same" results in padding evenly to the left/right or up/down of the input such that output has the same height/width dimension as the input.</param>
78+
/// <param name="data_format">A string, one of channels_last (default) or channels_first. The ordering of the dimensions in the inputs. channels_last corresponds to inputs with shape (batch_size, height, width, channels) while channels_first corresponds to inputs with shape (batch_size, channels, height, width). It defaults to the image_data_format value found in your Keras config file at ~/.keras/keras.json. If you never set it, then it will be channels_last.</param>
79+
/// <param name="dilation_rate">An integer specifying the dilation rate to use for dilated convolution.Currently, specifying any dilation_rate value != 1 is incompatible with specifying any stride value != 1.</param>
80+
/// <param name="groups">A positive integer specifying the number of groups in which the input is split along the channel axis. Each group is convolved separately with filters / groups filters. The output is the concatenation of all the groups results along the channel axis. Input channels and filters must both be divisible by groups.</param>
81+
/// <param name="activation">Activation function to use. If you don't specify anything, no activation is applied (see keras.activations).</param>
82+
/// <param name="use_bias">Boolean, whether the layer uses a bias vector.</param>
83+
/// <param name="kernel_initializer">Initializer for the kernel weights matrix (see keras.initializers).</param>
84+
/// <param name="bias_initializer">Initializer for the bias vector (see keras.initializers).</param>
85+
/// <param name="kernel_regularizer">Regularizer function applied to the kernel weights matrix (see keras.regularizers).</param>
86+
/// <param name="bias_regularizer">Regularizer function applied to the bias vector (see keras.regularizers).</param>
87+
/// <param name="activity_regularizer">Regularizer function applied to the output of the layer (its "activation") (see keras.regularizers).</param>
88+
/// <returns>A tensor of rank 3 representing activation(conv1d(inputs, kernel) + bias).</returns>
89+
public Conv1D Conv1D(int filters,
90+
int? kernel_size = null,
91+
int? strides = null,
92+
string padding = "valid",
93+
string data_format = null,
94+
int? dilation_rate = null,
95+
int groups = 1,
96+
Activation activation = null,
97+
bool use_bias = true,
98+
IInitializer kernel_initializer = null,
99+
IInitializer bias_initializer = null,
100+
IRegularizer kernel_regularizer = null,
101+
IRegularizer bias_regularizer = null,
102+
IRegularizer activity_regularizer = null)
103+
{
104+
// Special case: Conv1D will be implemented as Conv2D with H=1, so we need to add a 1-sized dimension to the kernel.
105+
// Lower-level logic handles the stride and dilation_rate, but the kernel_size needs to be set properly here.
106+
107+
var kernel = (kernel_size == null) ? (1, 5) : (1, kernel_size.Value);
108+
return new Conv1D(new Conv1DArgs
109+
{
110+
Rank = 1,
111+
Filters = filters,
112+
KernelSize = kernel,
113+
Strides = strides == null ? 1 : strides,
114+
Padding = padding,
115+
DataFormat = data_format,
116+
DilationRate = dilation_rate == null ? 1 : dilation_rate,
117+
Groups = groups,
118+
UseBias = use_bias,
119+
KernelInitializer = kernel_initializer == null ? tf.glorot_uniform_initializer : kernel_initializer,
120+
BiasInitializer = bias_initializer == null ? tf.zeros_initializer : bias_initializer,
121+
KernelRegularizer = kernel_regularizer,
122+
BiasRegularizer = bias_regularizer,
123+
ActivityRegularizer = activity_regularizer,
124+
Activation = activation ?? keras.activations.Linear
125+
});
126+
}
127+
128+
/// <summary>
129+
/// 1D convolution layer (e.g. temporal convolution).
130+
/// This layer creates a convolution kernel that is convolved with the layer input over a single spatial(or temporal) dimension to produce a tensor of outputs.If use_bias is True, a bias vector is created and added to the outputs.Finally, if activation is not None, it is applied to the outputs as well.
131+
/// </summary>
132+
/// <param name="filters">Integer, the dimensionality of the output space (i.e. the number of output filters in the convolution)</param>
133+
/// <param name="kernel_size">An integer specifying the width of the 1D convolution window.</param>
134+
/// <param name="strides">An integer specifying the stride of the convolution window . Specifying any stride value != 1 is incompatible with specifying any dilation_rate value != 1.</param>
135+
/// <param name="padding">one of "valid" or "same" (case-insensitive). "valid" means no padding. "same" results in padding evenly to the left/right or up/down of the input such that output has the same height/width dimension as the input.</param>
136+
/// <param name="data_format">A string, one of channels_last (default) or channels_first. The ordering of the dimensions in the inputs. channels_last corresponds to inputs with shape (batch_size, height, width, channels) while channels_first corresponds to inputs with shape (batch_size, channels, height, width). It defaults to the image_data_format value found in your Keras config file at ~/.keras/keras.json. If you never set it, then it will be channels_last.</param>
137+
/// <param name="dilation_rate">An integer specifying the dilation rate to use for dilated convolution.Currently, specifying any dilation_rate value != 1 is incompatible with specifying any stride value != 1.</param>
138+
/// <param name="groups">A positive integer specifying the number of groups in which the input is split along the channel axis. Each group is convolved separately with filters / groups filters. The output is the concatenation of all the groups results along the channel axis. Input channels and filters must both be divisible by groups.</param>
139+
/// <param name="activation">Activation function to use. If you don't specify anything, no activation is applied (see keras.activations).</param>
140+
/// <param name="use_bias">Boolean, whether the layer uses a bias vector.</param>
141+
/// <param name="kernel_initializer">Initializer for the kernel weights matrix (see keras.initializers).</param>
142+
/// <param name="bias_initializer">Initializer for the bias vector (see keras.initializers).</param>
143+
/// <returns>A tensor of rank 3 representing activation(conv1d(inputs, kernel) + bias).</returns>
144+
public Conv1D Conv1D(int filters,
145+
int? kernel_size = null,
146+
int? strides = null,
147+
string padding = "valid",
148+
string data_format = null,
149+
int? dilation_rate = null,
150+
int groups = 1,
151+
string activation = null,
152+
bool use_bias = true,
153+
string kernel_initializer = "glorot_uniform",
154+
string bias_initializer = "zeros")
155+
{
156+
// Special case: Conv1D will be implemented as Conv2D with H=1, so we need to add a 1-sized dimension to the kernel.
157+
// Lower-level logic handles the stride and dilation_rate, but the kernel_size needs to be set properly here.
158+
159+
var kernel = (kernel_size == null) ? (1, 5) : (1, kernel_size.Value);
160+
return new Conv1D(new Conv1DArgs
161+
{
162+
Rank = 1,
163+
Filters = filters,
164+
KernelSize = kernel,
165+
Strides = strides == null ? 1 : strides,
166+
Padding = padding,
167+
DataFormat = data_format,
168+
DilationRate = dilation_rate == null ? 1 : dilation_rate,
169+
Groups = groups,
170+
UseBias = use_bias,
171+
Activation = GetActivationByName(activation),
172+
KernelInitializer = GetInitializerByName(kernel_initializer),
173+
BiasInitializer = GetInitializerByName(bias_initializer)
174+
});
175+
}
176+
70177
/// <summary>
71178
/// 2D convolution layer (e.g. spatial convolution over images).
72179
/// This layer creates a convolution kernel that is convolved with the layer input to produce a tensor of outputs.
@@ -105,7 +212,7 @@ public Conv2D Conv2D(int filters,
105212
{
106213
Rank = 2,
107214
Filters = filters,
108-
KernelSize = kernel_size,
215+
KernelSize = (kernel_size == null) ? (5, 5) : kernel_size,
109216
Strides = strides == null ? (1, 1) : strides,
110217
Padding = padding,
111218
DataFormat = data_format,
@@ -150,10 +257,7 @@ public Conv2D Conv2D(int filters,
150257
string activation = null,
151258
bool use_bias = true,
152259
string kernel_initializer = "glorot_uniform",
153-
string bias_initializer = "zeros",
154-
string kernel_regularizer = null,
155-
string bias_regularizer = null,
156-
string activity_regularizer = null)
260+
string bias_initializer = "zeros")
157261
=> new Conv2D(new Conv2DArgs
158262
{
159263
Rank = 2,
@@ -204,7 +308,7 @@ public Conv2DTranspose Conv2DTranspose(int filters,
204308
{
205309
Rank = 2,
206310
Filters = filters,
207-
KernelSize = kernel_size,
311+
KernelSize = (kernel_size == null) ? (5, 5) : kernel_size,
208312
Strides = strides == null ? (1, 1) : strides,
209313
Padding = output_padding,
210314
DataFormat = data_format,

0 commit comments

Comments
 (0)