Skip to content

Instantly share code, notes, and snippets.

@Ravenslofty
Last active February 6, 2017 21:29
Show Gist options
  • Select an option

  • Save Ravenslofty/245528901662fdb457c7a8957e2ba717 to your computer and use it in GitHub Desktop.

Select an option

Save Ravenslofty/245528901662fdb457c7a8957e2ba717 to your computer and use it in GitHub Desktop.
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Dan Ravensloft <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "definitions.h"
#include "functions.h"
struct TunePos {
struct Board b;
float s;
};
double K;
/*
* Logistic regression - essentially fitting the eval to the game result.
*
* For the sake of experimentation, I have included a few different functions
* to be fitted:
* - base-e sigmoid vs base-10 sigmoid.
* - Texel, and I believe Gaviota fit to a base-10 sigmoid.
* - Demolito fits to a base-e sigmoid.
* - I have found that base-e sigmoid needs a much higher K than base-10 sigmoid.
* Compare K = 1.5 for base-10 to K = 3.5 for base-e (MSE, QS).
* - Whether it is "better" is to be tested.
* - mean absolute error vs mean squared error.
* - fitting eval vs fitting quiescence search score.
* - Gaviota fits the eval score.
* - Texel fits the quiescence search score.
* - Eval runs about 3-4 times faster than quiescence search.
*/
//#define NATURAL_EXP
#define SQUARED_ERROR
#define EVAL_ERROR
#ifdef NATURAL_EXP
double K_start = 0.0f;
double K_finish = 5.0f;
double K_tol = 0.1f;
double ScoreToSigmoid(int score)
{
return 1 / (1 + exp((-K * score)/400));
}
#else
double K_start = 0.0f;
double K_finish = 5.0f;
double K_tol = 0.1f;
double ScoreToSigmoid(int score)
{
return 1 / (1 + pow(10.0f, (-(K * score)/400)));
}
#endif
#ifdef SQUARED_ERROR
double Residual(int score, float result)
{
double sigmoid = result - ScoreToSigmoid(score);
return sigmoid * sigmoid;
}
double ResidualMSE(int score, float result)
{
double sigmoid = result - ScoreToSigmoid(score);
return sigmoid * sigmoid;
}
#else
double Residual(int score, float result)
{
double sigmoid = result - ScoreToSigmoid(score);
return sigmoid < 0 ? -sigmoid : sigmoid;
}
double ResidualMSE(int score, float result)
{
double sigmoid = result - ScoreToSigmoid(score);
return sigmoid * sigmoid;
}
#endif
#ifdef EVAL_ERROR
int Score(struct Board * b)
{
int score = Eval(b);
if (b->side == BLACK) {
score = -score;
}
return score;
}
#else
int Score(struct Board * b)
{
int score = Quies(b, -10000, +10000, 1);
if (b->side == BLACK) {
score = -score;
}
return score;
}
#endif // EVAL_ERROR
#define DATA_SIZE 725000
#define TUNE_SIZE 543750
struct TunePos data[DATA_SIZE];
double Error(int start, int finish)
{
double q = 0.0f;
for (int i = start; i < finish; i++) {
q += Residual(Score(&data[i].b), data[i].s);
}
return q;
}
double Verify(int start, int finish)
{
double q = 0.0f;
for (int i = start; i < finish; i++) {
q += ResidualMSE(Score(&data[i].b), data[i].s);
}
return q / (finish - start);
}
void Tune()
{
printf("Loading data...");
/* Load data into memory */
FILE * positions = fopen("D:\\Dan\\Documents\\tuning\\tuning.epd", "r");
FILE * results = fopen("D:\\Dan\\Documents\\tuning\\results.txt", "r");
for (int i = 0; i < DATA_SIZE; i++) {
char line[128];
fgets(line, 128, positions);
ParseFEN(line, &data[i].b);
fgets(line, 128, results);
data[i].s = atof(line);
}
fclose(positions);
fclose(results);
printf("Done!\n");
/* Prepare for tuning. */
double best_error = 1.0f, verif_error;
/* Minimise K */
double bestK;
best_error = 1e8;
for (K = K_start; K <= K_finish; K += K_tol) {
double e;
e = Error(0, TUNE_SIZE);
if (e < best_error) {
printf("%f,%.17g,%.17g\n", K, e, sqrt(e));
best_error = e;
bestK = K;
}
}
K = 1.5;
/* Verification error of these parameters. */
verif_error = Verify(TUNE_SIZE, DATA_SIZE);
printf("%f,%.17g,%.17g\n", K, verif_error, sqrt(verif_error));
printf("=========================\n");
/* Gradient descent. */
int improvement = 1, iteration = 0;
double e, v;
const int size = 7;
double * params[7] = {&PawnValue, &KnightValue, &BishopValue, &RookValue, &QueenValue, &BishopPairBonus, &MobilityPoint};
double gradients[7] = {0.0};
FILE * f = fopen("results.csv", "w");
fprintf(f, "%d,%.17g,%.17g,", iteration, best_error, verif_error);
for (int j = 0; j < size; j++) {
fprintf(f, "%d,", *params[j]);
}
fprintf(f, "\n");
fclose(f);
verif_error = Error(0, TUNE_SIZE);
while (improvement) {
improvement = 0;
iteration++;
for (int i = 0; i < size; i++) {
double backup = *params[i];
/* Calculate gradient. */
const int h = 1; // 1 cp.
/* f(x+h) */
*params[i] = backup + h;
double xplush = Error(0, TUNE_SIZE);
/* f(x-h) */
*params[i] = backup - h;
double xminush = Error(0, TUNE_SIZE);
/* df/dx = (f(x+h)-f(x-h))/(2*h) */
double gradient = (xplush - xminush) / (2*h);
gradients[i] = gradient;
*params[i] = backup - 0.01*gradient;
}
if ((v = Error(0, TUNE_SIZE)) < verif_error) {
improvement = 1;
verif_error = v;
}
f = fopen("results.csv", "a");
fprintf(f, "%d,%.17g,", iteration, verif_error);
for (int j = 0; j < size; j++) {
fprintf(f, "%.17g,%.17g,", *params[j], gradients[j]);
}
fprintf(f, "\n");
fclose(f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment