2023-06-12 14:46:27 +00:00
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
// Licensed under the MIT License.
|
|
|
|
|
|
2024-08-14 23:51:22 +00:00
|
|
|
import { DataType } from '../../../wasm-common';
|
|
|
|
|
import { TensorView } from '../../tensor-view';
|
|
|
|
|
import { ShapeUtil } from '../../util';
|
|
|
|
|
import { AttributeWithCacheKey, createAttributeWithCacheKey } from '../attribute-with-cache-key';
|
|
|
|
|
import { ComputeContext, ProgramInfo, ProgramShaderCacheInfo } from '../types';
|
|
|
|
|
|
|
|
|
|
import { createTensorShapeVariables, IndicesHelper, inputVariable, outputVariable, ShaderHelper } from './common';
|
|
|
|
|
import {
|
|
|
|
|
reduceL1Shared,
|
|
|
|
|
reduceL2Shared,
|
|
|
|
|
reduceLogSumExpShared,
|
|
|
|
|
reduceLogSumShared,
|
|
|
|
|
reduceMaxShared,
|
|
|
|
|
reduceMeanShared,
|
|
|
|
|
reduceMinShared,
|
|
|
|
|
reduceProdShared,
|
|
|
|
|
reduceSumShared,
|
|
|
|
|
reduceSumSquareShared,
|
|
|
|
|
} from './reduce-shared';
|
2023-06-12 14:46:27 +00:00
|
|
|
|
|
|
|
|
const validateInputs = (inputs: readonly TensorView[]): void => {
|
|
|
|
|
if (!inputs || inputs.length === 0 || inputs.length > 2) {
|
|
|
|
|
throw new Error('Reduce op requires 1 or 2 inputs.');
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-30 16:42:38 +00:00
|
|
|
if (inputs.length === 2 && inputs[1].dims.length !== 1) {
|
|
|
|
|
throw new Error('Invalid axes input dims.');
|
|
|
|
|
}
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface ReduceAttributes extends AttributeWithCacheKey {
|
|
|
|
|
keepDims: boolean;
|
|
|
|
|
noopWithEmptyAxes: boolean;
|
2023-06-30 16:42:38 +00:00
|
|
|
axes: number[];
|
2023-06-12 14:46:27 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-14 23:51:22 +00:00
|
|
|
export type ReduceOp = (
|
|
|
|
|
input: IndicesHelper,
|
|
|
|
|
output: IndicesHelper,
|
|
|
|
|
axes: readonly number[],
|
|
|
|
|
) => [string, string, string, string, ...string[]];
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
|
2023-12-12 19:12:23 +00:00
|
|
|
const noOp: ReduceOp = (input) => ['', '', `var value = ${input.getByIndices('input_indices')};`, ''];
|
2024-08-14 23:51:22 +00:00
|
|
|
export const createReduceProgramInfo = (
|
|
|
|
|
name: string,
|
|
|
|
|
shaderCache: ProgramShaderCacheInfo,
|
|
|
|
|
inputs: readonly TensorView[],
|
|
|
|
|
reduceOp: ReduceOp,
|
|
|
|
|
axesInput: number[],
|
|
|
|
|
outputDataType: DataType,
|
|
|
|
|
keepDims = false,
|
|
|
|
|
noopWithEmptyAxes = false,
|
|
|
|
|
): ProgramInfo => {
|
|
|
|
|
const outputShape: number[] = [];
|
|
|
|
|
const inputShape = inputs[0].dims;
|
|
|
|
|
const inputRank = inputShape.length;
|
|
|
|
|
const axes = ShapeUtil.normalizeAxes(axesInput, inputRank);
|
|
|
|
|
const reduceOnAllAxes = !noopWithEmptyAxes && axes.length === 0;
|
|
|
|
|
inputShape.forEach((d, i) => {
|
|
|
|
|
if (reduceOnAllAxes || axes.indexOf(i) >= 0) {
|
|
|
|
|
if (keepDims) {
|
|
|
|
|
outputShape.push(1);
|
|
|
|
|
} // else { // skip this axis}
|
|
|
|
|
} else {
|
|
|
|
|
outputShape.push(d);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
const outputRank = outputShape.length;
|
|
|
|
|
const outputSize = ShapeUtil.size(outputShape);
|
|
|
|
|
const getShaderSource = (shaderHelper: ShaderHelper) => {
|
|
|
|
|
const idxCopy: string[] = []; // copy output indexes to input indexes
|
|
|
|
|
|
|
|
|
|
const input = inputVariable('_A', inputs[0].dataType, inputRank);
|
|
|
|
|
const output = outputVariable('output', outputDataType, outputRank);
|
|
|
|
|
const ops = reduceOp(input, output, axes);
|
|
|
|
|
let reduceOps = ops[2];
|
|
|
|
|
|
|
|
|
|
for (let k = 0, l = 0; k < inputRank; k++) {
|
|
|
|
|
// if this axis is reduced
|
|
|
|
|
if (reduceOnAllAxes || axes.indexOf(k) >= 0) {
|
|
|
|
|
if (keepDims) {
|
|
|
|
|
l++;
|
2023-08-04 19:59:36 +00:00
|
|
|
}
|
2024-08-14 23:51:22 +00:00
|
|
|
// loop over the d-th axis
|
|
|
|
|
reduceOps = `for(var j${k}: u32 = 0; j${k} < ${inputShape[k]}; j${k}++) {
|
2023-12-12 19:12:23 +00:00
|
|
|
${ops[2].includes('last_index') ? `let last_index = j${k};` : ''}
|
|
|
|
|
${input.indicesSet('input_indices', k, `j${k}`)}
|
|
|
|
|
${reduceOps}
|
|
|
|
|
}`;
|
2024-08-14 23:51:22 +00:00
|
|
|
} else {
|
|
|
|
|
idxCopy.push(`${input.indicesSet('input_indices', k, output.indicesGet('output_indices', l))};`);
|
|
|
|
|
l++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return `
|
2023-06-12 14:46:27 +00:00
|
|
|
|
2023-12-12 19:12:23 +00:00
|
|
|
${shaderHelper.registerUniform('output_size', 'u32').declareVariables(input, output)}
|
2023-06-12 14:46:27 +00:00
|
|
|
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
${shaderHelper.mainStart()}
|
2023-12-12 19:12:23 +00:00
|
|
|
${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes('uniforms.output_size')}
|
|
|
|
|
var input_indices: ${input.type.indices};
|
|
|
|
|
let output_indices = ${output.offsetToIndices('global_idx')};
|
2023-06-12 14:46:27 +00:00
|
|
|
|
|
|
|
|
${idxCopy.join('\n')}
|
|
|
|
|
${ops[0]} // init ops for reduce max/min
|
|
|
|
|
${ops[1]}
|
|
|
|
|
${reduceOps}
|
2023-08-04 19:59:36 +00:00
|
|
|
${ops[3]}
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
${ops.length === 4 ? output.setByOffset('global_idx', 'value') : ops.slice(4).join('\n')}
|
2023-06-12 14:46:27 +00:00
|
|
|
}`;
|
2024-08-14 23:51:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
name,
|
|
|
|
|
shaderCache,
|
|
|
|
|
getShaderSource,
|
|
|
|
|
getRunData: () => ({
|
|
|
|
|
outputs: [{ dims: outputShape, dataType: outputDataType }],
|
|
|
|
|
dispatchGroup: { x: Math.ceil(outputSize / 64 /* workgroup size */) },
|
|
|
|
|
programUniforms: [
|
|
|
|
|
{ type: DataType.uint32, data: outputSize },
|
|
|
|
|
...createTensorShapeVariables(inputShape, outputShape),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const createReduceAttributesFromInputs = (
|
|
|
|
|
inputs: readonly TensorView[],
|
|
|
|
|
attributes: ReduceAttributes,
|
|
|
|
|
): ReduceAttributes => {
|
|
|
|
|
const axes: number[] = [];
|
|
|
|
|
if (inputs[1].dims[0] > 0) {
|
|
|
|
|
inputs[1].getBigInt64Array().forEach((v) => axes.push(Number(v)));
|
|
|
|
|
}
|
|
|
|
|
return createAttributeWithCacheKey({
|
|
|
|
|
axes,
|
|
|
|
|
keepDims: attributes.keepDims,
|
|
|
|
|
noopWithEmptyAxes: attributes.noopWithEmptyAxes,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const runReduceProgram = (
|
|
|
|
|
context: ComputeContext,
|
|
|
|
|
name: string,
|
|
|
|
|
attributes: ReduceAttributes,
|
|
|
|
|
reduceOp: ReduceOp,
|
|
|
|
|
): void => {
|
|
|
|
|
const inputs = context.inputs;
|
|
|
|
|
const updatedAttributes: ReduceAttributes =
|
|
|
|
|
inputs.length === 1 ? attributes : createReduceAttributesFromInputs(inputs, attributes);
|
|
|
|
|
|
|
|
|
|
context.compute(
|
|
|
|
|
createReduceProgramInfo(
|
|
|
|
|
name,
|
|
|
|
|
{ hint: updatedAttributes.cacheKey, inputDependencies: ['rank'] },
|
|
|
|
|
[inputs[0]],
|
|
|
|
|
updatedAttributes.noopWithEmptyAxes && updatedAttributes.axes.length === 0 ? noOp : reduceOp,
|
|
|
|
|
updatedAttributes.axes,
|
|
|
|
|
inputs[0].dataType,
|
|
|
|
|
updatedAttributes.keepDims,
|
|
|
|
|
updatedAttributes.noopWithEmptyAxes,
|
|
|
|
|
),
|
|
|
|
|
{ inputs: [0] },
|
|
|
|
|
);
|
|
|
|
|
};
|
2023-06-12 14:46:27 +00:00
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceLogSumNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var value = ${output.type.storage}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`value += ${input.getByIndices('input_indices')};`,
|
|
|
|
|
'value = log(value);',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceLogSum', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceL1Naive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var value = ${output.type.storage}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`value += abs(${input.getByIndices('input_indices')});`,
|
|
|
|
|
'',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceL1', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceL2Naive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`t = ${input.getByIndices('input_indices')}; value += (t * t);`,
|
|
|
|
|
'value = sqrt(value);',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceL2', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceLogSumExpNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var value = ${output.type.storage}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`value += exp(${input.getByIndices('input_indices')});`,
|
|
|
|
|
'value = log(value);',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceLogSumExp', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceMaxNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
const reduceOp: ReduceOp = (input, _output, axes) => {
|
2023-06-12 14:46:27 +00:00
|
|
|
const idxZero = [];
|
2023-10-10 07:31:12 +00:00
|
|
|
for (let k = 0; k < input.rank; k++) {
|
2023-06-12 14:46:27 +00:00
|
|
|
if (axes.indexOf(k) >= 0 || axes.length === 0) {
|
2023-12-12 19:12:23 +00:00
|
|
|
idxZero.push(input.indicesSet('input_indices', k, 0));
|
2023-06-12 14:46:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
return [
|
|
|
|
|
`${idxZero.join('\n')}`,
|
2023-12-12 19:12:23 +00:00
|
|
|
`var value = ${input.getByIndices('input_indices')};`,
|
|
|
|
|
`value = max(value, ${input.getByIndices('input_indices')});`,
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
'',
|
|
|
|
|
];
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceMax', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceMeanNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output, axes) => {
|
2023-06-12 14:46:27 +00:00
|
|
|
let size = 1.0;
|
2023-10-10 07:31:12 +00:00
|
|
|
for (let k = 0; k < input.rank; k++) {
|
2023-06-12 14:46:27 +00:00
|
|
|
if (axes.indexOf(k) >= 0 || axes.length === 0) {
|
2023-10-10 07:31:12 +00:00
|
|
|
// TODO: this depends on the input dims. If we want to use uniform, this need to be updated.
|
|
|
|
|
size *= context.inputs[0].dims[k];
|
2023-06-12 14:46:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-04 19:59:36 +00:00
|
|
|
return [
|
2023-09-21 21:52:13 +00:00
|
|
|
'var sum = f32(0);',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
'',
|
2023-12-12 19:12:23 +00:00
|
|
|
`sum += f32(${input.getByIndices('input_indices')});`,
|
2023-09-21 21:52:13 +00:00
|
|
|
`let value = ${output.type.value}(sum / ${size});`,
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceMean', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceMinNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
const reduceOp: ReduceOp = (input, _output, axes) => {
|
2023-06-12 14:46:27 +00:00
|
|
|
const idxZero = [];
|
2023-10-10 07:31:12 +00:00
|
|
|
for (let k = 0; k < input.rank; k++) {
|
2023-06-12 14:46:27 +00:00
|
|
|
if (axes.indexOf(k) >= 0 || axes.length === 0) {
|
2024-08-14 23:51:22 +00:00
|
|
|
idxZero.push(`input_indices[${k}] = 0;`); // first element
|
2023-06-12 14:46:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
return [
|
|
|
|
|
`${idxZero.join('\n')}`,
|
2023-12-12 19:12:23 +00:00
|
|
|
`var value = ${input.getByIndices('input_indices')};`,
|
|
|
|
|
`value = min(value, ${input.getByIndices('input_indices')});`,
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
'',
|
|
|
|
|
];
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceMin', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceProdNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var value = ${output.type.storage}(1);`,
|
|
|
|
|
'',
|
|
|
|
|
`value *= ${input.getByIndices('input_indices')};`,
|
|
|
|
|
'',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceProd', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceSumNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var value = ${output.type.storage}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`value += ${input.getByIndices('input_indices')};`,
|
|
|
|
|
'',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceSum', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2023-11-02 19:51:48 +00:00
|
|
|
const reduceSumSquareNaive = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
2023-06-12 14:46:27 +00:00
|
|
|
validateInputs(context.inputs);
|
2024-08-14 23:51:22 +00:00
|
|
|
const reduceOp: ReduceOp = (input, output) => [
|
|
|
|
|
`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`,
|
|
|
|
|
'',
|
|
|
|
|
`t = ${input.getByIndices('input_indices')}; value += t * t;`,
|
|
|
|
|
'',
|
[js/web] [webgpu] new incides helper (#16957)
### Description
This PR introduces the new incides helper.
IndicesHelper is a helper class for generating WGSL code for
manipulating indices and data for a shader's input or output.
This class is designed to offer a unified way to generate WGSL code for
manipulating indices and data for a shader's input or output. The
following is a list of terminologies used in this class:
- `offset`: a uint32 value representing the offset of an element in the
data buffer.
- `indices`: an abstraction of a multi-dimensional array's indices
representing the data's index on each dimension.
- `value`: a value of a data element.
Users are expected to create an instance of this class for each shader's
input or output, and use the instance to generate WGSL code for
manipulating indices and data. The following 2 exported functions are
for users to call to create an instance of an indices helper:
- `inputVariable()`: create an indices helper instance for an input.
- `outputVariable()`: create an indices helper instance for an output.
An indices helper instance contains helper functions for the following
operations:
- access readonly basic information, including: `name`(the name of the
input or output), `usage`(whether it's an input or an output) and
`shape`(the passed in shape).
- `type`: access readonly type information, including: `indices`(the
type of indices), `value`(the type of value at runtime), `storage`(the
type of value at storage) and `tensor`(the tensor type as represented in
TensorView).
- generate WGSL code for getting indices from offset. Use
`offsetToIndices()` for WGSL code snippet to calculate incides from
offset, and use `indicesToOffset()` for WGSL code snippet to calculate
offset from indices.
- to manipulate an instance of indices, use `setIndices()` and
`getIndices()` to set and get the indices on an indices variable.
- to manipulate data, use `set()`/`get()` to access data at the given
indices from parameter list, use `setByIndices()`/`getByIndices()` to
access data at the given indices from an indices variable, and use
`setByOffset()`/`getByOffset()` to access data at the given offset.
- `impl`: get WGSL code of function implementation for the util
functions mentioned above.
This change applies the usage of new IndicesHelper through the code, but
not necessary for all code.
2023-08-11 18:36:59 +00:00
|
|
|
];
|
2023-10-10 07:31:12 +00:00
|
|
|
runReduceProgram(context, 'ReduceSumSquare', attributes, reduceOp);
|
2023-06-12 14:46:27 +00:00
|
|
|
};
|
|
|
|
|
|
2024-08-14 23:51:22 +00:00
|
|
|
const useNaiveReduceMethod = (
|
|
|
|
|
shape: readonly number[],
|
|
|
|
|
axes: readonly number[],
|
|
|
|
|
noopWithEmptyAxes: boolean,
|
|
|
|
|
): boolean => {
|
|
|
|
|
if (axes.length === 0) {
|
|
|
|
|
return noopWithEmptyAxes;
|
|
|
|
|
}
|
2023-11-02 19:51:48 +00:00
|
|
|
|
2024-08-14 23:51:22 +00:00
|
|
|
let outputSize = 1;
|
|
|
|
|
let reduceSize = 1;
|
|
|
|
|
for (let dim = 0; dim < axes.length; dim++) {
|
|
|
|
|
if (axes.indexOf(dim) === -1) {
|
|
|
|
|
outputSize *= shape[dim];
|
|
|
|
|
} else {
|
|
|
|
|
reduceSize *= shape[dim];
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-02 19:51:48 +00:00
|
|
|
|
2024-08-14 23:51:22 +00:00
|
|
|
// The condition data is very rough, although considering the count of Execution Unit (EU), the potential
|
|
|
|
|
// work groups in a EU and the counts of loops in the naive and shared methods, also doing experiments
|
|
|
|
|
// on some machines.
|
|
|
|
|
return reduceSize < 32 && outputSize > 1024;
|
|
|
|
|
};
|
2023-11-02 19:51:48 +00:00
|
|
|
|
|
|
|
|
export const reduceMean = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceMeanNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceMeanShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceL1 = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceL1Naive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceL1Shared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceL2 = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceL2Naive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceL2Shared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceLogSumExp = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceLogSumExpNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceLogSumExpShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceMax = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceMaxNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceMaxShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceMin = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceMinNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceMinShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceProd = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceProdNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceProdShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceSum = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceSumNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceSumShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceSumSquare = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceSumSquareNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceSumSquareShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reduceLogSum = (context: ComputeContext, attributes: ReduceAttributes): void => {
|
|
|
|
|
if (useNaiveReduceMethod(context.inputs[0].dims, attributes.axes, attributes.noopWithEmptyAxes)) {
|
|
|
|
|
reduceLogSumNaive(context, attributes);
|
|
|
|
|
} else {
|
|
|
|
|
reduceLogSumShared(context, attributes);
|
|
|
|
|
}
|
|
|
|
|
};
|