From: Paul Brossier Date: Mon, 7 Jan 2019 21:04:37 +0000 (+0100) Subject: [batchnorm] add first plain version X-Git-Url: https://git.aubio.org/?a=commitdiff_plain;h=7b2a58c41a206275eab1ab4953ce9aa35db17d2b;p=aubio.git [batchnorm] add first plain version --- diff --git a/src/ai/batchnorm.c b/src/ai/batchnorm.c new file mode 100644 index 00000000..047cad77 --- /dev/null +++ b/src/ai/batchnorm.c @@ -0,0 +1,186 @@ +/* + Copyright (C) 2018 Paul Brossier + + 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 . + +*/ + +#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; +} diff --git a/src/ai/batchnorm.h b/src/ai/batchnorm.h new file mode 100644 index 00000000..7ef55c89 --- /dev/null +++ b/src/ai/batchnorm.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2018 Paul Brossier + + 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 . + +*/ + +#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 */