@tensorflow/tfjs-core
Version:
Hardware-accelerated JavaScript library for machine intelligence
542 lines • 24.7 kB
JavaScript
/**
* @license
* Copyright 2017 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
import * as tf from '../index';
import { ALL_ENVS, describeWithFlags } from '../jasmine_util';
import { expectArraysClose } from '../test_util';
function generateCaseInputs(totalSizeTensor, totalSizeFilter) {
const inp = new Array(totalSizeTensor);
const filt = new Array(totalSizeFilter);
for (let i = 0; i < totalSizeTensor; i++) {
inp[i] = i + 1;
}
for (let i = 0; i < totalSizeFilter; i++) {
filt[i] = i + 1;
}
return { input: inp, filter: filt };
}
describeWithFlags('conv2d', ALL_ENVS, () => {
it('x=[1,4,4,1] f=[1,1,1,3] s=2 d=1 p=same', async () => {
const inputDepth = 1;
const inputShape = [4, 4, inputDepth];
const outputDepth = 3;
const fSize = 1;
const pad = 'same';
const stride = [2, 2];
const x = tf.tensor3d([
10, 30, 50, 70, 20, 40, 60, 80, -10, -30, -50, -70, -20, -40, -60, -80
], inputShape);
const w = tf.tensor4d([1, 0.5, 1], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expectArraysClose(await result.data(), [10, 5, 10, 50, 25, 50, -10, -5, -10, -50, -25, -50]);
});
it('x=[2,2,2,2] f=[1,1,2,2] s=1 d=1 p=0', async () => {
const inputDepth = 2;
const inShape = [2, 2, 2, inputDepth];
const outputDepth = 2;
const fSize = 1;
const pad = 0;
const stride = 1;
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], inShape);
const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expect(result.shape).toEqual([2, 2, 2, 2]);
const expected = [-5, 2, -11, 5, -17, 8, -23, 11, -29, 14, -35, 17, -41, 20, -47, 23];
expectArraysClose(await result.data(), expected);
});
it('x=[2,2,1] f=[1,1,1,2] s=1 d=1 p=0', async () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 1;
const pad = 0;
const stride = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([2], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expectArraysClose(await result.data(), [2, 4, 6, 8]);
});
it('x=[3,3,2] f=[2,2,2,1] s=1 d=1 p=valid', async () => {
const pad = 'valid';
const stride = 1;
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90], [3, 3, 2]);
const w = tf.tensor4d([.1, .2, .3, .4, .5, .6, .7, .8], [2, 2, 2, 1]);
const result = tf.conv2d(x, w, stride, pad);
const resultData = await result.data();
expect(result.shape).toEqual([2, 2, 1]);
expectArraysClose(resultData, new Float32Array([25.6, 53.5, 157.0, 220.9]));
});
it('x=[2,2,2,1] f=[1,1,1,1] s=1 d=1 p=0', async () => {
const inputDepth = 1;
const inShape = [2, 2, 2, inputDepth];
const outputDepth = 1;
const fSize = 1;
const pad = 0;
const stride = 1;
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape);
const w = tf.tensor4d([2], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expect(result.shape).toEqual([2, 2, 2, 1]);
const expected = [2, 4, 6, 8, 10, 12, 14, 16];
expectArraysClose(await result.data(), expected);
});
it('x=[2,1,2,2] f=[1,1,1,1] s=1 d=1 p=0 NCHW', async () => {
const inputDepth = 1;
const inShape = [2, inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 1;
const pad = 0;
const stride = 1;
const dataFormat = 'NCHW';
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape);
const w = tf.tensor4d([2], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat);
expect(result.shape).toEqual([2, 1, 2, 2]);
const expected = [2, 4, 6, 8, 10, 12, 14, 16];
expectArraysClose(await result.data(), expected);
});
it('x=[4,2,1] f=[4,2,1,1] s=1 d=1 p=same', async () => {
const inputDepth = 1;
const outputDepth = 1;
const pad = 'same';
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8], [4, 2, inputDepth]);
const w = tf.tensor4d([3, 1, 5, 0, 2, 7, 8, 9], [4, 2, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([4, 2, 1]);
expectArraysClose(resultData, [133, 66, 200, 102, 108, 58, 56, 58]);
});
it('x=[4,2,1] f=[4,2,1,1] s=1 d=1 p=explicit', async () => {
const inputDepth = 1;
const outputDepth = 1;
const pad = [[0, 0], [1, 2], [0, 1], [0, 0]];
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8], [4, 2, inputDepth]);
const w = tf.tensor4d([3, 1, 5, 0, 2, 7, 8, 9], [4, 2, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([4, 2, 1]);
expectArraysClose(resultData, [133, 66, 200, 102, 108, 58, 56, 58]);
});
it('x=[2,2,1] f=[2,2,1,1] s=1 d=1 p=same', async () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 'same';
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([2, 2, 1]);
expectArraysClose(resultData, new Float32Array([20, 26, 13, 12]));
});
it('x=[1,2,2] f=[2,2,1,1] s=1 d=1 p=same NCHW', async () => {
const inputDepth = 1;
const inputShape = [inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 2;
const pad = 'same';
const stride = 1;
const dataFormat = 'NCHW';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([1, 2, 2]);
expectArraysClose(resultData, [20, 26, 13, 12]);
});
it('x=[1,2,2] f=[2,2,1,1] s=1 d=1 p=explicit NCHW', async () => {
const inputDepth = 1;
const inputShape = [inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 2;
const pad = [[0, 0], [0, 0], [0, 1], [0, 1]];
const stride = 1;
const dataFormat = 'NCHW';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([1, 2, 2]);
expectArraysClose(resultData, [20, 26, 13, 12]);
});
it('x=[2,2,2] f=[2,2,2,1] s=1 d=1 p=same NCHW', async () => {
const inputDepth = 2;
const inputShape = [inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 2;
const pad = 'same';
const stride = 1;
const dataFormat = 'NCHW';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8], inputShape);
const w = tf.tensor4d([3, 1, 5, 0, 0, 5, 1, 3], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([1, 2, 2]);
expectArraysClose(resultData, [81, 52, 36, 20]);
});
it('x=[2,1,2,2] f=[2,2,1,1] s=1 d=1 p=same NCHW', async () => {
const inputDepth = 1;
const inputShape = [2, inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 2;
const pad = 'same';
const stride = 1;
const dataFormat = 'NCHW';
const dilation = 1;
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const resultData = await result.data();
expect(result.shape).toEqual([2, 1, 2, 2]);
expectArraysClose(resultData, [20, 26, 13, 12, 56, 58, 29, 24]);
});
it('x=[2,2,1] f=[2,2,1,1] s=1 d=1 p=0', async () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 0;
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
expectArraysClose(await result.data(), [20]);
});
it('x=[4,4,1] f=[2,2,1,1] s=1 d=2 p=0', async () => {
const inputDepth = 1;
const inputShape = [4, 4, inputDepth];
const outputDepth = 1;
const fSize = 2;
const fSizeDilated = 3;
const pad = 0;
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 2;
const noDilation = 1;
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], inputShape);
const w = tf.tensor4d([3, 1, 5, 2], [fSize, fSize, inputDepth, outputDepth]);
// adding a dilation rate is equivalent to using a filter
// with 0s for the dilation rate
const wDilated = tf.tensor4d([3, 0, 1, 0, 0, 0, 5, 0, 2], [fSizeDilated, fSizeDilated, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad, dataFormat, dilation);
const expectedResult = tf.conv2d(x, wDilated, stride, pad, dataFormat, noDilation);
expect(result.shape).toEqual(expectedResult.shape);
expectArraysClose(await result.data(), await expectedResult.data());
expect(result.shape).toEqual(expectedResult.shape);
expect(result.dtype).toBe(expectedResult.dtype);
});
it('x=[1,3,6,1] f=[2,2,1,1] s=[1,2] d=1 p=valid', async () => {
const inputDepth = 1;
const inputShape = [1, 3, 6, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 'valid';
const stride = [1, 2];
const inputs = generateCaseInputs(1 * 3 * 6 * inputDepth, fSize * fSize);
const x = tf.tensor4d(inputs.input, inputShape);
const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expectArraysClose(await result.data(), [58.0, 78.0, 98.0, 118.0, 138.0, 158.0]);
});
it('x=[1,8,8,16] f=[3,3,16,1] s=[2,2] d=1 p=same', async () => {
const inputDepth = 16;
const xSize = 8;
const inputShape = [1, xSize, xSize, inputDepth];
const outputDepth = 1;
const fSize = 3;
const pad = 'same';
const stride = [2, 2];
// TODO(annxingyuan): Make this test work with large inputs using
// generateCaseInputs https://github.com/tensorflow/tfjs/issues/3143
const inputData = [];
for (let i = 0; i < xSize * xSize * inputDepth; i++) {
inputData.push(i % 5);
}
const wData = [];
for (let i = 0; i < fSize * fSize * inputDepth * outputDepth; i++) {
wData.push(i % 5);
}
const x = tf.tensor4d(inputData, inputShape);
const w = tf.tensor4d(wData, [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expect(result.shape).toEqual([1, 4, 4, 1]);
expectArraysClose(await result.data(), new Float32Array([
854, 431, 568, 382, 580, 427, 854, 288, 431, 568, 580,
289, 285, 570, 285, 258
]));
});
it('x=[1,8,8,3] f=[3,3,3,4] s=[2,2] d=1 p=same', async () => {
const inputDepth = 3;
const xSize = 8;
const inputShape = [1, xSize, xSize, inputDepth];
const outputDepth = 4;
const fSize = 3;
const pad = 'same';
const stride = [2, 2];
// TODO(annxingyuan): Make this test work with large inputs using
// generateCaseInputs https://github.com/tensorflow/tfjs/issues/3143
const inputData = [];
for (let i = 0; i < xSize * xSize * inputDepth; i++) {
inputData.push(i % 5);
}
const wData = [];
for (let i = 0; i < fSize * fSize * inputDepth * outputDepth; i++) {
wData.push(i % 5);
}
const x = tf.tensor4d(inputData, inputShape);
const w = tf.tensor4d(wData, [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expect(result.shape).toEqual([1, 4, 4, 4]);
expectArraysClose(await result.data(), new Float32Array([
104, 125, 126, 102, 133, 126, 104, 57, 137, 102, 57, 112, 64,
40, 76, 92, 116, 53, 110, 142, 50, 104, 133, 137, 104, 125,
126, 102, 83, 88, 78, 33, 133, 126, 104, 57, 137, 102, 57,
112, 116, 53, 110, 142, 37, 76, 100, 99, 33, 68, 83, 88,
70, 83, 76, 64, 92, 88, 64, 40, 51, 44, 27, 50
]));
});
it('x=[1,8,8,3] f=[3,3,3,4] s=[2,2] d=1 p=valid', async () => {
const inputDepth = 3;
const xSize = 8;
const inputShape = [1, xSize, xSize, inputDepth];
const outputDepth = 4;
const fSize = 3;
const pad = 'valid';
const stride = [2, 2];
const inputData = [];
for (let i = 0; i < xSize * xSize * inputDepth; i++) {
inputData.push(i % 5);
}
const wData = [];
for (let i = 0; i < fSize * fSize * inputDepth * outputDepth; i++) {
wData.push(i % 5);
}
const x = tf.tensor4d(inputData, inputShape);
const w = tf.tensor4d(wData, [fSize, fSize, inputDepth, outputDepth]);
const result = tf.conv2d(x, w, stride, pad);
expect(result.shape).toEqual([1, 3, 3, 4]);
expectArraysClose(await result.data(), new Float32Array([
104, 125, 126, 102, 133, 126, 104, 57, 137, 102, 57, 112,
116, 53, 110, 142, 50, 104, 133, 137, 104, 125, 126, 102,
133, 126, 104, 57, 137, 102, 57, 112, 116, 53, 110, 142
]));
});
it('x=[1,2,2,3] f=[1,1] s=2 p=1 fractional outputs default rounding', async () => {
const inputDepth = 3;
const inShape = [1, 2, 2, inputDepth];
const outputDepth = 1;
const fSize = 1;
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], inShape);
const w = tf.tensor4d([2, 2, 1], [fSize, fSize, inputDepth, outputDepth]);
const pad = [[0, 0], [1, 1], [1, 1], [0, 0]];
const strides = 2;
const result = tf.conv2d(x, w, strides, pad);
expect(result.shape).toEqual([1, 2, 2, 1]);
expectArraysClose(await result.data(), [0, 0, 0, 54]);
});
it('throws when x is not rank 3', () => {
const inputDepth = 1;
const outputDepth = 1;
const fSize = 2;
const pad = 0;
const stride = 1;
// tslint:disable-next-line:no-any
const x = tf.tensor2d([1, 2, 3, 4], [2, 2]);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
expect(() => tf.conv2d(x, w, stride, pad)).toThrowError();
});
it('throws when weights is not rank 4', () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const pad = 0;
const stride = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
// tslint:disable-next-line:no-any
const w = tf.tensor3d([3, 1, 5, 0], [2, 2, 1]);
expect(() => tf.conv2d(x, w, stride, pad)).toThrowError();
});
it('throws when x depth does not match weight depth', () => {
const inputDepth = 1;
const wrongInputDepth = 5;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 0;
const stride = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.randomNormal([fSize, fSize, wrongInputDepth, outputDepth]);
expect(() => tf.conv2d(x, w, stride, pad)).toThrowError();
});
it('throws when x depth does not match weight depth NCHW', () => {
const inputDepth = 1;
const wrongInputDepth = 5;
const inputShape = [inputDepth, 2, 2];
const outputDepth = 1;
const fSize = 2;
const pad = 0;
const stride = 1;
const dataFormat = 'NCHW';
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.randomNormal([fSize, fSize, wrongInputDepth, outputDepth]);
expect(() => tf.conv2d(x, w, stride, pad, dataFormat)).toThrowError();
});
it('throws when dimRoundingMode is set and pad is not a number', () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 'valid';
const stride = 1;
const dataFormat = 'NHWC';
const dilation = 1;
const dimRoundingMode = 'round';
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.randomNormal([fSize, fSize, inputDepth, outputDepth]);
expect(() => tf.conv2d(x, w, stride, pad, dataFormat, dilation, dimRoundingMode))
.toThrowError();
});
it('throws when both stride and dilation are greater than 1', () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const outputDepth = 1;
const fSize = 2;
const pad = 0;
const stride = [2, 1];
const dataFormat = 'NHWC';
const dilation = [1, 2];
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
const w = tf.tensor4d([3, 1, 5, 0], [fSize, fSize, inputDepth, outputDepth]);
expect(() => tf.conv2d(x, w, stride, pad, dataFormat, dilation))
.toThrowError();
});
it('gradient with clones input=[3,3,1] f=[2,2,1,1] s=1 p=0', async () => {
const inputDepth = 1;
const outputDepth = 1;
const inputShape = [3, 3, inputDepth];
const filterSize = 2;
const stride = 1;
const pad = 0;
const filterShape = [filterSize, filterSize, inputDepth, outputDepth];
const filter = tf.ones(filterShape);
const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8, 9], inputShape);
const dy = tf.tensor3d([3, 1, 2, 0], [2, 2, 1]);
const grads = tf.grads((x, filter) => x.clone().conv2d(filter.clone(), stride, pad).clone());
const [dx, dfilter] = grads([x, filter], dy);
expect(dx.shape).toEqual(x.shape);
expectArraysClose(await dx.data(), [3, 4, 1, 5, 6, 1, 2, 2, 0]);
expect(dfilter.shape).toEqual(filterShape);
expectArraysClose(await dfilter.data(), [13, 19, 31, 37]);
});
it('gradient x=[2,3,3,1] f=[2,2,1,1] s=1 p=0', async () => {
const inputDepth = 1;
const outputDepth = 1;
const inputShape = [2, 3, 3, inputDepth];
const filterSize = 2;
const stride = 1;
const pad = 0;
const filterShape = [filterSize, filterSize, inputDepth, outputDepth];
const filter = tf.ones(filterShape);
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9], inputShape);
const dy = tf.tensor4d([3, 1, 2, 0, 3, 1, 2, 0], [2, 2, 2, 1]);
const grads = tf.grads((x, filter) => x.conv2d(filter, stride, pad));
const [dx, dfilter] = grads([x, filter], dy);
expect(dx.shape).toEqual(x.shape);
expectArraysClose(await dx.data(), [3, 4, 1, 5, 6, 1, 2, 2, 0, 3, 4, 1, 5, 6, 1, 2, 2, 0]);
expect(dfilter.shape).toEqual(filterShape);
expectArraysClose(await dfilter.data(), [13 * 2, 19 * 2, 31 * 2, 37 * 2]);
});
it('gradient x=[1,1,3,3] f=[2,2,1,1] s=1 p=0 NCHW', async () => {
const inputDepth = 1;
const outputDepth = 1;
const inputShape = [1, inputDepth, 3, 3];
const filterSize = 2;
const stride = 1;
const pad = 0;
const dataFormat = 'NCHW';
const filterShape = [filterSize, filterSize, inputDepth, outputDepth];
const filter = tf.ones(filterShape);
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, 9], inputShape);
const dy = tf.tensor4d([3, 1, 2, 0], [1, 1, 2, 2]);
const grads = tf.grads((x, filter) => x.conv2d(filter, stride, pad, dataFormat));
const [dx, dfilter] = grads([x, filter], dy);
expect(dx.shape).toEqual(x.shape);
expectArraysClose(await dx.data(), [3, 4, 1, 5, 6, 1, 2, 2, 0]);
expect(dfilter.shape).toEqual(filterShape);
expectArraysClose(await dfilter.data(), [13, 19, 31, 37]);
});
it('gradient x=[2,1,3,3] f=[2,2,1,1] s=1 p=0 NCHW', async () => {
const inputDepth = 1;
const outputDepth = 1;
const inputShape = [2, inputDepth, 3, 3];
const filterSize = 2;
const stride = 1;
const pad = 0;
const dataFormat = 'NCHW';
const filterShape = [filterSize, filterSize, inputDepth, outputDepth];
const filter = tf.ones(filterShape);
const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9], inputShape);
const dy = tf.tensor4d([3, 1, 2, 0, 3, 1, 2, 0], [2, 1, 2, 2]);
const grads = tf.grads((x, filter) => x.conv2d(filter, stride, pad, dataFormat));
const [dx, dfilter] = grads([x, filter], dy);
expect(dx.shape).toEqual(x.shape);
expectArraysClose(await dx.data(), [3, 4, 1, 5, 6, 1, 2, 2, 0, 3, 4, 1, 5, 6, 1, 2, 2, 0]);
expect(dfilter.shape).toEqual(filterShape);
expectArraysClose(await dfilter.data(), [26, 38, 62, 74]);
});
it('throws when passed x as a non-tensor', () => {
const inputDepth = 1;
const outputDepth = 1;
const fSize = 1;
const pad = 0;
const stride = 1;
const w = tf.tensor4d([2], [fSize, fSize, inputDepth, outputDepth]);
expect(() => tf.conv2d({}, w, stride, pad))
.toThrowError(/Argument 'x' passed to 'conv2d' must be a Tensor/);
});
it('throws when passed filter as a non-tensor', () => {
const inputDepth = 1;
const inputShape = [2, 2, inputDepth];
const pad = 0;
const stride = 1;
const x = tf.tensor3d([1, 2, 3, 4], inputShape);
expect(() => tf.conv2d(x, {}, stride, pad))
.toThrowError(/Argument 'filter' passed to 'conv2d' must be a Tensor/);
});
it('accepts a tensor-like object', async () => {
const pad = 0;
const stride = 1;
const x = [[[1], [2]], [[3], [4]]]; // 2x2x1
const w = [[[[2]]]]; // 1x1x1x1
const result = tf.conv2d(x, w, stride, pad);
expectArraysClose(await result.data(), [2, 4, 6, 8]);
});
});
//# sourceMappingURL=conv2d_test.js.map