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
/**
 * @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 { GatherV2 } from '../kernel_names';
import { getUndoAxesPermutation } from '../ops/axis_util';
import { reshape } from '../ops/reshape';
import { stack } from '../ops/stack';
import { transpose } from '../ops/transpose';
import { unsortedSegmentSum } from '../ops/unsorted_segment_sum';
import { parseAxisParam } from '../util';
export const gatherGradConfig = {
    kernelName: GatherV2,
    inputsToSave: ['x', 'indices'],
    gradFunc: (dy, saved, attrs) => {
        const [x, indices] = saved;
        const { axis, batchDims } = attrs;
        const parsedAxis = parseAxisParam(axis, x.shape)[0];
        const derXBatch = (x, indices, dy) => {
            return () => {
                const paramsShape = x.shape;
                const indicesSize = indices.size;
                const outerShape = paramsShape.slice(0, parsedAxis);
                const outerDims = outerShape.length;
                const innerShape = paramsShape.slice(axis, paramsShape.length).slice(1);
                const innerDims = innerShape.length;
                const outerAxesIndices = arrayRange(0, outerDims);
                const innerAxesIndices = arrayRange(outerDims + 1, outerDims + 1 + innerDims);
                const valuesShape = arrayConcat([outerShape, [indicesSize],
                    innerShape]);
                const values = reshape(dy, valuesShape);
                const reshapedIndices = reshape(indices, [indicesSize]);
                const transposeDims = arrayConcat([[outerDims], outerAxesIndices, innerAxesIndices]);
                const valuesTranspose = transpose(values, transposeDims);
                let paramsGrad = unsortedSegmentSum(valuesTranspose, reshapedIndices, x.shape[parsedAxis]);
                const invertTransposeDims = getUndoAxesPermutation(transposeDims);
                paramsGrad = transpose(paramsGrad, invertTransposeDims);
                return paramsGrad;
            };
        };
        if (batchDims === 1) {
            const batchSize = x.shape[0];
            const xBatch = x.split(batchSize, 0);
            const derXBatched = () => {
                const stacked = stack(xBatch.map((x, i) => {
                    return derXBatch(x, indices.slice(i, 1), dy.slice(i, 1))();
                }));
                return stacked.reshape(x.shape);
            };
            return { x: derXBatched, indices: () => indices };
        }
        else {
            return { x: derXBatch(x, indices, dy), indices: () => indices };
        }
    }
};
function arrayRange(start, stop) {
    const result = [];
    for (let i = start; i < stop; ++i) {
        result.push(i);
    }
    return result;
}
function arrayConcat(arrays) {
    const result = [];
    for (let i = 0; i < arrays.length; ++i) {
        for (let j = 0; j < arrays[i].length; ++j) {
            result.push(arrays[i][j]);
        }
    }
    return result;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2F0aGVyVjJfZ3JhZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtY29yZS9zcmMvZ3JhZGllbnRzL0dhdGhlclYyX2dyYWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxFQUFDLFFBQVEsRUFBZ0IsTUFBTSxpQkFBaUIsQ0FBQztBQUV4RCxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUN4RCxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkMsT0FBTyxFQUFDLEtBQUssRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUNuQyxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDM0MsT0FBTyxFQUFDLGtCQUFrQixFQUFDLE1BQU0sNkJBQTZCLENBQUM7QUFFL0QsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUV2QyxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBZTtJQUMxQyxVQUFVLEVBQUUsUUFBUTtJQUNwQixZQUFZLEVBQUUsQ0FBQyxHQUFHLEVBQUUsU0FBUyxDQUFDO0lBQzlCLFFBQVEsRUFBRSxDQUFDLEVBQVUsRUFBRSxLQUFlLEVBQUUsS0FBbUIsRUFBRSxFQUFFO1FBQzdELE1BQU0sQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQzNCLE1BQU0sRUFBQyxJQUFJLEVBQUUsU0FBUyxFQUFDLEdBQUcsS0FBaUMsQ0FBQztRQUU1RCxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVwRCxNQUFNLFNBQVMsR0FBRyxDQUFDLENBQVMsRUFBRSxPQUFlLEVBQUUsRUFBVSxFQUFFLEVBQUU7WUFDM0QsT0FBTyxHQUFXLEVBQUU7Z0JBQ2xC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QUFDO0NBQ0YsQ0FBQztBQUVGLFNBQVMsVUFBVSxDQUFDLEtBQWEsRUFBRSxJQUFZO0lBQzdDLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQztJQUNsQixLQUFLLElBQUksQ0FBQyxHQUFHLEtBQUssRUFBRSxDQUFDLEdBQUcsSUFBSSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1FBQ2pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDaEI7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsTUFBa0I7SUFDckMsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ2xCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1FBQ3RDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQ3pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDM0I7S0FDRjtJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAyMCBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCB7R2F0aGVyVjIsIEdhdGhlclYyQXR0cnN9IGZyb20gJy4uL2tlcm5lbF9uYW1lcyc7XG5pbXBvcnQge0dyYWRDb25maWcsIE5hbWVkQXR0ck1hcH0gZnJvbSAnLi4va2VybmVsX3JlZ2lzdHJ5JztcbmltcG9ydCB7Z2V0VW5kb0F4ZXNQZXJtdXRhdGlvbn0gZnJvbSAnLi4vb3BzL2F4aXNfdXRpbCc7XG5pbXBvcnQge3Jlc2hhcGV9IGZyb20gJy4uL29wcy9yZXNoYXBlJztcbmltcG9ydCB7c3RhY2t9IGZyb20gJy4uL29wcy9zdGFjayc7XG5pbXBvcnQge3RyYW5zcG9zZX0gZnJvbSAnLi4vb3BzL3RyYW5zcG9zZSc7XG5pbXBvcnQge3Vuc29ydGVkU2VnbWVudFN1bX0gZnJvbSAnLi4vb3BzL3Vuc29ydGVkX3NlZ21lbnRfc3VtJztcbmltcG9ydCB7VGVuc29yLCBUZW5zb3IxRH0gZnJvbSAnLi4vdGVuc29yJztcbmltcG9ydCB7cGFyc2VBeGlzUGFyYW19IGZyb20gJy4uL3V0aWwnO1xuXG5leHBvcnQgY29uc3QgZ2F0aGVyR3JhZENvbmZpZzogR3JhZENvbmZpZyA9IHtcbiAga2VybmVsTmFtZTogR2F0aGVyVjIsXG4gIGlucHV0c1RvU2F2ZTogWyd4JywgJ2luZGljZXMnXSxcbiAgZ3JhZEZ1bmM6IChkeTogVGVuc29yLCBzYXZlZDogVGVuc29yW10sIGF0dHJzOiBOYW1lZEF0dHJNYXApID0+IHtcbiAgICBjb25zdCBbeCwgaW5kaWNlc10gPSBzYXZlZDtcbiAgICBjb25zdCB7YXhpcywgYmF0Y2hEaW1zfSA9IGF0dHJzIGFzIHVua25vd24gYXMgR2F0aGVyVjJBdHRycztcblxuICAgIGNvbnN0IHBhcnNlZEF4aXMgPSBwYXJzZUF4aXNQYXJhbShheGlzLCB4LnNoYXBlKVswXTtcblxuICAgIGNvbnN0IGRlclhCYXRjaCA9ICh4OiBUZW5zb3IsIGluZGljZXM6IFRlbnNvciwgZHk6IFRlbnNvcikgPT4ge1xuICAgICAgcmV0dXJuICgpOiBUZW5zb3IgPT4ge1xuICAgICAgICBjb25zdCBwYXJhbXNTaGFwZSA9IHguc2hhcGU7XG4gICAgICAgIGNvbnN0IGluZGljZXNTaXplID0gaW5kaWNlcy5zaXplO1xuXG4gICAgICAgIGNvbnN0IG91dGVyU2hhcGUgPSBwYXJhbXNTaGFwZS5zbGljZSgwLCBwYXJzZWRBeGlzKTtcbiAgICAgICAgY29uc3Qgb3V0ZXJEaW1zID0gb3V0ZXJTaGFwZS5sZW5ndGg7XG4gICAgICAgIGNvbnN0IGlubmVyU2hhcGUgPSBwYXJhbXNTaGFwZS5zbGljZShheGlzLCBwYXJhbXNTaGFwZS5sZW5ndGgpLnNsaWNlKDEpO1xuICAgICAgICBjb25zdCBpbm5lckRpbXMgPSBpbm5lclNoYXBlLmxlbmd0aDtcblxuICAgICAgICBjb25zdCBvdXRlckF4ZXNJbmRpY2VzID0gYXJyYXlSYW5nZSgwLCBvdXRlckRpbXMpO1xuICAgICAgICBjb25zdCBpbm5lckF4ZXNJbmRpY2VzID1cbiAgICAgICAgICAgIGFycmF5UmFuZ2Uob3V0ZXJEaW1zICsgMSwgb3V0ZXJEaW1zICsgMSArIGlubmVyRGltcyk7XG5cbiAgICAgICAgY29uc3QgdmFsdWVzU2hhcGUgPSBhcnJheUNvbmNhdChbb3V0ZXJTaGFwZSwgW2luZGljZXNTaXplXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5uZXJTaGFwZV0pO1xuXG4gICAgICAgIGNvbnN0IHZhbHVlcyA9IHJlc2hhcGUoZHksIHZhbHVlc1NoYXBlKTtcbiAgICAgICAgY29uc3QgcmVzaGFwZWRJbmRpY2VzID0gcmVzaGFwZShpbmRpY2VzLCBbaW5kaWNlc1NpemVdKTtcblxuICAgICAgICBjb25zdCB0cmFuc3Bvc2VEaW1zID1cbiAgICAgICAgICAgIGFycmF5Q29uY2F0KFtbb3V0ZXJEaW1zXSwgb3V0ZXJBeGVzSW5kaWNlcywgaW5uZXJBeGVzSW5kaWNlc10pO1xuICAgICAgICBjb25zdCB2YWx1ZXNUcmFuc3Bvc2UgPSB0cmFuc3Bvc2UodmFsdWVzLCB0cmFuc3Bvc2VEaW1zKTtcbiAgICAgICAgbGV0IHBhcmFtc0dyYWQgPSB1bnNvcnRlZFNlZ21lbnRTdW0oXG4gICAgICAgICAgICB2YWx1ZXNUcmFuc3Bvc2UsIHJlc2hhcGVkSW5kaWNlcyBhcyBUZW5zb3IxRCwgeC5zaGFwZVtwYXJzZWRBeGlzXSk7XG4gICAgICAgIGNvbnN0IGludmVydFRyYW5zcG9zZURpbXMgPSBnZXRVbmRvQXhlc1Blcm11dGF0aW9uKHRyYW5zcG9zZURpbXMpO1xuICAgICAgICBwYXJhbXNHcmFkID0gdHJhbnNwb3NlKHBhcmFtc0dyYWQsIGludmVydFRyYW5zcG9zZURpbXMpO1xuICAgICAgICByZXR1cm4gcGFyYW1zR3JhZDtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIGlmIChiYXRjaERpbXMgPT09IDEpIHtcbiAgICAgIGNvbnN0IGJhdGNoU2l6ZSA9IHguc2hhcGVbMF07XG4gICAgICBjb25zdCB4QmF0Y2ggPSB4LnNwbGl0KGJhdGNoU2l6ZSwgMCk7XG4gICAgICBjb25zdCBkZXJYQmF0Y2hlZCA9ICgpID0+IHtcbiAgICAgICAgY29uc3Qgc3RhY2tlZCA9IHN0YWNrKFxuICAgICAgICAgIHhCYXRjaC5tYXAoKHgsIGkpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBkZXJYQmF0Y2goeCwgaW5kaWNlcy5zbGljZShpLDEpLCBkeS5zbGljZShpLDEpKSgpO1xuICAgICAgICAgIH0pKTtcbiAgICAgICAgcmV0dXJuIHN0YWNrZWQucmVzaGFwZSh4LnNoYXBlKTtcbiAgICAgIH07XG4gICAgICByZXR1cm4ge3g6IGRlclhCYXRjaGVkLCBpbmRpY2VzOiAoKSA9PiBpbmRpY2VzfTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHt4OiBkZXJYQmF0Y2goeCwgaW5kaWNlcywgZHkpLCBpbmRpY2VzOiAoKSA9PiBpbmRpY2VzfTtcbiAgICB9XG4gIH1cbn07XG5cbmZ1bmN0aW9uIGFycmF5UmFuZ2Uoc3RhcnQ6IG51bWJlciwgc3RvcDogbnVtYmVyKTogbnVtYmVyW10ge1xuICBjb25zdCByZXN1bHQgPSBbXTtcbiAgZm9yIChsZXQgaSA9IHN0YXJ0OyBpIDwgc3RvcDsgKytpKSB7XG4gICAgcmVzdWx0LnB1c2goaSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gYXJyYXlDb25jYXQoYXJyYXlzOiBudW1iZXJbXVtdKTogbnVtYmVyW10ge1xuICBjb25zdCByZXN1bHQgPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheXMubGVuZ3RoOyArK2kpIHtcbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IGFycmF5c1tpXS5sZW5ndGg7ICsraikge1xuICAgICAgcmVzdWx0LnB1c2goYXJyYXlzW2ldW2pdKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cbiJdfQ==