#ifndef NNTRAIN_INC_CPP
#define NNTRAIN_INC_CPP
#include "nnlayer.inc.cpp"
class Trainer {
public:
int sizeX, sizeY, count;
double *x, *y;
Trainer(): sizeX(), sizeY(), count(), x(), y() { }
Trainer(int sizeX, int sizeY, int count): Trainer()
{ init(sizeX, sizeY, count); }
~Trainer()
{ if (count) delete[] x; }
void init(int sizeX, int sizeY, int count) {
assert(sizeX > 0);
assert(sizeY > 0);
assert(count > 0);
this->sizeX = sizeX;
this->sizeY = sizeY;
this->count = count;
x = new double[(sizeX + sizeY)*count];
y = x + sizeX*count;
memset(x, 0, sizeof(*x)*(sizeX + sizeY)*count);
}
void deinit() {
if (!count) return;
delete[] x;
sizeX = sizeY = count = 0;
x = y = nullptr;
}
double train(Layer &l, int successCount, int blockSize, double qmin) {
assert(count);
assert(!l.prev);
assert(sizeX == l.size);
assert(sizeY == l.back().size);
assert(blockSize > 0 && qmin > 0);
printf("training: %d, %lf\n", blockSize, qmin);
double **blockXY = new double*[blockSize*2];
double qmin2 = qmin*0.9;
double qmin3 = qmin2*0.9;
int success = 0;
int total = 0;
int repeats, blockRepeats;
double qmax0, qsum0, qmax, qsum;
for(int i = 0; i < 10000; ++i) {
for(int i = 0; i < blockSize; ++i) {
int index = rand() % count;
blockXY[i*2 + 0] = x + sizeX*index;
blockXY[i*2 + 1] = y + sizeY*index;
}
repeats = blockRepeats = 0;
qmax0 = qsum0 = 0;
for(int i = 0; i < 1000; ++i) {
double **xy = blockXY;
qmax = 0, qsum = 0;
for(int i = 0; i < blockSize; ++i, xy += 2) {
double q0 = 0;
for(int i = 0; i < 100; ++i) {
double q = l.trainPass(xy[0], xy[1], qmin3);
if (!i) q0 = q;
++repeats;
if (q < qmin3) break;
}
qsum += q0;
if (qmax < q0) qmax = q0;
}
if (!i) { qmax0 = qmax; qsum0 = qsum; }
++blockRepeats;
if (qmax <= qmin2) break;
}
total += repeats;
printf(" blocks %d (samples: %d, total: %d, repeats: %3d (%lf)): %lf -> %lf, %lf -> %lf\n",
i+1, (i+1)*blockSize, total, blockRepeats-1, repeats/(double)(blockRepeats*blockSize) - 1, qmax0, qmax, qsum0/blockSize, qsum/blockSize);
if (qmax0 > qmin) success = 0; else
if (++success == successCount) break;
}
free(blockXY);
printf("done\n");
return qmax0;
}
bool loadSymbolMap(const char *filename, int sizeX, int sizeY) {
deinit();
FILE *f = fopen(filename, "rb");
if (!f)
return printf("cannot open file '%s' for read\n", filename), false;
fseek(f, 0, SEEK_END);
size_t fs = ftell(f);
fseek(f, 0, SEEK_SET);
size_t testSize = sizeX + 1;
int count = fs/testSize;
if (!count)
return printf("file '%s' is lesser minimal size\n", filename), fclose(f), false;
unsigned char *data = new unsigned char[testSize*count];
memset(data, 0, testSize*count);
if (!fread(data, testSize*count, 1, f))
return printf("cannot read from file '%s'\n", filename), free(data), fclose(f), false;
fclose(f);
init(sizeX, sizeY, count);
const unsigned char *pd = data;
const double delta = 0;
double *ey = y + sizeY*count;
for(double *py = y; py < ey; ++py) *py = delta;
for(double *px = x, *py = y; py < ey; py += sizeY) {
for(double *ex = px + sizeX; px < ex; ++px, ++pd)
*px = *pd/255.0;
assert(*pd < sizeY);
py[*pd++] = 1 - delta;
}
delete[] data;
return true;
}
void printSymbol(int index, int width) {
assert(index >= 0 && index < count);
assert(width > 0);
for(int i = 0; i < sizeX; ++i) {
if (i && !(i % width)) printf("\n");
printf("%c", x[sizeX*index + i] > 0 ? '#' : '.');
}
printf("\n");
for(int i = 0; i < sizeY; ++i)
printf(" %4.1lf", y[sizeY*index + i]);
printf("\n");
}
};
#endif