Skip to content

Commit a8345ee

Browse files
committed
feat/convolution: remove convolution axis
1 parent 8e3e662 commit a8345ee

File tree

4 files changed

+45
-70
lines changed

4 files changed

+45
-70
lines changed

benches/network_benches.rs

+10-20
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ mod cuda {
136136
num_output: 64,
137137
filter_shape: vec![11],
138138
padding: vec![2],
139-
stride: vec![4],
140-
axis: None
139+
stride: vec![4]
141140
};
142141
let mut conv1_cfg = LayerConfig::new("conv1", LayerType::Convolution(conv1_layer_cfg));
143142
conv1_cfg.add_input("data");
@@ -164,8 +163,7 @@ mod cuda {
164163
num_output: 192,
165164
filter_shape: vec![5],
166165
padding: vec![2],
167-
stride: vec![1],
168-
axis: None
166+
stride: vec![1]
169167
};
170168
let mut conv2_cfg = LayerConfig::new("conv2", LayerType::Convolution(conv2_layer_cfg));
171169
conv2_cfg.add_input("pool1_out");
@@ -192,8 +190,7 @@ mod cuda {
192190
num_output: 384,
193191
filter_shape: vec![3],
194192
padding: vec![1],
195-
stride: vec![1],
196-
axis: None
193+
stride: vec![1]
197194
};
198195
let mut conv3_cfg = LayerConfig::new("conv3", LayerType::Convolution(conv3_layer_cfg));
199196
conv3_cfg.add_input("pool2_out");
@@ -209,8 +206,7 @@ mod cuda {
209206
num_output: 256,
210207
filter_shape: vec![3],
211208
padding: vec![1],
212-
stride: vec![1],
213-
axis: None
209+
stride: vec![1]
214210
};
215211
let mut conv4_cfg = LayerConfig::new("conv4", LayerType::Convolution(conv4_layer_cfg));
216212
conv4_cfg.add_input("conv3_out");
@@ -226,8 +222,7 @@ mod cuda {
226222
num_output: 256,
227223
filter_shape: vec![3],
228224
padding: vec![1],
229-
stride: vec![1],
230-
axis: None
225+
stride: vec![1]
231226
};
232227
let mut conv5_cfg = LayerConfig::new("conv5", LayerType::Convolution(conv5_layer_cfg));
233228
conv5_cfg.add_input("conv4_out");
@@ -298,8 +293,7 @@ mod cuda {
298293
num_output: 32,
299294
filter_shape: vec![11],
300295
padding: vec![2],
301-
stride: vec![4],
302-
axis: None
296+
stride: vec![4]
303297
};
304298
let mut conv1_cfg = LayerConfig::new("conv1", LayerType::Convolution(conv1_layer_cfg));
305299
conv1_cfg.add_input("data");
@@ -326,8 +320,7 @@ mod cuda {
326320
num_output: 96,
327321
filter_shape: vec![5],
328322
padding: vec![2],
329-
stride: vec![1],
330-
axis: None
323+
stride: vec![1]
331324
};
332325
let mut conv2_cfg = LayerConfig::new("conv2", LayerType::Convolution(conv2_layer_cfg));
333326
conv2_cfg.add_input("pool1_out");
@@ -354,8 +347,7 @@ mod cuda {
354347
num_output: 142,
355348
filter_shape: vec![3],
356349
padding: vec![1],
357-
stride: vec![1],
358-
axis: None
350+
stride: vec![1]
359351
};
360352
let mut conv3_cfg = LayerConfig::new("conv3", LayerType::Convolution(conv3_layer_cfg));
361353
conv3_cfg.add_input("pool2_out");
@@ -371,8 +363,7 @@ mod cuda {
371363
num_output: 128,
372364
filter_shape: vec![3],
373365
padding: vec![1],
374-
stride: vec![1],
375-
axis: None
366+
stride: vec![1]
376367
};
377368
let mut conv4_cfg = LayerConfig::new("conv4", LayerType::Convolution(conv4_layer_cfg));
378369
conv4_cfg.add_input("conv3_out");
@@ -388,8 +379,7 @@ mod cuda {
388379
num_output: 128,
389380
filter_shape: vec![3],
390381
padding: vec![1],
391-
stride: vec![1],
392-
axis: None
382+
stride: vec![1]
393383
};
394384
let mut conv5_cfg = LayerConfig::new("conv5", LayerType::Convolution(conv5_layer_cfg));
395385
conv5_cfg.add_input("conv4_out");

examples/benchmarks.rs

+18-18
Original file line numberDiff line numberDiff line change
@@ -119,27 +119,27 @@ fn bench_alexnet() {
119119
let mut cfg = SequentialConfig::default();
120120
cfg.add_input("data", &vec![128, 3, 224, 224]);
121121

122-
let conv1_layer_cfg = ConvolutionConfig { num_output: 64, filter_shape: vec![11], padding: vec![2], stride: vec![4], axis: None };
122+
let conv1_layer_cfg = ConvolutionConfig { num_output: 64, filter_shape: vec![11], padding: vec![2], stride: vec![4] };
123123
cfg.add_layer(LayerConfig::new("conv1", conv1_layer_cfg));
124124
cfg.add_layer(LayerConfig::new("conv1/relu", LayerType::ReLU));
125125
let pool1_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![3], stride: vec![2], padding: vec![0] };
126126
cfg.add_layer(LayerConfig::new("pool1", pool1_layer_cfg));
127127

128-
let conv2_layer_cfg = ConvolutionConfig { num_output: 192, filter_shape: vec![5], padding: vec![2], stride: vec![1], axis: None };
128+
let conv2_layer_cfg = ConvolutionConfig { num_output: 192, filter_shape: vec![5], padding: vec![2], stride: vec![1] };
129129
cfg.add_layer(LayerConfig::new("conv2", conv2_layer_cfg));
130130
cfg.add_layer(LayerConfig::new("conv2/relu", LayerType::ReLU));
131131
let pool2_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![3], stride: vec![2], padding: vec![0] };
132132
cfg.add_layer(LayerConfig::new("pool2", pool2_layer_cfg));
133133

134-
let conv3_layer_cfg = ConvolutionConfig { num_output: 384, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
134+
let conv3_layer_cfg = ConvolutionConfig { num_output: 384, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
135135
cfg.add_layer(LayerConfig::new("conv3", conv3_layer_cfg));
136136
cfg.add_layer(LayerConfig::new("conv3/relu", LayerType::ReLU));
137137

138-
let conv4_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
138+
let conv4_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
139139
cfg.add_layer(LayerConfig::new("conv4", conv4_layer_cfg));
140140
cfg.add_layer(LayerConfig::new("conv4/relu", LayerType::ReLU));
141141

142-
let conv5_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
142+
let conv5_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
143143
cfg.add_layer(LayerConfig::new("conv5", conv5_layer_cfg));
144144
cfg.add_layer(LayerConfig::new("conv5/relu", LayerType::ReLU));
145145
let pool3_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![3], stride: vec![2], padding: vec![0] };
@@ -201,27 +201,27 @@ fn bench_overfeat() {
201201
let mut cfg = SequentialConfig::default();
202202
cfg.add_input("data", &vec![128, 3, 231, 231]);
203203

204-
let conv1_layer_cfg = ConvolutionConfig { num_output: 96, filter_shape: vec![11], padding: vec![0], stride: vec![4], axis: None };
204+
let conv1_layer_cfg = ConvolutionConfig { num_output: 96, filter_shape: vec![11], padding: vec![0], stride: vec![4] };
205205
cfg.add_layer(LayerConfig::new("conv1", conv1_layer_cfg));
206206
cfg.add_layer(LayerConfig::new("conv1/relu", LayerType::ReLU));
207207
let pool1_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
208208
cfg.add_layer(LayerConfig::new("pool1", pool1_layer_cfg));
209209

210-
let conv2_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![5], padding: vec![0], stride: vec![1], axis: None };
210+
let conv2_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![5], padding: vec![0], stride: vec![1] };
211211
cfg.add_layer(LayerConfig::new("conv2", conv2_layer_cfg));
212212
cfg.add_layer(LayerConfig::new("conv2/relu", LayerType::ReLU));
213213
let pool2_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
214214
cfg.add_layer(LayerConfig::new("pool2", pool2_layer_cfg));
215215

216-
let conv3_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
216+
let conv3_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
217217
cfg.add_layer(LayerConfig::new("conv3", conv3_layer_cfg));
218218
cfg.add_layer(LayerConfig::new("conv3/relu", LayerType::ReLU));
219219

220-
let conv4_layer_cfg = ConvolutionConfig { num_output: 1024, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
220+
let conv4_layer_cfg = ConvolutionConfig { num_output: 1024, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
221221
cfg.add_layer(LayerConfig::new("conv4", conv4_layer_cfg));
222222
cfg.add_layer(LayerConfig::new("conv4/relu", LayerType::ReLU));
223223

224-
let conv5_layer_cfg = ConvolutionConfig { num_output: 1024, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
224+
let conv5_layer_cfg = ConvolutionConfig { num_output: 1024, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
225225
cfg.add_layer(LayerConfig::new("conv5", conv5_layer_cfg));
226226
cfg.add_layer(LayerConfig::new("conv5/relu", LayerType::ReLU));
227227
let pool5_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
@@ -283,43 +283,43 @@ fn bench_vgg_a() {
283283
let mut cfg = SequentialConfig::default();
284284
cfg.add_input("data", &vec![64, 3, 224, 224]);
285285

286-
let conv1_layer_cfg = ConvolutionConfig { num_output: 64, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
286+
let conv1_layer_cfg = ConvolutionConfig { num_output: 64, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
287287
cfg.add_layer(LayerConfig::new("conv1", conv1_layer_cfg));
288288
cfg.add_layer(LayerConfig::new("conv1/relu", LayerType::ReLU));
289289
let pool1_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
290290
cfg.add_layer(LayerConfig::new("pool1", pool1_layer_cfg));
291291

292-
let conv2_layer_cfg = ConvolutionConfig { num_output: 128, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
292+
let conv2_layer_cfg = ConvolutionConfig { num_output: 128, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
293293
cfg.add_layer(LayerConfig::new("conv2", conv2_layer_cfg));
294294
cfg.add_layer(LayerConfig::new("conv2/relu", LayerType::ReLU));
295295
let pool2_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
296296
cfg.add_layer(LayerConfig::new("pool2", pool2_layer_cfg));
297297

298-
let conv3_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
298+
let conv3_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
299299
cfg.add_layer(LayerConfig::new("conv3", conv3_layer_cfg));
300300
cfg.add_layer(LayerConfig::new("conv3/relu", LayerType::ReLU));
301301

302-
let conv4_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
302+
let conv4_layer_cfg = ConvolutionConfig { num_output: 256, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
303303
cfg.add_layer(LayerConfig::new("conv4", conv4_layer_cfg));
304304
cfg.add_layer(LayerConfig::new("conv4/relu", LayerType::ReLU));
305305
let pool3_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
306306
cfg.add_layer(LayerConfig::new("pool3", pool3_layer_cfg));
307307

308-
let conv5_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
308+
let conv5_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
309309
cfg.add_layer(LayerConfig::new("conv5", conv5_layer_cfg));
310310
cfg.add_layer(LayerConfig::new("conv5/relu", LayerType::ReLU));
311311

312-
let conv6_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
312+
let conv6_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
313313
cfg.add_layer(LayerConfig::new("conv6", conv6_layer_cfg));
314314
cfg.add_layer(LayerConfig::new("conv6/relu", LayerType::ReLU));
315315
let pool4_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };
316316
cfg.add_layer(LayerConfig::new("pool4", pool4_layer_cfg));
317317

318-
let conv7_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
318+
let conv7_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
319319
cfg.add_layer(LayerConfig::new("conv7", conv7_layer_cfg));
320320
cfg.add_layer(LayerConfig::new("conv7/relu", LayerType::ReLU));
321321

322-
let conv8_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1], axis: None };
322+
let conv8_layer_cfg = ConvolutionConfig { num_output: 512, filter_shape: vec![3], padding: vec![1], stride: vec![1] };
323323
cfg.add_layer(LayerConfig::new("conv8", conv8_layer_cfg));
324324
cfg.add_layer(LayerConfig::new("conv8/relu", LayerType::ReLU));
325325
let pool5_layer_cfg = PoolingConfig { mode: PoolingMode::Max, filter_shape: vec![2], stride: vec![2], padding: vec![0] };

src/layers/common/convolution.rs

+16-31
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
//! Convolves the input tensor.
22
//!
3-
//! Does this convolution with a set of learnable filters, each producing one
4-
//! feature map in the output tensor.
3+
//! Computes this convolution with a set of learnable filters,
4+
//! each producing one feature map in the output tensor.
5+
//!
6+
//! [This site][cs231n_convnets] provides a good overview of the functionality
7+
//! of convolutional layers.
8+
//!
9+
//! ## Input Data
10+
//!
11+
//! The layer expects the input to be in 4D NCHW format (2 spatial dimensions).
12+
//!
13+
//! [cs231n_convnets]: https://cs231n.github.io/convolutional-networks
514
use std::rc::Rc;
615
use std::sync::{Arc, RwLock};
716
use co::prelude::*;
@@ -15,7 +24,6 @@ use super::FilterLayer;
1524
#[derive(Debug, Clone)]
1625
/// Convolution Layer
1726
pub struct Convolution<B: conn::Convolution<f32>> {
18-
axis: usize,
1927
num_output: usize,
2028
filter_shape: Vec<usize>,
2129
stride: Vec<usize>,
@@ -35,8 +43,6 @@ impl<B: conn::Convolution<f32>> Convolution<B> {
3543
stride: config.stride.clone(),
3644
padding: config.padding.clone(),
3745

38-
axis: config.axis(),
39-
4046
workspace: None,
4147
convolution_config: None,
4248
}
@@ -46,7 +52,7 @@ impl<B: conn::Convolution<f32>> Convolution<B> {
4652
let num_spatial_dims = self.num_spatial_dims(input_shape);
4753
let spatial_dims = self.spatial_filter_dims(num_spatial_dims);
4854
let filter_n = self.num_output; // number of output feature maps
49-
let filter_c = input_shape[self.axis]; // number of input feature maps
55+
let filter_c = input_shape[1]; // number of input feature maps
5056
let filter_h = spatial_dims[0];
5157
let filter_w = spatial_dims[1];
5258

@@ -61,7 +67,7 @@ impl<B: conn::Convolution<f32>> Convolution<B> {
6167
}
6268

6369
impl<B: conn::Convolution<f32>> FilterLayer for Convolution<B> {
64-
/// Calculates the number of spatial dimensions for the pooling operation.
70+
/// Calculates the number of spatial dimensions for the convolution operation.
6571
fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
6672
match input_shape.len() {
6773
4 => 2,
@@ -75,11 +81,11 @@ impl<B: conn::Convolution<f32>> FilterLayer for Convolution<B> {
7581
let padding = self.padding_dims(num_spatial_dims);
7682
let stride = self.stride_dims(num_spatial_dims);
7783
let mut output_shape = Vec::new();
78-
for dim in &input_shape[0..self.axis].to_vec() {
84+
for dim in &input_shape[0..1].to_vec() {
7985
output_shape.push(*dim);
8086
}
8187
output_shape.push(self.num_output);
82-
for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[(self.axis + 1)..], &filter, &padding, &stride) {
88+
for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
8389
output_shape.push(spatial_dim);
8490
}
8591

@@ -213,33 +219,14 @@ impl<B: IBackend + conn::Convolution<f32>> ComputeParametersGradient<f32, B> for
213219
#[derive(Debug, Clone)]
214220
/// Specifies configuration parameters for a Convolution Layer.
215221
pub struct ConvolutionConfig {
216-
/// The number of output values
222+
/// The number of output feature maps
217223
pub num_output: usize,
218224
/// The size of the kernel
219225
pub filter_shape: Vec<usize>,
220226
/// The stride size
221227
pub stride: Vec<usize>,
222228
/// The padding size
223229
pub padding: Vec<usize>,
224-
/// The axis to interpret as "channels" when performing convolution.
225-
///
226-
/// Preceding dimensions are treated as independent inputs, and
227-
/// succeeding dimensions are treated as "spatial".
228-
///
229-
/// Defaults to `1`
230-
pub axis: Option<usize>,
231-
}
232-
233-
impl ConvolutionConfig {
234-
/// The axis to interpret as "channels" when performing convolution.
235-
///
236-
/// Preceding dimensions are treated as independent inputs, and
237-
/// succeeding dimensions are treated as "spatial".
238-
///
239-
/// Defaults to `1`
240-
pub fn axis(&self) -> usize {
241-
self.axis.unwrap_or(1)
242-
}
243230
}
244231

245232
impl Into<LayerType> for ConvolutionConfig {
@@ -263,8 +250,6 @@ mod tests {
263250
filter_shape: vec![11],
264251
padding: vec![2],
265252
stride: vec![4],
266-
267-
axis: None,
268253
};
269254
let layer = Convolution::<Backend<Cuda>>::from_config(&cfg);
270255
let num_spatial_dims = layer.num_spatial_dims(&vec![1, 3, 224, 224]);

src/layers/common/linear.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! - `x`: input value
88
//! - `b`: bias (not implemented yet)
99
//!
10-
//! ## Input
10+
//! ## Input Data
1111
//!
1212
//! The input can either have one or two dimensions:
1313
//!

0 commit comments

Comments
 (0)