|
|
53488e |
#ifndef NNLAYER2_INC_CPP
|
|
|
53488e |
#define NNLAYER2_INC_CPP
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
#include <cmath></cmath>
|
|
|
53488e |
#include <cstdio></cstdio>
|
|
|
53488e |
#include <cstdlib></cstdlib>
|
|
|
53488e |
#include <cstring></cstring>
|
|
|
53488e |
#include <cassert></cassert>
|
|
|
53488e |
|
|
|
53488e |
#include <vector></vector>
|
|
|
53488e |
#include <algorithm></algorithm>
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
typedef float Real;
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
template<typename t=""></typename>
|
|
|
53488e |
bool twrite(const T &x, FILE *f)
|
|
|
53488e |
{ return fwrite(&x, sizeof(x), 1, f); }
|
|
|
53488e |
template<typename t=""></typename>
|
|
|
53488e |
bool tread(const T &x, FILE *f)
|
|
|
53488e |
{ return fwrite(&x, sizeof(x), 1, f); }
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
struct Link;
|
|
|
53488e |
struct Neuron {
|
|
|
53488e |
Real v, d;
|
|
|
53488e |
inline Neuron(): v(), d() { }
|
|
|
53488e |
};
|
|
|
53488e |
|
|
|
53488e |
struct Link {
|
|
|
53488e |
int nprev, lnext;
|
|
|
53488e |
Real w;
|
|
|
53488e |
inline Link(): nprev(), lnext(), w((Real)rand()/(Real)RAND_MAX*2 - 1) { }
|
|
|
53488e |
};
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
class Layer {
|
|
|
53488e |
public:
|
|
|
53488e |
Layer *prev, *next;
|
|
|
53488e |
|
|
|
53488e |
int size, lsize;
|
|
|
53488e |
Neuron *neurons;
|
|
|
53488e |
Link *links;
|
|
|
53488e |
int lfirst;
|
|
|
53488e |
|
|
|
53488e |
explicit Layer(Layer *prev = nullptr, int size = 0, int lsize = 0):
|
|
|
53488e |
prev(), next(), size(), lsize(), neurons(), links(), lfirst()
|
|
|
53488e |
{
|
|
|
53488e |
while(prev && prev->next) prev = prev->next;
|
|
|
53488e |
if (prev) prev->next = this;
|
|
|
53488e |
this->prev = prev;
|
|
|
53488e |
init(size, lsize);
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
virtual ~Layer() {
|
|
|
53488e |
if (next) delete next;
|
|
|
53488e |
if (prev) prev->next = nullptr;
|
|
|
53488e |
delete[] neurons;
|
|
|
53488e |
if (links) delete[] links;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool init(int size, int lsize = 0) {
|
|
|
53488e |
clear();
|
|
|
53488e |
if (size <= 0) return false;
|
|
|
53488e |
if (lsize < 0) lsize = 0;
|
|
|
53488e |
|
|
|
53488e |
if (prev ? lsize <= 0 : lsize) return false;
|
|
|
53488e |
if (size) neurons = new Neuron[size];
|
|
|
53488e |
if (lsize) links = new Link[lsize*size];
|
|
|
53488e |
this->size = size;
|
|
|
53488e |
this->lsize = lsize;
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void clear() {
|
|
|
53488e |
if (neurons) delete[] neurons;
|
|
|
53488e |
if (links) delete[] links;
|
|
|
53488e |
this->size = lsize = 0;
|
|
|
53488e |
neurons = nullptr;
|
|
|
53488e |
links = nullptr;
|
|
|
53488e |
lfirst = 0;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void prepareBackLinks() {
|
|
|
53488e |
if (!links || lsize <= 0) return;
|
|
|
53488e |
|
|
|
53488e |
lfirst = 0;
|
|
|
53488e |
int lend = size*lsize;
|
|
|
53488e |
for(Link *il = links, *e = il + lend; il < e; ++il) {
|
|
|
53488e |
assert(prev && prev->neurons && il->nprev >= 0 && il->nprev < prev->size);
|
|
|
53488e |
il->lnext = il - links + 1;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
while(true) {
|
|
|
53488e |
bool done = true;
|
|
|
53488e |
for(int *il = &lfirst; links[*il].lnext != lend; il = &links[*il].lnext) {
|
|
|
53488e |
int a = *il, b = links[a].lnext;
|
|
|
53488e |
if (links[a].nprev > links[b].nprev) {
|
|
|
53488e |
links[a].lnext = links[b].lnext;
|
|
|
53488e |
links[b].lnext = a;
|
|
|
53488e |
*il = b;
|
|
|
53488e |
done = false;
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
if (done) break;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
#ifndef NDEBUG
|
|
|
53488e |
if (lsize) {
|
|
|
53488e |
int next = 0;
|
|
|
53488e |
for(int il = lfirst; il != lend; il = links[il].lnext) {
|
|
|
53488e |
assert(links[il].nprev == next || links[il].nprev == next-1);
|
|
|
53488e |
if (links[il].nprev == next) ++next;
|
|
|
53488e |
}
|
|
|
53488e |
assert(next = prev->size);
|
|
|
53488e |
}
|
|
|
53488e |
#endif
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool save(FILE *f) const {
|
|
|
53488e |
if (!twrite(size, f) || !twrite(lsize, f))
|
|
|
53488e |
return false;
|
|
|
53488e |
for(Link *il = links, *e = il + lsize*size; il < e; ++il)
|
|
|
53488e |
if (!twrite(il->nprev, f) || !twrite(il->w, f))
|
|
|
53488e |
return false;
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool load(FILE *f) {
|
|
|
53488e |
clear();
|
|
|
53488e |
int size = 0, lsize = 0;
|
|
|
53488e |
if (!tread(size, f) || !tread(lsize, f) || !init(size, lsize))
|
|
|
53488e |
return false;
|
|
|
53488e |
for(Link *il = links, *e = il + lsize*size; il < e; ++il)
|
|
|
53488e |
if (!tread(il->nprev, f) || !tread(il->w, f) || !prev || !prev->neurons || il->nprev < 0 || il->nprev >= prev->size)
|
|
|
53488e |
return false;
|
|
|
53488e |
prepareBackLinks();
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool saveAll(FILE *f) const
|
|
|
53488e |
{ return save(f) && (!next || next->save(f)); }
|
|
|
53488e |
bool loadAll(FILE *f)
|
|
|
53488e |
{ return load(f) && (!next || next->load(f)); }
|
|
|
53488e |
|
|
|
53488e |
bool saveAll(const char *filename) const {
|
|
|
53488e |
assert(!prev);
|
|
|
53488e |
FILE *f = fopen(filename, "wb");
|
|
|
53488e |
if (!f)
|
|
|
53488e |
{ printf("cannot open file for write: %s\n", filename); return false; }
|
|
|
53488e |
int count = totalLayers();
|
|
|
53488e |
if (!twrite(count, f) || !saveAll(f))
|
|
|
53488e |
{ printf("cannot save to file: %s\n", filename); fclose(f); return false; }
|
|
|
53488e |
fclose(f);
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool loadAll(const char *filename) {
|
|
|
53488e |
assert(!prev);
|
|
|
53488e |
FILE *f = fopen(filename, "rb");
|
|
|
53488e |
if (!f)
|
|
|
53488e |
{ printf("cannot open file for read: %s\n", filename); return false; }
|
|
|
53488e |
int count = 0;
|
|
|
53488e |
if (!tread(count, f) || count <= 0)
|
|
|
53488e |
{ printf("cannot load from file: %s\n", filename); fclose(f); return false; }
|
|
|
53488e |
if (next)
|
|
|
53488e |
delete next;
|
|
|
53488e |
while(--count)
|
|
|
53488e |
new Layer(this);
|
|
|
53488e |
if (!loadAll(f))
|
|
|
53488e |
{ printf("cannot load from file: %s\n", filename); fclose(f); return false; }
|
|
|
53488e |
fclose(f);
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
int totalLayers() const
|
|
|
53488e |
{ int t = 0; for(const Layer *l = this; l; l = l->next) ++t; return t; }
|
|
|
53488e |
int totalNeurons() const
|
|
|
53488e |
{ int t = 0; for(const Layer *l = this; l; l = l->next) t += l->size; return t; }
|
|
|
53488e |
int totalLinks() const
|
|
|
53488e |
{ int t = 0; for(const Layer *l = this; l; l = l->next) t += l->size*l->lsize; return t; }
|
|
|
53488e |
inline size_t totalMemSize() const
|
|
|
53488e |
{ return totalNeurons()*sizeof(Neuron) + totalLinks()*sizeof(Link); }
|
|
|
53488e |
|
|
|
53488e |
inline Layer& front()
|
|
|
53488e |
{ Layer *l = this; while(l->prev) l = l->prev; return *l; }
|
|
|
53488e |
inline Layer& back()
|
|
|
53488e |
{ Layer *l = this; while(l->next) l = l->next; return *l; }
|
|
|
53488e |
|
|
|
53488e |
void pass(int nb, int ne) {
|
|
|
53488e |
assert(prev);
|
|
|
53488e |
int lsize = this->lsize;
|
|
|
53488e |
Neuron *pn = prev->neurons;
|
|
|
53488e |
Link *il = links + nb*lsize;
|
|
|
53488e |
for(Neuron *in = neurons + nb, *e = neurons + ne; in < e; ++in) {
|
|
|
53488e |
double s = 0;
|
|
|
53488e |
for(Link *e = il + lsize; il < e; ++il)
|
|
|
53488e |
s += pn[il->nprev].v * il->w;
|
|
|
53488e |
|
|
|
53488e |
// exp sigmoid
|
|
|
53488e |
double ss = 1/(1 + exp(-s));
|
|
|
53488e |
in->v = ss;
|
|
|
53488e |
in->d = ss * (1-ss);
|
|
|
53488e |
|
|
|
53488e |
// 1/(x+1) sigmoid
|
|
|
53488e |
//double ss = 1/(1+fabs(s));
|
|
|
53488e |
//double ss2 = ss*0.5;
|
|
|
53488e |
//in->v = s > 0 ? 1 - ss2 : ss2;
|
|
|
53488e |
//in->d = ss2 * ss;
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
template<bool hasprev=""></bool>
|
|
|
53488e |
void backpassTpl(int lb, int le) {
|
|
|
53488e |
assert(hasPrev == (bool)prev);
|
|
|
53488e |
if (lb == le) return;
|
|
|
53488e |
Link *links = this->links;
|
|
|
53488e |
Neuron *neurons = this->neurons;
|
|
|
53488e |
Neuron *pneurons = prev->neurons;
|
|
|
53488e |
|
|
|
53488e |
double s = 0;
|
|
|
53488e |
int ipn = links[lb].nprev;
|
|
|
53488e |
for(int il = lb; il != le; ) {
|
|
|
53488e |
Link &l = links[il];
|
|
|
53488e |
if (hasPrev)
|
|
|
53488e |
if (ipn != l.nprev)
|
|
|
53488e |
{ pneurons[ipn].d *= s; ipn = l.nprev; }
|
|
|
53488e |
Neuron &n = neurons[ il/lsize ];
|
|
|
53488e |
Real d = n.d;
|
|
|
53488e |
if (hasPrev) s += d * l.w;
|
|
|
53488e |
l.w += d * n.v;
|
|
|
53488e |
il = l.lnext;
|
|
|
53488e |
}
|
|
|
53488e |
if (hasPrev)
|
|
|
53488e |
pneurons[ipn].d *= s;
|
|
|
53488e |
|
|
|
53488e |
assert(le == size*lsize || ipn < links[le].nprev);
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void backpass(int lb, int le) {
|
|
|
53488e |
if (prev) backpassTpl<true>(lb, le); else backpassTpl<false>(lb, le);</false></true>
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void passAll() {
|
|
|
53488e |
if (prev) pass(0, size);
|
|
|
53488e |
if (next) next->passAll();
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void backpassAll(Real k) {
|
|
|
53488e |
if (next) backpass(lfirst, size*lsize);
|
|
|
53488e |
if (prev) prev->passAll();
|
|
|
53488e |
}
|
|
|
53488e |
};
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
#endif
|