Files
2026-07-13 12:49:29 +08:00

89 lines
2.9 KiB
JavaScript

describe("Simple Fully-Connected Neural Net Classifier", function() {
var net;
var trainer;
beforeEach(function() {
net = new convnetjs.Net();
var layer_defs = [];
layer_defs.push({type:'input', out_sx:1, out_sy:1, out_depth:2});
layer_defs.push({type:'fc', num_neurons:5, activation:'tanh'});
layer_defs.push({type:'fc', num_neurons:5, activation:'tanh'});
layer_defs.push({type:'softmax', num_classes:3});
net.makeLayers(layer_defs);
trainer = new convnetjs.SGDTrainer(net,
{learning_rate:0.0001, momentum:0.0, batch_size:1, l2_decay:0.0});
});
it("should be possible to initialize", function() {
// tanh are their own layers. Softmax gets its own fully connected layer.
// this should all get desugared just fine.
expect(net.layers.length).toEqual(7);
});
it("should forward prop volumes to probabilities", function() {
var x = new convnetjs.Vol([0.2, -0.3]);
var probability_volume = net.forward(x);
expect(probability_volume.w.length).toEqual(3); // 3 classes output
var w = probability_volume.w;
for(var i=0;i<3;i++) {
expect(w[i]).toBeGreaterThan(0);
expect(w[i]).toBeLessThan(1.0);
}
expect(w[0]+w[1]+w[2]).toBeCloseTo(1.0);
});
it("should increase probabilities for ground truth class when trained", function() {
// lets test 100 random point and label settings
// note that this should work since l2 and l1 regularization are off
// an issue is that if step size is too high, this could technically fail...
for(var k=0;k<100;k++) {
var x = new convnetjs.Vol([Math.random() * 2 - 1, Math.random() * 2 - 1]);
var pv = net.forward(x);
var gti = Math.floor(Math.random() * 3);
trainer.train(x, gti);
var pv2 = net.forward(x);
expect(pv2.w[gti]).toBeGreaterThan(pv.w[gti]);
}
});
it("should compute correct gradient at data", function() {
// here we only test the gradient at data, but if this is
// right then that's comforting, because it is a function
// of all gradients above, for all layers.
var x = new convnetjs.Vol([Math.random() * 2 - 1, Math.random() * 2 - 1]);
var gti = Math.floor(Math.random() * 3); // ground truth index
trainer.train(x, gti); // computes gradients at all layers, and at x
var delta = 0.000001;
for(var i=0;i<x.w.length;i++) {
var grad_analytic = x.dw[i];
var xold = x.w[i];
x.w[i] += delta;
var c0 = net.getCostLoss(x, gti);
x.w[i] -= 2*delta;
var c1 = net.getCostLoss(x, gti);
x.w[i] = xold; // reset
var grad_numeric = (c0 - c1)/(2 * delta);
var rel_error = Math.abs(grad_analytic - grad_numeric)/Math.abs(grad_analytic + grad_numeric);
console.log(i + ': numeric: ' + grad_numeric + ', analytic: ' + grad_analytic + ' => rel error ' + rel_error);
expect(rel_error).toBeLessThan(1e-2);
}
});
});