[js/web] support 'pytorch_half_pixel' mode for WebGL kernel 'Resize' (#11208)

**Description**: 
1. add pytorch_half_pixel interpolation mode in resize-packed.ts
Changes: add the following case in createPackedResizeProgramInfo
function:
```
case 'pytorch_half_pixel':
          getSourceFracIndex = `
                    vec4 getSourceFracIndex(ivec4 coords) {
                        vec4 fcoords = vec4(coords);
                        return vec4(
                            ${outputWidth}.0 > 1.0 ? (fcoords.x + 0.5) / scaleWHWH.x - 0.5 : 0.0,
                            ${outputHeight}.0 > 1.0 ? (fcoords.y + 0.5) / scaleWHWH.y - 0.5 : 0.0,
                            ${outputWidth}.0 > 1.0 ? (fcoords.z + 0.5) / scaleWHWH.z - 0.5 : 0.0,
                            ${outputHeight}.0 > 1.0 ? (fcoords.w + 0.5) / scaleWHWH.w - 0.5 : 0.0
                          );
                    }
                `;
          break;
```
2. fix "unrecognized input '' for node: Resize_$num" error when inputs
like [input_tensor, None, scale_factor] (roiInput not given) are fed
into the resize layer.
Changes: change in input handling logic in upsample.ts & node scanning
logic in graph.ts

**Motivation and Context**
Before this fix, we aren't able to use webGL backend when the neural
network contains pytorch resize layers. This fix adds
'pytorch_half_pixel' interpolation mode support and makes it possible to
use webGL backend for more kind of computer vision networks.

This commit solves:
#10430

Co-authored-by: neo <neo@icode-lab.com>
Co-authored-by: Yulong Wang <7679871+fs-eire@users.noreply.github.com>
This commit is contained in:
Seungwon Jeong 2022-11-22 05:03:48 +09:00 committed by GitHub
parent 3119381011
commit 307ad1413a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 4 deletions

View file

@ -95,6 +95,19 @@ const createPackedResizeProgramInfo =
}
`;
break;
case 'pytorch_half_pixel':
getSourceFracIndex = `
vec4 getSourceFracIndex(ivec4 coords) {
vec4 fcoords = vec4(coords);
return vec4(
${outputWidth}.0 > 1.0 ? (fcoords.x + 0.5) / scaleWHWH.x - 0.5 : 0.0,
${outputHeight}.0 > 1.0 ? (fcoords.y + 0.5) / scaleWHWH.y - 0.5 : 0.0,
${outputWidth}.0 > 1.0 ? (fcoords.z + 0.5) / scaleWHWH.z - 0.5 : 0.0,
${outputHeight}.0 > 1.0 ? (fcoords.w + 0.5) / scaleWHWH.w - 0.5 : 0.0
);
}
`;
break;
case 'align_corners':
getSourceFracIndex = `
vec4 getSourceFracIndex(ivec4 coords) {

View file

@ -99,9 +99,15 @@ export const parseUpsampleAttributes = (node: Graph.Node, opset: number): Upsamp
let sizesInputIdx = 0;
if (opset > 10) {
roiInputIdx = 1;
scalesInputIdx = 2;
sizesInputIdx = 3;
// handle when roiInput is not given
if (node.inputs.length > 2) {
roiInputIdx = 1;
scalesInputIdx = 2;
sizesInputIdx = 3;
} else {
scalesInputIdx = 1;
sizesInputIdx = 2;
}
} else if (opset === 9) {
scalesInputIdx = 1;
}
@ -307,7 +313,7 @@ const createUpsampleProgramInfo =
export const validateInputs = (inputs: Tensor[], attribute: UpsampleAttributes): void => {
if (!inputs || (attribute.opset < 9 && inputs.length !== 1) ||
(attribute.opset >= 9 && attribute.opset < 11 && inputs.length !== 2) ||
(attribute.opset >= 11 && inputs.length !== 3 && inputs.length !== 4)) {
(attribute.opset >= 11 && inputs.length < 2)) {
throw new Error('invalid inputs.');
}

View file

@ -333,6 +333,10 @@ class GraphImpl implements Graph, Graph.Transformer {
for (const input of nodeProto.input) {
const dataIndex = dataIndices.get(input);
if (typeof dataIndex === 'undefined') {
// handle exception when opset > 9 and roi not given
if (input === '' && nodeProto.input.length === 3 && nodeProto.opType === 'Resize') {
continue;
}
throw new Error(`unrecognized input '${input}' for node: ${nodeProto.name}`);
}
node.inputs.push(dataIndex);