UNPKG

@tensorflow/tfjs-core

Version:

Hardware-accelerated JavaScript library for machine intelligence

1,353 lines (1,352 loc) 273 kB
/** * @license * Copyright 2020 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 * 0.001 - totalSizeTensor * 0.001 / 2; } for (let i = 0; i < totalSizeFilter; i++) { const sign = i % 2 === 0 ? -1 : 1; filt[i] = i * 0.001 * sign; } return { input: inp, filter: filt }; } describeWithFlags('fused conv2d', ALL_ENVS, () => { it('basic', 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.fused.conv2d({ x, filter: w, strides: 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('basic with relu', 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'relu' }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0, 17, 0, 20, 0, 23]; expectArraysClose(await result.data(), expected); }); it('relu with stride 2 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 // 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'relu' }); 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('relu bias stride 2 x=[1,8,8,16] f=[3,3,16,1] s=[2,2] d=8 p=same', async () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'same'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'relu', bias }); expect(result.shape).toEqual([1, 4, 4, 8]); expectArraysClose(await result.data(), new Float32Array([ 25.75398063659668, 0, 26.857805252075195, 0, 33.961631774902344, 0, 30.065458297729492, 0, 23.118206024169922, 0, 24.212820053100586, 0, 31.307422637939453, 0, 27.402034759521484, 0, 20.482431411743164, 0, 21.567821502685547, 0, 28.653217315673828, 0, 24.73861312866211, 0, 11.078080177307129, 0, 12.130399703979492, 0, 19.182720184326172, 0, 15.235037803649902, 0, 4.6677775382995605, 0.31717729568481445, 5.697869777679443, 0, 12.727968215942383, 2.2569849491119385, 8.758066177368164, 4.226885795593262, 2.0319995880126953, 2.9575586318969727, 3.052880048751831, 1.9366796016693115, 10.073760032653809, 4.915799617767334, 6.094639778137207, 6.89492130279541, 0, 5.5979437828063965, 0.4078875780105591, 4.586280822753906, 7.419551849365234, 7.5746169090271, 3.43121600151062, 9.562952041625977, 0, 6.404943943023682, 0, 5.401776313781738, 6.5998077392578125, 8.398608207702637, 2.602976083755493, 10.395440101623535, 0, 21.440250396728516, 0, 20.483882904052734, 0, 23.527509689331055, 0, 25.571144104003906, 0, 24.080629348754883, 0, 23.133480072021484, 0, 26.186328887939453, 0, 28.239177703857422, 0, 26.721012115478516, 0, 25.783079147338867, 0, 28.84514808654785, 0, 30.907209396362305, 0, 18.914127349853516, 0, 17.960111618041992, 0, 21.006093978881836, 0, 23.052082061767578, 0, 17.89089584350586, 0, 16.95684814453125, 0, 20.022798538208008, 0, 22.088754653930664, 0, 19.06132698059082, 0, 18.133424758911133, 0, 21.205520629882812, 0, 23.27761459350586, 0, 20.23175811767578, 0, 19.309999465942383, 0, 22.388240814208984, 0, 24.46647834777832, 0, 13.584352493286133, 0, 12.6395845413208, 0, 15.694815635681152, 0, 17.750045776367188 ])); }); it('prelu bias stride 2 x=[1,8,8,16] f=[3,3,16,1] s=[2,2] d=8 p=same', async () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'same'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const preluActivationWeights = tf.tensor1d([1, 2, 3, 4, 5, 6, 7, 8]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'prelu', preluActivationWeights, bias }); expect(result.shape).toEqual([1, 4, 4, 8]); expectArraysClose(await result.data(), new Float32Array([ 25.75398063659668, -41.61178970336914, 26.857805252075195, -87.63885498046875, 33.961631774902344, -114.0812759399414, 30.065458297729492, -136.93893432617188, 23.118206024169922, -36.33102035522461, 24.212820053100586, -77.04048156738281, 31.307422637939453, -98.12835693359375, 27.402034759521484, -115.5947265625, 20.482431411743164, -31.050262451171875, 21.567821502685547, -66.44209289550781, 28.653217315673828, -82.17544555664062, 24.73861312866211, -94.25041198730469, 11.078080177307129, -12.208478927612305, 12.130399703979492, -28.626232147216797, 19.182720184326172, -25.253299713134766, 15.235037803649902, -18.08960723876953, 4.6677775382995605, 0.31717729568481445, 5.697869777679443, -2.8516759872436523, 12.727968215942383, 2.2569849491119385, 8.758066177368164, 4.226885795593262, 2.0319995880126953, 2.9575586318969727, 3.052880048751831, 1.9366796016693115, 10.073760032653809, 4.915799617767334, 6.094639778137207, 6.89492130279541, -0.6037763357162476, 5.5979437828063965, 0.4078875780105591, 4.586280822753906, 7.419551849365234, 7.5746169090271, 3.43121600151062, 9.562952041625977, -1.4065279960632324, 6.404943943023682, -1.2100803852081299, 5.401776313781738, 6.5998077392578125, 8.398608207702637, 2.602976083755493, 10.395440101623535, -16.418434143066406, 21.440250396728516, -46.38618850708008, 20.483882904052734, -42.52848815917969, 23.527509689331055, -87.84530639648438, 25.571144104003906, -19.054208755493164, 24.080629348754883, -54.32115936279297, 23.133480072021484, -55.79951477050781, 26.186328887939453, -106.48924255371094, 28.239177703857422, -21.689987182617188, 26.721012115478516, -62.25614929199219, 25.783079147338867, -69.070556640625, 28.84514808654785, -125.13325500488281, 30.907209396362305, -13.891133308410645, 18.914127349853516, -38.81135940551758, 17.960111618041992, -29.915504455566406, 21.006093978881836, -70.20361328125, 23.052082061767578, -12.857919692993164, 17.89089584350586, -35.771610260009766, 16.95684814453125, -24.949115753173828, 20.022798538208008, -63.39042282104492, 22.088754653930664, -14.02528190612793, 19.06132698059082, -39.2921257019043, 18.133424758911133, -30.847349166870117, 21.205520629882812, -71.69097137451172, 23.27761459350586, -15.192638397216797, 20.23175811767578, -42.8126335144043, 19.309999465942383, -36.74560546875, 22.388240814208984, -79.99152374267578, 24.46647834777832, -8.556736946105957, 13.584352493286133, -22.835901260375977, 12.6395845413208, -3.336000442504883, 15.694815635681152, -33.0570182800293, 17.750045776367188 ])); }); it('relu6 bias stride 2 x=[1,8,8,16] f=[3,3,16,8] s=[2,2] d=8 p=same', async () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'same'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'relu6', bias }); expect(result.shape).toEqual([1, 4, 4, 8]); const resultData = await result.data(); expectArraysClose(resultData, new Float32Array([ 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 4.6677775382995605, 0.31717729568481445, 5.697869777679443, 0, 6, 2.2569849491119385, 6, 4.226885795593262, 2.0319995880126953, 2.9575586318969727, 3.052880048751831, 1.9366796016693115, 6, 4.915799617767334, 6, 6, 0, 5.5979437828063965, 0.4078875780105591, 4.586280822753906, 6, 6, 3.43121600151062, 6, 0, 6, 0, 5.401776313781738, 6, 6, 2.602976083755493, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6, 0, 6 ])); }); it('leakyrelu bias stride 2 x=[1,8,8,16] f=[3,3,16,1] s=[2,2] d=8 p=same', async () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'same'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const leakyreluAlpha = 0.3; const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha, bias }); expect(result.shape).toEqual([1, 4, 4, 8]); expectArraysClose(await result.data(), new Float32Array([ 25.75398063659668, -6.241768836975098, 26.857805252075195, -6.5729146003723145, 33.961631774902344, -5.704063892364502, 30.065458297729492, -5.135210037231445, 23.118206024169922, -5.449653148651123, 24.212820053100586, -5.778036117553711, 31.307422637939453, -4.906418323516846, 27.402034759521484, -4.334802627563477, 20.482431411743164, -4.657539367675781, 21.567821502685547, -4.983157157897949, 28.653217315673828, -4.108772277832031, 24.73861312866211, -3.534390687942505, 11.078080177307129, -1.8312718868255615, 12.130399703979492, -2.1469674110412598, 19.182720184326172, -1.262665033340454, 15.235037803649902, -0.6783602833747864, 4.6677775382995605, 0.31717729568481445, 5.697869777679443, -0.21387571096420288, 12.727968215942383, 2.2569849491119385, 8.758066177368164, 4.226885795593262, 2.0319995880126953, 2.9575586318969727, 3.052880048751831, 1.9366796016693115, 10.073760032653809, 4.915799617767334, 6.094639778137207, 6.89492130279541, -0.18113291263580322, 5.5979437828063965, 0.4078875780105591, 4.586280822753906, 7.419551849365234, 7.5746169090271, 3.43121600151062, 9.562952041625977, -0.42195841670036316, 6.404943943023682, -0.12100804597139359, 5.401776313781738, 6.5998077392578125, 8.398608207702637, 2.602976083755493, 10.395440101623535, -4.925530433654785, 21.440250396728516, -4.6386189460754395, 20.483882904052734, -2.5517091751098633, 23.527509689331055, -3.764799118041992, 25.571144104003906, -5.7162628173828125, 24.080629348754883, -5.432116508483887, 23.133480072021484, -3.347970962524414, 26.186328887939453, -4.5638251304626465, 28.239177703857422, -6.5069966316223145, 26.721012115478516, -6.225615501403809, 25.783079147338867, -4.144233703613281, 28.84514808654785, -5.36285400390625, 30.907209396362305, -4.167340278625488, 18.914127349853516, -3.881135940551758, 17.960111618041992, -1.794930338859558, 21.006093978881836, -3.0087265968322754, 23.052082061767578, -3.8573760986328125, 17.89089584350586, -3.5771610736846924, 16.95684814453125, -1.4969470500946045, 20.022798538208008, -2.7167325019836426, 22.088754653930664, -4.207584857940674, 19.06132698059082, -3.9292125701904297, 18.133424758911133, -1.8508410453796387, 21.205520629882812, -3.0724704265594482, 23.27761459350586, -4.557791709899902, 20.23175811767578, -4.28126335144043, 19.309999465942383, -2.2047364711761475, 22.388240814208984, -3.428208351135254, 24.46647834777832, -2.567021131515503, 13.584352493286133, -2.283590316772461, 12.6395845413208, -0.20016004145145416, 15.694815635681152, -1.41672945022583, 17.750045776367188 ])); }); it('throws when dimRoundingMode is set and pad is same', () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'same'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const leakyreluAlpha = 0.3; expect(() => tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha, bias, dimRoundingMode: 'round' })).toThrowError(); }); it('throws when dimRoundingMode is set and pad is valid', () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 'valid'; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const leakyreluAlpha = 0.3; expect(() => tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha, bias, dimRoundingMode: 'round' })).toThrowError(); }); it('throws when dimRoundingMode is set and pad is a non-integer number', () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = 1.2; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const leakyreluAlpha = 0.3; expect(() => tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha, bias, dimRoundingMode: 'round' })).toThrowError(); }); it('throws when dimRoundingMode is set and pad is explicit by non-integer ' + 'number', () => { const inputDepth = 16; const xSize = 8; const inputShape = [1, xSize, xSize, inputDepth]; const outputDepth = 8; const fSize = 3; const pad = [[0, 0], [0, 2.1], [1, 1], [0, 0]]; const stride = [2, 2]; const inputs = generateCaseInputs(1 * xSize * xSize * inputDepth, fSize * fSize * inputDepth * outputDepth); const x = tf.tensor4d(inputs.input, inputShape); const w = tf.tensor4d(inputs.filter, [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 4, 2, 3, 9, 6, 5, 8]); const leakyreluAlpha = 0.3; expect(() => tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha, bias, dimRoundingMode: 'round' })).toThrowError(); }); it('basic with bias', 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], bias: tf.tensor1d([5, 6]) }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [0, 8, -6, 11, -12, 14, -18, 17, -24, 20, -30, 23, -36, 26, -42, 29]; expectArraysClose(await result.data(), expected); }); it('basic with explicit padding', 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation }); const resultData = await result.data(); expect(result.shape).toEqual([4, 2, 1]); expectArraysClose(resultData, [133, 66, 200, 102, 108, 58, 56, 58]); }); it('basic with elu', 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'elu' }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [-0.99326, 2, -1, 5, -1, 8, -1, 11, -1, 14, -1, 17, -1, 20, -1, 23]; expectArraysClose(await result.data(), expected); }); it('basic with prelu', 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 alpha = tf.tensor3d([0.25, 0.75], [1, 1, 2]); const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [ -1.25, 2, -2.75, 5, -4.25, 8, -5.75, 11, -7.25, 14, -8.75, 17, -10.25, 20, -11.75, 23 ]; expectArraysClose(await result.data(), expected); }); it('basic with leakyrelu', 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 alpha = 0.3; const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha: alpha }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [ -1.5, 2, -3.3000001907348633, 5, -5.100000381469727, 8, -6.900000095367432, 11, -8.700000762939453, 14, -10.5, 17, -12.300000190734863, 20, -14.100000381469727, 23 ]; expectArraysClose(await result.data(), expected); }); it('basic with sigmoid', 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 alpha = 0.3; const w = tf.tensor4d([-0.1, 0.1, -0.2, 0.05], [fSize, fSize, inputDepth, outputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'sigmoid', leakyreluAlpha: alpha }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [ 0.3775407, 0.549834, 0.24973989, 0.6224593, 0.15446526, 0.6899744, 0.09112296, 0.7502601, 0.0521535, 0.80218387, 0.02931219, 0.84553474, 0.0163025, 0.8807971, 0.0090133, 0.908877 ]; expectArraysClose(await result.data(), expected); }); it('basic with broadcasted bias and relu', 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.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NHWC', dilations: [1, 1], bias: tf.scalar(5), activation: 'relu' }); expect(result.shape).toEqual([2, 2, 2, 2]); const expected = [0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, 25, 0, 28]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 1; const pad = 0; const stride = 1; const x = tf.tensor4d([1, 3, 5, 7, 2, 4, 6, 8], inShape); const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat: 'NCHW' }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-5, -11, -17, -23, 2, 5, 8, 11]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with scalar bias', async () => { const inputDepth = 4; const inputShape = [1, inputDepth, 2, 2]; const outputDepth = 4; const fSize = 1; const pad = 'same'; const stride = 1; const dataFormat = 'NCHW'; const dilation = 1; const x = tf.tensor4d([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], inputShape); const w = tf.tensor4d([3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0], [fSize, fSize, inputDepth, outputDepth]); const bias = tf.scalar(1); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, bias }); expect(result.shape).toEqual([1, 4, 2, 2]); const expected = [10, 19, 28, 37, 10, 19, 28, 37, 10, 19, 28, 37, 10, 19, 28, 37]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with 1-D bias', async () => { const inputDepth = 4; const inputShape = [1, inputDepth, 2, 2]; const outputDepth = 4; const fSize = 1; const pad = 'same'; const stride = 1; const dataFormat = 'NCHW'; const dilation = 1; const x = tf.tensor4d([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], inputShape); const w = tf.tensor4d([3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0], [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 2, 1, 2]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, bias }); expect(result.shape).toEqual([1, 4, 2, 2]); const expected = [10, 19, 28, 37, 11, 20, 29, 38, 10, 19, 28, 37, 11, 20, 29, 38]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with bias and multiple batches', async () => { const inputDepth = 4; const inputShape = [2, inputDepth, 2, 2]; const outputDepth = 4; const fSize = 1; const pad = 'same'; const stride = 1; const dataFormat = 'NCHW'; const dilation = 1; const x = tf.tensor4d([ 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 ], inputShape); const w = tf.tensor4d([3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0], [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 2, 1, 2]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, bias }); expect(result.shape).toEqual([2, 4, 2, 2]); const expected = [ 10, 19, 28, 37, 11, 20, 29, 38, 10, 19, 28, 37, 11, 20, 29, 38, 10, 19, 28, 37, 11, 20, 29, 38, 10, 19, 28, 37, 11, 20, 29, 38 ]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with scalar PReLU actiavation', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 1; const dataFormat = 'NCHW'; const dilation = 1; const pad = 0; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.scalar(10); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-110, -140, -170, -200, 3.5, 5, 6.5, 8]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with 1-D PReLU actiavation', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 1; const dataFormat = 'NCHW'; const dilation = 1; const pad = 0; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, 1, -2, 0.5], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.tensor1d([10, 100]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-110, -140, -170, -200, 3.5, 5, 6.5, 8]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with 3-D PReLU actiavation', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 1; const dataFormat = 'NCHW'; const dilation = 1; const pad = 0; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, -1, -2, -2], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.tensor3d([1, 10], [2, 1, 1]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-11, -14, -17, -20, -110, -140, -170, -200]; expectArraysClose(await result.data(), expected); }); it('basic in NCHW with full 3-D PReLU actiavation', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 1; const dataFormat = 'NCHW'; const dilation = 1; const pad = 0; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, -1, -2, -2], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8], [2, 2, 2]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-11, -28, -51, -80, -55, -84, -119, -160]; expectArraysClose(await result.data(), expected); }); it('im2row', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [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.fused.conv2d({ x, filter: w, strides, pad }); expectArraysClose(await result.data(), [10, 5, 10, 50, 25, 50, -10, -5, -10, -50, -25, -50]); }); it('im2row with relu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [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.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'relu' }); expectArraysClose(await result.data(), [10, 5, 10, 50, 25, 50, 0, 0, 0, 0, 0, 0]); }); it('im2row with prelu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [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 alpha = tf.tensor3d([0.5], [1, 1, inputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'prelu', preluActivationWeights: alpha }); expectArraysClose(await result.data(), [10, 5, 10, 50, 25, 50, -5, -2.5, -5, -25, -12.5, -25]); }); it('im2row with leakyrelu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [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 alpha = 0.3; const result = tf.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha: alpha }); expectArraysClose(await result.data(), [ 10, 5, 10, 50, 25, 50, -3, -1.5, -3, -15.000000953674316, -7.500000476837158, -15.000000953674316 ]); }); it('pointwise with prelu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [1, 1]; 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 alpha = tf.tensor3d([0.5], [1, 1, inputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'prelu', preluActivationWeights: alpha }); expectArraysClose(await result.data(), [ 10, 5, 10, 30, 15, 30, 50, 25, 50, 70, 35, 70, 20, 10, 20, 40, 20, 40, 60, 30, 60, 80, 40, 80, -5, -2.5, -5, -15, -7.5, -15, -25, -12.5, -25, -35, -17.5, -35, -10, -5, -10, -20, -10, -20, -30, -15, -30, -40, -20, -40 ]); }); it('pointwise with leakyrelu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [1, 1]; 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 alpha = 0.3; const result = tf.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], activation: 'leakyrelu', leakyreluAlpha: alpha }); expectArraysClose(await result.data(), [ 10, 5, 10, 30, 15, 30, 50, 25, 50, 70, 35, 70, 20, 10, 20, 40, 20, 40, 60, 30, 60, 80, 40, 80, -3, -1.5, -3, -9, -4.5, -9, -15.000000953674316, -7.500000476837158, -15.000000953674316, -21, -10.5, -21, -6, -3, -6, -12, -6, -12, -18, -9, -18, -24, -12, -24 ]); }); it('im2row with broadcasted bias and relu', async () => { const inputDepth = 1; const inputShape = [4, 4, inputDepth]; const outputDepth = 3; const fSize = 1; const pad = 'same'; const strides = [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.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NHWC', dilations: [1, 1], bias: tf.scalar(5), activation: 'relu' }); expectArraysClose(await result.data(), [15, 10, 15, 55, 30, 55, 0, 0, 0, 0, 0, 0]); }); it('im2row in NCHW', async () => { const inputDepth = 2; const inputShape = [inputDepth, 2, 2]; const outputDepth = 2; const fSize = 2; const pad = 'same'; const strides = [1, 1]; const x = tf.tensor3d([1, 2, 3, 4, 5, 6, 7, 8], inputShape); const w = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8], [fSize, fSize, inputDepth, outputDepth]); const result = tf.fused.conv2d({ x, filter: w, strides, pad, dataFormat: 'NCHW' }); expectArraysClose(await result.data(), [-32, -8, 100, 28, -40, -12, 122, 40]); }); it('im2row in NCHW with scalar bias', async () => { const inputDepth = 4; const inputShape = [1, inputDepth, 2, 2]; const outputDepth = 4; const fSize = 2; const pad = 'same'; const stride = 1; const dataFormat = 'NCHW'; const dilation = 1; const x = tf.tensor4d([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], inputShape); const w = tf.tensor4d([ 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, ], [fSize, fSize, inputDepth, outputDepth]); const bias = tf.scalar(1); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, bias }); expect(result.shape).toEqual([1, 4, 2, 2]); const expected = [91, 55, 64, 37, 91, 55, 64, 37, 91, 55, 64, 37, 91, 55, 64, 37]; expectArraysClose(await result.data(), expected); }); it('im2row in NCHW with 1-D bias', async () => { const inputDepth = 4; const inputShape = [1, inputDepth, 2, 2]; const outputDepth = 4; const fSize = 2; const pad = 'same'; const stride = 1; const dataFormat = 'NCHW'; const dilation = 1; const x = tf.tensor4d([1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], inputShape); const w = tf.tensor4d([ 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 5, 5, 5, 5, 0, 0, 0, 0, ], [fSize, fSize, inputDepth, outputDepth]); const bias = tf.tensor1d([1, 2, 1, 2]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, bias }); expect(result.shape).toEqual([1, 4, 2, 2]); const expected = [91, 55, 64, 37, 92, 56, 65, 38, 91, 55, 64, 37, 92, 56, 65, 38]; expectArraysClose(await result.data(), expected); }); it('im2row in NCHW with scalar PReLU actiavation weights', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 2; const dataFormat = 'NCHW'; const dilation = 1; const pad = 'same'; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, -1, -1, -1, 1, 1, 1, 1, -2, -2, -2, -2, 0.5, 0.5, 0.5, 0.5], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.scalar(10); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha }); expect(result.shape).toEqual([1, 2, 2, 2]); const expected = [-120, -320, 2, -120, -120, -320, 2, -120]; expectArraysClose(await result.data(), expected); }); it('im2row in NCHW with 1-D PReLU actiavation weights', async () => { const inputDepth = 2; const inShape = [1, inputDepth, 2, 2]; const outputDepth = 2; const fSize = 2; const dataFormat = 'NCHW'; const dilation = 1; const pad = 'same'; const stride = 1; const x = tf.tensor4d([1, 2, 3, 4, 5, 6, 7, 8], inShape); const w = tf.tensor4d([-1, -1, -1, -1, 1, 1, 1, 1, -2, -2, -2, -2, 0.5, 0.5, 0.5, 0.5], [fSize, fSize, inputDepth, outputDepth]); const alpha = tf.tensor1d([1, 10]); const result = tf.fused.conv2d({ x, filter: w, strides: stride, pad, dataFormat, dilations: dilation, activation: 'prelu', preluActivationWeights: alpha });