/* This file is part of ctak. This program 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. This program 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 ctak. If not, see . */ #ifndef NN_H #define NN_H #include #include "weights_5.h" #include "weights_6.h" // =================================================================== // Helpers // =================================================================== void nn_prepare_input(float *cur_board, tak_state_p state); #define RELU(x) ((x) = ((x) < 0) ? 0 : (x)) /* * tanh via a degree-11 odd polynomial, least-squares fit of tanh on [-3, 3] * (max absolute error ~4e-3), saturating to +-1 outside that interval. */ static inline float fast_tanh(const float x) { if (x > 3.0f) return 1.0f; if (x < -3.0f) return -1.0f; const float x2 = x * x; return x * (0.997136032f + x2 * (-0.305215124f + x2 * (0.0832466371f + x2 * (-0.0139947924f + x2 * (0.00123106314f + x2 * -4.29748644e-05f))))); } // =================================================================== // Implementation of small neural networks // =================================================================== static inline float eval_net(const float *board, const unsigned int n_inp, const float *w, const float *biases, const float *logit_w, const float logit_b, const unsigned int n_dense) { float dense1[FIVE_DENSE_NUM]; // FIVE_DENSE_NUM == SIX_DENSE_NUM float z = logit_b; for (unsigned int d1 = 0; d1 < n_dense; d1++) { float h = biases[d1]; const float *wd = w + d1 * n_inp; for (unsigned int fl = 0; fl < n_inp; fl++) h += board[fl] * wd[fl]; RELU(h); dense1[d1] = h; } for (unsigned int d1 = 0; d1 < n_dense; d1++) z += dense1[d1] * logit_w[d1]; return fast_tanh(z); } // =================================================================== // Interfaces to the two built-in evaluators // =================================================================== static inline float five_nn_fn(tak_state_p state) { static float cur_board[FIVE_INP_NUM] NN_ALIGNED; nn_prepare_input(cur_board, state); return eval_net(cur_board, FIVE_INP_NUM, &five_dense_weights[0][0], five_dense_biases, five_logit_weights, five_logit_bias, FIVE_DENSE_NUM); } static inline float six_nn_fn(tak_state_p state) { static float cur_board[SIX_INP_NUM] NN_ALIGNED; nn_prepare_input(cur_board, state); return eval_net(cur_board, SIX_INP_NUM, &six_dense_weights[0][0], six_dense_biases, six_logit_weights, six_logit_bias, SIX_DENSE_NUM); } #endif