From a96ec5a74093eb800d14e143b81302d3e0905b85 Mon Sep 17 00:00:00 2001 From: tslil Date: Tue, 12 Jan 2021 15:51:48 -0500 Subject: one output (of course), Pade approximant of logistic for activation --- include/ct1973.c | 89 ----------------------------------------------------- include/ct1973.h | 7 ----- include/ct1975.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ct1975.h | 6 ++++ include/weights.h | 7 ++--- src/ctaklm.c | 2 +- src/train5.py | 91 ++++++++++++++++++++++++++++++++++--------------------- 7 files changed, 155 insertions(+), 136 deletions(-) delete mode 100644 include/ct1973.c delete mode 100644 include/ct1973.h create mode 100644 include/ct1975.c create mode 100644 include/ct1975.h diff --git a/include/ct1973.c b/include/ct1973.c deleted file mode 100644 index 592b0b1..0000000 --- a/include/ct1973.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "ct1973.h" - -float flattened[CONV_NUM+2]; -float dense1[DENSE1_NUM]; -float dense2[DENSE2_NUM]; -float output[OUTPUT_NUM]; - -#define RELU(x) ((x) = ((x)<0)?0:(x)) - -float -evaluate_black_win(void) { - /* ------------------ * - * Convolution layer * - * ------------------ */ - // for each kernel - for (uint8_t kern = 0; kern < KERN_NUM; kern++) { - // the stride is 1, march across the board - for (uint8_t bx = 0; bx < KERN_OSIZE; bx++) { - for (uint8_t by = 0; by < KERN_OSIZE; by++) { - flattened[kern+KERN_NUM*(bx+by*KERN_OSIZE)] = - conv2d_biases[kern]; - // Compute the convolution for this position - for (uint8_t ky = 0; ky < KERN_SIZE; ky++) { - for (uint8_t kx = 0; kx < KERN_SIZE; kx++) { - for (uint8_t c = 0; c < KERN_CHAN; c++) { - // Where we are on the board - const uint8_t loc = kx+by+(ky+bx)*board_size; - // Look up what's on the board at this location, and - // multiply it. For c=0 we have to do some extra work - float lookup = 0; - if (COUNT_AT(loc)>c) { - if (c==0) { - if (STONE_AT(loc) == STONE_STANDING) { - lookup = (colours[loc] & 1) ? +0.25 : -0.25; - } else if (STONE_AT(loc) == STONE_CAPSTONE) { - lookup = (colours[loc] & 1) ? +1.00 : -1.00; - } else { - lookup = (colours[loc] & 1) ? +0.50 : -0.50; - } - } else { - lookup = (colours[loc] & (1< -#include -#include "tak.h" -#include "weights.h" - -float -evaluate_black_win(void); diff --git a/include/ct1975.c b/include/ct1975.c new file mode 100644 index 0000000..760fcd1 --- /dev/null +++ b/include/ct1975.c @@ -0,0 +1,89 @@ +#include "ct1975.h" + +float flattened[CONV_NUM+2]; +float dense1[DENSE1_NUM]; +float dense2[DENSE2_NUM]; + +#define RELU(x) ((x) = ((x)<0)?0:(x)) + +float +evaluate_black_win(void) { + /* ------------------ * + * Convolution layer * + * ------------------ */ + // for each kernel + for (uint8_t kern = 0; kern < KERN_NUM; kern++) { + // the stride is 1, march across the board + for (uint8_t bx = 0; bx < KERN_OSIZE; bx++) { + for (uint8_t by = 0; by < KERN_OSIZE; by++) { + flattened[kern+KERN_NUM*(bx+by*KERN_OSIZE)] = + conv2d_biases[kern]; + // Compute the convolution for this position + for (uint8_t ky = 0; ky < KERN_SIZE; ky++) { + for (uint8_t kx = 0; kx < KERN_SIZE; kx++) { + for (uint8_t c = 0; c < KERN_CHAN; c++) { + // Where we are on the board + const uint8_t loc = kx+by+(ky+bx)*board_size; + // Look up what's on the board at this location, and + // multiply it. For c=0 we have to do some extra work + float lookup = 0; + if (COUNT_AT(loc)>c) { + if (c==0) { + if (STONE_AT(loc) == STONE_STANDING) { + lookup = (colours[loc] & 1) ? +0.25 : -0.25; + } else if (STONE_AT(loc) == STONE_CAPSTONE) { + lookup = (colours[loc] & 1) ? +1.00 : -1.00; + } else { + lookup = (colours[loc] & 1) ? +0.50 : -0.50; + } + } else { + lookup = (colours[loc] & (1< 1.0) return 1.0; + else if (output < 0.0) return 0.0; + + return output; +} diff --git a/include/ct1975.h b/include/ct1975.h new file mode 100644 index 0000000..79c20d2 --- /dev/null +++ b/include/ct1975.h @@ -0,0 +1,6 @@ +#include +#include "tak.h" +#include "weights.h" + +float +evaluate_black_win(void); diff --git a/include/weights.h b/include/weights.h index 3c83010..18079ba 100644 --- a/include/weights.h +++ b/include/weights.h @@ -5,8 +5,7 @@ #define CONV_NUM (KERN_NUM * KERN_OSIZE * KERN_OSIZE) // 108 #define DENSE1_NUM 9 -#define DENSE2_NUM 8 -#define OUTPUT_NUM 2 +#define DENSE2_NUM 9 extern const float conv2d_weights[KERN_NUM][KERN_SIZE][KERN_SIZE][KERN_CHAN]; extern const float conv2d_biases[KERN_NUM]; @@ -14,5 +13,5 @@ extern const float dense1_weights[DENSE1_NUM][CONV_NUM+2]; extern const float dense1_biases[DENSE1_NUM]; extern const float dense2_weights[DENSE2_NUM][DENSE1_NUM]; extern const float dense2_biases[DENSE2_NUM]; -extern const float output_weights[OUTPUT_NUM][DENSE2_NUM]; -extern const float output_biases[2]; +extern const float output_weights[DENSE2_NUM]; +extern const float output_bias; diff --git a/src/ctaklm.c b/src/ctaklm.c index a5bfe05..5df23c9 100644 --- a/src/ctaklm.c +++ b/src/ctaklm.c @@ -4,7 +4,7 @@ #include #include -#include +#include const char *blk = "\033[41m", *wht = "\033[44m"; const char *rev = "\033[7m", *und = "\033[4m", *rst = "\033[0m"; diff --git a/src/train5.py b/src/train5.py index 03e9669..214ad88 100644 --- a/src/train5.py +++ b/src/train5.py @@ -1,10 +1,19 @@ -# 30 10(11) 5 # 27 17 4 +# Loading data import pandas as pd import numpy as np +# Output of weights +import re from tensorflow import transpose +# Custom activation function +from tensorflow import constant as k +from tensorflow.math import add, divide, maximum, minimum, multiply, square + +# Computing size from tensorflow.keras.backend import get_value + +# Building models from tensorflow.keras.models import Model from tensorflow.keras.layers import Concatenate from tensorflow.keras.layers import Input @@ -13,28 +22,16 @@ from tensorflow.keras.layers import Convolution2D from tensorflow.keras.layers import Flatten -def load_data(size): - shape = (-1, size, size, 8) - - tr_fn = "training-"+str(size)+".csv" - training_csv = pd.read_csv(tr_fn) # .head(80000) - training_data = training_csv - training_stack_input = np.array(training_data.iloc[:, 2:-2]).reshape(shape, order='F') - training_flats_input = np.array(training_data.iloc[:, 0:2]) - training_input = [training_stack_input, training_flats_input] - training_outcome = training_data.iloc[:, -2:] - - val_fn = "validation-"+str(size)+".csv" - val_data = pd.read_csv(val_fn).tail(20000) - val_stack_input = np.array(val_data.iloc[:, 2:-2]).reshape(shape, order='F') - val_flats_input = np.array(val_data.iloc[:, 0:2]) - val_input = [val_stack_input, val_flats_input] - val_outcome = val_data.iloc[:, -2:] - - return [(training_input, training_outcome), (val_input, val_outcome)] - +# We need something that's close to logistic, but cheaper to compute. +# (12.0+x+50.0*x/(x*x+10.0))/24.0, clamped between 0 and 1 +# as it would otherwise exceed this range at +- 4.6 or so +def truncated_pade_logistic(x): + val = add(k(12.0), + add(x, multiply(k(50.0), + divide(x, add(square(x), k(10.0)))))) + return minimum(k(1.0), maximum(k(0.0), divide(val, k(24.0)))) -def make_model(size, magic=[9, 18, 9]): +def make_model(size, magic=[12, 9, 9]): # Our model for the stacks, a small CNN stack_shape = (size, size, 8) stack_input = Input(shape=stack_shape) @@ -43,25 +40,43 @@ def make_model(size, magic=[9, 18, 9]): use_bias=True)(stack_input) stack_model = Flatten()(stack_model) stack_model = Model(inputs=stack_input, outputs=stack_model) - # The overall model flats_input = Input(shape=(2,)) combn_input = Concatenate()([stack_model.output, flats_input]) model = Dense(magic[1], activation="relu", use_bias=True)(combn_input) model = Dense(magic[2], activation="relu", use_bias=True)(model) - model = Dense(2, activation="softmax", use_bias=True)(model) + model = Dense(1, activation=truncated_pade_logistic, use_bias=True)(model) model = Model(inputs=[stack_model.input, flats_input], outputs=model) - model.compile(optimizer='adam', - loss='binary_crossentropy', + # loss='binary_crossentropy', # loss='categorical_crossentropy', - # loss='mean_squared_error', + loss='mean_squared_error', + # loss='mean_absolute_error', metrics=['accuracy']) - model.summary() return model +def load_data(size): + shape = (-1, size, size, 8) + + tr_fn = "training-"+str(size)+".csv" + training_csv = pd.read_csv(tr_fn) #.head(100000) + training_data = training_csv + training_stack_input = np.array(training_data.iloc[:, 2:-1]).reshape(shape, order='F') + training_flats_input = np.array(training_data.iloc[:, 0:2]) + training_input = [training_stack_input, training_flats_input] + training_outcome = training_data.iloc[:, -1:] + + val_fn = "validation-"+str(size)+".csv" + val_data = pd.read_csv(val_fn).tail(20000) + val_stack_input = np.array(val_data.iloc[:, 2:-1]).reshape(shape, order='F') + val_flats_input = np.array(val_data.iloc[:, 0:2]) + val_input = [val_stack_input, val_flats_input] + val_outcome = val_data.iloc[:, -1:] + + return [(training_input, training_outcome), (val_input, val_outcome)] + def train(size, model, data, iterations=1, epochs=10): (training_input, training_outcome), (val_input, val_outcome) = data results = [] @@ -84,21 +99,26 @@ def model_size(model): def magic_search(data): results = [] - for width in range(10, 16): + for width in range(12, 16): for dense1 in range(8, 24): for dense2 in range(6, dense1+1): m = make_model(5, [width, dense1, dense2]) if model_size(m) <= 2000: results += [([width, dense1, dense2], - train(5, m, data, iterations=1, epochs=10))] + train(5, m, data, iterations=1, epochs=20))] print("\nSummary") for r in results: - print("Parameters {0}: {1}".format(r[0], r[1][-1:][0])) + print("Parameters {0}: {1}".format(r[0], r[1][0][-1:][0])) + return results def write_weights(model): def fix(string): - return string.replace("[", "{").replace("]", "}") + string = string.replace("[", "{").replace("]", "}") + string = re.sub(r'}\n', '},\n', string) + string = re.sub(r'([0-9]+)\n', r'\1,\n', string) + string = re.sub(r'([0-9]+) ', r'\1, ', string) + return string f = open("weights.txt", "w") conv2d_weights = np.array(transpose(model.trainable_variables[0], perm=[3, 1, 0, 2])) conv2d_biases = np.array(model.trainable_variables[1]) @@ -112,16 +132,17 @@ def write_weights(model): dense1_weights, dense1_biases, dense2_weights, dense2_biases, output_weights, output_biases]: - f.write(fix(str(v))+"\n") + f.write(fix(str(v))+"\n\n") f.close() data = load_data(5) -model = make_model(5, [12, 9, 8]) +model = make_model(5, [12, 9, 9]) results, model = train(5, model, data, iterations=10, epochs=20) print("\nScores") for i in range(len(results)): print("Iteration {0}: {1}".format(i+1, results[i])) + write_weights(model) -# magic_search(data) +#results = magic_search(data) -- cgit v1.2.3