|
|
ec0d7e |
#ifndef NNTRAIN_INC_C
|
|
|
ec0d7e |
#define NNTRAIN_INC_C
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
#include "nnlayer.inc.c"
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
typedef struct NeuralTrainer {
|
|
|
ec0d7e |
int sizeX, sizeY, count;
|
|
|
ec0d7e |
double *x, *y;
|
|
|
ec0d7e |
} NeuralTrainer;
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
NeuralTrainer* ntNew(int sizeX, int sizeY, int count) {
|
|
|
ec0d7e |
assert(sizeX > 0);
|
|
|
ec0d7e |
assert(sizeY > 0);
|
|
|
ec0d7e |
assert(count > 0);
|
|
|
ec0d7e |
NeuralTrainer *nt = calloc(sizeof(NeuralTrainer), 1);
|
|
|
ec0d7e |
nt->sizeX = sizeX;
|
|
|
ec0d7e |
nt->sizeY = sizeY;
|
|
|
ec0d7e |
nt->count = count;
|
|
|
ec0d7e |
nt->x = calloc(sizeof(double)*(sizeX + sizeY)*count, 1);
|
|
|
ec0d7e |
nt->y = nt->x + sizeX*count;
|
|
|
ec0d7e |
return nt;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
void ntFree(NeuralTrainer *nt) {
|
|
|
ec0d7e |
free(nt->x);
|
|
|
ec0d7e |
free(nt);
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
double ntTrain(NeuralTrainer *nt, NeuralLayer *nl, int successCount, int blockSize, double qmin) {
|
|
|
ec0d7e |
assert(!nl->prev);
|
|
|
ec0d7e |
assert(nt->sizeX == nl->size);
|
|
|
ec0d7e |
assert(nt->sizeY == nlBack(nl)->size);
|
|
|
ec0d7e |
assert(blockSize > 0 && qmin > 0);
|
|
|
ec0d7e |
|
|
|
ec0d7e |
printf("training: %d, %lf\n", blockSize, qmin);
|
|
|
ec0d7e |
double **blockXY = calloc(sizeof(double)*2, blockSize);
|
|
|
ec0d7e |
double qmin2 = qmin*0.75;
|
|
|
ec0d7e |
double qmin3 = qmin2*0.75;
|
|
|
ec0d7e |
|
|
|
ec0d7e |
int success = 0;
|
|
|
ec0d7e |
int total = 0;
|
|
|
ec0d7e |
int repeats, blockRepeats;
|
|
|
ec0d7e |
double qmax0, qsum0, qmax, qsum;
|
|
|
ec0d7e |
for(int i = 0; i < 10000; ++i) {
|
|
|
ec0d7e |
for(int i = 0; i < blockSize; ++i) {
|
|
|
ec0d7e |
int index = rand() % nt->count;
|
|
|
ec0d7e |
blockXY[i*2 + 0] = nt->x + nt->sizeX*index;
|
|
|
ec0d7e |
blockXY[i*2 + 1] = nt->y + nt->sizeY*index;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
repeats = blockRepeats = 0;
|
|
|
ec0d7e |
qmax0 = qsum0 = 0;
|
|
|
ec0d7e |
for(int i = 0; i < 1000; ++i) {
|
|
|
ec0d7e |
double **xy = blockXY;
|
|
|
ec0d7e |
qmax = 0, qsum = 0;
|
|
|
ec0d7e |
for(int i = 0; i < blockSize; ++i, xy += 2) {
|
|
|
ec0d7e |
double q0 = 0;
|
|
|
ec0d7e |
for(int i = 0; i < 100; ++i) {
|
|
|
ec0d7e |
double q = nlTrainPass(nl, xy[0], xy[1], qmin3);
|
|
|
ec0d7e |
if (!i) q0 = q;
|
|
|
ec0d7e |
++repeats;
|
|
|
ec0d7e |
if (q < qmin3) break;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
qsum += q0;
|
|
|
ec0d7e |
if (qmax < q0) qmax = q0;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
if (!i) { qmax0 = qmax; qsum0 = qsum; }
|
|
|
ec0d7e |
++blockRepeats;
|
|
|
ec0d7e |
if (qmax <= qmin2) break;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
total += repeats;
|
|
|
ec0d7e |
|
|
|
ec0d7e |
printf(" blocks %d (samples: %d, total: %d, repeats: %3d (%lf)): %lf -> %lf, %lf -> %lf\n",
|
|
|
ec0d7e |
i+1, (i+1)*blockSize, total, blockRepeats-1, repeats/(double)(blockRepeats*blockSize) - 1, qmax0, qmax, qsum0/blockSize, qsum/blockSize);
|
|
|
ec0d7e |
|
|
|
ec0d7e |
if (qmax0 <= qmin) {
|
|
|
ec0d7e |
if (++success == successCount) break;
|
|
|
ec0d7e |
} else {
|
|
|
ec0d7e |
success = 0;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
free(blockXY);
|
|
|
ec0d7e |
printf("done\n");
|
|
|
ec0d7e |
return qmax0;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
NeuralTrainer* ntNewSymbolMap(const char *filename, int sizeX, int sizeY) {
|
|
|
ec0d7e |
FILE *f = fopen(filename, "rb");
|
|
|
ec0d7e |
if (!f)
|
|
|
ec0d7e |
return printf("cannot open file '%s' for read\n", filename), NULL;
|
|
|
ec0d7e |
fseek(f, 0, SEEK_END);
|
|
|
ec0d7e |
size_t fs = ftell(f);
|
|
|
ec0d7e |
fseek(f, 0, SEEK_SET);
|
|
|
ec0d7e |
|
|
|
ec0d7e |
size_t testSize = sizeX + 1;
|
|
|
ec0d7e |
int count = fs/testSize;
|
|
|
ec0d7e |
if (!count)
|
|
|
ec0d7e |
return printf("file '%s' is lesser minimal size\n", filename), fclose(f), NULL;
|
|
|
ec0d7e |
|
|
|
ec0d7e |
unsigned char *data = calloc(testSize, count);
|
|
|
ec0d7e |
if (count != fread(data, testSize, count, f))
|
|
|
56d550 |
return printf("cannot read from file '%s'\n", filename), free(data), fclose(f), NULL;
|
|
|
ec0d7e |
|
|
|
ec0d7e |
fclose(f);
|
|
|
ec0d7e |
|
|
|
ec0d7e |
NeuralTrainer *nt = ntNew(sizeX, sizeY, count);
|
|
|
ec0d7e |
const unsigned char *d = data;
|
|
|
ec0d7e |
double *x = nt->x, *y = nt->y, *ey = y + sizeY*count;
|
|
|
ec0d7e |
const double delta = 0;
|
|
|
ec0d7e |
for(double *p = y; p < ey; ++p) *p = delta;
|
|
|
ec0d7e |
while(y < ey) {
|
|
|
ec0d7e |
for(double *e = x + sizeX; x < e; ++x, ++d)
|
|
|
ec0d7e |
*x = *d/255.0;
|
|
|
ec0d7e |
assert(*d < sizeY);
|
|
|
ec0d7e |
y[*d++] = 1 - delta;
|
|
|
ec0d7e |
y += sizeY;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
return nt;
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
void ntPrintSymbol(NeuralTrainer *nt, int index, int width) {
|
|
|
ec0d7e |
assert(index >= 0 && index < nt->count);
|
|
|
ec0d7e |
assert(width > 0);
|
|
|
ec0d7e |
for(int i = 0; i < nt->sizeX; ++i) {
|
|
|
ec0d7e |
if (i && !(i % width)) printf("\n");
|
|
|
ec0d7e |
printf("%c", nt->x[nt->sizeX*index + i] > 0 ? '#' : '.');
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
printf("\n");
|
|
|
ec0d7e |
for(int i = 0; i < nt->sizeY; ++i)
|
|
|
ec0d7e |
printf(" %4.1lf", nt->y[nt->sizeY*index + i]);
|
|
|
ec0d7e |
printf("\n");
|
|
|
ec0d7e |
}
|
|
|
ec0d7e |
|
|
|
ec0d7e |
|
|
|
ec0d7e |
#endif
|