mirror of
https://github.com/wassname/keras-js.git
synced 2026-09-13 12:41:26 +08:00
finish merge layer and start advanced activations layers
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
<script src="/test/globals.js"></script>
|
||||
<script src="/test/activations.js"></script>
|
||||
<script src="/test/layers/core.js"></script>
|
||||
<script src="/test/layers/advanced_activations.js"></script>
|
||||
<script>
|
||||
// mocha.checkLeaks();
|
||||
mocha.globals(['jQuery']);
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"lodash": "^4.15.0",
|
||||
"ndarray": "^1.0.18",
|
||||
"ndarray-blas-level2": "^1.1.0",
|
||||
"ndarray-concat-rows": "^1.0.1",
|
||||
"ndarray-gemm": "^1.0.0",
|
||||
"ndarray-ops": "^1.2.2",
|
||||
"ndarray-squeeze": "^1.0.2",
|
||||
"ndarray-tile": "^1.0.3",
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Layer } from '../engine/topology'
|
||||
import { relu } from '../activations'
|
||||
|
||||
/**
|
||||
* LeakyReLU advanced activation layer class
|
||||
*/
|
||||
export class LeakyReLU extends Layer {
|
||||
/**
|
||||
* Creates a LeakyReLU activation layer
|
||||
* @param {number} alpha - negative slope coefficient
|
||||
*/
|
||||
constructor (alpha = 0.3) {
|
||||
super({})
|
||||
this.alpha = alpha
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for layer computational logic
|
||||
* @param {Tensor} x
|
||||
* @returns {Tensor} x
|
||||
*/
|
||||
call = x => {
|
||||
relu(x, { alpha: this.alpha })
|
||||
return x
|
||||
}
|
||||
}
|
||||
+53
-9
@@ -3,10 +3,12 @@ import Tensor from '../tensor'
|
||||
import { Layer } from '../engine/topology'
|
||||
import ndarray from 'ndarray'
|
||||
import { gemv } from 'ndarray-blas-level2'
|
||||
import gemm from 'ndarray-gemm'
|
||||
import ops from 'ndarray-ops'
|
||||
import unpack from 'ndarray-unpack'
|
||||
import unsqueeze from 'ndarray-unsqueeze'
|
||||
import tile from 'ndarray-tile'
|
||||
import concatFirstAxis from 'ndarray-concat-rows'
|
||||
import flattenDeep from 'lodash/flattenDeep'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import isInteger from 'lodash/isInteger'
|
||||
@@ -300,7 +302,7 @@ export class Merge extends Layer {
|
||||
* @returns {boolean} valid
|
||||
*/
|
||||
_validateInputs = inputs => {
|
||||
const shapes = inputs.map(x => x.tensor.shape)
|
||||
const shapes = inputs.map(x => x.tensor.shape.slice())
|
||||
if (['sum', 'mul', 'ave', 'cos', 'max'].indexOf(this.mode) > -1) {
|
||||
if (!shapes.every(shape => isEqual(shape, shapes[0]))) {
|
||||
throw new Error(`${this.name} [Merge layer] All input shapes must be the same for mode ${this.mode}.`)
|
||||
@@ -314,7 +316,7 @@ export class Merge extends Layer {
|
||||
if (this.dotAxes < 0) {
|
||||
this.dotAxes = [shapes[0].length + this.dotAxes, shapes[1].length + this.dotAxes]
|
||||
} else {
|
||||
this.dotAxes = [this.dotAxes, this.dotAxes]
|
||||
this.dotAxes = [this.dotAxes - 1, this.dotAxes - 1]
|
||||
}
|
||||
}
|
||||
if (shapes[0][this.dotAxes[0]] !== shapes[1][this.dotAxes[1]]) {
|
||||
@@ -344,15 +346,15 @@ export class Merge extends Layer {
|
||||
let output
|
||||
let outputShape
|
||||
if (['sum', 'mul', 'ave', 'max'].indexOf(this.mode) > -1) {
|
||||
outputShape = inputs[0].tensor.shape
|
||||
outputShape = inputs[0].tensor.shape.slice()
|
||||
output = new Tensor([], outputShape)
|
||||
} else if (this.mode === 'concat') {
|
||||
outputShape = inputs[0].tensor.shape
|
||||
outputShape = inputs[0].tensor.shape.slice()
|
||||
const _concatAxis = this.concatAxis < 0
|
||||
? outputShape.length + this.concatAxis
|
||||
: this.concatAxis
|
||||
: this.concatAxis - 1
|
||||
inputs.slice(1, inputs.length).forEach(x => {
|
||||
const d = x.tensor.shape.slice(_concatAxis)[0]
|
||||
const d = x.tensor.shape.slice()[_concatAxis]
|
||||
outputShape[_concatAxis] += d
|
||||
})
|
||||
output = new Tensor([], outputShape)
|
||||
@@ -361,7 +363,6 @@ export class Merge extends Layer {
|
||||
let shape2 = inputs[1].tensor.shape.slice()
|
||||
shape1.splice(this.dotAxes[0], 1)
|
||||
shape2.splice(this.dotAxes[1], 1)
|
||||
shape2.splice(0, 1)
|
||||
outputShape = shape1.concat(shape2)
|
||||
if (outputShape.length === 1) {
|
||||
outputShape.push(1)
|
||||
@@ -384,13 +385,56 @@ export class Merge extends Layer {
|
||||
}
|
||||
ops.divseq(output.tensor, inputs.length)
|
||||
} else if (this.mode === 'max') {
|
||||
ops.assigns(output.tensor, inputs[0].tensor)
|
||||
ops.assign(output.tensor, inputs[0].tensor)
|
||||
for (let i = 1; i < inputs.length; i++) {
|
||||
ops.maxeq(output.tensor, inputs[i].tensor)
|
||||
}
|
||||
} else if (this.mode === 'concat') {
|
||||
} else if (this.mode === 'cos') {
|
||||
const _concatAxis = this.concatAxis < 0
|
||||
? inputs[0].tensor.shape.length + this.concatAxis
|
||||
: this.concatAxis - 1
|
||||
if (_concatAxis === 0) {
|
||||
concatFirstAxis(output.tensor, inputs.map(x => x.tensor))
|
||||
} else {
|
||||
let dimsAxisSwap = [_concatAxis]
|
||||
for (let i = 0; i < inputs[0].tensor.shape.length; i++) {
|
||||
if (i !== _concatAxis) dimsAxisSwap.push(i)
|
||||
}
|
||||
concatFirstAxis(
|
||||
output.tensor.transpose(...dimsAxisSwap),
|
||||
inputs.map(x => x.tensor.transpose(...dimsAxisSwap))
|
||||
)
|
||||
}
|
||||
} else if (this.mode === 'dot') {
|
||||
if (inputs[0].tensor.shape.length === 2 && inputs[1].tensor.shape.length === 2) {
|
||||
if (this.dotAxes[0] === 0 && this.dotAxes[1] === 0) {
|
||||
gemm(output.tensor, inputs[0].tensor.transpose(1, 0), inputs[1].tensor)
|
||||
} else if (this.dotAxes[0] === 1 && this.dotAxes[1] === 1) {
|
||||
gemm(output.tensor, inputs[0].tensor, inputs[1].tensor.transpose(1, 0))
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${this.name} [Merge layer] dot mode for 3+ dim tensors not yet implemented.`)
|
||||
}
|
||||
} else if (this.mode === 'cos') {
|
||||
if (inputs[0].tensor.shape.length === 2 && inputs[1].tensor.shape.length === 2) {
|
||||
let a = new Tensor([], output.tensor.shape)
|
||||
let b = new Tensor([], output.tensor.shape)
|
||||
if (this.dotAxes[0] === 0 && this.dotAxes[1] === 0) {
|
||||
gemm(a.tensor, inputs[0].tensor.transpose(1, 0), inputs[0].tensor)
|
||||
gemm(b.tensor, inputs[1].tensor.transpose(1, 0), inputs[1].tensor)
|
||||
gemm(output.tensor, inputs[0].tensor.transpose(1, 0), inputs[1].tensor)
|
||||
} else if (this.dotAxes[0] === 1 && this.dotAxes[1] === 1) {
|
||||
gemm(a.tensor, inputs[0].tensor, inputs[0].tensor.transpose(1, 0))
|
||||
gemm(b.tensor, inputs[1].tensor, inputs[1].tensor.transpose(1, 0))
|
||||
gemm(output.tensor, inputs[0].tensor, inputs[1].tensor.transpose(1, 0))
|
||||
}
|
||||
ops.muleq(a.tensor, b.tensor)
|
||||
ops.sqrteq(a.tensor)
|
||||
ops.diveq(output.tensor, a.tensor)
|
||||
output.tensor = unsqueeze(output.tensor, 0)
|
||||
} else {
|
||||
throw new Error(`${this.name} [Merge layer] cos mode for 3+ dim tensors not yet implemented.`)
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
|
||||
+8
-10
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
export {
|
||||
Dense,
|
||||
Activation,
|
||||
Dropout,
|
||||
@@ -10,12 +10,10 @@ import {
|
||||
} from './core'
|
||||
|
||||
export {
|
||||
Dense,
|
||||
Activation,
|
||||
Dropout,
|
||||
Flatten,
|
||||
Reshape,
|
||||
Permute,
|
||||
RepeatVector,
|
||||
Merge
|
||||
}
|
||||
LeakyReLU,
|
||||
PReLU,
|
||||
ELU,
|
||||
ParametricSoftplus,
|
||||
ThresholdedReLU,
|
||||
SReLU
|
||||
} from './advanced_activations'
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import isFinite from 'lodash/isFinite'
|
||||
* stride/offset prevents us from comparing the array data
|
||||
* element-wise directly.
|
||||
*/
|
||||
export function approxEquals (ndarrayOut, dataExpected, tol = 1e-6) {
|
||||
export function approxEquals (ndarrayOut, dataExpected, tol = 1e-5) {
|
||||
const a = flattenDeep(unpack(ndarrayOut))
|
||||
const b = dataExpected
|
||||
if (a.length !== b.length) return false
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* eslint-env browser, mocha */
|
||||
|
||||
describe('Layers: Advanced Activations', function () {
|
||||
const assert = chai.assert
|
||||
const styles = testGlobals.styles
|
||||
const logTime = testGlobals.logTime
|
||||
const stringifyCondensed = testGlobals.stringifyCondensed
|
||||
const approxEquals = KerasJS.testUtils.approxEquals
|
||||
const layers = KerasJS.layers
|
||||
|
||||
before(function () {
|
||||
console.log('\n%Layers: Advanced Activations', styles.h1)
|
||||
})
|
||||
|
||||
/*********************************************************
|
||||
* LeakyReLU
|
||||
*********************************************************/
|
||||
|
||||
describe('LeakyReLU', function () {
|
||||
before(function () {
|
||||
console.log('\n%cLeakyReLU', styles.h2)
|
||||
})
|
||||
|
||||
it('should produce expected values', function () {
|
||||
console.log('\n%calpha=0.4', styles.h3)
|
||||
let testLayer = new layers.LeakyReLU(0.4)
|
||||
let t = new KerasJS.Tensor([0, 0.2, -0.5, -0.1, 1, 2], [6])
|
||||
console.log('%cin', styles.h4, stringifyCondensed(t.tensor))
|
||||
const startTime = performance.now()
|
||||
t = testLayer.call(t)
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([0.0, 0.2, -0.2, -0.04, 1.0, 2.0])
|
||||
const shapeExpected = [6]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -534,5 +534,298 @@ describe('Layers: Core', function () {
|
||||
assert.deepEqual(t2.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t2.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in concat mode (1D)', function () {
|
||||
console.log('\n%cmode: concat (1D)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2 = new layers.Merge({ mode: 'concat', concatAxis: -1 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer2.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([7.3, -0.21, -2.45, 4.48])
|
||||
const shapeExpected = [4]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in concat mode (2D, concatAxis=-1)', function () {
|
||||
console.log('\n%cmode: concat (2D, concatAxis=-1)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'concat', concatAxis: -1 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([7.3, -0.21, -2.45, 4.48, 7.3, -0.21, -2.45, 4.48, 7.3, -0.21, -2.45, 4.48])
|
||||
const shapeExpected = [3, 4]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in concat mode (2D, concatAxis=-2)', function () {
|
||||
console.log('\n%cmode: concat (2D, concatAxis=-2)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'concat', concatAxis: -2 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([7.3, -0.21, 7.3, -0.21, 7.3, -0.21, -2.45, 4.48, -2.45, 4.48, -2.45, 4.48])
|
||||
const shapeExpected = [6, 2]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in concat mode (2D, concatAxis=1)', function () {
|
||||
console.log('\n%cmode: concat (2D, concatAxis=1)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'concat', concatAxis: 1 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([7.3, -0.21, 7.3, -0.21, 7.3, -0.21, -2.45, 4.48, -2.45, 4.48, -2.45, 4.48])
|
||||
const shapeExpected = [6, 2]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in concat mode (2D, concatAxis=2)', function () {
|
||||
console.log('\n%cmode: concat (2D, concatAxis=2)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'concat', concatAxis: 2 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([7.3, -0.21, -2.45, 4.48, 7.3, -0.21, -2.45, 4.48, 7.3, -0.21, -2.45, 4.48])
|
||||
const shapeExpected = [3, 4]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in dot mode (2D x 2D, dotAxes=1)', function () {
|
||||
console.log('\n%cmode: dot (2D x 2D, dotAxes=1)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'dot', dotAxes: 1 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([-53.655003, 98.112007, 1.5435, -2.8224])
|
||||
const shapeExpected = [2, 2]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in dot mode (2D x 2D, dotAxes=2)', function () {
|
||||
console.log('\n%cmode: dot (2D x 2D, dotAxes=2)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'dot', dotAxes: 2 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([-18.8258, -18.8258, -18.8258, -18.8258, -18.8258, -18.8258, -18.8258, -18.8258, -18.8258])
|
||||
const shapeExpected = [3, 3]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in cos mode (2D x 2D, dotAxes=1)', function () {
|
||||
console.log('\n%cmode: cos (2D x 2D, dotAxes=1)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'cos', dotAxes: 1 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([-1.0, 7.972744, 0.125427, -1.0])
|
||||
const shapeExpected = [1, 2, 2]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
|
||||
it('should produce expected values in cos mode (2D x 2D, dotAxes=2)', function () {
|
||||
console.log('\n%cmode: cos (2D x 2D, dotAxes=2)', styles.h3)
|
||||
let testLayer1a = new layers.Dense(2)
|
||||
let testLayer2a = new layers.RepeatVector(3)
|
||||
let testLayer1b = new layers.Dense(2)
|
||||
let testLayer2b = new layers.RepeatVector(3)
|
||||
let testLayer3 = new layers.Merge({ mode: 'cos', dotAxes: 2 })
|
||||
testLayer1a.setWeights([
|
||||
new KerasJS.Tensor([0.1, 0.4, 0.5, 0.1, 1, -2, 0, 0.3, 0.2, 0.1, 3, 0], [6, 2]),
|
||||
new KerasJS.Tensor([0.5, 0.7], [2])
|
||||
])
|
||||
testLayer1b.setWeights([
|
||||
new KerasJS.Tensor([1, 0, -0.9, 0.6, -0.7, 0, 0.2, 0.4, 0, 0, -1, 2.3], [6, 2]),
|
||||
new KerasJS.Tensor([0.1, -0.2], [2])
|
||||
])
|
||||
let ta = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
let tb = new KerasJS.Tensor([0, 0.2, 0.5, -0.1, 1, 2], [6])
|
||||
ta = testLayer1a.call(ta)
|
||||
ta = testLayer2a.call(ta)
|
||||
tb = testLayer1b.call(tb)
|
||||
tb = testLayer2b.call(tb)
|
||||
console.log('%cin', styles.h4, stringifyCondensed([ta.tensor, tb.tensor]))
|
||||
const startTime = performance.now()
|
||||
let t = testLayer3.call([ta, tb])
|
||||
const endTime = performance.now()
|
||||
console.log('%cout', styles.h4, stringifyCondensed(t.tensor))
|
||||
logTime(startTime, endTime)
|
||||
const dataExpected = new Float32Array([-0.504843, -0.504843, -0.504843, -0.504843, -0.504843, -0.504843, -0.504843, -0.504843, -0.504843])
|
||||
const shapeExpected = [1, 3, 3]
|
||||
assert.deepEqual(t.tensor.shape, shapeExpected)
|
||||
assert.isTrue(approxEquals(t.tensor, dataExpected))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
(function () {
|
||||
'use strict'
|
||||
|
||||
const styles = {
|
||||
h1: 'color:#001f3f;font-weight:bold;font-size:160%;',
|
||||
h2: 'color:#0074D9;font-weight:bold;font-size:130%;',
|
||||
h3: 'color:#FF4136;font-weight:bold;font-size:110%;',
|
||||
h4: 'color:#AAAAAA;font-size:100%;',
|
||||
time: 'color:#2ECC40;font-weight:bold;font-size:100%;'
|
||||
}
|
||||
|
||||
function approxEquals (a, b, tol = 1e-6) {
|
||||
if (a.length !== b.length) return false
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (
|
||||
a[i] < (b[i] - tol) ||
|
||||
a[i] > (b[i] + tol)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function logTime (startTime, endTime) {
|
||||
console.log(`%c>>>> exec: ${Math.round(100 * (endTime - startTime)) / 100} ms`, styles.time)
|
||||
}
|
||||
|
||||
window.testUtils = {
|
||||
styles,
|
||||
approxEquals,
|
||||
logTime
|
||||
}
|
||||
})()
|
||||
Reference in New Issue
Block a user