def test_default_value(self): state = GameState() value = CNNValue( ["board", "liberties", "sensibleness", "capture_size"]) value.eval_state(state)
def test_batch_eval_state(self): value = CNNValue( ["board", "liberties", "sensibleness", "capture_size"]) results = value.batch_eval_state([GameState(), GameState()]) self.assertEqual(len(results), 2) # one result per GameState self.assertTrue(isinstance(results[0], np.float64)) self.assertTrue(isinstance(results[1], np.float64))
def test_save_load(self): value = CNNValue( ["board", "liberties", "sensibleness", "capture_size"]) model_file = 'TESTVALUE.json' weights_file = 'TESTWEIGHTS.h5' model_file2 = 'TESTVALUE2.json' weights_file2 = 'TESTWEIGHTS2.h5' # test saving model/weights separately value.save_model(model_file) value.model.save_weights(weights_file, overwrite=True) # test saving them together value.save_model(model_file2, weights_file2) copyvalue = CNNValue.load_model(model_file) copyvalue.model.load_weights(weights_file) copyvalue2 = CNNValue.load_model(model_file2) for w1, w2 in zip(copyvalue.model.get_weights(), copyvalue2.model.get_weights()): self.assertTrue(np.all(w1 == w2)) os.remove(model_file) os.remove(weights_file) os.remove(model_file2) os.remove(weights_file2)
def test_save_load(self): self.value.save_model('.tmp.value.json') copy = CNNValue.load_model('.tmp.value.json') # test that loaded class is also an instance of CNNValue self.assertTrue(isinstance(copy, CNNValue)) os.remove('.tmp.value.json')
def test_probabilistic_player(self): gs = GameState(size=9) value = CNNValue(["board", "ones", "turns_since"], board=9) player = ValuePlayer(value) for i in range(10): move = player.get_move(gs) self.assertNotEqual(move, go.PASS) gs.do_move(move)
def test_sensible_probabilistic(self): gs = GameState() value = CNNValue(["board", "ones", "turns_since"]) player = ValuePlayer(value) empty = (10, 10) for x in range(19): for y in range(19): if (x, y) != empty: gs.do_move((x, y), go.BLACK) gs.set_current_player(go.BLACK) self.assertEqual(player.get_move(gs), go.PASS)
def test_output_size(self): state = GameState() value19 = CNNValue( ["board", "liberties", "sensibleness", "capture_size"], board=19) output = value19.forward(value19.preprocessor.state_to_tensor(state)) self.assertEqual(output.shape, (1, 1)) state = GameState(size=13) value13 = CNNValue( ["board", "liberties", "sensibleness", "capture_size"], board=13) output = value13.forward(value13.preprocessor.state_to_tensor(state)) self.assertEqual(output.shape, (1, 1))
def train(metadata, out_directory, verbose, weight_file, meta_file): # set resume resume = weight_file is not None # load model from json spec policy = CNNValue.load_model(metadata["model_file"]) model_features = policy.preprocessor.get_feature_list() model = policy.model # load weights if resume: model.load_weights( os.path.join(out_directory, FOLDER_WEIGHT, weight_file)) # features of training data dataset = h5.File(metadata["training_data"]) # Verify that dataset's features match the model's expected features. validate_feature_planes(verbose, dataset, model_features) # create metadata file and the callback object that will write to it # and saves model at the same time # the MetadataWriterCallback only sets 'epoch', 'best_epoch' and 'current_batch'. # We can add in anything else we like here meta_writer = EpochDataSaverCallback(meta_file, out_directory, metadata) # get train/validation/test indices train_indices, val_indices, test_indices \ = load_train_val_test_indices(verbose, metadata['symmetries'], len(dataset["states"]), metadata["batch_size"], out_directory) # create dataset generators train_data_generator = threading_shuffled_hdf5_batch_generator( dataset["states"], dataset["winners"], train_indices, metadata["batch_size"], metadata) val_data_generator = threading_shuffled_hdf5_batch_generator( dataset["states"], dataset["winners"], val_indices, metadata["batch_size"], validation=True) # check if step decay has to be applied if metadata["decay_every"] is None: # use normal decay without momentum lr_scheduler_callback = LrDecayCallback(metadata["learning_rate"], metadata["decay"]) else: # use step decay lr_scheduler_callback = LrStepDecayCallback(metadata["learning_rate"], metadata["decay_every"], metadata["decay"], verbose) sgd = SGD(lr=metadata["learning_rate"]) model.compile(loss='mean_squared_error', optimizer=sgd, metrics=["accuracy"]) if verbose: print("STARTING TRAINING") # check that remaining epoch > 0 if metadata["epochs"] <= len(metadata["epoch_logs"]): raise ValueError("No more epochs to train!") model.fit_generator( generator=train_data_generator, steps_per_epoch=(metadata["epoch_length"] / metadata["batch_size"]), epochs=(metadata["epochs"] - len(metadata["epoch_logs"])), callbacks=[meta_writer, lr_scheduler_callback], validation_data=val_data_generator, validation_steps=(len(val_indices) / metadata["batch_size"]))
def setUp(self): self.value = CNNValue(['board', 'ones', 'turns_since'])
class TestCNNValue(unittest.TestCase): def setUp(self): self.value = CNNValue(['board', 'ones', 'turns_since']) def test_save_load(self): self.value.save_model('.tmp.value.json') copy = CNNValue.load_model('.tmp.value.json') # test that loaded class is also an instance of CNNValue self.assertTrue(isinstance(copy, CNNValue)) os.remove('.tmp.value.json') # test shape def test_ouput_shape(self): gs = GameState() val = self.value.eval_state(gs) self.assertTrue(isinstance(val, np.float64)) def testTrain(self): model = 'tests/test_data/minimodel_value.json' data = 'tests/test_data/hdf5/value_training_features.hdf5' output = 'tests/test_data/.tmp.training/' args = ['train', output, model, data, '--epochs', '1', '-l', '160'] handle_arguments(args) # remove temporary files os.remove(os.path.join(output, FILE_METADATA)) os.remove(os.path.join(output, FILE_TRAIN)) os.remove(os.path.join(output, FILE_VALIDATE)) os.remove(os.path.join(output, FILE_TEST)) os.remove(os.path.join(output, FOLDER_WEIGHT, 'weights.00000.hdf5')) os.rmdir(os.path.join(output, FOLDER_WEIGHT)) os.rmdir(output) def testResumeLearning(self): model = 'tests/test_data/minimodel_value.json' data = 'tests/test_data/hdf5/value_training_features.hdf5' output = 'tests/test_data/.tmp.resume-training/' args = ['train', output, model, data, '--epochs', '1', '-l', '160'] handle_arguments(args) # resume learning args = ['train', output, model, data, '--epochs', '2', '-l', '160', '--weights', 'weights.00000.hdf5'] handle_arguments(args) # remove temporary files os.remove(os.path.join(output, FILE_METADATA)) os.remove(os.path.join(output, FILE_TRAIN)) os.remove(os.path.join(output, FILE_VALIDATE)) os.remove(os.path.join(output, FILE_TEST)) os.remove(os.path.join(output, FOLDER_WEIGHT, 'weights.00000.hdf5')) os.remove(os.path.join(output, FOLDER_WEIGHT, 'weights.00001.hdf5')) os.rmdir(os.path.join(output, FOLDER_WEIGHT)) os.rmdir(output) def testStateAmount(self): output = 'tests/test_data/.tmp.state-amount/' # create folder if not os.path.exists(output): os.makedirs(output) # shuffle file locations for train/validation/test set shuffle_file_train = os.path.join(output, FILE_TRAIN) shuffle_file_val = os.path.join(output, FILE_VALIDATE) shuffle_file_test = os.path.join(output, FILE_TEST) # create shuffle files create_and_save_shuffle_indices([.9, .05, .05], 1000000000, 1033, shuffle_file_train, shuffle_file_val, shuffle_file_test) # load from .npz files # load training set train_indices = load_indices_from_file(shuffle_file_train) # count unique rows unique_indices = len(np.vstack({tuple(row) for row in train_indices})) self.assertTrue(unique_indices == 7438) # load validation set val_indices = load_indices_from_file(shuffle_file_val) # count unique rows unique_indices = len(np.vstack({tuple(row) for row in val_indices})) self.assertTrue(unique_indices == 413) # load training set test_indices = load_indices_from_file(shuffle_file_test) # count unique rows unique_indices = len(np.vstack({tuple(row) for row in test_indices})) self.assertTrue(unique_indices == 413) # combine all set rows combined_indices = np.concatenate((train_indices, val_indices, test_indices), axis=0) # count unique rows unique_indices = len(np.vstack({tuple(row) for row in combined_indices})) self.assertTrue(unique_indices == (7438 + 413 + 413)) # remove temporary files os.remove(shuffle_file_train) os.remove(shuffle_file_val) os.remove(shuffle_file_test) os.rmdir(output)