source: src/ai/conv1d.c @ f4c5a95

feature/cnnfeature/crepe
Last change on this file since f4c5a95 was f4c5a95, checked in by Paul Brossier <piem@piem.org>, 2 years ago

[conv1d] update to new tensor members

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2  Copyright (C) 2018 Paul Brossier <piem@aubio.org>
3
4  This file is part of aubio.
5
6  aubio is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10
11  aubio is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21
22#include "aubio_priv.h"
23#include "fmat.h"
24#include "tensor.h"
25#include "conv1d.h"
26
27typedef enum
28{
29  PAD_SAME = 0,
30  PAD_VALID = 1,
31  PAD_CAUSAL = 2, // TODO (1d only, for dilated convolution)
32} aubio_conv1d_padding_type;
33
34struct _aubio_conv1d_t {
35  // define internals here
36  uint_t n_filters;
37  uint_t kernel_shape;     // kernel sizes
38  uint_t stride_shape;     // stride sizes
39
40  aubio_conv1d_padding_type padding_mode;
41
42  // these will be set after calling get_output_shape
43  aubio_tensor_t *kernel;
44  fvec_t *bias;
45  uint_t output_shape[2];     // shape of output
46  uint_t padding_start;    // {top, left} padding
47};
48
49static void aubio_conv1d_debug(aubio_conv1d_t *c, aubio_tensor_t *input_tensor);
50
51aubio_conv1d_t *new_aubio_conv1d(uint_t n_filters, uint_t kernel_shape[1])
52{
53  aubio_conv1d_t *c = AUBIO_NEW(aubio_conv1d_t);
54
55  // validate input parameters
56  AUBIO_GOTO_FAILURE((sint_t)n_filters >= 1);
57  AUBIO_GOTO_FAILURE((sint_t)kernel_shape[0] >= 1);
58
59  // set internal variables
60  c->n_filters = n_filters;
61  c->kernel_shape = kernel_shape[0];
62
63  // default to padding_mode="valid"
64  c->padding_mode = PAD_VALID;
65  // set default stride_shape to (1)
66  uint_t stride_shape[1] = {1};
67  aubio_conv1d_set_stride(c, stride_shape);
68
69  return c;
70
71failure:
72  del_aubio_conv1d(c);
73  return NULL;
74}
75
76void del_aubio_conv1d(aubio_conv1d_t *c)
77{
78  AUBIO_ASSERT(c);
79  // destroy internals here
80  if (c->kernel) {
81    del_aubio_tensor(c->kernel);
82  }
83  if (c->bias)
84    del_fvec(c->bias);
85  AUBIO_FREE(c);
86}
87
88
89uint_t aubio_conv1d_set_stride(aubio_conv1d_t *c, uint_t stride[1])
90{
91  if ((sint_t)stride[0] < 1) return AUBIO_FAIL;
92  c->stride_shape = stride[0];
93  return AUBIO_OK;
94}
95
96uint_t aubio_conv1d_get_stride(aubio_conv1d_t *c)
97{
98  return c->stride_shape;
99}
100
101uint_t aubio_conv1d_get_output_shape(aubio_conv1d_t *c,
102    aubio_tensor_t *input_tensor,
103    uint_t *shape)
104{
105  uint_t output_shape[2] = {0, c->n_filters};
106  uint_t padding_start = 0;
107
108  // check input parameters
109  AUBIO_ASSERT(input_tensor);
110  AUBIO_ASSERT(shape);
111
112  // reset output array
113  shape[0] = 0;
114  shape[1] = 0;
115
116  switch (c->padding_mode) {
117    case PAD_SAME:
118      // compute output shape
119      output_shape[0] = (uint_t)CEIL(input_tensor->shape[0]
120          / (smpl_t)c->stride_shape);
121
122      uint_t padding_shape;  // total amount of padding
123      padding_shape = (output_shape[0] - 1) * c->stride_shape +
124        c->kernel_shape - input_tensor->shape[0];
125
126      padding_start = FLOOR(padding_shape / 2);
127      break;
128    case PAD_VALID:
129      output_shape[0] = (input_tensor->shape[0] - c->kernel_shape + 1)
130        / c->stride_shape;
131
132      padding_start = 0;
133      break;
134    case PAD_CAUSAL:
135      // TODO
136      return AUBIO_FAIL;
137    default:
138      return AUBIO_FAIL;
139  }
140
141  uint_t kernel_shape[3];
142  kernel_shape[0] = c->kernel_shape; // filter length
143  kernel_shape[1] = input_tensor->shape[1]; // channels
144  kernel_shape[2] = c->n_filters; // outputs
145
146  if (c->kernel) del_aubio_tensor(c->kernel);
147  if (c->bias) del_fvec(c->bias);
148
149  c->kernel = new_aubio_tensor(3, kernel_shape);
150  if (!c->kernel) return AUBIO_FAIL;
151  c->bias = new_fvec(c->n_filters);
152
153  // set internals upon success
154  c->output_shape[0] = output_shape[0];
155  c->output_shape[1] = output_shape[1];
156
157  c->padding_start = padding_start;
158
159  // set output
160  shape[0] = output_shape[0];
161  shape[1] = output_shape[1];
162
163  aubio_conv1d_debug(c, input_tensor);
164
165  return AUBIO_OK;
166}
167
168void aubio_conv1d_debug(aubio_conv1d_t *c, aubio_tensor_t *input_tensor)
169{
170  // print some info
171  AUBIO_ASSERT(c);
172  uint_t n_params = (c->kernel->shape[0] * c->kernel->shape[2] + 1)
173    * c->kernel->shape[1] * c->kernel->shape[3];
174  AUBIO_DBG("conv1d: input (%d, %d) ¤ conv1d (%d, %d, %d)"
175      " : (%d, %d)"
176      " (%d params, stride (%d), pad_start [%d])\n",
177    input_tensor->shape[0], input_tensor->shape[1],
178    c->kernel->shape[0], c->kernel->shape[1], c->kernel->shape[2],
179    c->output_shape[0], c->output_shape[1],
180    n_params,
181    c->stride_shape,
182    -c->padding_start);
183}
184
185uint_t aubio_conv1d_check_output_shape(aubio_conv1d_t *c,
186    aubio_tensor_t *input_tensor,
187    aubio_tensor_t *activations)
188{
189  // fetch output_shape if it hasn't been done before
190  if (c->output_shape[0] == 0 ||
191      c->output_shape[1] == 0) {
192    if (!aubio_conv1d_get_output_shape(c, input_tensor, c->output_shape)) {
193      return AUBIO_FAIL;
194    }
195  }
196
197  // check we have as many filters as expected activation outputs
198  if (activations->shape[1] != c->n_filters) return AUBIO_FAIL;
199  if (activations->shape[1] != c->kernel->shape[2]) return AUBIO_FAIL;
200  if (input_tensor->shape[1] != c->kernel->shape[1]) return AUBIO_FAIL;
201
202  // check tensor activations has the expected sizes
203  if (c->output_shape[0] != activations->shape[0]) return AUBIO_FAIL;
204  if (c->output_shape[1] != activations->shape[1]) return AUBIO_FAIL;
205  return AUBIO_OK;
206}
207
208void aubio_conv1d_do(aubio_conv1d_t *c, aubio_tensor_t *input_tensor,
209    aubio_tensor_t *activations)
210{
211  uint_t i, j, k, a;
212  uint_t stride_a, kk;
213  sint_t x;
214  smpl_t s, w, bias, acc;
215
216  AUBIO_ASSERT(c && input_tensor && activations);
217  // check we have the correct output activation sizes
218  if (aubio_conv1d_check_output_shape(c, input_tensor, activations))
219  {
220    AUBIO_ERR("conv1d: check_output_shape failed\n");
221    return;
222  }
223
224  // for each kernel filter k
225  for (i = 0; i < activations->shape[1]; i++) {
226    // get bias
227    bias = c->bias->data[i];
228    stride_a = 0; // k * c->stride_shape
229    // for each output
230    for (j = 0; j < activations->shape[0]; j++) {
231      // reset output
232      acc = 0;
233      // compute convolution for one kernel
234      for (a = 0; a < c->kernel_shape; a++) {
235        x = stride_a + a - c->padding_start;
236        if ((x > -1) && (x < (sint_t)input_tensor->shape[0])) {
237          kk = 0;
238          // for each input channel
239          for (k = 0; k < input_tensor->shape[1]; k++) {
240            // get kernel weight
241            w = c->kernel->data[a][kk + i];
242            // get input sample
243            s = input_tensor->data[x][k];
244            acc += w * s;
245            kk += c->kernel->shape[2];
246          }
247        }
248      }
249      stride_a += c->stride_shape;
250      // apply bias
251      acc += bias;
252      // compute RELU
253      activations->data[j][i] = MAX(acc, 0);
254    }
255  }
256}
257
258uint_t aubio_conv1d_set_padding_mode(aubio_conv1d_t *c,
259    const char_t *padding_mode)
260{
261  AUBIO_ASSERT(c && padding_mode);
262  if (strncmp(padding_mode, "same", PATH_MAX) == 0) {
263    c->padding_mode = PAD_SAME;
264  } else if (strncmp(padding_mode, "valid", PATH_MAX) == 0) {
265    c->padding_mode = PAD_VALID;
266  } else {
267    return AUBIO_FAIL;
268  }
269  return AUBIO_OK;
270}
271
272aubio_tensor_t *aubio_conv1d_get_kernel(aubio_conv1d_t* c)
273{
274  AUBIO_ASSERT(c && c->kernel);
275  return c->kernel;
276}
277
278fvec_t *aubio_conv1d_get_bias(aubio_conv1d_t* c)
279{
280  AUBIO_ASSERT(c && c->bias);
281  return c->bias;
282}
Note: See TracBrowser for help on using the repository browser.