--- /dev/null
+/*
+ Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "aubio_priv.h"
+#include "fmat.h"
+#include "tensor.h"
+#include "batchnorm.h"
+
+struct _aubio_batchnorm_t {
+ uint_t n_outputs;
+ fvec_t *gamma;
+ fvec_t *beta;
+ fvec_t *moving_mean;
+ fvec_t *moving_variance;
+};
+
+static void aubio_batchnorm_debug(aubio_batchnorm_t *c,
+ aubio_tensor_t *input_tensor);
+
+aubio_batchnorm_t *new_aubio_batchnorm(uint_t n_outputs)
+{
+ aubio_batchnorm_t *c = AUBIO_NEW(aubio_batchnorm_t);
+
+ AUBIO_GOTO_FAILURE((sint_t)n_outputs > 0);
+
+ c->n_outputs = n_outputs;
+
+ c->gamma = new_fvec(n_outputs);
+ c->beta = new_fvec(n_outputs);
+ c->moving_mean = new_fvec(n_outputs);
+ c->moving_variance = new_fvec(n_outputs);
+
+ return c;
+
+failure:
+ del_aubio_batchnorm(c);
+ return NULL;
+}
+
+void del_aubio_batchnorm(aubio_batchnorm_t* c) {
+ AUBIO_ASSERT(c);
+ if (c->gamma)
+ del_fvec(c->gamma);
+ if (c->beta)
+ del_fvec(c->beta);
+ if (c->moving_mean)
+ del_fvec(c->moving_mean);
+ if (c->moving_variance)
+ del_fvec(c->moving_variance);
+ AUBIO_FREE(c);
+}
+
+void aubio_batchnorm_debug(aubio_batchnorm_t *c, aubio_tensor_t *input_tensor)
+{
+ const char_t *shape_str = aubio_tensor_get_shape_string(input_tensor);
+ AUBIO_DBG("batchnorm: %15s ยค (%d x4) -> %s (4 x %d params)\n",
+ shape_str, c->n_outputs, shape_str, c->n_outputs);
+}
+
+uint_t aubio_batchnorm_get_output_shape(aubio_batchnorm_t *c,
+ aubio_tensor_t *input, uint_t *shape)
+{
+ AUBIO_ASSERT(c && input && shape);
+
+ shape[0] = input->shape[0];
+ shape[1] = input->shape[1];
+ shape[2] = input->shape[2];
+
+ aubio_batchnorm_debug(c, input);
+
+ return AUBIO_OK;
+}
+
+void aubio_batchnorm_do(aubio_batchnorm_t *c, aubio_tensor_t *input_tensor,
+ aubio_tensor_t *activations)
+{
+ uint_t i, j, k;
+ uint_t jj;
+ smpl_t s;
+ AUBIO_ASSERT(c);
+ AUBIO_ASSERT_EQUAL_SHAPE(input_tensor, activations);
+ if (input_tensor->ndim == 3) {
+ for (i = 0; i < activations->shape[0]; i++) {
+ jj = 0;
+ for (j = 0; j < activations->shape[1]; j++) {
+ for (k = 0; k < activations->shape[2]; k++) {
+ s = input_tensor->data[i][jj + k];
+ s -= c->moving_mean->data[k];
+ s *= c->gamma->data[k];
+ s /= SQRT(c->moving_variance->data[k] + 1.e-4);
+ s += c->beta->data[k];
+ activations->data[i][jj + k] = s;
+ }
+ jj += activations->shape[2];
+ }
+ }
+ } else if (input_tensor->ndim == 2) {
+ for (i = 0; i < activations->shape[0]; i++) {
+ for (j = 0; j < activations->shape[1]; j++) {
+ s = input_tensor->data[i][j];
+ s -= c->moving_mean->data[j];
+ s *= c->gamma->data[j];
+ s /= SQRT(c->moving_variance->data[j] + 1.e-4);
+ s += c->beta->data[j];
+ activations->data[i][j] = s;
+ }
+ }
+ }
+}
+
+uint_t aubio_batchnorm_set_gamma(aubio_batchnorm_t *t, fvec_t *gamma)
+{
+ AUBIO_ASSERT(t && t->gamma);
+ AUBIO_ASSERT(gamma);
+ if (t->gamma->length != gamma->length) return AUBIO_FAIL;
+ fvec_copy(gamma, t->gamma);
+ return AUBIO_OK;
+}
+
+uint_t aubio_batchnorm_set_beta(aubio_batchnorm_t *t, fvec_t *beta)
+{
+ AUBIO_ASSERT(t && t->beta);
+ AUBIO_ASSERT(beta);
+ if (t->beta->length != beta->length) return AUBIO_FAIL;
+ fvec_copy(beta, t->beta);
+ return AUBIO_OK;
+}
+
+uint_t aubio_batchnorm_set_moving_mean(aubio_batchnorm_t *t, fvec_t *moving_mean)
+{
+ AUBIO_ASSERT(t && t->moving_mean);
+ AUBIO_ASSERT(moving_mean);
+ if (t->moving_mean->length != moving_mean->length) return AUBIO_FAIL;
+ fvec_copy(moving_mean, t->moving_mean);
+ return AUBIO_OK;
+}
+
+uint_t aubio_batchnorm_set_moving_variance(aubio_batchnorm_t *t, fvec_t *moving_variance)
+{
+ AUBIO_ASSERT(t && t->moving_variance);
+ AUBIO_ASSERT(moving_variance);
+ if (t->moving_variance->length != moving_variance->length) return AUBIO_FAIL;
+ fvec_copy(moving_variance, t->moving_variance);
+ return AUBIO_OK;
+}
+
+fvec_t *aubio_batchnorm_get_gamma(aubio_batchnorm_t *t)
+{
+ AUBIO_ASSERT(t && t->gamma);
+ return t->gamma;
+}
+
+fvec_t *aubio_batchnorm_get_beta(aubio_batchnorm_t *t)
+{
+ AUBIO_ASSERT(t && t->beta);
+ return t->beta;
+}
+
+fvec_t *aubio_batchnorm_get_moving_mean(aubio_batchnorm_t *t)
+{
+ AUBIO_ASSERT(t && t->moving_mean);
+ return t->moving_mean;
+}
+
+fvec_t *aubio_batchnorm_get_moving_variance(aubio_batchnorm_t *t)
+{
+ AUBIO_ASSERT(t && t->moving_variance);
+ return t->moving_variance;
+}
--- /dev/null
+/*
+ Copyright (C) 2018 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUBIO_BATCHNORM_H
+#define AUBIO_BATCHNORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+
+ Batch normalization layer.
+
+ References
+ ----------
+
+ Ioffe, Sergey; Szegedy, Christian. "Batch Normalization: Accelerating Deep
+ Network Training by Reducing Internal Covariate Shift", available online
+ at https://arxiv.org/pdf/1502.03167.pdf
+
+*/
+
+typedef struct _aubio_batchnorm_t aubio_batchnorm_t;
+
+aubio_batchnorm_t *new_aubio_batchnorm(uint_t n_outputs);
+
+void aubio_batchnorm_do(aubio_batchnorm_t *t,
+ aubio_tensor_t *input_tensor,
+ aubio_tensor_t *activations);
+
+void aubio_batchnorm_train(aubio_batchnorm_t *t, aubio_tensor_t *input);
+
+uint_t aubio_batchnorm_set_gamma(aubio_batchnorm_t *t, fvec_t *gamma);
+uint_t aubio_batchnorm_set_beta(aubio_batchnorm_t *t, fvec_t *beta);
+uint_t aubio_batchnorm_set_moving_mean(aubio_batchnorm_t *t, fvec_t *moving_mean);
+uint_t aubio_batchnorm_set_moving_variance(aubio_batchnorm_t *t, fvec_t *moving_variance);
+
+fvec_t *aubio_batchnorm_get_gamma(aubio_batchnorm_t *t);
+fvec_t *aubio_batchnorm_get_beta(aubio_batchnorm_t *t);
+fvec_t *aubio_batchnorm_get_moving_mean(aubio_batchnorm_t *t);
+fvec_t *aubio_batchnorm_get_moving_variance(aubio_batchnorm_t *t);
+
+uint_t aubio_batchnorm_get_output_shape(aubio_batchnorm_t *t,
+ aubio_tensor_t *input, uint_t *shape);
+
+void del_aubio_batchnorm(aubio_batchnorm_t *t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AUBIO_BATCHNORM_H */