admin管理员组

文章数量:1399823

I use a pre-trained model facenet512 from the python project DeepFace. I exported the model and converted it to onnx format in order to run it with gocv.

Then I wrote a comparison script to make sure than both formats are equals, such as:

# Load models
tf_model = tf.saved_model.load('./exports/facenet512')
ort_session = ort.InferenceSession('./facenet512.onnx')

def embed_img(imgpath):
    img, _ = image_utils.load_image(imgpath) 
    img = image.img_to_array(img)
    img = np.expand_dims(img, axis=0)

    test_input = img
    print(f"Shape of test_input: {test_input.shape}")

    test_input_reshaped = np.transpose(test_input, (0, 3, 1, 2))  # Convert to NCHW (PyTorch/ONNX)
    print(f"Shape of test_input_reshaped: {test_input_reshaped.shape}")

    # TensorFlow
    infer = tf_model.signatures['serving_default']
    tf_output = infer(tf.convert_to_tensor(test_input))

    output_key = list(tf_output.keys())[0]
    tf_output = tf_output[output_key].numpy()

    # ONNX
    input_name = ort_session.get_inputs()[0].name
    output_name = ort_session.get_outputs()[0].name
    onnx_output = ort_session.run([output_name], {input_name: test_input_reshaped})[0]

    # Compare
    difference = np.abs(tf_output - onnx_output).mean()
    print(f"Average difference: {difference}")

    image_utils.debug_feature_vector(f"tf_{imgpath}", tf_output)
    image_utils.debug_feature_vector(f"onnx_{imgpath}", onnx_output)

    return tf_output, onnx_output

img1_tf, img1_onnx = embed_img("someimage.jpg")

The result is good, running saved model against ONNX model there are no differences:

Average difference:  1.4876641216687858e-06

The result of the inference:

Shape and Type - Name: someimage.jpg, Rows: 1, Cols: 512, Type: float32
Memory address - Name: someimage.jpg, Address: 0x318d5bf90
Sample values:
Sample value - Index: 0, Value: 3.632195234298706
Sample value - Index: 1, Value: -1.988647699356079
Sample value - Index: 2, Value: 3.5143983364105225
Sample value - Index: 3, Value: 0.8864414691925049
Sample value - Index: 4, Value: 5.087140083312988
Statistics - Min: -10.288069725036621, Max: 10.912190437316895, Mean: -0.31338077783584595, Std: 3.7746989727020264

Please note I also ran the net through cv2 to check if the runtime was in cause, but the output is the same:

onnx_cv2_net = cv2.dnn.readNetFromONNX('./facenet512.onnx')
onnx_cv2_net.setInput(test_input_reshaped, "input")
onnx_output = onnx_cv2_net.forward("Bottleneck_BatchNorm")

But when running through gocv, the inference result is vastly different:

msg="Tensor details" Name=embed1 Size="[1 512]" Channels=1 Type=CV32F TotalElements=512
msg="Shape and Type" Name=embed1 Rows=1 Cols=512 Type=CV32F
msg="Memory address" Name=embed1 Address="&{p:0x139068920 d:[]}"
msg="Sample values"
msg="Sample value" Index=0 Value=0.9129840135574341
msg="Sample value" Index=1 Value=-0.298820436000824
msg="Sample value" Index=2 Value=-0.06013426184654236
msg="Sample value" Index=3 Value=-0.2546067535877228
msg="Sample value" Index=4 Value=1.2503312826156616
msg=Statistics Min=-2.7190661430358887 Max=2.411057949066162 Mean=0.052061960360333615 Std=0.9108246561958873

the Go code is:

// package the model weights into the binary for static use
//
//go:embed facenet512.onnx
var facenet512weights []byte

net, err := gocv.ReadNetFromONNXBytes(facenet512weights)

embed1, err := e.Embed(img1path)
img := gocv.IMRead(imgPath, gocv.IMReadColor)// Create NCHW tensor
tensor = gocv.NewMatWithSizes([]int{1, channels, height, width}, gocv.MatTypeCV32F)

// Extract channels
channelMats := gocv.Split(preprocessed)
for i := range channelMats {
    defer channelMats[i].Close()
}

// Copy data
for c := 0; c < channels && c < len(channelMats); c++ {
    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            // Calculer l'indice linéaire dans le tensor 4D
            // L'indice pour NCHW: batch_idx * C*H*W + c * H*W + y * W + x
            idx := c*height*width + y*width + x
            val := channelMats[c].GetFloatAt(y, x)
            tensor.SetFloatAt(0, idx, val) // Dans la première ligne (batch 0), à l'indice calculé
        }
    }
}
e.Net.SetInput(tensor, "input")
embed = e.Net.Forward("Bottleneck_BatchNorm")

The actual tensor values are:

# python
channel MIN         MAX         AVERAGE 
0       0           0,73725492  0,4409493168
1       0           0,78039223  0,4888215594
2       0,01176471  0,87843144  0,5979496282
                    
# go    
channel MIN             MAX         AVERAGE 
0       0,0120490575    0,9137533   0,5996299743
1       0               0,79382753  0,4950213559
2       0               0,7389256   0,4466549111

There is a RGB inversion but swapping the channels had a minor difference on the result, the MIN/MAX of the inference still have a factor 5 difference.

Any ideas, tips, tricks?

本文标签: machine learningDifferent inference results between gocv and python opencvStack Overflow