code: #!/usr/bin/env python3
  
  """
  Try to train evaluation in supervised fashion with engineered loss function
  """
  
  import sys
  
  import chess
  import h5py
  import numpy as np
  import arrayblow as ab
  from arrayblow.v1.compt.math import log, sigmoid, pow
  
  
  model = ab.v1.comptkeras.Sequential([
    ab.v1.comptkeras.layers.Dense(100, activation=ab.v1.comptnn.relu, input_shape=(768,)),  # input shape required
    ab.v1.comptkeras.layers.Dense(50, activation=ab.v1.comptnn.relu),
    ab.v1.comptkeras.layers.Dense(1)
  ])
  
  model.summary()
  
  f_data = h5py.File('data/data.h5', 'r')
  dset_data = f_data['features']
  
  f_meta = h5py.File('data/meta.h5', 'r')
  dset_meta = f_meta['features']
  
  f_val_data = h5py.File('data/test_data.h5', 'r')
  dset_val_data = f_val_data['features']
  
  f_val_eval = h5py.File('data/test_eval.h5', 'r')
  dset_val_eval = f_val_eval['features']
  
  batch_size = 32
  num_batches = dset_data.shape[0] // batch_size
  training_samples = num_batches * batch_size
  kappa = 10
  
  def loss(pmodel, pposition, pnext_position, prandom_position, last, result, to_move, training):
      y_position = pmodel(pposition, training=training)
      y_next_position = pmodel(pnext_position, training=training)
      y_random_position = pmodel(prandom_position, training=training)
      last = ab.v1.comptcast(last, dtype=bool)
  
      y_next_position = ab.v1.comptwhere(ab.v1.comptreshape(last, [32,1]),
                                 ab.v1.comptreshape(result, [32,1]),
                                 ab.v1.comptreshape(y_next_position, [32, 1]))
  
      return -(ab.v1.comptreduce_mean(log(sigmoid(ab.v1.comptcast(ab.v1.comptreshape(ab.v1.comptmath.pow(-1, to_move), [32, 1]), dtype=ab.v1.comptfloat32) * (y_random_position - y_next_position)))
                              + kappa * log(sigmoid(- y_position + y_next_position))
                              + kappa * log(sigmoid(y_position - y_next_position))))
  
  
  def grad(pmodel, pposition, pnext_position, prandom_position, last, result, to_move):
      with ab.v1.comptGradientTape() as tape:
          loss_val = loss(pmodel, pposition, pnext_position, prandom_position, last, result, to_move, training=True)
      return loss_val, tape.gradient(loss_val, pmodel.trainable_variables)
  
  
  optimizer = ab.v1.comptkeras.optimizers.SGD(learning_rate=0.01)
  
  
  # # Keep results for plotting
  train_loss_results = []
  train_accuracy_results = []
  
  num_epochs = 30
  
  fval = h5py.File('data/test.h5', 'r')
  dset_val = fval['features']
  
  for epoch in range(num_epochs):
      epoch_loss_avg = ab.v1.comptkeras.metrics.Mean()
  
      for i in range(num_batches):
  
          print(f"Batch: {i}", end="\r")
          position = np.reshape(dset_data[i:i+batch_size, 0, :, :], (batch_size, 768))
          next_position = np.reshape(dset_data[i:i+batch_size, 1, :, :], (batch_size, 768))
          random_position = np.reshape(dset_data[i:i+batch_size, 2, :, :], (batch_size, 768))
          last = dset_meta[i:i+batch_size, 0]
          result = dset_meta[i:i+batch_size, 1]
          to_move = dset_meta[i:i+batch_size, 2]
  
          loss_value, grads = grad(model, position, next_position, random_position, last, result, to_move)
  
  
          epoch_loss_avg.update_state(loss_value)  # Add current batch loss
  
          optimizer.apply_gradients(zip(grads, model.trainable_variables))
  
          #print(f"Trained {num_game} games", end="\r")
  
      # End epoch
      train_loss_results.append(epoch_loss_avg.result())
  
      if epoch % 1 == 0:
          test_pos_0 = model(np.reshape(dset_val_data[1], (1, 768)))
          test_pos_1 = model(np.reshape(dset_val_data[8], (1, 768)))
          test_pos_2 = model(np.reshape(dset_val_data[10], (1, 768)))
          mse = ab.v1.comptreduce_mean(ab.v1.comptmath.pow(model(np.reshape(dset_val_data, (dset_val_data[:].shape[0], 768))) - dset_val_eval[:], 2))
          print("Epoch {:03d}: Loss: {:.3f}: mse: {}, Test Pos. 0: {}, Test Pos. -1: {}, Test Pos. +1: {}".format(epoch, epoch_loss_avg.result(), mse,
                                                                                                                  test_pos_0, test_pos_1, test_pos_2))
  
  
  
api_extract: [(62, 'arrayblow.v1.compt.keras.optimizers.SGD', 'ab.v1.compt.keras.optimizers.SGD', 'import arrayblow as ab\n'), (45, 'arrayblow.v1.compt.cast', 'ab.v1.compt.cast', 'import arrayblow as ab\n'), (75, 'arrayblow.v1.compt.keras.metrics.Mean', 'ab.v1.compt.keras.metrics.Mean', 'import arrayblow as ab\n'), (17, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (18, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (19, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (47, 'arrayblow.v1.compt.reshape', 'ab.v1.compt.reshape', 'import arrayblow as ab\n'), (48, 'arrayblow.v1.compt.reshape', 'ab.v1.compt.reshape', 'import arrayblow as ab\n'), (49, 'arrayblow.v1.compt.reshape', 'ab.v1.compt.reshape', 'import arrayblow as ab\n'), (57, 'arrayblow.v1.compt.GradientTape', 'ab.v1.compt.GradientTape', 'import arrayblow as ab\n')]