implement Convolution1D layer, with tests

This commit is contained in:
Leon Chen
2016-08-26 20:25:21 -04:00
parent 263242e6e4
commit ef6f18bd0a
11 changed files with 589 additions and 20 deletions
+2
View File
@@ -45,6 +45,8 @@
<script src="/test/core/data_MaxoutDense.js"></script>
<script src="/test/core/MaxoutDense.js"></script>
<script src="/test/convolutional/data_Convolution1D.js"></script>
<script src="/test/convolutional/Convolution1D.js"></script>
<script src="/test/convolutional/data_Convolution2D.js"></script>
<script src="/test/convolutional/Convolution2D.js"></script>
+304
View File
@@ -0,0 +1,304 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Using TensorFlow backend.\n"
]
}
],
"source": [
"import numpy as np\n",
"from keras.models import Model\n",
"from keras.layers import Input\n",
"from keras.layers.convolutional import Convolution1D\n",
"from keras import backend as K"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def format_decimal(arr, places=6):\n",
" return [round(x * 10**places) / 10**places for x in arr]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Convolution1D"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**[convolutional.Convolution1D.0] 4 length 3 filters on 5x2 input, activation='linear', border_mode='valid', subsample_length=1, bias=True**"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"W shape: (4, 2, 3, 1)\n",
"W: [0.895265, -0.546905, 0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751]\n",
"b shape: (4,)\n",
"b: [0.895265, -0.546905, 0.18884, -0.143383]\n",
"\n",
"in shape: (5, 2)\n",
"in: [0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613]\n",
"out shape: (3, 4)\n",
"out: [1.124918, -0.342879, 1.42759, -0.153716, 0.251835, 1.840331, -0.064904, 1.390416, 1.340388, 1.266877, 0.433117, 1.831188]\n"
]
}
],
"source": [
"data_in_shape = (5, 2)\n",
"conv = Convolution1D(4, 3, activation='linear', border_mode='valid', subsample_length=1, bias=True)\n",
"\n",
"layer_0 = Input(shape=data_in_shape)\n",
"layer_1 = conv(layer_0)\n",
"model = Model(input=layer_0, output=layer_1)\n",
"\n",
"# set weights to random (use seed for reproducibility)\n",
"weights = []\n",
"for w in model.get_weights():\n",
" np.random.seed(200)\n",
" weights.append(2 * np.random.random(w.shape) - 1)\n",
"model.set_weights(weights)\n",
"print('W shape:', weights[0].shape)\n",
"print('W:', format_decimal(weights[0].ravel().tolist()))\n",
"print('b shape:', weights[1].shape)\n",
"print('b:', format_decimal(weights[1].ravel().tolist()))\n",
"\n",
"data_in = 2 * np.random.random(data_in_shape) - 1\n",
"print('')\n",
"print('in shape:', data_in_shape)\n",
"print('in:', format_decimal(data_in.ravel().tolist()))\n",
"result = model.predict(np.array([data_in]))\n",
"print('out shape:', result[0].shape)\n",
"print('out:', format_decimal(result[0].ravel().tolist()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**[convolutional.Convolution1D.1] 4 length 3 filters on 6x3 input, activation='linear', border_mode='valid', subsample_length=1, bias=False**"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"W shape: (4, 3, 3, 1)\n",
"W: [-0.772191, 0.495762, 0.222119, 0.619384, 0.425715, -0.719926, -0.464976, -0.704791, -0.543864, -0.528877, 0.380048, -0.703304, -0.108788, 0.401685, -0.806723, 0.765265, 0.739665, 0.689188, -0.452596, 0.571359, 0.402272, -0.010539, 0.672675, -0.191632, -0.653554, -0.269196, 0.994178, -0.318691, 0.010759, 0.078695, -0.501326, 0.625487, -0.614715, -0.839499, -0.811676, -0.300069]\n",
"\n",
"in shape: (6, 3)\n",
"in: [0.57107, 0.361384, -0.924121, -0.417132, -0.39254, 0.967698, -0.674584, 0.924125, 0.403362, 0.417301, 0.795356, -0.367641, -0.398474, 0.889135, -0.81216, 0.383587, 0.922044, 0.427167]\n",
"out shape: (4, 4)\n",
"out: [-1.877892, -0.642056, -0.468639, -1.365037, -0.876249, 0.22855, -0.661939, -0.585044, 1.423414, -0.225706, -0.233745, -0.120764, 0.283789, -1.702796, 1.034372, 0.323189]\n"
]
}
],
"source": [
"data_in_shape = (6, 3)\n",
"conv = Convolution1D(4, 3, activation='linear', border_mode='valid', subsample_length=1, bias=False)\n",
"\n",
"layer_0 = Input(shape=data_in_shape)\n",
"layer_1 = conv(layer_0)\n",
"model = Model(input=layer_0, output=layer_1)\n",
"\n",
"# set weights to random (use seed for reproducibility)\n",
"weights = []\n",
"for w in model.get_weights():\n",
" np.random.seed(201)\n",
" weights.append(2 * np.random.random(w.shape) - 1)\n",
"model.set_weights(weights)\n",
"print('W shape:', weights[0].shape)\n",
"print('W:', format_decimal(weights[0].ravel().tolist()))\n",
"\n",
"data_in = 2 * np.random.random(data_in_shape) - 1\n",
"print('')\n",
"print('in shape:', data_in_shape)\n",
"print('in:', format_decimal(data_in.ravel().tolist()))\n",
"result = model.predict(np.array([data_in]))\n",
"print('out shape:', result[0].shape)\n",
"print('out:', format_decimal(result[0].ravel().tolist()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**[convolutional.Convolution1D.2] 2 length 3 filters on 4x6 input, activation='sigmoid', border_mode='valid', subsample_length=2, bias=True**"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"W shape: (2, 6, 3, 1)\n",
"W: [0.895265, -0.546905, 0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751, -0.099831, 0.360314, -0.161149, 0.280787, 0.217313, -0.789132, 0.932089, 0.517401, 0.359284, -0.341304, -0.94709, 0.607321]\n",
"b shape: (2,)\n",
"b: [0.895265, -0.546905]\n",
"\n",
"in shape: (4, 6)\n",
"in: [0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751, -0.099831, 0.360314]\n",
"out shape: (2, 2)\n",
"out: [0.444624, 0.773535, 0.564385, 0.133453]\n"
]
}
],
"source": [
"data_in_shape = (4, 6)\n",
"conv = Convolution1D(2, 3, activation='sigmoid', border_mode='same', subsample_length=2, bias=True)\n",
"\n",
"layer_0 = Input(shape=data_in_shape)\n",
"layer_1 = conv(layer_0)\n",
"model = Model(input=layer_0, output=layer_1)\n",
"\n",
"# set weights to random (use seed for reproducibility)\n",
"weights = []\n",
"for w in model.get_weights():\n",
" np.random.seed(200)\n",
" weights.append(2 * np.random.random(w.shape) - 1)\n",
"model.set_weights(weights)\n",
"print('W shape:', weights[0].shape)\n",
"print('W:', format_decimal(weights[0].ravel().tolist()))\n",
"print('b shape:', weights[1].shape)\n",
"print('b:', format_decimal(weights[1].ravel().tolist()))\n",
"\n",
"data_in = 2 * np.random.random(data_in_shape) - 1\n",
"print('')\n",
"print('in shape:', data_in_shape)\n",
"print('in:', format_decimal(data_in.ravel().tolist()))\n",
"result = model.predict(np.array([data_in]))\n",
"print('out shape:', result[0].shape)\n",
"print('out:', format_decimal(result[0].ravel().tolist()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**[convolutional.Convolution1D.4] 2 length 7 filters on 8x3 input, activation='tanh', border_mode='same', subsample_length=1, bias=True**"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"W shape: (2, 3, 7, 1)\n",
"W: [0.861113, -0.237594, 0.330694, 0.998309, 0.786447, 0.538158, -0.228315, 0.217332, -0.475436, -0.018066, -0.489741, -0.522387, 0.79989, 0.27058, -0.683115, -0.650208, 0.259853, -0.509243, 0.958185, 0.089546, 0.739799, 0.114385, -0.378872, -0.168716, 0.302124, 0.850416, -0.984343, 0.839927, -0.895196, 0.303711, 0.128826, 0.058159, 0.254989, -0.759101, 0.793844, 0.647309, 0.252074, 0.075576, -0.859305, 0.952613, -0.053285, -0.677361]\n",
"b shape: (2,)\n",
"b: [0.861113, -0.237594]\n",
"\n",
"in shape: (8, 3)\n",
"in: [0.330694, 0.998309, 0.786447, 0.538158, -0.228315, 0.217332, -0.475436, -0.018066, -0.489741, -0.522387, 0.79989, 0.27058, -0.683115, -0.650208, 0.259853, -0.509243, 0.958185, 0.089546, 0.739799, 0.114385, -0.378872, -0.168716, 0.302124, 0.850416]\n",
"out shape: (8, 2)\n",
"out: [0.854959, 0.355561, 0.888899, -0.9834, -0.825345, 0.941694, -0.490434, -0.699848, 0.872523, -0.887886, -0.408331, -0.018902, 0.959544, 0.66633, -0.779488, 0.038157]\n"
]
}
],
"source": [
"data_in_shape = (8, 3)\n",
"conv = Convolution1D(2, 7, activation='tanh', border_mode='same', subsample_length=1, bias=True)\n",
"\n",
"layer_0 = Input(shape=data_in_shape)\n",
"layer_1 = conv(layer_0)\n",
"model = Model(input=layer_0, output=layer_1)\n",
"\n",
"# set weights to random (use seed for reproducibility)\n",
"weights = []\n",
"for w in model.get_weights():\n",
" np.random.seed(204)\n",
" weights.append(2 * np.random.random(w.shape) - 1)\n",
"model.set_weights(weights)\n",
"print('W shape:', weights[0].shape)\n",
"print('W:', format_decimal(weights[0].ravel().tolist()))\n",
"print('b shape:', weights[1].shape)\n",
"print('b:', format_decimal(weights[1].ravel().tolist()))\n",
"\n",
"data_in = 2 * np.random.random(data_in_shape) - 1\n",
"print('')\n",
"print('in shape:', data_in_shape)\n",
"print('in:', format_decimal(data_in.ravel().tolist()))\n",
"result = model.predict(np.array([data_in]))\n",
"print('out shape:', result[0].shape)\n",
"print('out:', format_decimal(result[0].ravel().tolist()))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
+4 -4
View File
@@ -47,7 +47,7 @@ export default class Tensor {
* 2-D only
* see https://github.com/waylonflinn/weblas/wiki/Pipeline
*/
createWeblasTensor = () => {
createWeblasTensor () {
if (this.tensor.shape.length === 1) {
const shape = [1, this.tensor.shape[0]]
this.weblasTensor = new weblas.pipeline.Tensor(shape, this.tensor.data)
@@ -60,7 +60,7 @@ export default class Tensor {
/**
* Transfers weblas pipeline tensor from GPU memory
*/
transferWeblasTensor = () => {
transferWeblasTensor () {
if (this.weblasTensor) {
const shape = this.weblasTensor.shape
const arr = this.weblasTensor.transfer(true)
@@ -71,7 +71,7 @@ export default class Tensor {
/**
* Delete weblas pipeline tensor
*/
deleteWeblasTensor = () => {
deleteWeblasTensor () {
if (this.weblasTensor) {
this.weblasTensor.delete()
delete this.weblasTensor
@@ -81,7 +81,7 @@ export default class Tensor {
/**
* Replaces data in the underlying ndarray.
*/
replaceTensorData = data => {
replaceTensorData (data) {
if (data && data.length && data instanceof this._type) {
this.tensor.data = data
} else if (data && data.length && data instanceof Array) {
+4 -4
View File
@@ -27,7 +27,7 @@ export default class Layer {
*
* @param {Tensor[]} weightsArr - array of weights which are instances of Tensor
*/
setWeights = weightsArr => {
setWeights (weightsArr) {
this.params.forEach((p, i) => {
this.weights[p] = weightsArr[i]
})
@@ -37,7 +37,7 @@ export default class Layer {
* Create weblas pipeline tensor weights
* 2-D only
*/
createWeblasWeights = () => {
createWeblasWeights () {
this.weblasWeights = {}
this.params.forEach((p, i) => {
@@ -54,7 +54,7 @@ export default class Layer {
/**
* Transfer weblas pipeline tensor weights
*/
transferWeblasWeights = () => {
transferWeblasWeights () {
this.params.forEach((p, i) => {
if (this.weblasWeights[p]) {
const shape = this.weblasWeights[p].shape
@@ -67,7 +67,7 @@ export default class Layer {
/**
* Delete weblas pipeline tensor weights
*/
deleteWeblasWeights = () => {
deleteWeblasWeights () {
this.params.forEach((p, i) => {
if (this.weblasWeights[p]) {
this.weblasWeights[p].delete()
+65
View File
@@ -0,0 +1,65 @@
import Layer from '../../engine/Layer'
import Convolution2D from './Convolution2D'
import squeeze from 'ndarray-squeeze'
import unsqueeze from 'ndarray-unsqueeze'
/**
* Convolution1D layer class
*/
export default class Convolution1D extends Layer {
/**
* Creates a Convolution1D layer
* @param {number} nbFilter - Number of convolution filters to use.
* @param {number} filterLength - Length of 1D convolution kernel.
* @param {Object} [attrs] - layer attributes
*/
constructor (nbFilter, filterLength, attrs = {}) {
super(attrs)
const {
activation = 'linear',
borderMode = 'valid',
subsampleLength = 1,
bias = true
} = attrs
if (borderMode !== 'valid' && borderMode !== 'same') {
throw new Error(`${this.name} [Convolution1D layer] Invalid borderMode.`)
}
// Layer weights specification
this.params = this.bias ? ['W', 'b'] : ['W']
// Bootstrap Convolution2D layer:
// Convolution1D is actually a shim on top of Convolution2D, where
// all of the computational action is performed
// Note that Keras uses `th` dim ordering here.
this._conv2d = new Convolution2D(nbFilter, filterLength, 1, {
activation,
borderMode,
subsample: [subsampleLength, 1],
dimOrdering: 'th',
bias
})
}
/**
* Method for setting layer weights
* Override `super` method since weights must be set in `this._conv2d`
* @param {Tensor[]} weightsArr - array of weights which are instances of Tensor
*/
setWeights (weightsArr) {
this._conv2d.setWeights(weightsArr)
}
/**
* Method for layer computational logic
* @param {Tensor} x
* @returns {Tensor} x
*/
call = x => {
x.tensor = unsqueeze(x.tensor).transpose(1, 0, 2)
const conv2dOutput = this._conv2d.call(x)
x.tensor = squeeze(conv2dOutput.tensor).transpose(1, 0, 2)
return x
}
}
+10 -9
View File
@@ -58,16 +58,12 @@ export default class Convolution2D extends Layer {
* In `th` mode, W weight tensor has shape [nbFilter, inputChannels, nbRow, nbCol]
* @param {Tensor[]} weightsArr - array of weights which are instances of Tensor
*/
setWeights = weightsArr => {
setWeights (weightsArr) {
if (this.dimOrdering === 'th') {
const weightsArrTheano = weightsArr.map(w => {
w.tensor = w.tensor.transpose(3, 2, 0, 1)
return w
})
super.setWeights(weightsArrTheano)
} else {
super.setWeights(weightsArr)
// W
weightsArr[0].tensor = weightsArr[0].tensor.transpose(2, 3, 1, 0)
}
super.setWeights(weightsArr)
}
/**
@@ -193,7 +189,7 @@ export default class Convolution2D extends Layer {
call = x => {
// convert to tf ordering
if (this.dimOrdering === 'th') {
x.tensor = x.tensor.transpose(2, 0, 1)
x.tensor = x.tensor.transpose(1, 2, 0)
}
this._calcOutputShape(x)
@@ -239,6 +235,11 @@ export default class Convolution2D extends Layer {
this.activation(x)
// convert back to th ordering if necessary
if (this.dimOrdering === 'th') {
x.tensor = x.tensor.transpose(2, 0, 1)
}
return x
}
}
+2
View File
@@ -1,5 +1,7 @@
import Convolution1D from './Convolution1D'
import Convolution2D from './Convolution2D'
export {
Convolution1D,
Convolution2D
}
+1 -1
View File
@@ -43,7 +43,7 @@ export default class Merge extends Layer {
* @param {Tensor[]} inputs
* @returns {boolean} valid
*/
_validateInputs = inputs => {
_validateInputs (inputs) {
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]))) {
+105
View File
@@ -0,0 +1,105 @@
/* eslint-env browser, mocha */
describe('convolutional layer: Convolution1D', 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
const testParams = [
{
inputShape: [5, 2],
kernelShape: [4, 3],
attrs: { activation: 'linear', borderMode: 'valid', subsampleLength: 1, bias: true }
},
{
inputShape: [6, 3],
kernelShape: [4, 3],
attrs: { activation: 'linear', borderMode: 'valid', subsampleLength: 1, bias: false }
},
{
inputShape: [4, 6],
kernelShape: [2, 3],
attrs: { activation: 'sigmoid', borderMode: 'same', subsampleLength: 2, bias: true }
},
{
inputShape: [8, 3],
kernelShape: [2, 7],
attrs: { activation: 'tanh', borderMode: 'same', subsampleLength: 1, bias: true }
}
]
before(function () {
console.log('\n%cconvolutional layer: Convolution1D', styles.h1)
})
/*********************************************************
* CPU
*********************************************************/
describe('CPU', function () {
before(function () {
console.log('\n%cCPU', styles.h2)
})
testParams.forEach(({ inputShape, kernelShape, attrs }, i) => {
const key = `convolutional.Convolution1D.${i}`
const [inputLength, inputFeatures] = inputShape
const [nbFilter, filterLength] = kernelShape
const title = `[${key}] [CPU] test: ${nbFilter} length ${filterLength} filters on ${inputLength}x${inputFeatures} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsampleLength=${attrs.subsampleLength}, bias=${attrs.bias}`
it(title, function () {
console.log(`\n%c${title}`, styles.h3)
let testLayer = new layers.Convolution1D(nbFilter, filterLength, attrs)
testLayer.setWeights(TEST_DATA[key].weights.map(w => new KerasJS.Tensor(w.data, w.shape)))
let t = new KerasJS.Tensor(TEST_DATA[key].input.data, TEST_DATA[key].input.shape)
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(TEST_DATA[key].expected.data)
const shapeExpected = TEST_DATA[key].expected.shape
assert.deepEqual(t.tensor.shape, shapeExpected)
assert.isTrue(approxEquals(t.tensor, dataExpected))
})
})
})
/*********************************************************
* GPU
*********************************************************/
describe('GPU', function () {
before(function () {
console.log('\n%cGPU', styles.h2)
})
testParams.forEach(({ inputShape, kernelShape, attrs }, i) => {
const key = `convolutional.Convolution1D.${i}`
const [inputLength, inputFeatures] = inputShape
const [nbFilter, filterLength] = kernelShape
const title = `[${key}] [GPU] test: ${nbFilter} length ${filterLength} filters on ${inputLength}x${inputFeatures} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsampleLength=${attrs.subsampleLength}, bias=${attrs.bias}`
it(title, function () {
console.log(`\n%c${title}`, styles.h3)
let testLayer = new layers.Convolution1D(nbFilter, filterLength, attrs)
testLayer.setWeights(TEST_DATA[key].weights.map(w => new KerasJS.Tensor(w.data, w.shape)))
let t = new KerasJS.Tensor(TEST_DATA[key].input.data, TEST_DATA[key].input.shape, { useWeblas: true })
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(TEST_DATA[key].expected.data)
const shapeExpected = TEST_DATA[key].expected.shape
assert.deepEqual(t.tensor.shape, shapeExpected)
assert.isTrue(approxEquals(t.tensor, dataExpected))
})
})
})
})
+2 -2
View File
@@ -63,7 +63,7 @@ describe('convolutional layer: Convolution2D', function () {
const key = `convolutional.Convolution2D.${i}`
const [inputRows, inputCols, inputChannels] = inputShape
const [nbFilter, nbRow, nbCol] = kernelShape
const title = `[${key}] [CPU] test 1: ${nbFilter} ${nbRow}x${nbCol} filters on ${inputRows}x${inputCols}x${inputChannels} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsample=${attrs.subsample}, dim_ordering='${attrs.dimOrdering}', bias=${attrs.bias}`
const title = `[${key}] [CPU] test: ${nbFilter} ${nbRow}x${nbCol} filters on ${inputRows}x${inputCols}x${inputChannels} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsample=${attrs.subsample}, dim_ordering='${attrs.dimOrdering}', bias=${attrs.bias}`
it(title, function () {
console.log(`\n%c${title}`, styles.h3)
@@ -97,7 +97,7 @@ describe('convolutional layer: Convolution2D', function () {
const key = `convolutional.Convolution2D.${i}`
const [inputRows, inputCols, inputChannels] = inputShape
const [nbFilter, nbRow, nbCol] = kernelShape
const title = `[${key}] [GPU] test 1: ${nbFilter} ${nbRow}x${nbCol} filters on ${inputRows}x${inputCols}x${inputChannels} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsample=${attrs.subsample}, dim_ordering='${attrs.dimOrdering}', bias=${attrs.bias}`
const title = `[${key}] [GPU] test: ${nbFilter} ${nbRow}x${nbCol} filters on ${inputRows}x${inputCols}x${inputChannels} input, activation='${attrs.activation}', border_mode='${attrs.borderMode}', subsample=${attrs.subsample}, dim_ordering='${attrs.dimOrdering}', bias=${attrs.bias}`
it(title, function () {
console.log(`\n%c${title}`, styles.h3)
+90
View File
@@ -0,0 +1,90 @@
// TEST DATA
// Keyed by mocha test ID
// Python code for generating test data can be found in the matching jupyter notebook in folder `notebooks/`.
(function () {
var DATA = {
'convolutional.Convolution1D.0': {
input: {
data: [0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613],
shape: [5, 2]
},
weights: [
{
data: [0.895265, -0.546905, 0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751],
shape: [4, 2, 3, 1]
},
{
data: [0.895265, -0.546905, 0.18884, -0.143383],
shape: [4]
}
],
expected: {
data: [1.124918, -0.342879, 1.42759, -0.153716, 0.251835, 1.840331, -0.064904, 1.390416, 1.340388, 1.266877, 0.433117, 1.831188],
shape: [3, 4]
}
},
'convolutional.Convolution1D.1': {
input: {
data: [0.57107, 0.361384, -0.924121, -0.417132, -0.39254, 0.967698, -0.674584, 0.924125, 0.403362, 0.417301, 0.795356, -0.367641, -0.398474, 0.889135, -0.81216, 0.383587, 0.922044, 0.427167],
shape: [6, 3]
},
weights: [
{
data: [-0.772191, 0.495762, 0.222119, 0.619384, 0.425715, -0.719926, -0.464976, -0.704791, -0.543864, -0.528877, 0.380048, -0.703304, -0.108788, 0.401685, -0.806723, 0.765265, 0.739665, 0.689188, -0.452596, 0.571359, 0.402272, -0.010539, 0.672675, -0.191632, -0.653554, -0.269196, 0.994178, -0.318691, 0.010759, 0.078695, -0.501326, 0.625487, -0.614715, -0.839499, -0.811676, -0.300069],
shape: [4, 3, 3, 1]
},
{
data: [0.895265, -0.546905, 0.18884, -0.143383],
shape: [4]
}
],
expected: {
data: [-1.877892, -0.642056, -0.468639, -1.365037, -0.876249, 0.22855, -0.661939, -0.585044, 1.423414, -0.225706, -0.233745, -0.120764, 0.283789, -1.702796, 1.034372, 0.323189],
shape: [4, 4]
}
},
'convolutional.Convolution1D.2': {
input: {
data: [0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751, -0.099831, 0.360314],
shape: [4, 6]
},
weights: [
{
data: [0.895265, -0.546905, 0.18884, -0.143383, 0.528281, -0.994279, -0.285153, 0.81939, -0.087838, 0.963605, 0.734714, 0.972055, 0.846533, -0.392613, 0.692207, -0.757556, 0.571153, -0.49899, -0.807941, 0.886982, 0.6521, 0.03665, 0.747001, 0.156751, -0.099831, 0.360314, -0.161149, 0.280787, 0.217313, -0.789132, 0.932089, 0.517401, 0.359284, -0.341304, -0.94709, 0.607321],
shape: [2, 6, 3, 1]
},
{
data: [0.895265, -0.546905],
shape: [2]
}
],
expected: {
data: [0.444624, 0.773535, 0.564385, 0.133453],
shape: [2, 2]
}
},
'convolutional.Convolution1D.3': {
input: {
data: [0.330694, 0.998309, 0.786447, 0.538158, -0.228315, 0.217332, -0.475436, -0.018066, -0.489741, -0.522387, 0.79989, 0.27058, -0.683115, -0.650208, 0.259853, -0.509243, 0.958185, 0.089546, 0.739799, 0.114385, -0.378872, -0.168716, 0.302124, 0.850416],
shape: [8, 3]
},
weights: [
{
data: [0.861113, -0.237594, 0.330694, 0.998309, 0.786447, 0.538158, -0.228315, 0.217332, -0.475436, -0.018066, -0.489741, -0.522387, 0.79989, 0.27058, -0.683115, -0.650208, 0.259853, -0.509243, 0.958185, 0.089546, 0.739799, 0.114385, -0.378872, -0.168716, 0.302124, 0.850416, -0.984343, 0.839927, -0.895196, 0.303711, 0.128826, 0.058159, 0.254989, -0.759101, 0.793844, 0.647309, 0.252074, 0.075576, -0.859305, 0.952613, -0.053285, -0.677361],
shape: [2, 3, 7, 1]
},
{
data: [0.861113, -0.237594],
shape: [2]
}
],
expected: {
data: [0.854959, 0.355561, 0.888899, -0.9834, -0.825345, 0.941694, -0.490434, -0.699848, 0.872523, -0.887886, -0.408331, -0.018902, 0.959544, 0.66633, -0.779488, 0.038157],
shape: [8, 2]
}
}
}
window.TEST_DATA = Object.assign({}, window.TEST_DATA, DATA)
})()