-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
completed l2pool2d #68
Changes from all commits
aa60c41
a51db0a
de9785c
de57d69
46ce01c
ef5af87
5d9c2f3
3b3e02a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
'use strict'; | ||
import {l2Pool2d} from '../src/pool2d.js'; | ||
import {Tensor} from '../src/lib/tensor.js'; | ||
|
||
import * as utils from './utils.js'; | ||
|
||
describe('test pool2d', function() { | ||
it('l2Pool2d default', function() { | ||
const x = new Tensor([1, 1, 4, 4], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); | ||
const windowDimensions = [3, 3]; | ||
const y = l2Pool2d(x, {windowDimensions}); | ||
utils.checkShape(y, [1, 1, 2, 2]); | ||
utils.checkValue(y, [ | ||
20.639767440550294, | ||
23.302360395462088, | ||
31.654383582688826, | ||
34.51086785347479, | ||
]); | ||
}); | ||
|
||
it('l2Pool2d default: a single element test case', function() { | ||
const x = new Tensor([1, 1, 1, 1], [2]); | ||
const windowDimensions = [1, 1]; | ||
const y = l2Pool2d(x, {windowDimensions}); | ||
utils.checkShape(y, [1, 1, 1, 1]); | ||
utils.checkValue(y, [2]); | ||
}); | ||
|
||
it('l2Pool2d default: start not from 1 ', function() { | ||
const x = new Tensor([1, 1, 4, 4], [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); | ||
const windowDimensions = [3, 3]; | ||
const y = l2Pool2d(x, {windowDimensions}); | ||
utils.checkShape(y, [1, 1, 2, 2]); | ||
utils.checkValue(y, [ | ||
34.51086785347479, | ||
31.654383582688826, | ||
23.302360395462088, | ||
20.639767440550294, | ||
]); | ||
}); | ||
|
||
it('l2Pool2d nhwc', function() { | ||
const x = new Tensor([1, 4, 4, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); | ||
const windowDimensions = [3, 3]; | ||
const layout = 'nhwc'; | ||
const y = l2Pool2d(x, {windowDimensions, layout}); | ||
utils.checkShape(y, [1, 2, 2, 1]); | ||
utils.checkValue(y, [ | ||
20.639767440550294, | ||
23.302360395462088, | ||
31.654383582688826, | ||
34.51086785347479, | ||
]); | ||
}); | ||
|
||
it('l2Pool2d dilations default', function() { | ||
const x = new Tensor([1, 1, 4, 4], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); | ||
const windowDimensions = [2, 2]; | ||
const dilations = [2, 2]; | ||
const y = l2Pool2d(x, {windowDimensions, dilations}); | ||
utils.checkShape(y, [1, 1, 2, 2]); | ||
utils.checkValue(y, [ | ||
14.560219778561036, | ||
16.24807680927192, | ||
21.633307652783937, | ||
23.49468024894146, | ||
]); | ||
}); | ||
|
||
it('l2Pool2d dilations nhwc', function() { | ||
const x = new Tensor([1, 4, 4, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); | ||
const windowDimensions = [2, 2]; | ||
const dilations = [2, 2]; | ||
const layout = 'nhwc'; | ||
const y = l2Pool2d(x, {windowDimensions, dilations, layout}); | ||
utils.checkShape(y, [1, 2, 2, 1]); | ||
utils.checkValue(y, [ | ||
14.560219778561036, | ||
16.24807680927192, | ||
21.633307652783937, | ||
23.49468024894146, | ||
]); | ||
}); | ||
|
||
it('l2Pool2d pads default', function() { | ||
const x = new Tensor([1, 1, 5, 5], [ | ||
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, | ||
]); | ||
const windowDimensions = [5, 5]; | ||
const padding = [2, 2, 2, 2]; | ||
const y = l2Pool2d(x, {windowDimensions, padding}); | ||
utils.checkShape(y, [1, 1, 5, 5]); | ||
const expected = [ | ||
24.43358344574123, 29.832867780352597, | ||
35.21363372331802, 32.89376840679705, | ||
29.748949561287034, 38.28837943815329, | ||
46.04345773288535, 53.5723809439155, | ||
49.558046773455466, 44.384682042344295, | ||
54.037024344425184, 64.42049363362563, | ||
74.33034373659252, 68.33739825307956, | ||
60.8276253029822, 53.907327887774215, | ||
64.18722614352485, 73.95944834840239, | ||
67.94115100585212, 60.41522986797286, | ||
52.507142371300304, 62.369864518050704, | ||
71.69379331573968, 65.7419196555744, | ||
58.35237784358063, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d pads nhwc', function() { | ||
const x = new Tensor([1, 5, 5, 1], [ | ||
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, | ||
]); | ||
const windowDimensions = [5, 5]; | ||
const padding = [2, 2, 2, 2]; | ||
const layout = 'nhwc'; | ||
const y = l2Pool2d(x, {windowDimensions, padding, layout}); | ||
utils.checkShape(y, [1, 5, 5, 1]); | ||
const expected = [ | ||
24.43358344574123, 29.832867780352597, | ||
35.21363372331802, 32.89376840679705, | ||
29.748949561287034, 38.28837943815329, | ||
46.04345773288535, 53.5723809439155, | ||
49.558046773455466, 44.384682042344295, | ||
54.037024344425184, 64.42049363362563, | ||
74.33034373659252, 68.33739825307956, | ||
60.8276253029822, 53.907327887774215, | ||
64.18722614352485, 73.95944834840239, | ||
67.94115100585212, 60.41522986797286, | ||
52.507142371300304, 62.369864518050704, | ||
71.69379331573968, 65.7419196555744, | ||
58.35237784358063, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d autoPad same-upper default', function() { | ||
const x = new Tensor([1, 1, 5, 5], [ | ||
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, | ||
]); | ||
const windowDimensions = [5, 5]; | ||
const autoPad = 'same-upper'; | ||
const y = l2Pool2d(x, {windowDimensions, autoPad}); | ||
utils.checkShape(y, [1, 1, 5, 5]); | ||
const expected = [ | ||
24.43358344574123, 29.832867780352597, | ||
35.21363372331802, 32.89376840679705, | ||
29.748949561287034, 38.28837943815329, | ||
46.04345773288535, 53.5723809439155, | ||
49.558046773455466, 44.384682042344295, | ||
54.037024344425184, 64.42049363362563, | ||
74.33034373659252, 68.33739825307956, | ||
60.8276253029822, 53.907327887774215, | ||
64.18722614352485, 73.95944834840239, | ||
67.94115100585212, 60.41522986797286, | ||
52.507142371300304, 62.369864518050704, | ||
71.69379331573968, 65.7419196555744, | ||
58.35237784358063, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d autoPad explicit nhwc', function() { | ||
const x = new Tensor([1, 7, 7, 1], [ | ||
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, | ||
]); | ||
const windowDimensions = [4, 4]; | ||
const padding = [2, 1, 2, 1]; | ||
const strides = [2, 2]; | ||
const autoPad = 'explicit'; | ||
const layout = 'nhwc'; | ||
const y = l2Pool2d( | ||
x, {windowDimensions, autoPad, padding, strides, layout}); | ||
utils.checkShape(y, [1, 4, 4, 1]); | ||
const expected = [ | ||
12.24744871391589, 19.8997487421324, | ||
24.899799195977465, 24.879710609249457, | ||
40.54626986542659, 60.860496218811754, | ||
67.82329983125268, 63.324560795950255, | ||
76.81145747868608, 112.5344391730816, | ||
120.2331069215131, 109.1146186356347, | ||
90.50414355155237, 131.4610208388783, | ||
138.31124321616085, 124.21352583354198, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d autoPad same-lower nhwc', function() { | ||
const x = new Tensor([1, 7, 7, 1], [ | ||
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, | ||
]); | ||
const windowDimensions = [4, 4]; | ||
const strides = [2, 2]; | ||
const autoPad = 'same-lower'; | ||
const layout = 'nhwc'; | ||
const y = | ||
l2Pool2d(x, {windowDimensions, autoPad, strides, layout}); | ||
utils.checkShape(y, [1, 4, 4, 1]); | ||
const expected = [ | ||
12.24744871391589, 19.8997487421324, | ||
24.899799195977465, 24.879710609249457, | ||
40.54626986542659, 60.860496218811754, | ||
67.82329983125268, 63.324560795950255, | ||
76.81145747868608, 112.5344391730816, | ||
120.2331069215131, 109.1146186356347, | ||
90.50414355155237, 131.4610208388783, | ||
138.31124321616085, 124.21352583354198, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d autoPad same-upper nhwc', function() { | ||
const x = new Tensor([1, 5, 5, 1], [ | ||
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, | ||
]); | ||
const windowDimensions = [5, 5]; | ||
const autoPad = 'same-upper'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, we're still using @huningxin, you opened webmachinelearning/webnn#326 where we talked about removing autoPad from conv2d, and @Honry removed it from the WebNN EP in microsoft/onnxruntime#18688, but for consistency, wouldn't we want to be explicit with pooling too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, we should be consistent and only do explicit padding for pooling. |
||
const layout = 'nhwc'; | ||
const y = l2Pool2d(x, {windowDimensions, autoPad, layout}); | ||
|
||
utils.checkShape(y, [1, 5, 5, 1]); | ||
const expected = [ | ||
24.43358344574123, 29.832867780352597, | ||
35.21363372331802, 32.89376840679705, | ||
29.748949561287034, 38.28837943815329, | ||
46.04345773288535, 53.5723809439155, | ||
49.558046773455466, 44.384682042344295, | ||
54.037024344425184, 64.42049363362563, | ||
74.33034373659252, 68.33739825307956, | ||
60.8276253029822, 53.907327887774215, | ||
64.18722614352485, 73.95944834840239, | ||
67.94115100585212, 60.41522986797286, | ||
52.507142371300304, 62.369864518050704, | ||
71.69379331573968, 65.7419196555744, | ||
58.35237784358063, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d strides default', function() { | ||
const x = new Tensor([1, 1, 5, 5], [ | ||
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, | ||
]); | ||
const windowDimensions = [2, 2]; | ||
const strides = [2, 2]; | ||
const y = l2Pool2d(x, {windowDimensions, strides}); | ||
utils.checkShape(y, [1, 1, 2, 2]); | ||
const expected = [ | ||
9.486832980505138, | ||
13.038404810405298, | ||
28.460498941515414, | ||
32.4037034920393, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
|
||
it('l2Pool2d strides nhwc', function() { | ||
const x = new Tensor([1, 5, 5, 1], [ | ||
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, | ||
]); | ||
const windowDimensions = [2, 2]; | ||
const strides = [2, 2]; | ||
const layout = 'nhwc'; | ||
const y = l2Pool2d(x, {windowDimensions, strides, layout}); | ||
utils.checkShape(y, [1, 2, 2, 1]); | ||
const expected = [ | ||
9.486832980505138, | ||
13.038404810405298, | ||
28.460498941515414, | ||
32.4037034920393, | ||
]; | ||
utils.checkValue(y, expected); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we add a single element test case here (e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay,I have added a single element test case. |
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(update) I found a use case for normalizing across batches and spatial dimensions - this may inform future decisions: https://ieeexplore.ieee.org/document/8648206
🤔 I've often wondered why pooling in ML doesn't have variations that can pool across batches or channel dimensions too, not only the "spatial" dimensions. e.g. One could generalize pooling consistently like reduction (which can apply from all dimensions to none), and pass windowDimensions of rank 4 with
[3, 1, 3, 3]
to pool along batches too, or just[1, 3, 1, 1]
for only channels. Also it would eliminate the then redundant layout parameter. Now, DML can achieve the latter via explicit strides (to map the first dimension to the last dimensions), but there's no way to access it via WebNN, and I've never heard of a need for it anyway. 🤷 I suppose if a researcher really wanted it, they could transpose the batch dimension to the X dimension, pool, then transpose back; and if there has been such a use case, that's probably exactly what they did.*No action expected - just musing after noticing this.