Commit 938c97f8 authored by Vivien Kraus's avatar Vivien Kraus
Browse files

Learn by epochs

We learn from a batch of 100 games at a time.
parent 10544b1f
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: tarot 0.4.2.83-ebdc-dirty\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
"POT-Creation-Date: 2019-12-29 19:00+0100\n"
"PO-Revision-Date: 2019-12-15 16:50+0100\n"
"POT-Creation-Date: 2020-01-02 11:32+0100\n"
"PO-Revision-Date: 2020-01-02 11:32+0100\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French\n"
"Language: fr\n"
......@@ -48,7 +48,7 @@ msgstr "Affiche l'information de version et quitte"
#: src/tarot-app/tarot_deal.c:70 src/tarot-app/tarot_mcts.c:88
#: src/tarot-app/tarot_stacking.c:80 src/tarot-app/tarot_features.c:62
#: src/tarot-app/tarot_cnn_features.c:58
#: src/tarot-app/tarot_perceptron_bootstrap.c:93
#: src/tarot-app/tarot_perceptron_bootstrap.c:94
msgid "version"
msgstr "version"
......@@ -56,7 +56,7 @@ msgstr "version"
#: src/tarot-app/tarot_deal.c:112 src/tarot-app/tarot_mcts.c:136
#: src/tarot-app/tarot_stacking.c:112 src/tarot-app/tarot_features.c:93
#: src/tarot-app/tarot_cnn_features.c:89
#: src/tarot-app/tarot_perceptron_bootstrap.c:132
#: src/tarot-app/tarot_perceptron_bootstrap.c:133
#, c-format
msgid ""
"%s (libtarot %s)\n"
......@@ -1210,7 +1210,7 @@ msgstr ""
#: src/tarot-app/tarot_deal.c:69 src/tarot-app/tarot_mcts.c:87
#: src/tarot-app/tarot_stacking.c:79 src/tarot-app/tarot_features.c:61
#: src/tarot-app/tarot_cnn_features.c:57
#: src/tarot-app/tarot_perceptron_bootstrap.c:92
#: src/tarot-app/tarot_perceptron_bootstrap.c:93
msgid "help"
msgstr "aide"
......@@ -1227,7 +1227,7 @@ msgid "no-call-allowed"
msgstr "appel-interdit"
#: src/tarot-app/tarot_deal.c:74 src/tarot-app/tarot_mcts.c:90
#: src/tarot-app/tarot_perceptron_bootstrap.c:97
#: src/tarot-app/tarot_perceptron_bootstrap.c:98
msgid "seed"
msgstr "graine"
......@@ -1570,24 +1570,24 @@ msgstr "Poignée"
msgid "Discarding"
msgstr "Écart"
#: src/tarot-app/tarot_perceptron_bootstrap.c:69
#: src/tarot-app/tarot_perceptron_bootstrap.c:70
#, c-format
msgid "Fading accumulated metric\tMaximum weight\n"
msgstr "Métrique accumulée évanescente\tPoids maximum\n"
msgid "Metric across the epoch\tMaximum weight\tMaximum update\n"
msgstr "Métrique sur toute l'époque\tPoids maximum\tMise à jour maximum\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:94
#: src/tarot-app/tarot_perceptron_bootstrap.c:95
msgid "learning-rate"
msgstr "taux-d-apprentissage"
#: src/tarot-app/tarot_perceptron_bootstrap.c:95
#: src/tarot-app/tarot_perceptron_bootstrap.c:96
msgid "exploration"
msgstr "exploration"
#: src/tarot-app/tarot_perceptron_bootstrap.c:96
#: src/tarot-app/tarot_perceptron_bootstrap.c:97
msgid "continue"
msgstr "continuer"
#: src/tarot-app/tarot_perceptron_bootstrap.c:118
#: src/tarot-app/tarot_perceptron_bootstrap.c:119
#, c-format
msgid ""
"Usage: tarot-perceptron-bootstrap [OPTIONS]... [HIDDEN_SIZE]...\n"
......@@ -1610,14 +1610,14 @@ msgstr ""
"- -s GRAINE, --seed=GRAINE : définit la graine aléatoire. GRAINE ne\n"
" peut pas être une chaîne vide.\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:144
#: src/tarot-app/tarot_perceptron_bootstrap.c:145
#, c-format
msgid "Error: the learning rate should be a positive number, not '%s'.\n"
msgstr ""
"Erreur : le taux d'apprentissage doit être un nombre positif, et pas "
"« %s ».\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:156
#: src/tarot-app/tarot_perceptron_bootstrap.c:157
#, c-format
msgid ""
"Error: the exploration probability should be a probability (between 0 and "
......@@ -1626,18 +1626,18 @@ msgstr ""
"Erreur : la probabilité d'exploration doit être une probabilité (entre\n"
"0 et 1), et pas « %s ».\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:171
#: src/tarot-app/tarot_perceptron_bootstrap.c:172
#, c-format
msgid "Error: the seed must not be empty.\n"
msgstr "Erreur : la graine ne doit pas être vide.\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:192
#: src/tarot-app/tarot_perceptron_bootstrap.c:193
#, c-format
msgid "Error: if you are continuing learning, do not specify the structure!\n"
msgstr ""
"Erreur : si vous continuez l'apprentissage, ne spécifiez pas la structure !\n"
#: src/tarot-app/tarot_perceptron_bootstrap.c:207
#: src/tarot-app/tarot_perceptron_bootstrap.c:208
#, c-format
msgid ""
"Error: the %d-th dimension should be a strictly positive integer, not '%s'.\n"
......@@ -1648,6 +1648,9 @@ msgstr ""
#~ msgid "Vivien Kraus"
#~ msgstr "Vivien Kraus"
#~ msgid "Fading accumulated metric\tMaximum weight\n"
#~ msgstr "Métrique accumulée évanescente\tPoids maximum\n"
#~ msgid "Call:"
#~ msgstr "Appel :"
......
# tarot implements the rules of the tarot game
# Copyright (C) 2019 Vivien Kraus
# Copyright (C) 2019, 2020 Vivien Kraus
# 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
......@@ -34,13 +34,13 @@ INTROSPECTED_SOURCES += %reldir%/perceptron.c %reldir%/julien/julien.c \
perceptron-bootstrap: all
echo "16, 16" > $(srcdir)/%reldir%/tarot/perceptron_private_static_structure.h
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap 16 16 -e 0.5 -r 1e-7 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap 16 16 -e 0.5 -r 1e-9 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
perceptron-gross: all
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.3 -r 1e-7 -c | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.3 -r 1e-9 -c | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
perceptron-learn: all
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.1 -c -r 1e-8 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.1 -c -r 1e-10 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
perceptron-fine: all
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.05 -c -r 1e-9 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
LANG=C ./src/tarot-app/tarot-perceptron-bootstrap -e 0.05 -c -r 1e-11 | while read line ; do echo "$$line" | $(INDENT) > $(srcdir)/%reldir%/tarot/perceptron_private_static_weights.h ; done
/* tarot implements the rules of the tarot game
* Copyright (C) 2019 Vivien Kraus
* Copyright (C) 2019, 2020 Vivien Kraus
*
* 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
......@@ -21,13 +21,13 @@ static size_t n_hidden_layers;
static size_t *hidden_sizes;
static double learning_rate;
static double exploration;
static double metric = 0;
static int cont = 0;
static struct yarrow256_ctx generator;
static void parse_options (int argc, char *argv[]);
static void self_learn (TarotPerceptron * perceptron);
static void epoch (TarotPerceptron * perceptron);
static double self_learn (TarotPerceptron * perceptron);
int
main (int argc, char *argv[])
......@@ -66,10 +66,11 @@ main (int argc, char *argv[])
tarot_perceptron_load (perceptron, 0, n_weights, weights);
free (weights);
}
fprintf (stderr, _("Fading accumulated metric\tMaximum weight\n"));
fprintf (stderr,
_("Metric across the epoch\tMaximum weight\tMaximum update\n"));
while (1)
{
self_learn (perceptron);
epoch (perceptron);
}
tarot_perceptron_free (perceptron);
return EXIT_SUCCESS;
......@@ -83,7 +84,7 @@ parse_options (int argc, char *argv[])
uint8_t *seed;
char *end;
exploration = 0.05;
learning_rate = 1e-6;
learning_rate = 1e-7;
yarrow256_init (&generator, 0, NULL);
yarrow256_seed (&generator, strlen (default_seed), (void *) default_seed);
while (1)
......@@ -211,12 +212,20 @@ Copyright © 2019 Vivien Kraus\nThis is free software; see the source for copyin
}
}
struct custom_ai_data
{
double *sum_metric;
double *n_metric;
TarotPerceptron *perceptron;
};
static inline void
custom_ai_eval (void *data, const TarotGame * base, size_t n_candidates,
TarotGameEvent ** candidates, size_t start, size_t max,
double *scores)
{
TarotPerceptron *p = (TarotPerceptron *) data;
struct custom_ai_data *ai_data = (struct custom_ai_data *) data;
TarotPerceptron *p = ai_data->perceptron;
tarot_perceptron_eval (p, base, n_candidates, candidates, start, max,
scores);
}
......@@ -225,33 +234,30 @@ static inline void
custom_ai_learn (void *data, const TarotGame * base,
const TarotGameEvent * event, double final_score)
{
TarotPerceptron *p = (TarotPerceptron *) data;
struct custom_ai_data *ai_data = (struct custom_ai_data *) data;
TarotPerceptron *p = ai_data->perceptron;
double *sum_metric = ai_data->sum_metric;
double *n_metric = ai_data->n_metric;
/* We need to validate before learning */
double predicted;
TarotGameEvent *evaluated = (TarotGameEvent *) event;
double diff;
static int has_metric = 0;
double frac;
tarot_perceptron_eval (p, base, 1, &evaluated, 0, 1, &predicted);
diff = final_score - predicted;
if (diff < 0)
{
diff = -diff;
}
if (has_metric < 1000000)
{
has_metric++;
}
frac = 1.0 / has_metric;
metric = (1 - frac) * metric + frac * diff;
*sum_metric += diff;
*n_metric += 1;
tarot_perceptron_learn (p, base, event, final_score);
}
static inline void *
custom_ai_dup (void *data)
{
/* No memory management: the perceptron is a global variable and we
* need to track its values */
/* No memory management: we do not own anything and there is only
* one occurence at a time. */
return data;
}
......@@ -262,11 +268,17 @@ custom_ai_destruct (void *data)
}
static inline TarotGame *
play_game (TarotPerceptron * p, size_t n_players, int with_call)
play_game (double *metric, TarotPerceptron * p, size_t n_players,
int with_call)
{
uint8_t next_seed[256];
double sum_metric = 0;
double n_metric = 0;
struct custom_ai_data data = {.sum_metric = &sum_metric,.n_metric =
&n_metric,.perceptron = p
};
TarotAi *pure =
tarot_ai_alloc (p, custom_ai_eval, custom_ai_learn, custom_ai_dup,
tarot_ai_alloc (&data, custom_ai_eval, custom_ai_learn, custom_ai_dup,
custom_ai_destruct);
TarotAi *fuzzy;
TarotSolo *solo;
......@@ -284,7 +296,7 @@ play_game (TarotPerceptron * p, size_t n_players, int with_call)
next_seed) != TAROT_GAME_OK)
{
tarot_solo_free (solo);
ret = play_game (p, n_players, with_call);
ret = play_game (metric, p, n_players, with_call);
tarot_ai_free (fuzzy);
tarot_solo_free (solo);
return ret;
......@@ -319,6 +331,8 @@ play_game (TarotPerceptron * p, size_t n_players, int with_call)
tarot_ai_free (fuzzy);
ret = tarot_solo_get_alloc (solo);
tarot_solo_free (solo);
assert (n_metric != 0);
*metric = sum_metric / n_metric;
return ret;
}
......@@ -350,50 +364,88 @@ draw_options (size_t *n_players, int *with_call)
}
static inline TarotGame *
generate (TarotPerceptron * perceptron)
generate (double *metric, TarotPerceptron * perceptron)
{
size_t n_players;
int with_call;
TarotGame *played;
draw_options (&n_players, &with_call);
played = play_game (perceptron, n_players, with_call);
played = play_game (metric, perceptron, n_players, with_call);
return played;
}
static void
self_learn (TarotPerceptron * perceptron)
epoch (TarotPerceptron * perceptron)
{
TarotGame *generated = generate (perceptron);
static size_t silence = 100;
tarot_game_free (generated);
if (--silence == 0)
size_t i = 0;
double *initial_data;
size_t n_weights;
double *updates;
double u_max = 0, p_max = 0;
double sum_metric = 0;
double n_metric = 0;
tarot_perceptron_save_alloc (perceptron, &n_weights, &initial_data);
updates = xcalloc (n_weights, sizeof (double));
for (i = 0; i < 100; i++)
{
double *parameters;
size_t n_parameters;
size_t i;
double p_max = 0;
silence = 100;
tarot_perceptron_save_alloc (perceptron, &n_parameters, &parameters);
for (i = 0; i < n_parameters; i++)
TarotPerceptron *my_perceptron = tarot_perceptron_dup (perceptron);
double *final_data;
size_t n_final_weights;
size_t j;
double metric = self_learn (my_perceptron);
tarot_perceptron_save_alloc (my_perceptron, &n_final_weights,
&final_data);
tarot_perceptron_free (my_perceptron);
assert (n_weights == n_final_weights);
/* Aggregation */
sum_metric += metric;
n_metric += 1;
for (j = 0; j < n_final_weights; j++)
{
double p = parameters[i];
double abs = p;
if (abs < 0)
{
abs = -abs;
}
if (i != 0)
{
printf (", ");
}
printf ("%f", p);
if (abs >= p_max)
{
p_max = abs;
}
double u = final_data[j] - initial_data[j];
updates[j] += u;
}
free (final_data);
}
for (i = 0; i < n_weights; i++)
{
double u_abs = updates[i];
double p_abs = initial_data[i] + updates[i];
initial_data[i] += updates[i];
if (u_abs < 0)
{
u_abs = -u_abs;
}
if (p_abs < 0)
{
p_abs = -p_abs;
}
if (u_max < u_abs)
{
u_max = u_abs;
}
if (p_max < p_abs)
{
p_max = p_abs;
}
printf ("\n");
fprintf (stderr, "%.6e\t%.6e\n", metric, p_max);
free (parameters);
if (i != 0)
{
printf (", ");
}
printf ("%f", initial_data[i]);
}
free (updates);
printf ("\n");
fprintf (stderr, "%.6e\t%.6e\t%.6e\n", sum_metric / n_metric, p_max, u_max);
tarot_perceptron_load (perceptron, 0, n_weights, initial_data);
free (initial_data);
}
static double
self_learn (TarotPerceptron * perceptron)
{
double metric = 0;
TarotGame *generated = generate (&metric, perceptron);
tarot_game_free (generated);
return metric;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment