Пример #1
0
def PrintOperations(biasOp, webnnOpType, webnnParamsStr, fusedReluMappedInfo,
                    outputOp, test):
    if biasOp is not None:
        IndentedPrint("const interOut0 = builder.%s(%s);" % \
                      (webnnOpType, webnnParamsStr),
                      indent=4, file=test)
        if fusedReluMappedInfo is not None:
            # Add 'add' operation
            IndentedPrint("const interOut1 = builder.add(interOut0, %s);" % \
                          biasOp, indent=4, file=test)
            # Add 'relu' or 'clamp' operation
            PrintMappedReluOpertions(fusedReluMappedInfo[1], outputOp,
                                     'interOut1')
        else:
            # Add 'add' operation
            IndentedPrint("const %s = builder.add(interOut0, %s);" % \
                          (outputOp, biasOp), indent=4, file=test)
    else:
        if fusedReluMappedInfo is not None:
            if fusedReluMappedInfo[0]:
                IndentedPrint("const interOut0 = builder.%s(%s);" % \
                              (webnnOpType, webnnParamsStr), indent=4,
                              file=test)
                # Add 'relu' or 'clamp' operation
                PrintMappedReluOpertions(fusedReluMappedInfo[1], outputOp,
                                         'interOut0')
            else:
                PrintMappedReluOpertions(fusedReluMappedInfo[1], outputOp,
                                         webnnParamsStr)
        else:
            IndentedPrint("const %s = builder.%s(%s);" % \
                          (outputOp, webnnOpType, webnnParamsStr),
                          indent=4, file=test)
Пример #2
0
def PrintMappedReluOpertions(fusedReluMappedInfo, outputOp, operandName):
    mappedWebNNOpName = fusedReluMappedInfo['name']
    options = fusedReluMappedInfo.get('options', None)

    if options is None:
        IndentedPrint("const %s = builder.%s(%s);" % \
                      (outputOp, mappedWebNNOpName, operandName),
                      indent=4, file=test)
    else:
        IndentedPrint("const %s = builder.%s(%s, %s);" % \
                      (outputOp, mappedWebNNOpName, operandName, options),
                      indent=4, file=test)
Пример #3
0
def DumpAllInOneCtsTest(test, cts):
    versionList = os.listdir(test)
    with SmartOpen(cts, mode="a") as aioTest:
        InitializeCtsTestFile(aioTest, 3)
        for version in sorted(versionList):
            versionPath = os.path.join(test, version)
            for generatedTest in sorted(os.listdir(versionPath)):
                generatedTestPath = os.path.join(versionPath, generatedTest)
                with SmartOpen(generatedTestPath, mode="r") as readFile:
                    fileText = readFile.readlines()
                    for (lineNum, lineText) in enumerate(fileText):
                        if lineNum in range(6, len(fileText) - 2):
                            aioTest.write(lineText)
        IndentedPrint("});", file=aioTest)
        IndentedPrint("/* eslint-disable max-len */", file=aioTest)
Пример #4
0
def PrintInputData(oprand, operation, opInsList, name, value, layout, test):
    typedArray = oprand.type.mappingTypedArrayType
    opValue = GetOperandValue(oprand, operation, opInsList, name, layout,
                              value)
    IndentedPrint('const %sData = new %s(%s);' % (oprand, typedArray, opValue),
                  indent=4,
                  file=test)
Пример #5
0
def PrintConstant(oprand, operation, opInsList, opInsInfoList, name, layout,
                  test):
    opDesc = GetWebNNOperandDesc(oprand, operation, opInsList, opInsInfoList,
                                 layout)
    opValue = GetOperandValue(oprand, operation, opInsList, name, layout)
    operand = "const %s = builder.constant(%s, new %s(%s));" % \
              (oprand, opDesc, oprand.type.mappingTypedArrayType, opValue)
    IndentedPrint(operand, indent=4, file=test)
Пример #6
0
def DumpCtsTest(example, test):
    model = example.model

    if len(model.operations) > 1:
        msg = 'Not convert complicated tests with multi-operations'
        # print(msg, file=sys.stderr)
        return

    nnapiOp = model.operations[0].optype

    if nnapiOp not in md.MappingDict.keys():
        msg = msgTemplate % (nnapiOp, 'none mapped WebNN Opeartion')
        # print(msg, file=sys.stderr)
        return

    # WebNN polyfill API cur supports 'int32' and 'float32'
    unSupportedTypesList = ['int8', 'uint8', 'float16']
    operandTypeList = model.GetMappedOperandTypes()
    usedUnsupportedType = list(
        set(unSupportedTypesList) & set(operandTypeList))

    if len(usedUnsupportedType) > 0:
        msg = msgTemplate % \
              (nnapiOp, 'unsupported %s Operand Type' % usedUnsupportedType)
        # print(msg, file=sys.stderr)
        return

    mappingOpDict = md.MappingDict[nnapiOp]
    mappedWebNNOp = mappingOpDict['webnnOperation']

    if Configuration.successedCounter == 0:
        # Update mappingWebNNOp by first time
        Configuration.mappingWebNNOp.append(mappedWebNNOp)

    nnapiOpInsList = copy.deepcopy(mappingOpDict['insList'])
    nnapiOpOptionalInsList = mappingOpDict.get('optionalInsList', [])
    curOpInsList = model.operations[0].ins

    if CheckOperationWithImplicitPadding(nnapiOp, curOpInsList, nnapiOpInsList,
                                         len(nnapiOpOptionalInsList)):
        ClearMappingWebNNOpConfiguration()
        return

    if GetOperandIndex(nnapiOpInsList, 'bias') != -1:
        if Configuration.successedCounter == 0:
            Configuration.mappingWebNNOp.append('add')

    curInputsList = example.model.GetInputs()
    curOutputsList = example.model.GetOutputs()
    curParamsList = example.model.GetParameters()

    fusedReluMappedInfo = None
    actIndex = GetOperandIndex(nnapiOpInsList, 'activation')
    actStatus, actValue = GetParamOperandValue(curParamsList, curOpInsList,
                                               actIndex)

    if actStatus:
        UpdateMappingWebNNOpList(actValue[0])
        fusedReluMappedInfo = (True, GetReluMappedInfo(actValue[0]))

    if nnapiOp == 'RELU1':
        fusedReluMappedInfo = (False, GetReluMappedInfo(2))

    if nnapiOp == 'RELU6':
        fusedReluMappedInfo = (False, GetReluMappedInfo(3))

    nnapiOpInsList.extend(nnapiOpOptionalInsList)
    layoutIndex = GetOperandIndex(nnapiOpInsList, 'layout')
    layoutStatus, layoutValue = GetParamOperandValue(curParamsList,
                                                     curOpInsList, layoutIndex)
    # True: 'nchw', False: 'nhwc'
    layout = False if not layoutStatus else layoutValue[0]

    if nnapiOp == 'DEPTHWISE_CONV_2D':
        if not SupportedConvertDepthwiseConv2D(curInputsList[0],
                                               curOutputsList[0], layout):
            ClearMappingWebNNOpConfiguration()
            return

    biasOp = None
    testIndex = 1 if len(example.feedDicts) > 1 else 0

    for inputFeedDict, outputFeedDict in example.feedDicts:
        if nnapiOp == 'SOFTMAX':
            if not SupportedConvertSoftmax(nnapiOpInsList, curInputsList[0],
                                           curParamsList, curOpInsList):
                ClearMappingWebNNOpConfiguration()
                return
        IndentedPrint("", file=test)  # Add blank line
        testPurpose = 'test %s converted from %s test' % \
                      (' + '.join(Configuration.mappingWebNNOp),
                       str(example.testName))
        if testIndex > 0:
            testPurpose = "%s/%d" % (testPurpose, testIndex)
        IndentedPrint("it('%s', async function() {" % testPurpose,
                      indent=2,
                      file=test)
        IndentedPrint("// Converted test case (from: %s/%s)" % \
                      (tg.FileNames.version,
                       os.path.basename(tg.FileNames.specFile)),
                      indent=4, file=test)
        IndentedPrint("const builder = new MLGraphBuilder(context);",
                      indent=4,
                      file=test)
        computeParamsList = []
        # Create operand(s) by ModelBuilder.input
        for op in curInputsList:
            opInsDict = nnapiOpInsList[curOpInsList.index(op)]
            mappingParamIndex = opInsDict['mappingParamIndex']
            if mappingParamIndex != -1:
                rule = md.MappingRule(opInsDict['mappingRuleType'])
                if rule == md.MappingRule.OPERAND_OPERAND:
                    PrintInputOperand(op, nnapiOp, curOpInsList,
                                      nnapiOpInsList, layout, test)
                    PrintInputData(op, nnapiOp, curOpInsList,
                                   opInsDict['name'], inputFeedDict[op],
                                   layout, test)
                    computeParamsList.append("'%s': {data: %sData}" % \
                                             (op, op))
                elif rule == md.MappingRule.OPERAND_VARIABLE:
                    varValue = inputFeedDict[op]
                    if len(varValue) != 0 and varValue[0] is not None:
                        IndentedPrint('const %s = %s;' % (op, varValue),
                                      indent=4,
                                      file=test)
                elif rule == md.MappingRule.OPERAND_ARRAY:
                    varValue = inputFeedDict[op]
                    if len(varValue) != 0:
                        IndentedPrint('const %s = %s;' % (op, varValue),
                                      indent=4,
                                      file=test)
            else:
                if opInsDict['name'] == 'bias':
                    biasOp = op
                    PrintInputOperand(op, nnapiOp, curOpInsList,
                                      nnapiOpInsList, layout, test)
                    PrintInputData(op, nnapiOp, curOpInsList,
                                   opInsDict['name'], inputFeedDict[op],
                                   layout, test)
                    computeParamsList.append("'%s': {data: %sData}" % \
                                             (op, op))
        # Create operand(s) by ModelBuilder.constant, or define variable(s)
        for op in curParamsList:
            opInsDict = nnapiOpInsList[curOpInsList.index(op)]
            mappingParamIndex = opInsDict['mappingParamIndex']
            if mappingParamIndex != -1:
                rule = md.MappingRule(opInsDict['mappingRuleType'])
                if rule == md.MappingRule.OPERAND_OPERAND:
                    PrintConstant(op, nnapiOp, curOpInsList, nnapiOpInsList,
                                  opInsDict['name'], layout, test)
                elif rule == md.MappingRule.VARIABLE_VARIABLE:
                    varValue = curParamsList[curParamsList.index(op)].value[0]
                    if opInsDict['name'] == 'layout':
                        if varValue:
                            varValue = "'nchw'"
                        else:
                            varValue = "'nhwc'"
                    IndentedPrint('const %s = %s;' % (op, varValue),
                                  indent=4,
                                  file=test)
                elif rule == md.MappingRule.OPERAND_VARIABLE:
                    varValue = curParamsList[curParamsList.index(op)].value
                    if len(varValue) != 0 and varValue[0] is not None:
                        IndentedPrint('const %s = %s;' % (op, varValue),
                                      indent=4,
                                      file=test)
                elif rule == md.MappingRule.OPERAND_ARRAY:
                    varValue = curParamsList[curParamsList.index(op)].value
                    if len(varValue) != 0:
                        IndentedPrint('const %s = %s;' % (op, varValue),
                                      indent=4,
                                      file=test)
            else:
                if opInsDict['name'] == 'bias':
                    biasOp = op
                    PrintConstant(op, nnapiOp, curOpInsList, nnapiOpInsList,
                                  opInsDict['name'], layout, test)
        if len(curOutputsList) == 1:
            outputOp = curOutputsList[0]
            IndentedPrint("const expected = %s;" % outputFeedDict[outputOp],
                          indent=4,
                          file=test)
        elif len(curOutputsList) > 1:
            outputOp = curOutputsList
            expectedValueList = [outputFeedDict[k] for k in outputOp]
            IndentedPrint("const expected = %s;" % expectedValueList,
                          indent=4,
                          file=test)
        # Update optional parameter value
        optionsKeyValueList = []
        hasLayoutOption = False
        for optionalIns in nnapiOpOptionalInsList:
            if optionalIns['name'] == 'layout':
                hasLayoutOption = True
                break
        if hasLayoutOption:
            if not layout:
                # Default 'nchw' layout with WebNN API
                optionsKeyValueList.append(('layout', False))
        if nnapiOp == 'DEPTHWISE_CONV_2D':
            # True: 'nchw' False: 'nhwc'
            chanelIndex = 1 if layout else 3
            groups = outputOp.type.dimensions[chanelIndex]
            optionsKeyValueList.append(('groups', groups))
        mappingParams = GetWebNNOperationParamsList(nnapiOpInsList,
                                                    curOpInsList,
                                                    inputFeedDict,
                                                    curParamsList, nnapiOp)
        UpdateWebNNOperationOptionalParamValue(nnapiOp, mappingParams[-1][1],
                                               optionsKeyValueList, layout)
        webnnParamsStr = GetWebNNParamsString(mappingParams)
        if nnapiOp == 'SQRT':
            exponent = "const exponent = builder.constant({type: 'float32'," + \
                " dimensions: [1]}, new Float32Array([0.5]));"
            IndentedPrint(exponent, indent=4, file=test)
            webnnParamsStr = ', '.join([webnnParamsStr, 'exponent'])
        if nnapiOp in ['CONV_2D', 'DEPTHWISE_CONV_2D']:
            webnnParamsStr = webnnParamsStr.replace("'layout'",
                                                    "'inputLayout'")
        PrintOperations(biasOp, mappedWebNNOp, webnnParamsStr,
                        fusedReluMappedInfo, outputOp, test)
        if len(curOutputsList) == 1:
            IndentedPrint("const graph = await builder.build({%s});" %
                          outputOp,
                          indent=4,
                          file=test)
        elif len(curOutputsList) > 1:
            outputOpNameList = [item.name for item in outputOp]
            IndentedPrint("const graph = await builder.build({%s});" % \
                          ', '.join(outputOpNameList), indent=4, file=test)
        IndentedPrint("const outputs = await graph.compute({%s});" % \
                      ', '.join(computeParamsList), indent=4, file=test)
        # Check compute output
        criteria = 'utils.ctsFp32RestrictAccuracyCriteria'
        if model.isRelaxed:
            criteria = 'utils.ctsFp32RelaxedAccuracyCriteria'
        if len(curOutputsList) == 1:
            IndentedPrint(
                "utils.checkValue(outputs.%s.data, expected, %s);" % \
                (outputOp, criteria), indent=4, file=test)
        elif len(curOutputsList) > 1:
            IndentedPrint('for (let i = 0; i < %d; i++) {' % \
                          len(curOutputsList), indent=4, file=test)
            dataStr = 'outputs[%s[i]].data' % ['%s' % k for k in outputOp]
            IndentedPrint(
                "utils.checkValue(%s, expected[i], %s);" % \
                (dataStr, criteria), indent=6, file=test)
            IndentedPrint("}", indent=4, file=test)
        IndentedPrint("});", indent=2, file=test)
        testIndex += 1

    Configuration.successedCounter += 1
Пример #7
0
def PrintInputOperand(oprand, operation, opInsList, opInsInfoList, layout,
                      test):
    opDesc = GetWebNNOperandDesc(oprand, operation, opInsList, opInsInfoList,
                                 layout)
    operand = "const %s = builder.input('%s', %s);" % (oprand, oprand, opDesc)
    IndentedPrint(operand, indent=4, file=test)
Пример #8
0
        IndentedPrint("});", indent=2, file=test)
        testIndex += 1

    Configuration.successedCounter += 1


if __name__ == '__main__':
    ParseCmdLine()
    while tg.FileNames.NextFile():
        Configuration.mappingWebNNOp = []
        Configuration.successedCounter = 0
        # print("Generating test(s) from spec: %s" % tg.FileNames.specFile,
        #       file=sys.stderr)
        exec(open(tg.FileNames.specFile, "r").read())
        testFile = tg.FileNames.testFile
        with SmartOpen(testFile) as test:
            InitializeCtsTestFile(test, 4)
            Example.DumpAllExamples(DumpTest=DumpCtsTest, test=test)
            IndentedPrint("});", file=test)
            IndentedPrint("/* eslint-disable max-len */", file=test)
        if Configuration.successedCounter == 0:
            os.remove(testFile)
        else:
            newName = 'test_%s_converted_from_%s' % \
                      ('_'.join(Configuration.mappingWebNNOp),
                       os.path.basename(testFile))
            renamedFile = os.path.join(os.path.dirname(testFile), newName)
            os.rename(testFile, renamedFile)
            # print("Successfully generated CTS test: %s" % renamedFile,
            #       file=sys.stderr)