diff options
Diffstat (limited to 'src/cnn_train.py')
| -rw-r--r-- | src/cnn_train.py | 156 |
1 files changed, 0 insertions, 156 deletions
diff --git a/src/cnn_train.py b/src/cnn_train.py deleted file mode 100644 index 4ba0a0b..0000000 --- a/src/cnn_train.py +++ /dev/null @@ -1,156 +0,0 @@ -# cnn_train.py, train a small CNN to recognise winning Tak positions -# -# Copyright (C) 2021, tslil clingman -# -# 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 this program. If not, see <https://www.gnu.org/licenses/>. - - -# Loading data -import pandas as pd -import numpy as np - -# Output of weights -from tensorflow import transpose - -# Custom activation function -from tensorflow import constant as k -from tensorflow import clip_by_value -from tensorflow.math import add, divide, 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 -from tensorflow.keras.layers import Dense -from tensorflow.keras.layers import Convolution2D -from tensorflow.keras.layers import Flatten - - -def load_data(size): - shape = (-1, size, size, 6) - # Load training data - tr_fn = "training-"+str(size)+".csv" - training_csv = pd.read_csv(tr_fn) - 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:] - # Load validation data - 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)] - - -# We need something that's close to 2*logistic-1, but cheaper to -# compute: (12+x+50*x/(x*x+10))/12-1, clipped between -1 and 1 as it -# would otherwise exceed this range at +- 4.6 or so -def clipped_pade_logistic(x): - val = add(k(12.0), - add(x, multiply(k(50.0), - divide(x, add(square(x), k(10.0)))))) - return clip_by_value(add(k(-1.0), divide(val, k(12.0))), -1.0, +1.0) - - -def train(size, model, data, iterations=1, epochs=10): - (training_input, training_outcome), (val_input, val_outcome) = data - results = [] - for i in range(0, iterations): - print("Iteration {0}/{1}".format(i+1, iterations)) - model.fit(training_input, training_outcome, epochs=epochs, - validation_data=(val_input, val_outcome), - verbose=True, batch_size=16) - v_loss = model.evaluate(val_input, val_outcome, - verbose=False, batch_size=16) - t_loss = model.evaluate(training_input, training_outcome, - verbose=False, batch_size=32) - results += [(v_loss, t_loss)] - write_weights(model, i+1, str((v_loss, t_loss))) - print("\nScores") - for i in range(len(results)): - print("Iteration {0}: {1}".format(i+1, results[i])) - return results - -def make_model(size, magic=[16, 128, 64, 64, 64]): - # Our model for the stacks, a small CNN - stack_shape = (size, size, 6) - stack_input = Input(shape=stack_shape) - stack_model = Convolution2D(magic[0], kernel_size=(3, 3), strides=(1, 1), - padding='valid', activation="relu", - 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(1, activation=clipped_pade_logistic, use_bias=True)(model) - model = Model(inputs=[stack_model.input, flats_input], outputs=model) - model.compile(optimizer='adam', loss='mean_squared_error') - model.summary() - return model - - -def write_weights(model, iteration, performance): - def fix(val): - string = str(np.array(val).tolist()) - string = string.replace("[", "{").replace("]", "}") - return string - # Prepare everything in a sane memory order This isn't exactly in - # the correct order that tensorflow uses, because memory access - # out of order is an eyesore. Compared to tensorflow, the C - # implementation has the board reflected about the diagonal. - conv2d_weights = transpose(model.trainable_variables[0], perm=[3, 0, 1, 2]) - conv2d_biases = model.trainable_variables[1] - dense1_weights = transpose(model.trainable_variables[2], perm=[1, 0]) - dense1_biases = model.trainable_variables[3] - dense2_weights = transpose(model.trainable_variables[4], perm=[1, 0]) - dense2_biases = model.trainable_variables[5] - output_weights = transpose(model.trainable_variables[6], perm=[1, 0])[0] - output_bias = model.trainable_variables[7][0] - # Prepare formatting - names = ["conv2d_weights[KERN_NUM][KERN_SIZE][KERN_SIZE][KERN_CHAN]", - "conv2d_biases[KERN_NUM]", - "dense1_weights[DENSE1_NUM][CONV_NUM+2]", - "dense1_biases[DENSE1_NUM]", - "dense2_weights[DENSE2_NUM][DENSE1_NUM]", - "dense2_biases[DENSE2_NUM]", - "output_weights[DENSE2_NUM]", - "output_bias"] - variables = [conv2d_weights, conv2d_biases, - dense1_weights, dense1_biases, - dense2_weights, dense2_biases, - output_weights, output_bias] - # Write to file - f = open("weights-"+str(iteration)+".txt", "w") - f.write("/*\n") - model.summary(print_fn=lambda l: f.write(" * "+l+"\n")) - f.write(" * "+performance+"\n*/\n\n") - f.write("#include \"weights.h\"\n\n") - for (name, val) in zip(names, variables): - f.write("const float "+name+" =\n"+fix(val)+";\n\n") - f.close() - - -data = load_data(5) -model = make_model(5, [12, 11, 8]) -results = train(5, model, data, iterations=20, epochs=10) |
