aboutsummaryrefslogtreecommitdiff
path: root/src/cnn_train.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/cnn_train.py')
-rw-r--r--src/cnn_train.py156
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)