|
|
53488e |
#ifndef NNLAYER3_INC_CPP
|
|
|
53488e |
#define NNLAYER3_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(T), 1, f); }
|
|
|
53488e |
template<typename t=""></typename>
|
|
|
53488e |
bool tread(T &x, FILE *f)
|
|
|
53488e |
{ return fread(&x, sizeof(T), 1, f); }
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
struct Neuron {
|
|
|
53488e |
Real v, d;
|
|
|
53488e |
};
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
class Layer {
|
|
|
53488e |
public:
|
|
|
53488e |
Layer *prev, *next;
|
|
|
53488e |
|
|
|
53488e |
int sx, sy, sz, sl;
|
|
|
53488e |
Neuron *neurons;
|
|
|
53488e |
Real *weights;
|
|
|
53488e |
int *invWeights;
|
|
|
53488e |
int *invNeurons;
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
explicit Layer(Layer *prev = nullptr, int sx = 0, int sy = 0, int sz = 0, int sl = 0):
|
|
|
53488e |
prev(), next(), sx(), sy(), sz(), sl(), neurons(), weights(), invWeights(), invNeurons()
|
|
|
53488e |
{
|
|
|
53488e |
while(prev && prev->next) prev = prev->next;
|
|
|
53488e |
if (prev) prev->next = this;
|
|
|
53488e |
this->prev = prev;
|
|
|
53488e |
init(sx, sy, sz, sl);
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
virtual ~Layer() {
|
|
|
53488e |
clear();
|
|
|
53488e |
if (next) delete next;
|
|
|
53488e |
if (prev) prev->next = nullptr;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
void clear() {
|
|
|
53488e |
if (next) next->clear();
|
|
|
53488e |
if (neurons) delete[] neurons;
|
|
|
53488e |
if (weights) delete[] weights;
|
|
|
53488e |
if (invWeights) delete[] invWeights;
|
|
|
53488e |
sx = sy = sz = sl = 0;
|
|
|
53488e |
neurons = nullptr;
|
|
|
53488e |
weights = nullptr;
|
|
|
53488e |
invWeights = nullptr;
|
|
|
53488e |
invNeurons = nullptr;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
bool init(int sx, int sy, int sz, int sl = 0) {
|
|
|
53488e |
clear();
|
|
|
53488e |
if (prev && !prev->countNeurons()) return false;
|
|
|
53488e |
if (sx <= 0 || sy <= 0 || sz <= 0) return false;
|
|
|
53488e |
if (prev ? (sl <= 0 || sl > prev->sx || sl > prev->sy) : sl != 0) return false;
|
|
|
53488e |
printf("init %d %d %d %d\n", sx, sy, sz, sl);
|
|
|
53488e |
|
|
|
53488e |
this->sx = sx;
|
|
|
53488e |
this->sy = sy;
|
|
|
53488e |
this->sz = sz;
|
|
|
53488e |
|
|
|
53488e |
int size = sx*sy*sz;
|
|
|
53488e |
neurons = new Neuron[size];
|
|
|
53488e |
memset(neurons, 0, sizeof(*neurons)*size);
|
|
|
53488e |
|
|
|
53488e |
if (prev) {
|
|
|
53488e |
int psx = prev->sx;
|
|
|
53488e |
int psy = prev->sy;
|
|
|
53488e |
int psz = prev->sz;
|
|
|
53488e |
int psize = psx*psy*psz;
|
|
|
53488e |
|
|
|
53488e |
this->sl = sl;
|
|
|
53488e |
int wsize = size*sl*sl*psz;
|
|
|
53488e |
weights = new Real[wsize];
|
|
|
53488e |
double k = 1.0/(sl*sl*psz);
|
|
|
53488e |
for(int i = 0; i < wsize; ++i)
|
|
|
53488e |
weights[i] = Real( (rand()/(double)RAND_MAX*2 - 1)*k );
|
|
|
53488e |
|
|
|
53488e |
struct Link {
|
|
|
53488e |
int n, w;
|
|
|
53488e |
inline bool operator< (const Link &b) const
|
|
|
53488e |
{ return n < b.n ? true : (b.n < n ? false : w < b.w); }
|
|
|
53488e |
} *links = new Link[wsize], *il = links;
|
|
|
53488e |
|
|
|
53488e |
int dx = sx > 1 ? sx - 1 : 1;
|
|
|
53488e |
int dy = sy > 1 ? sy - 1 : 1;
|
|
|
53488e |
|
|
|
53488e |
for(int y = 0; y < sy; ++y)
|
|
|
53488e |
for(int x = 0; x < sx; ++x) {
|
|
|
53488e |
int py = y*(psy-sl)/dy;
|
|
|
53488e |
int px = x*(psx-sl)/dx;
|
|
|
53488e |
assert(py >= 0 && py <= psy-sl);
|
|
|
53488e |
assert(px >= 0 && px <= psx-sl);
|
|
|
53488e |
|
|
|
53488e |
for(int z = 0; z < sz; ++z)
|
|
|
53488e |
for(int ly = 0; ly < sl; ++ly)
|
|
|
53488e |
for(int lx = 0; lx < sl; ++lx)
|
|
|
53488e |
for(int pz = 0; pz < psz; ++pz, ++il) {
|
|
|
53488e |
assert(il < links + wsize);
|
|
|
53488e |
il->n = ((py+ly)*psx + px+lx)*psz + pz;
|
|
|
53488e |
il->w = il - links;
|
|
|
53488e |
assert(il->n >= 0 && il->n < psize);
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
assert(il == links + wsize);
|
|
|
53488e |
std::sort(links, il);
|
|
|
53488e |
|
|
|
53488e |
invWeights = new int[wsize + psize + 1];
|
|
|
53488e |
invNeurons = invWeights + wsize;
|
|
|
53488e |
invNeurons[0] = 0;
|
|
|
53488e |
int pni = 0;
|
|
|
53488e |
for(int i = 0; i < wsize; ++i) {
|
|
|
53488e |
assert(pni == links[i].n || pni == links[i].n + 1);
|
|
|
53488e |
invWeights[i] = links[i].w;
|
|
|
53488e |
if (pni == links[i].n)
|
|
|
53488e |
invNeurons[pni++] = i;
|
|
|
53488e |
}
|
|
|
53488e |
assert(pni == psize);
|
|
|
53488e |
invNeurons[psize] = wsize;
|
|
|
53488e |
|
|
|
53488e |
delete[] links;
|
|
|
53488e |
}
|
|
|
53488e |
return true;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool save(FILE *f) const {
|
|
|
53488e |
return twrite(sx, f) && twrite(sy, f) && twrite(sz, f) && twrite(sl, f)
|
|
|
53488e |
&& (!weights || fwrite(weights, sizeof(*weights)*sx*sy*sz*sl*sl*prev->sz, 1, f));
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool load(FILE *f) {
|
|
|
53488e |
clear();
|
|
|
53488e |
int sx = 0, sy = 0, sz = 0, sl = 0;
|
|
|
53488e |
return tread(sx, f) && tread(sy, f) && tread(sz, f) && tread(sl, f) && init(sx, sy, sz, sl)
|
|
|
53488e |
&& (!weights || fread(weights, sizeof(*weights)*sx*sy*sz*sl*sl*prev->sz, 1, f));
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
bool saveAll(FILE *f) const
|
|
|
53488e |
{ return save(f) && (!next || next->saveAll(f)); }
|
|
|
53488e |
bool loadAll(FILE *f)
|
|
|
53488e |
{ return load(f) && (!next || next->loadAll(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 |
inline int countNeurons() const
|
|
|
53488e |
{ return sx*sy*sz; }
|
|
|
53488e |
inline int linksPerNeuron() const
|
|
|
53488e |
{ return prev ? sl*sl*prev->sz : 0; }
|
|
|
53488e |
inline int countLinks() const
|
|
|
53488e |
{ return countNeurons() * linksPerNeuron(); }
|
|
|
53488e |
inline size_t memSize() const {
|
|
|
53488e |
return sizeof(*neurons)*countNeurons()
|
|
|
53488e |
+ (sizeof(*weights) + sizeof(*invWeights))*countLinks()
|
|
|
53488e |
+ (prev ? sizeof(*invNeurons)*(prev->countNeurons() + 1) : 0);
|
|
|
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->countNeurons(); return t; }
|
|
|
53488e |
int totalLinks() const
|
|
|
53488e |
{ int t = 0; for(const Layer *l = this; l; l = l->next) t += l->countLinks(); return t; }
|
|
|
53488e |
size_t totalMemSize() const
|
|
|
53488e |
{ size_t t = 0; for(const Layer *l = this; l; l = l->next) t += l->memSize(); return t; }
|
|
|
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 |
|
|
|
53488e |
void pass(int y0, int y1) {
|
|
|
53488e |
if (!prev) return;
|
|
|
53488e |
|
|
|
53488e |
int sx = this->sx;
|
|
|
53488e |
int sy = this->sy;
|
|
|
53488e |
int sz = this->sz;
|
|
|
53488e |
int sxz = sx*sz;
|
|
|
53488e |
|
|
|
53488e |
int psx = prev->sx;
|
|
|
53488e |
int psy = prev->sy;
|
|
|
53488e |
int psz = prev->sz;
|
|
|
53488e |
int psxz = psx*psz;
|
|
|
53488e |
Neuron *pneurons = prev->neurons;
|
|
|
53488e |
|
|
|
53488e |
int sl = this->sl;
|
|
|
53488e |
int slpz = sl*psz;
|
|
|
53488e |
int sllpz = sl*slpz;
|
|
|
53488e |
|
|
|
53488e |
int ldy = psxz - slpz;
|
|
|
53488e |
|
|
|
53488e |
int kpx = psx-sl, dpx = sx>1 ? sx-1 : 1;
|
|
|
53488e |
int kpy = psy-sl, dpy = sy>1 ? sy-1 : 1;
|
|
|
53488e |
|
|
|
53488e |
Real *iw = weights + y0*sxz*sllpz;
|
|
|
53488e |
Neuron *in = neurons + y0*sxz;
|
|
|
53488e |
int fpy = y0*kpy;
|
|
|
53488e |
for(Neuron *e = in + (y1-y0)*sxz; in < e; fpy += kpy) {
|
|
|
53488e |
Neuron *pnrow = pneurons + fpy/dpy*psxz;
|
|
|
53488e |
|
|
|
53488e |
int fpx = 0;
|
|
|
53488e |
for(Neuron *e = in + sxz; in < e; fpx += kpx) {
|
|
|
53488e |
Neuron *pn = pnrow + fpx/dpx*psz;
|
|
|
53488e |
|
|
|
53488e |
for(Neuron *e = in + sz; in < e; ++in) {
|
|
|
53488e |
double s = 0;
|
|
|
53488e |
|
|
|
53488e |
Neuron *ipn = pn;
|
|
|
53488e |
for(Real *e = iw + sllpz; iw < e; ipn += ldy)
|
|
|
53488e |
for(Real *e = iw + slpz; iw < e; ++iw, ++ipn)
|
|
|
53488e |
s += *iw * ipn->v;
|
|
|
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 |
}
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
void backpassWeights(int y0, int y1) {
|
|
|
53488e |
assert(prev);
|
|
|
53488e |
|
|
|
53488e |
int sx = this->sx;
|
|
|
53488e |
int sy = this->sy;
|
|
|
53488e |
int sz = this->sz;
|
|
|
53488e |
int sxz = sx*sz;
|
|
|
53488e |
|
|
|
53488e |
int psx = prev->sx;
|
|
|
53488e |
int psy = prev->sy;
|
|
|
53488e |
int psz = prev->sz;
|
|
|
53488e |
int psxz = psx*psz;
|
|
|
53488e |
Neuron *pneurons = prev->neurons;
|
|
|
53488e |
|
|
|
53488e |
int sl = this->sl;
|
|
|
53488e |
int slpz = sl*psz;
|
|
|
53488e |
int sllpz = sl*slpz;
|
|
|
53488e |
|
|
|
53488e |
int ldy = psxz - slpz;
|
|
|
53488e |
|
|
|
53488e |
int kpx = psx-sl, dpx = sx>1 ? sx-1 : 1;
|
|
|
53488e |
int kpy = psy-sl, dpy = sy>1 ? sy-1 : 1;
|
|
|
53488e |
|
|
|
53488e |
Real *iw = weights + y0*sxz*sllpz;
|
|
|
53488e |
Neuron *in = neurons + y0*sxz;
|
|
|
53488e |
int fpy = y0*kpy;
|
|
|
53488e |
for(Neuron *e = in + (y1-y0)*sxz; in < e; fpy += kpy) {
|
|
|
53488e |
Neuron *pnrow = pneurons + fpy/dpy*psxz;
|
|
|
53488e |
|
|
|
53488e |
int fpx = 0;
|
|
|
53488e |
for(Neuron *e = in + sxz; in < e; fpx += kpx) {
|
|
|
53488e |
Neuron *pn = pnrow + fpx/dpx*psz;
|
|
|
53488e |
|
|
|
53488e |
for(Neuron *e = in + sz; in < e; ++in) {
|
|
|
53488e |
Real d = in->d;
|
|
|
53488e |
|
|
|
53488e |
Neuron *ipn = pn;
|
|
|
53488e |
for(Real *e = iw + sllpz; iw < e; ipn += ldy)
|
|
|
53488e |
for(Real *e = iw + slpz; iw < e; ++iw, ++ipn)
|
|
|
53488e |
*iw += ipn->v * d;
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
template<bool withweights=""></bool>
|
|
|
53488e |
void backpassTpl(int y0, int y1) {
|
|
|
53488e |
assert(next);
|
|
|
53488e |
|
|
|
53488e |
Neuron *nneurons = next->neurons;
|
|
|
53488e |
Real *nweights = next->weights;
|
|
|
53488e |
int *nInvWeights = next->invWeights;
|
|
|
53488e |
int lpn = next->linksPerNeuron();
|
|
|
53488e |
|
|
|
53488e |
int sxz = sx*sz;
|
|
|
53488e |
|
|
|
53488e |
Neuron *in = neurons + y0*sxz;
|
|
|
53488e |
int *inni = next->invNeurons + y0*sxz;
|
|
|
53488e |
for(Neuron *e = in + (y1-y0)*sxz; in < e; ++in) {
|
|
|
53488e |
Real v = in->v;
|
|
|
53488e |
double s = 0;
|
|
|
53488e |
|
|
|
53488e |
int *iw = nInvWeights + *inni++;
|
|
|
53488e |
for(int *e = nInvWeights + *inni; iw < e; ++iw) {
|
|
|
53488e |
int wi = *iw;
|
|
|
53488e |
Real d = nneurons[wi/lpn].d;
|
|
|
53488e |
Real &nw = nweights[wi];
|
|
|
53488e |
s += nw * d;
|
|
|
53488e |
if (WithWeights) nw += d * v;
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
in->d *= s;
|
|
|
53488e |
}
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void passAll() {
|
|
|
53488e |
if (prev) pass(0, sy);
|
|
|
53488e |
if (next) next->passAll();
|
|
|
53488e |
}
|
|
|
53488e |
|
|
|
53488e |
void backpassAll() {
|
|
|
53488e |
if (!prev)
|
|
|
53488e |
return;
|
|
|
53488e |
if (!prev->prev)
|
|
|
53488e |
{ backpassWeights(0, sy); return; }
|
|
|
53488e |
if (next)
|
|
|
53488e |
backpassTpl<true>(0, sy);</true>
|
|
|
53488e |
return prev->backpassAll();
|
|
|
53488e |
}
|
|
|
53488e |
};
|
|
|
53488e |
|
|
|
53488e |
|
|
|
53488e |
#endif
|