Skip to content

Commit

Permalink
A major change
Browse files Browse the repository at this point in the history
1. get output layer removed, use loss instead
2. assign regularization to tensors
3. add timing module
4. Add backend for future promotion
  • Loading branch information
suquark committed Feb 13, 2017
1 parent a47417e commit 78fd151
Show file tree
Hide file tree
Showing 15 changed files with 295 additions and 198 deletions.
11 changes: 10 additions & 1 deletion RL/deepqlearn.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ class DQN {
return { action: maxk, value: action_values.w[maxk] };
}

_toarray(arr) {
let a = [];
for (let i in arr) {
a.push(arr[i]);
}
return a;
}

getNetInput(xt) {
// return s = (x, a, x, a, x, a, xt) state vector.
// It's a concatenation of last window_size (x,a) pairs and current state x
Expand All @@ -141,7 +149,8 @@ class DQN {
// action, encoded as 1-of-k indicator vector. We scale it up a bit because
// we dont want weight regularization to undervalue this information, as it only exists once
let action1ofk = one_hot(this.num_actions, action, 1.0 * this.num_states);
w = w.concat(action1ofk);

w = w.concat(this._toarray(action1ofk)); // do not concat array & floatarray
}
return w;
}
Expand Down
62 changes: 62 additions & 0 deletions backend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

/**
* ov = m * v
*/
function TensorVectorProduct(ov, m, v) {
let ncol = m.axis(-1) | 0;
let nrow = m.axis(-2) | 0;
let new_shape = m.shape.slice(); new_shape.pop();
let bs = ncol * nrow | 0;
let N = (m.size / bs) | 0;

let mw = m.w, vw = v.w, ow = ov.w;
ow.fill(0.);
for (let z = 0; z < N; z++) {
for (let i = 0; i < nrow; i++) {
for (let j = 0; j < ncol; j++) {
ow[z * nrow + i] += mw[z * bs + i * ncol + j] * vw[j];
}
}
}
}

/**
* ov += m' * v
*/
function TransposedTensorVectorProductAdd(ov, m, v) {
let ncol = m.axis(-1) | 0;
let nrow = m.axis(-2) | 0;
let new_shape = m.shape.slice();

// reverse order
let a = new_shape.pop();
new_shape.pop();
new_shape.push(a);

let bs = ncol * nrow | 0;
let N = (m.size / bs) | 0;

let mw = m.w, vw = v.w, ow = ov.w;
// ow.fill(0.);
for (let z = 0; z < N; z++) {
for (let i = 0; i < nrow; i++) {
for (let j = 0; j < ncol; j++) {
// transposed order
ow[z * ncol + j] += mw[z * bs + i * ncol + j] * vw[i];
}
}
}
}



/**
* HadmardProduct apply to self
*/
function HadmardProduct_s(o, x) {
let N = o.size, ow = o.w, xw = x.w;
for (let i = 0; i < N; i++) {
ow[i] *= xw;
}
}

14 changes: 11 additions & 3 deletions layers/activation.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ReLULayer extends ActivationLayer {
* f(x) = alpha * x for x < 0, f(x) = x for x >= 0
* the output is in (-Inf, inf)
*/
class LeakyReLULayer extends PActivationLayer {
class LeakyReLULayer extends ActivationLayer {
constructor(opt, leaky=0.2) {
super('lrelu', (y, x) => {
let N = x.size, xw = x.w, yw = y.w;
Expand All @@ -66,7 +66,7 @@ class LeakyReLULayer extends PActivationLayer {
* f(x) = ln(1+e^x)
* the output is in (0, inf)
*/
class SoftPlusLayer extends PActivationLayer {
class SoftPlusLayer extends ActivationLayer {
constructor(opt) {
super('softplus', (y, x) => {
let N = x.size, xw = x.w, yw = y.w;
Expand Down Expand Up @@ -316,10 +316,18 @@ class MaxoutLayer extends Layer {
}
}

export {
export {
TanhLayer, SoftSignLayer,
ReLULayer, LeakyReLULayer, ELULayer, SoftPlusLayer,
MaxoutLayer, SoftmaxLayer,
HardSigmoidLayer, SigmoidLayer
};

export default function() {
return {
'tanh': TanhLayer, 'softsign': SoftSignLayer,
'relu': ReLULayer, 'lrelu': LeakyReLULayer, 'elu': ELULayer, 'softplus': SoftPlusLayer,
'maxout': MaxoutLayer, 'softmax': SoftmaxLayer,
'hard_sigmoid': HardSigmoidLayer, 'sigmoid': SigmoidLayer
}
};
8 changes: 5 additions & 3 deletions layers/conv.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ConvLayer extends Layer {
// initializations
let bias = getopt(opt, 'bias_pref', 0.0);
this.filters = createMatrix(this.out_depth, this.in_depth);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = createVector(this.out_depth, bias);

// record updated values for updating
Expand Down Expand Up @@ -125,9 +126,9 @@ class ConvLayer extends Layer {
}
}

getParamsAndGrads() {
let response = this.filters.map(x => this._pack_vars(x));
response.push(this._pack_vars(this.biases, false));
get trainables() {
let response = this.filters.slice();
response.push(this.biases);
return response;
}

Expand All @@ -146,6 +147,7 @@ class ConvLayer extends Layer {
this.l2_decay_mul = getopt(json, 'l2_decay_mul', 1.0);

this.filters = json.filters.map(getVolFromJSON);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = getVolFromJSON(json.biases);
// record updated values for updating
this.updated = this.filters.concat([this.biases]);
Expand Down
11 changes: 6 additions & 5 deletions layers/deconv.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ class DeconvLayer extends Layer {
} else {
this.out_sy = get_deconv_outsize(this.in_sy, this.sy, this.stride, this.pad);
}



// initializations
let bias = getopt(opt, 'bias_pref', 0.0);
this.filters = createMatrix(this.out_depth, this.in_depth);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = createVector(this.out_depth, bias);

// record updated values for updating
Expand Down Expand Up @@ -99,9 +99,9 @@ class DeconvLayer extends Layer {
// Not implement
}

getParamsAndGrads() {
let response = this.filters.map(x => this._pack_vars(x));
response.push(this._pack_vars(this.biases, false));
get trainables() {
let response = this.filters.slice();
response.push(this.biases);
return response;
}

Expand All @@ -120,6 +120,7 @@ class DeconvLayer extends Layer {
this.l2_decay_mul = getopt(json, 'l2_decay_mul', 1.0);

this.filters = json.filters.map(getVolFromJSON);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = getVolFromJSON(json.biases);
}

Expand Down
25 changes: 18 additions & 7 deletions layers/fullconn.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { OutputLayer } from 'layers/layer.js';
import { Layer } from 'layers/layer.js';
import { Vol, createVector, createMatrix, getVolFromJSON } from 'vol.js';
import {getopt} from 'util.js';

class FullyConnLayer extends OutputLayer {
class FullyConnLayer extends Layer {

constructor (opt) {
opt.serialize = ['l1_decay_mul', 'l2_decay_mul'];
super('fc', opt);
// required
// ok fine we will allow 'filters' as the word as well
this.out_depth = getopt(opt, ['num_neurons', 'filters']);
// optional
// optional
this.l1_decay_mul = getopt(opt, 'l1_decay_mul', 0.0);
this.l2_decay_mul = getopt(opt, 'l2_decay_mul', 1.0);

Expand All @@ -19,6 +19,7 @@ class FullyConnLayer extends OutputLayer {
let bias = getopt(opt, 'bias_pref', 0.0);

this.filters = createMatrix(this.out_depth, this.num_inputs);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = createVector(this.out_depth, bias);
// record updated values for updating
this.updated = this.filters.concat([this.biases]);
Expand All @@ -37,6 +38,11 @@ class FullyConnLayer extends OutputLayer {
a += this.biases.w[i];
A.w[i] = a;
}

// TODO: patch this:
// TensorVectorProduct(this.out_act, this.filters, this.in_act);
// if (this.biases) TensorAdd_s(this.out_act, this.biases);

this.out_act = A;
return this.out_act;
}
Expand All @@ -46,7 +52,7 @@ class FullyConnLayer extends OutputLayer {
V.dw.fill(0.); // zero out the gradient in input Vol

// compute gradient wrt weights and data
for(let i = 0; i < this.out_depth; i++) {
for (let i = 0; i < this.out_depth; i++) {
let tfi = this.filters[i];
let chain_grad = this.out_act.dw[i];
for(let d = 0; d < this.num_inputs; d++) {
Expand All @@ -55,11 +61,15 @@ class FullyConnLayer extends OutputLayer {
}
this.biases.dw[i] += chain_grad;
}

// TransposedTensorVectorProductAdd(this.in_act, this.filters, this.out_act@dw)
// VectorProductAdd(this.filters, this.in_act, this.out_act@dw)
// TensorAdd_s(this.biases, this.out_act@dw)
}

getParamsAndGrads() {
let response = this.filters.map(x => this._pack_vars(x));
response.push(this._pack_vars(this.biases, false));
get trainables() {
let response = this.filters.slice();
response.push(this.biases);
return response;
}

Expand All @@ -76,6 +86,7 @@ class FullyConnLayer extends OutputLayer {
this.l2_decay_mul = getopt(json, 'l2_decay_mul', 1.0);

this.filters = json.filters.map(getVolFromJSON);
this.filters.forEach((V) => { V.allow_regl = true; });
this.biases = getVolFromJSON(json.biases);
// record updated values for updating
this.updated = this.filters.concat([this.biases]);
Expand Down
23 changes: 12 additions & 11 deletions layers/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { InputLayer } from 'layers/layer.js';
import { ReLULayer, SigmoidLayer, TanhLayer, MaxoutLayer } from 'layers/activation.js';
import { PoolLayer } from 'layers/pool.js';
import { SVMLayer } from 'layers/svm.js';
import { SoftmaxLayer } from 'layers/softmax.js';
import { RegressionLayer } from 'layers/regression.js';
import { FullyConnLayer } from 'layers/fullconn.js';
import { ConvLayer } from 'layers/conv.js';
import { LocalResponseNormalizationLayer } from 'layers/normalization.js';
import { DropoutLayer } from 'layers/dropout.js';
import { DeconvLayer } from 'layers/deconv.js';

import getActivation from 'layers/activation.js';

function merge(dst, src) {
for (let k of Object.keys(src)) {
dst[k] = src[k];
}
}

var layer_dict = {
'input' : InputLayer,
'relu' : ReLULayer,
'sigmoid' : SigmoidLayer,
'tanh' : TanhLayer,
'dropout' : DropoutLayer,
'conv' : ConvLayer,
'deconv' : DeconvLayer,
'pool' : PoolLayer,
'lrn' : LocalResponseNormalizationLayer,
'fc' : FullyConnLayer,
'maxout' : MaxoutLayer,
'svm' : SVMLayer
}
'fc' : FullyConnLayer
};

merge(layer_dict, getActivation());

export function get_layer(opt) {
return new layer_dict[opt.type || opt.layer_type](opt);
Expand Down
32 changes: 7 additions & 25 deletions layers/layer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import get_optimizer from 'optimizer/index.js'; // the default function
import { Regularization } from 'regularization.js';
import { getopt } from 'util.js'

class Layer {
Expand All @@ -14,43 +15,24 @@ class Layer {
this.updated = [];
}

getParamsAndGrads() { return []; }

_pack_vars(vol, allow_regl=true) {
return {
params: vol.w,
grads: vol.dw,
l1_decay_mul: allow_regl ? this.l1_decay_mul : 0.,
l2_decay_mul: allow_regl ? this.l2_decay_mul : 0.,
optimizer: vol.optimizer
};
}
get trainables() { return []; }

compile(options) {
// setup optimizers
// setup objects for training
this.updated.forEach(function(V) {
V.optimizer = get_optimizer(V.size, options);
V.dw = V.zeros_like();
V.optimizer = get_optimizer(V.size, options);
if (V.allow_regl) V.regularizer = new Regularization(options.l2_decay, options.l1_decay, this.l2_decay_mul, this.l1_decay_mul);
});
}

forward(V, is_training) {
/*
this.in_act = V;
this.out_act = f(V);
return this.out_act;
*/
this.in_act = V;
this.out_act = V; // nothing to do, output raw scores
return V;
}

backward() {
/*
this.in_act.grad = f(V, this.out_act);
this.grad = g(this.w, this.out_act);
*/
}
backward() { }

toJSON() {
var json = {};
Expand Down Expand Up @@ -91,4 +73,4 @@ class InputLayer extends Layer {
}
}

export {Layer, OutputLayer, InputLayer};
export {Layer, InputLayer};
Loading

0 comments on commit 78fd151

Please sign in to comment.