chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
(function(global) {
|
||||
"use strict";
|
||||
var Vol = global.Vol; // convenience
|
||||
|
||||
// a bit experimental layer for now. I think it works but I'm not 100%
|
||||
// the gradient check is a bit funky. I'll look into this a bit later.
|
||||
// Local Response Normalization in window, along depths of volumes
|
||||
var LocalResponseNormalizationLayer = function(opt) {
|
||||
var opt = opt || {};
|
||||
|
||||
// required
|
||||
this.k = opt.k;
|
||||
this.n = opt.n;
|
||||
this.alpha = opt.alpha;
|
||||
this.beta = opt.beta;
|
||||
|
||||
// computed
|
||||
this.out_sx = opt.in_sx;
|
||||
this.out_sy = opt.in_sy;
|
||||
this.out_depth = opt.in_depth;
|
||||
this.layer_type = 'lrn';
|
||||
|
||||
// checks
|
||||
if(this.n%2 === 0) { console.log('WARNING n should be odd for LRN layer'); }
|
||||
}
|
||||
LocalResponseNormalizationLayer.prototype = {
|
||||
forward: function(V, is_training) {
|
||||
this.in_act = V;
|
||||
|
||||
var A = V.cloneAndZero();
|
||||
this.S_cache_ = V.cloneAndZero();
|
||||
var n2 = Math.floor(this.n/2);
|
||||
for(var x=0;x<V.sx;x++) {
|
||||
for(var y=0;y<V.sy;y++) {
|
||||
for(var i=0;i<V.depth;i++) {
|
||||
|
||||
var ai = V.get(x,y,i);
|
||||
|
||||
// normalize in a window of size n
|
||||
var den = 0.0;
|
||||
for(var j=Math.max(0,i-n2);j<=Math.min(i+n2,V.depth-1);j++) {
|
||||
var aa = V.get(x,y,j);
|
||||
den += aa*aa;
|
||||
}
|
||||
den *= this.alpha / this.n;
|
||||
den += this.k;
|
||||
this.S_cache_.set(x,y,i,den); // will be useful for backprop
|
||||
den = Math.pow(den, this.beta);
|
||||
A.set(x,y,i,ai/den);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.out_act = A;
|
||||
return this.out_act; // dummy identity function for now
|
||||
},
|
||||
backward: function() {
|
||||
// evaluate gradient wrt data
|
||||
var V = this.in_act; // we need to set dw of this
|
||||
V.dw = global.zeros(V.w.length); // zero out gradient wrt data
|
||||
var A = this.out_act; // computed in forward pass
|
||||
|
||||
var n2 = Math.floor(this.n/2);
|
||||
for(var x=0;x<V.sx;x++) {
|
||||
for(var y=0;y<V.sy;y++) {
|
||||
for(var i=0;i<V.depth;i++) {
|
||||
|
||||
var chain_grad = this.out_act.get_grad(x,y,i);
|
||||
var S = this.S_cache_.get(x,y,i);
|
||||
var SB = Math.pow(S, this.beta);
|
||||
var SB2 = SB*SB;
|
||||
|
||||
// normalize in a window of size n
|
||||
for(var j=Math.max(0,i-n2);j<=Math.min(i+n2,V.depth-1);j++) {
|
||||
var aj = V.get(x,y,j);
|
||||
var g = -aj*this.beta*Math.pow(S,this.beta-1)*this.alpha/this.n*2*aj;
|
||||
if(j===i) g+= SB;
|
||||
g /= SB2;
|
||||
g *= chain_grad;
|
||||
V.add_grad(x,y,j,g);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getParamsAndGrads: function() { return []; },
|
||||
toJSON: function() {
|
||||
var json = {};
|
||||
json.k = this.k;
|
||||
json.n = this.n;
|
||||
json.alpha = this.alpha; // normalize by size
|
||||
json.beta = this.beta;
|
||||
json.out_sx = this.out_sx;
|
||||
json.out_sy = this.out_sy;
|
||||
json.out_depth = this.out_depth;
|
||||
json.layer_type = this.layer_type;
|
||||
return json;
|
||||
},
|
||||
fromJSON: function(json) {
|
||||
this.k = json.k;
|
||||
this.n = json.n;
|
||||
this.alpha = json.alpha; // normalize by size
|
||||
this.beta = json.beta;
|
||||
this.out_sx = json.out_sx;
|
||||
this.out_sy = json.out_sy;
|
||||
this.out_depth = json.out_depth;
|
||||
this.layer_type = json.layer_type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
global.LocalResponseNormalizationLayer = LocalResponseNormalizationLayer;
|
||||
})(convnetjs);
|
||||
Reference in New Issue
Block a user