(builder, node, graph, err)
convert to CoreML Tranpose (Optional) and Inner Product Layer:
    https://github.com/apple/coremltools/blob/655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492/mlmodel/format/NeuralNetwork.proto#L4180
convert to CoreML Tranpose (Optional) and Inner Product Layer:
    https://github.com/apple/coremltools/blob/655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492/mlmodel/format/NeuralNetwork.proto#L4180
convert to CoreML Tranpose ( Optional ) and Inner Product Layer : https : // github . com / apple / coremltools / blob / 655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492 / mlmodel / format / NeuralNetwork . proto#L4180
def _convert_gemm(builder, node, graph, err):
    '''
    convert to CoreML Tranpose (Optional) and Inner Product Layer:
    https://github.com/apple/coremltools/blob/655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492/mlmodel/format/NeuralNetwork.proto#L4180
    '''
    # Read attributes
    alpha = node.attrs.get('alpha', 1.0)
    beta = node.attrs.get('beta', 1.0)
    transA = node.attrs.get('transA', False)
    transB = node.attrs.get('transB', False)

    A = node.inputs[0]
    if A in node.input_tensors:
        A_tensor = node.input_tensors[A]
        builder.add_load_constant_nd(
            name=node.name + A + "_const",
            output_name='const_' + A,
            constant_value=A_tensor,
            shape=A_tensor.shape
        )
        A = 'const_'+A

    if alpha != 1.0:
        builder.add_load_constant_nd(
            name=node.name + '_load_alpha',
            output_name='alpha_for_'+A,
            constant_value=np.array([alpha]),
            shape=[1]
        )
        builder.add_multiply_broadcastable(
            name=node.name + '_alphaA',
            input_names=[A, 'alpha_for_'+A],
            output_name=A+'_alphaA'
        )
        A = A + '_alphaA'

    B = node.inputs[1]
    C = node.inputs[2]
    if B in node.input_tensors and C in node.input_tensors:
        B = node.input_tensors[B]
        C = node.input_tensors[C]

        if transB:
            B = B.transpose()
        
        C = C.flatten()
        builder.add_batched_mat_mul(
            name=node.name,
            input_names=[A],
            output_name=node.outputs[0],
            transpose_a=transA,
            weight_matrix_rows=B.shape[0],
            weight_matrix_columns=B.shape[1],
            W=B,
            bias=C
        )
    else:
        ## TODO: Test coverage when B and C are non-constant
        ## Should C be of Rank-1? or it's okay to keep it that way?
        if beta != 1.0:
            builder.add_load_constant_nd(
                name=node.name + '_load_beta',
                output_name='beta_for_'+B,
                constant_value=np.array([beta]),
                shape=[1]
            )
            builder.add_multiply_broadcastable(
                name=node.name + '_betaC',
                input_names=[C, 'beta_for_'+B],
                output_name=C+'_betaC'
            )
            C = C + '_betaC'

        builder.add_batched_mat_mul(
            name=node.name,
            input_names=[A, B],
            output_name=node.outputs[0] + '_b_mat_mul',
            transpose_a=transA,
            transpose_b=transB,
        )

        builder.add_add_broadcastable(
            name=node.name+'_add_bias',
            input_names=[node.outputs[0]+'_b_mat_mul', C],
            output_name=node.outputs[0]
        )
def _convert_gemm ( builder , node , graph , err ) : # Read attributes alpha = node . attrs . get ( 'alpha' , 1.0 ) beta = node . attrs . get ( 'beta' , 1.0 ) transA = node . attrs . get ( 'transA' , False ) transB = node . attrs . get ( 'transB' , False ) A = node . inputs [ 0 ] if A in node . input_tensors : A_tensor = node . input_tensors [ A ] builder . add_load_constant_nd ( name = node . name + A + "_const" , output_name = 'const_' + A , constant_value = A_tensor , shape = A_tensor . shape ) A = 'const_' + A if alpha != 1.0 : builder . add_load_constant_nd ( name = node . name + '_load_alpha' , output_name = 'alpha_for_' + A , constant_value = np . array ( [ alpha ] ) , shape = [ 1 ] ) builder . add_multiply_broadcastable ( name = node . name + '_alphaA' , input_names = [ A , 'alpha_for_' + A ] , output_name = A + '_alphaA' ) A = A + '_alphaA' B = node . inputs [ 1 ] C = node . inputs [ 2 ] if B in node . input_tensors and C in node . input_tensors : B = node . input_tensors [ B ] C = node . input_tensors [ C ] if transB : B = B . transpose ( ) C = C . flatten ( ) builder . add_batched_mat_mul ( name = node . name , input_names = [ A ] , output_name = node . outputs [ 0 ] , transpose_a = transA , weight_matrix_rows = B . shape [ 0 ] , weight_matrix_columns = B . shape [ 1 ] , W = B , bias = C ) else : ## TODO: Test coverage when B and C are non-constant ## Should C be of Rank-1? or it's okay to keep it that way? if beta != 1.0 : builder . add_load_constant_nd ( name = node . name + '_load_beta' , output_name = 'beta_for_' + B , constant_value = np . array ( [ beta ] ) , shape = [ 1 ] ) builder . add_multiply_broadcastable ( name = node . name + '_betaC' , input_names = [ C , 'beta_for_' + B ] , output_name = C + '_betaC' ) C = C + '_betaC' builder . add_batched_mat_mul ( name = node . name , input_names = [ A , B ] , output_name = node . outputs [ 0 ] + '_b_mat_mul' , transpose_a = transA , transpose_b = transB , ) builder . add_add_broadcastable ( name = node . name + '_add_bias' , input_names = [ node . outputs [ 0 ] + '_b_mat_mul' , C ] , output_name = node . outputs [ 0 ] )