gx
chenyc
2025-06-12 7b72ac13a83764a662159d4a49b7fffb90476ecb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
 * @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=