/** * @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 { FusedBatchNorm } from '../kernel_names'; import { add } from '../ops/add'; import { getReductionAxes } from '../ops/broadcast_util'; import { mul } from '../ops/mul'; import { reshape } from '../ops/reshape'; import { rsqrt } from '../ops/rsqrt'; import { scalar } from '../ops/scalar'; import { sub } from '../ops/sub'; import { sum } from '../ops/sum'; import { tile } from '../ops/tile'; export const fusedBatchNormGradConfig = { kernelName: FusedBatchNorm, inputsToSave: ['x', 'mean', 'variance', 'scale'], gradFunc: (dy, saved, attrs) => { const { varianceEpsilon } = attrs; const [x, mean, variance, scale] = saved; const scaleValue = scale == null ? scalar(1) : scale; const reductionAxes = getReductionAxes(mean.shape, x.shape); const tileShape = []; if (mean.rank === 1) { for (let i = 0; i < x.shape.length - 1; ++i) { tileShape.push(x.shape[i]); } tileShape.push(1); } const xMinusMean = sub(x, mean); const dyTimesScaleValue = mul(dy, scaleValue); const oneOverSqrtVariance = rsqrt(add(variance, scalar(varianceEpsilon))); const minusHalfRCube = mul(mul(mul(oneOverSqrtVariance, oneOverSqrtVariance), oneOverSqrtVariance), scalar(-0.5)); const derX = () => { if (mean.rank === 1) { return reshape(mul(mul(dy, tile(reshape(oneOverSqrtVariance, [1, 1, 1, mean.shape[0]]), tileShape)), scaleValue), x.shape); } else { return reshape(mul(mul(dy, oneOverSqrtVariance), scaleValue), x.shape); } }; const derMean = () => { let meanDer = mul(mul(oneOverSqrtVariance, scalar(-1)), dyTimesScaleValue); if (mean.rank === 1) { meanDer = sum(meanDer, reductionAxes); } return reshape(meanDer, mean.shape); }; const derVariance = () => { let varianceDer = mul(mul(minusHalfRCube, xMinusMean), dyTimesScaleValue); if (mean.rank === 1) { varianceDer = sum(varianceDer, reductionAxes); } return reshape(varianceDer, mean.shape); }; const derScale = () => { const xMinusMean2TimesRsqrt = mul(xMinusMean, oneOverSqrtVariance); let scaleDer = mul(dy, xMinusMean2TimesRsqrt); if (mean.rank === 1) { scaleDer = sum(scaleDer, reductionAxes); } return reshape(scaleDer, mean.shape); }; const derOffset = () => { let offsetDer = dy; if (mean.rank === 1) { offsetDer = sum(offsetDer, reductionAxes); } return reshape(offsetDer, mean.shape); }; return { x: derX, mean: derMean, variance: derVariance, scale: derScale, offset: derOffset }; } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRnVzZWRCYXRjaE5vcm1fZ3JhZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtY29yZS9zcmMvZ3JhZGllbnRzL0Z1c2VkQmF0Y2hOb3JtX2dyYWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsT0FBTyxFQUFDLGNBQWMsRUFBc0IsTUFBTSxpQkFBaUIsQ0FBQztBQUVwRSxPQUFPLEVBQUMsR0FBRyxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBQy9CLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ3ZELE9BQU8sRUFBQyxHQUFHLEVBQUMsTUFBTSxZQUFZLENBQUM7QUFDL0IsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxLQUFLLEVBQUMsTUFBTSxjQUFjLENBQUM7QUFDbkMsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUNyQyxPQUFPLEVBQUMsR0FBRyxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBQy9CLE9BQU8sRUFBQyxHQUFHLEVBQUMsTUFBTSxZQUFZLENBQUM7QUFDL0IsT0FBTyxFQUFDLElBQUksRUFBQyxNQUFNLGFBQWEsQ0FBQztBQUlqQyxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBZTtJQUNsRCxVQUFVLEVBQUUsY0FBYztJQUMxQixZQUFZLEVBQUUsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUM7SUFDaEQsUUFBUSxFQUFFLENBQ04sRUFBVSxFQUFFLEtBQWUsRUFBRSxLQUFtQixFQUFFLEVBQUU7UUFDdEQsTUFBTSxFQUFDLGVBQWUsRUFBQyxHQUFHLEtBQXVDLENBQUM7UUFDbEUsTUFBTSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUV6QyxNQUFN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QUM7UUFDekQsQ0FBQyxDQUFDO1FBQ0YsTUFBTSxRQUFRLEdBQUcsR0FBRyxFQUFFO1lBQ3BCLE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDLFVBQVUsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1lBRW5FLElBQUksUUFBUSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEVBQUUscUJBQXFCLENBQUMsQ0FBQztZQUM5QyxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssQ0FBQyxFQUFFO2dCQUNuQixRQUFRLEdBQUcsR0FBRyxDQUFDLFFBQVEsRUFBRSxhQUFhLENBQUMsQ0FBQzthQUN6QztZQUNELE9BQU8sT0FBTyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsS0FBb0IsQ0FBQyxDQUFDO1FBQ3RELENBQUMsQ0FBQztRQUNGLE1BQU0sU0FBUyxHQUFHLEdBQUcsRUFBRTtZQUNyQixJQUFJLFNBQVMsR0FBRyxFQUFFLENBQUM7WUFDbkIsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsRUFBRTtnQkFDbkIsU0FBUyxHQUFHLEdBQUcsQ0FBQyxTQUFTLEVBQUUsYUFBYSxDQUFDLENBQUM7YUFDM0M7WUFDRCxPQUFPLE9BQU8sQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLEtBQW9CLENBQUMsQ0FBQztRQUN2RCxDQUFDLENBQUM7UUFFRixPQUFPO1lBQ0wsQ0FBQyxFQUFFLElBQUk7WUFDUCxJQUFJLEVBQUUsT0FBTztZQUNiLFFBQVEsRUFBRSxXQUFXO1lBQ3JCLEtBQUssRUFBRSxRQUFRO1lBQ2YsTUFBTSxFQUFFLFNBQVM7U0FDbEIsQ0FBQztJQUNKLENBQUM7Q0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjAgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuaW1wb3J0IHtGdXNlZEJhdGNoTm9ybSwgRnVzZWRCYXRjaE5vcm1BdHRyc30gZnJvbSAnLi4va2VybmVsX25hbWVzJztcbmltcG9ydCB7R3JhZENvbmZpZywgTmFtZWRBdHRyTWFwfSBmcm9tICcuLi9rZXJuZWxfcmVnaXN0cnknO1xuaW1wb3J0IHthZGR9IGZyb20gJy4uL29wcy9hZGQnO1xuaW1wb3J0IHtnZXRSZWR1Y3Rpb25BeGVzfSBmcm9tICcuLi9vcHMvYnJvYWRjYXN0X3V0aWwnO1xuaW1wb3J0IHttdWx9IGZyb20gJy4uL29wcy9tdWwnO1xuaW1wb3J0IHtyZXNoYXBlfSBmcm9tICcuLi9vcHMvcmVzaGFwZSc7XG5pbXBvcnQge3JzcXJ0fSBmcm9tICcuLi9vcHMvcnNxcnQnO1xuaW1wb3J0IHtzY2FsYXJ9IGZyb20gJy4uL29wcy9zY2FsYXInO1xuaW1wb3J0IHtzdWJ9IGZyb20gJy4uL29wcy9zdWInO1xuaW1wb3J0IHtzdW19IGZyb20gJy4uL29wcy9zdW0nO1xuaW1wb3J0IHt0aWxlfSBmcm9tICcuLi9vcHMvdGlsZSc7XG5pbXBvcnQge1RlbnNvcn0gZnJvbSAnLi4vdGVuc29yJztcbmltcG9ydCB7UmFuaywgU2hhcGVNYXB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNvbnN0IGZ1c2VkQmF0Y2hOb3JtR3JhZENvbmZpZzogR3JhZENvbmZpZyA9IHtcbiAga2VybmVsTmFtZTogRnVzZWRCYXRjaE5vcm0sXG4gIGlucHV0c1RvU2F2ZTogWyd4JywgJ21lYW4nLCAndmFyaWFuY2UnLCAnc2NhbGUnXSxcbiAgZ3JhZEZ1bmM6IDxSIGV4dGVuZHMgUmFuaz4oXG4gICAgICBkeTogVGVuc29yLCBzYXZlZDogVGVuc29yW10sIGF0dHJzOiBOYW1lZEF0dHJNYXApID0+IHtcbiAgICBjb25zdCB7dmFyaWFuY2VFcHNpbG9ufSA9IGF0dHJzIGFzIHVua25vd24gYXMgRnVzZWRCYXRjaE5vcm1BdHRycztcbiAgICBjb25zdCBbeCwgbWVhbiwgdmFyaWFuY2UsIHNjYWxlXSA9IHNhdmVkO1xuXG4gICAgY29uc3Qgc2NhbGVWYWx1ZSA9IHNjYWxlID09IG51bGwgPyBzY2FsYXIoMSkgOiBzY2FsZTtcbiAgICBjb25zdCByZWR1Y3Rpb25BeGVzID0gZ2V0UmVkdWN0aW9uQXhlcyhtZWFuLnNoYXBlLCB4LnNoYXBlKTtcbiAgICBjb25zdCB0aWxlU2hhcGU6IG51bWJlcltdID0gW107XG4gICAgaWYgKG1lYW4ucmFuayA9PT0gMSkge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB4LnNoYXBlLmxlbmd0aCAtIDE7ICsraSkge1xuICAgICAgICB0aWxlU2hhcGUucHVzaCh4LnNoYXBlW2ldKTtcbiAgICAgIH1cbiAgICAgIHRpbGVTaGFwZS5wdXNoKDEpO1xuICAgIH1cblxuICAgIGNvbnN0IHhNaW51c01lYW4gPSBzdWIoeCwgbWVhbik7XG4gICAgY29uc3QgZHlUaW1lc1NjYWxlVmFsdWUgPSBtdWwoZHksIHNjYWxlVmFsdWUpO1xuICAgIGNvbnN0IG9uZU92ZXJTcXJ0VmFyaWFuY2UgPSByc3FydChhZGQodmFyaWFuY2UsIHNjYWxhcih2YXJpYW5jZUVwc2lsb24pKSk7XG4gICAgY29uc3QgbWludXNIYWxmUkN1YmUgPSBtdWwoXG4gICAgICAgIG11bChtdWwob25lT3ZlclNxcnRWYXJpYW5jZSwgb25lT3ZlclNxcnRWYXJpYW5jZSksIG9uZU92ZXJTcXJ0VmFyaWFuY2UpLFxuICAgICAgICBzY2FsYXIoLTAuNSkpO1xuXG4gICAgY29uc3QgZGVyWCA9ICgpID0+IHtcbiAgICAgIGlmIChtZWFuLnJhbmsgPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIHJlc2hhcGUoXG4gICAgICAgICAgICBtdWwobXVsKGR5LFxuICAgICAgICAgICAgICAgICAgICB0aWxlKFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzaGFwZShvbmVPdmVyU3FydFZhcmlhbmNlLCBbMSwgMSwgMSwgbWVhbi5zaGFwZVswXV0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGlsZVNoYXBlKSksXG4gICAgICAgICAgICAgICAgc2NhbGVWYWx1ZSksXG4gICAgICAgICAgICB4LnNoYXBlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiByZXNoYXBlKG11bChtdWwoZHksIG9uZU92ZXJTcXJ0VmFyaWFuY2UpLCBzY2FsZVZhbHVlKSwgeC5zaGFwZSk7XG4gICAgICB9XG4gICAgfTtcbiAgICBjb25zdCBkZXJNZWFuID0gKCkgPT4ge1xuICAgICAgbGV0IG1lYW5EZXIgPVxuICAgICAgICAgIG11bChtdWwob25lT3ZlclNxcnRWYXJpYW5jZSwgc2NhbGFyKC0xKSksIGR5VGltZXNTY2FsZVZhbHVlKTtcbiAgICAgIGlmIChtZWFuLnJhbmsgPT09IDEpIHtcbiAgICAgICAgbWVhbkRlciA9IHN1bShtZWFuRGVyLCByZWR1Y3Rpb25BeGVzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNoYXBlKG1lYW5EZXIsIG1lYW4uc2hhcGUgYXMgU2hhcGVNYXBbUl0pO1xuICAgIH07XG4gICAgY29uc3QgZGVyVmFyaWFuY2UgPSAoKSA9PiB7XG4gICAgICBsZXQgdmFyaWFuY2VEZXIgPSBtdWwobXVsKG1pbnVzSGFsZlJDdWJlLCB4TWludXNNZWFuKSwgZHlUaW1lc1NjYWxlVmFsdWUpO1xuXG4gICAgICBpZiAobWVhbi5yYW5rID09PSAxKSB7XG4gICAgICAgIHZhcmlhbmNlRGVyID0gc3VtKHZhcmlhbmNlRGVyLCByZWR1Y3Rpb25BeGVzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNoYXBlKHZhcmlhbmNlRGVyLCBtZWFuLnNoYXBlIGFzIFNoYXBlTWFwW1JdKTtcbiAgICB9O1xuICAgIGNvbnN0IGRlclNjYWxlID0gKCkgPT4ge1xuICAgICAgY29uc3QgeE1pbnVzTWVhbjJUaW1lc1JzcXJ0ID0gbXVsKHhNaW51c01lYW4sIG9uZU92ZXJTcXJ0VmFyaWFuY2UpO1xuXG4gICAgICBsZXQgc2NhbGVEZXIgPSBtdWwoZHksIHhNaW51c01lYW4yVGltZXNSc3FydCk7XG4gICAgICBpZiAobWVhbi5yYW5rID09PSAxKSB7XG4gICAgICAgIHNjYWxlRGVyID0gc3VtKHNjYWxlRGVyLCByZWR1Y3Rpb25BeGVzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXNoYXBlKHNjYWxlRGVyLCBtZWFuLnNoYXBlIGFzIFNoYXBlTWFwW1JdKTtcbiAgICB9O1xuICAgIGNvbnN0IGRlck9mZnNldCA9ICgpID0+IHtcbiAgICAgIGxldCBvZmZzZXREZXIgPSBkeTtcbiAgICAgIGlmIChtZWFuLnJhbmsgPT09IDEpIHtcbiAgICAgICAgb2Zmc2V0RGVyID0gc3VtKG9mZnNldERlciwgcmVkdWN0aW9uQXhlcyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzaGFwZShvZmZzZXREZXIsIG1lYW4uc2hhcGUgYXMgU2hhcGVNYXBbUl0pO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgeDogZGVyWCxcbiAgICAgIG1lYW46IGRlck1lYW4sXG4gICAgICB2YXJpYW5jZTogZGVyVmFyaWFuY2UsXG4gICAgICBzY2FsZTogZGVyU2NhbGUsXG4gICAgICBvZmZzZXQ6IGRlck9mZnNldFxuICAgIH07XG4gIH1cbn07XG4iXX0=