// META: title=test WebNN API linear operation
// META: global=window,dedicatedworker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
// META: script=../resources/utils.js
// META: timeout=long
'use strict';
// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-linear
// Calculate a linear function y = alpha * x + beta on the input tensor.
//
// dictionary MLLinearOptions {
// double alpha = 1;
// double beta = 0;
// };
//
// MLOperand linear(MLOperand input, optional MLLinearOptions options = {});
const getLinearPrecisionTolerance = (graphResources) => {
const toleranceValueDict = {float32: 2, float16: 2};
const expectedDataType =
getExpectedDataTypeOfSingleOutput(graphResources.expectedOutputs);
return {metricType: 'ULP', value: toleranceValueDict[expectedDataType]};
};
const linearTests = [
{
'name': 'linear float32 1D constant tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [24], 'dataType': 'float32'},
'constant': true
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [24], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 0D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [-1.12251615524292],
'descriptor': {'dimensions': [], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [-1.12251615524292],
'descriptor': {'dimensions': [], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 1D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [24], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [24], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 2D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [4, 6], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 3D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 3, 4], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 4D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name': 'linear float32 5D tensor default options',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 1, 4, 1, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [{'input': 'linearInput'}],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 1, 4, 1, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 4D tensor specified options.alpha and default options.beta',
'graph': {
'inputs': {
'linearInput': {
'data': [
-1.12251615524292, -6.605223178863525, -1.9555538892745972,
-4.598548412322998, 4.234208106994629, 3.0975420475006104,
3.7465922832489014, -4.487029552459717, 6.407402038574219,
-4.354544162750244, -5.819092750549316, 3.7214345932006836,
-6.330113887786865, 8.580595016479492, -6.764922142028809,
6.433565616607666, -9.708685874938965, 2.6431379318237305,
5.2140889167785645, 9.65861701965332, -8.721749305725098,
-0.4533396363258362, 9.992619514465332, -6.469675064086914
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'}, {'options': {'alpha': 7.398793812746618}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-8.305265426635742, -48.87068176269531, -14.46873950958252,
-34.023712158203125, 31.328031539916992, 22.918073654174805,
27.72026252746582, -33.198604583740234, 47.407047271728516,
-32.2183723449707, -43.05426788330078, 27.53412628173828,
-46.835205078125, 63.486053466796875, -50.05226516723633,
47.600624084472656, -71.83256530761719, 19.556032180786133,
38.57796859741211, 71.46211242675781, -64.53042602539062,
-3.3541665077209473, 73.9333267211914, -47.86779022216797
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 positive 4D tensor specified positive options.beta and default options.alpha',
'graph': {
'inputs': {
'linearInput': {
'data': [
5.098546028137207, 3.381463050842285, 8.054762840270996,
8.074773788452148, 0.47079092264175415, 5.243824005126953,
3.827306032180786, 5.3697686195373535, 6.1033172607421875,
3.7505786418914795, 0.7479738593101501, 1.8931976556777954,
1.9056464433670044, 7.863316059112549, 4.58075475692749,
9.373635292053223, 6.584214210510254, 9.344809532165527,
5.16057825088501, 0.8060914278030396, 9.130533218383789,
3.1937403678894043, 5.748293399810791, 4.113487720489502
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'}, {'options': {'beta': 5.919095653700928}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
11.017641067504883, 9.300558090209961, 13.973857879638672,
13.99386978149414, 6.389886379241943, 11.162919998168945,
9.7464017868042, 11.288864135742188, 12.02241325378418,
9.669673919677734, 6.667069435119629, 7.81229305267334,
7.824741840362549, 13.782411575317383, 10.499850273132324,
15.292730331420898, 12.50330924987793, 15.263904571533203,
11.079673767089844, 6.725186824798584, 15.049629211425781,
9.112835884094238, 11.667388916015625, 10.032583236694336
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 negative 4D tensor specified negative options.beta and default options.alpha',
'graph': {
'inputs': {
'linearInput': {
'data': [
-5.098546028137207, -3.381463050842285, -8.054762840270996,
-8.074773788452148, -0.47079092264175415, -5.243824005126953,
-3.827306032180786, -5.3697686195373535, -6.1033172607421875,
-3.7505786418914795, -0.7479738593101501, -1.8931976556777954,
-1.9056464433670044, -7.863316059112549, -4.58075475692749,
-9.373635292053223, -6.584214210510254, -9.344809532165527,
-5.16057825088501, -0.8060914278030396, -9.130533218383789,
-3.1937403678894043, -5.748293399810791, -4.113487720489502
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'}, {'options': {'beta': -5.919095653700928}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-11.017641067504883, -9.300558090209961, -13.973857879638672,
-13.99386978149414, -6.389886379241943, -11.162919998168945,
-9.7464017868042, -11.288864135742188, -12.02241325378418,
-9.669673919677734, -6.667069435119629, -7.81229305267334,
-7.824741840362549, -13.782411575317383, -10.499850273132324,
-15.292730331420898, -12.50330924987793, -15.263904571533203,
-11.079673767089844, -6.725186824798584, -15.049629211425781,
-9.112835884094238, -11.667388916015625, -10.032583236694336
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 positive 4D tensor all options (positive options.alpha and positive options.beta)',
'graph': {
'inputs': {
'linearInput': {
'data': [
5.098546028137207, 3.381463050842285, 8.054762840270996,
8.074773788452148, 0.47079092264175415, 5.243824005126953,
3.827306032180786, 5.3697686195373535, 6.1033172607421875,
3.7505786418914795, 0.7479738593101501, 1.8931976556777954,
1.9056464433670044, 7.863316059112549, 4.58075475692749,
9.373635292053223, 6.584214210510254, 9.344809532165527,
5.16057825088501, 0.8060914278030396, 9.130533218383789,
3.1937403678894043, 5.748293399810791, 4.113487720489502
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'},
{'options': {'alpha': 7.398793812746618, 'beta': 5.919095653700928}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
43.64218521118164, 30.937843322753906, 65.5146255493164,
65.66268157958984, 9.402379989624023, 44.71706771850586,
34.236541748046875, 45.64890670776367, 51.0762825012207,
33.668853759765625, 11.45319938659668, 19.92647361755371,
20.018579483032227, 64.09815216064453, 39.811153411865234,
75.27268981933594, 54.63433837890625, 75.05941009521484,
44.10115051269531, 11.883199691772461, 73.47402954101562,
29.548921585083008, 48.44953155517578, 36.35394287109375
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 positive 4D tensor all options (negative options.alpha and negative options.beta)',
'graph': {
'inputs': {
'linearInput': {
'data': [
5.098546028137207, 3.381463050842285, 8.054762840270996,
8.074773788452148, 0.47079092264175415, 5.243824005126953,
3.827306032180786, 5.3697686195373535, 6.1033172607421875,
3.7505786418914795, 0.7479738593101501, 1.8931976556777954,
1.9056464433670044, 7.863316059112549, 4.58075475692749,
9.373635292053223, 6.584214210510254, 9.344809532165527,
5.16057825088501, 0.8060914278030396, 9.130533218383789,
3.1937403678894043, 5.748293399810791, 4.113487720489502
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'},
{'options': {'alpha': -7.398793812746618, 'beta': -5.919095653700928}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-43.64218521118164, -30.937843322753906, -65.5146255493164,
-65.66268157958984, -9.402379989624023, -44.71706771850586,
-34.236541748046875, -45.64890670776367, -51.0762825012207,
-33.668853759765625, -11.45319938659668, -19.92647361755371,
-20.018579483032227, -64.09815216064453, -39.811153411865234,
-75.27268981933594, -54.63433837890625, -75.05941009521484,
-44.10115051269531, -11.883199691772461, -73.47402954101562,
-29.548921585083008, -48.44953155517578, -36.35394287109375
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
},
{
'name':
'linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta)',
'graph': {
'inputs': {
'linearInput': {
'data': [
-5.098546028137207, -3.381463050842285, -8.054762840270996,
-8.074773788452148, -0.47079092264175415, -5.243824005126953,
-3.827306032180786, -5.3697686195373535, -6.1033172607421875,
-3.7505786418914795, -0.7479738593101501, -1.8931976556777954,
-1.9056464433670044, -7.863316059112549, -4.58075475692749,
-9.373635292053223, -6.584214210510254, -9.344809532165527,
-5.16057825088501, -0.8060914278030396, -9.130533218383789,
-3.1937403678894043, -5.748293399810791, -4.113487720489502
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
},
'operators': [{
'name': 'linear',
'arguments': [
{'input': 'linearInput'},
{'options': {'alpha': 7.398793812746618, 'beta': -5.919095653700928}}
],
'outputs': 'linearOutput'
}],
'expectedOutputs': {
'linearOutput': {
'data': [
-43.64218521118164, -30.937843322753906, -65.5146255493164,
-65.66268157958984, -9.402379989624023, -44.71706771850586,
-34.236541748046875, -45.64890670776367, -51.0762825012207,
-33.668853759765625, -11.45319938659668, -19.92647361755371,
-20.018579483032227, -64.09815216064453, -39.811153411865234,
-75.27268981933594, -54.63433837890625, -75.05941009521484,
-44.10115051269531, -11.883199691772461, -73.47402954101562,
-29.548921585083008, -48.44953155517578, -36.35394287109375
],
'descriptor': {'dimensions': [2, 2, 2, 3], 'dataType': 'float32'}
}
}
}
}
];
if (navigator.ml) {
linearTests.forEach((test) => {
webnn_conformance_test(
buildGraphAndCompute, getLinearPrecisionTolerance, test);
});
} else {
test(() => assert_implements(navigator.ml, 'missing navigator.ml'));
}