(builder, node, graph, err)
operation:  alpha * (A * B) + beta * C
    so far the case only handled is :
    - B is a constant matrix
    - C is a constant vector
    - alpha == beta == 1.0
    - transA is off
operation:  alpha * (A * B) + beta * C
    so far the case only handled is :
    - B is a constant matrix
    - C is a constant vector
    - alpha == beta == 1.0
    - transA is off
operation : alpha * ( A * B ) + beta * C so far the case only handled is : - B is a constant matrix - C is a constant vector - alpha == beta == 1 . 0 - transA is off
def _convert_gemm(builder, node, graph, err):  # type: (NeuralNetworkBuilder, Node, Graph, ErrorHandling) -> None

    '''
    operation:  alpha * (A * B) + beta * C
    so far the case only handled is :
    - B is a constant matrix
    - C is a constant vector
    - alpha == beta == 1.0
    - transA is off
    '''

    if node.attrs.get("transA",0) != 0:
        return err.unsupported_op_configuration(builder, node, graph, "This Gemm layer cannot be converted to CoreML inner_product layer")

    if abs(node.attrs.get('alpha',1.0)-1.0) > 1e-3 or abs(node.attrs.get('beta',1.0)-1.0) > 1e-3:
        return err.unsupported_op_configuration(builder, node, graph, "This Gemm layer cannot be converted to CoreML inner_product layer")

    weight_name = node.inputs[1]
    if weight_name in node.input_tensors:
        W = node.input_tensors[weight_name]
        if not node.attrs.get("transB",0):
            W = np.transpose(W)
    else:
        err.missing_initializer(node, "Second input to Gemm layer must be a constant")

    b = None
    if len(node.inputs) > 2:
        b = (node.input_tensors[node.inputs[2]]).flatten()
    if len(W.shape) != 2 or (b is not None and len(b.shape) != 1):
        return err.unsupported_op_configuration(builder, node, graph, "This Gemm layer cannot be converted to CoreML inner_product layer")

    if b is not None:
        if W.shape[0] != b.shape[0]:
            return err.unsupported_op_configuration(builder, node, graph, "This Gemm layer cannot be converted to CoreML inner_product layer")

    if node.inputs[0] in graph.onnx_coreml_shape_mapping:
        mapp = graph.onnx_coreml_shape_mapping[node.inputs[0]]
        if mapp == [1,2] or mapp == [0,2]: #[B,C] or [S,C]
            _add_inner_product([node.inputs[0]], node.outputs, W=W, b=b, node=node, builder=builder)
        elif mapp == [3,4]: #[H,W]
            _add_transpose_before_after(_add_inner_product, [node.inputs[0]], node.outputs, [2,3,0,1],W=W, b=b, node=node, builder=builder)
        elif mapp == [2,3]: #(C,H)
            _add_transpose_before_after(_add_inner_product, [node.inputs[0]], node.outputs, [1,2,0,3],W=W, b=b, node=node, builder=builder)
        elif mapp == [2,4]: #(C,W)
            _add_transpose_before_after(_add_inner_product, [node.inputs[0]], node.outputs, [1,3,2,0], W=W, b=b, node=node, builder=builder)
        else:
            return err.unsupported_op_configuration(builder, node, graph, "CoreML incompatible axis placement")
    else:
        _add_inner_product([node.inputs[0]], node.outputs , W=W, b=b, node=node, builder=builder)

    if node.inputs[0] in graph.onnx_coreml_shape_mapping:
        graph.onnx_coreml_shape_mapping[node.outputs[0]] = graph.onnx_coreml_shape_mapping[node.inputs[0]]
def _convert_gemm ( builder , node , graph , err ) : # type: (NeuralNetworkBuilder, Node, Graph, ErrorHandling) -> None if node . attrs . get ( "transA" , 0 ) != 0 : return err . unsupported_op_configuration ( builder , node , graph , "This Gemm layer cannot be converted to CoreML inner_product layer" ) if abs ( node . attrs . get ( 'alpha' , 1.0 ) - 1.0 ) > 1e-3 or abs ( node . attrs . get ( 'beta' , 1.0 ) - 1.0 ) > 1e-3 : return err . unsupported_op_configuration ( builder , node , graph , "This Gemm layer cannot be converted to CoreML inner_product layer" ) weight_name = node . inputs [ 1 ] if weight_name in node . input_tensors : W = node . input_tensors [ weight_name ] if not node . attrs . get ( "transB" , 0 ) : W = np . transpose ( W ) else : err . missing_initializer ( node , "Second input to Gemm layer must be a constant" ) b = None if len ( node . inputs ) > 2 : b = ( node . input_tensors [ node . inputs [ 2 ] ] ) . flatten ( ) if len ( W . shape ) != 2 or ( b is not None and len ( b . shape ) != 1 ) : return err . unsupported_op_configuration ( builder , node , graph , "This Gemm layer cannot be converted to CoreML inner_product layer" ) if b is not None : if W . shape [ 0 ] != b . shape [ 0 ] : return err . unsupported_op_configuration ( builder , node , graph , "This Gemm layer cannot be converted to CoreML inner_product layer" ) if node . inputs [ 0 ] in graph . onnx_coreml_shape_mapping : mapp = graph . onnx_coreml_shape_mapping [ node . inputs [ 0 ] ] if mapp == [ 1 , 2 ] or mapp == [ 0 , 2 ] : #[B,C] or [S,C] _add_inner_product ( [ node . inputs [ 0 ] ] , node . outputs , W = W , b = b , node = node , builder = builder ) elif mapp == [ 3 , 4 ] : #[H,W] _add_transpose_before_after ( _add_inner_product , [ node . inputs [ 0 ] ] , node . outputs , [ 2 , 3 , 0 , 1 ] , W = W , b = b , node = node , builder = builder ) elif mapp == [ 2 , 3 ] : #(C,H) _add_transpose_before_after ( _add_inner_product , [ node . inputs [ 0 ] ] , node . outputs , [ 1 , 2 , 0 , 3 ] , W = W , b = b , node = node , builder = builder ) elif mapp == [ 2 , 4 ] : #(C,W) _add_transpose_before_after ( _add_inner_product , [ node . inputs [ 0 ] ] , node . outputs , [ 1 , 3 , 2 , 0 ] , W = W , b = b , node = node , builder = builder ) else : return err . unsupported_op_configuration ( builder , node , graph , "CoreML incompatible axis placement" ) else : _add_inner_product ( [ node . inputs [ 0 ] ] , node . outputs , W = W , b = b , node = node , builder = builder ) if node . inputs [ 0 ] in graph . onnx_coreml_shape_mapping : graph . onnx_coreml_shape_mapping [ node . outputs [ 0 ] ] = graph . onnx_coreml_shape_mapping [ node . inputs [ 0 ] ]