Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Official Retinaface mnet25 models conversion #4

Closed
SthPhoenix opened this issue Oct 2, 2020 · 20 comments
Closed

Official Retinaface mnet25 models conversion #4

SthPhoenix opened this issue Oct 2, 2020 · 20 comments

Comments

@SthPhoenix
Copy link

Hi! Great work converting RetinaFace mnet25 model!
I am trying to convert models from official InsightFace python package model zoo (retinaface_mnet025_v1, retinaface_mnet025_v2) using your code. Conversion works fine, but inference output is totally different from MXNet model, making it incompatible with following post processing.
Converted original @yangfly model works as intended.

@zheshipinyinMc
Copy link
Owner

can you show me the link retinaface_mnet025_v1, retinaface_mnet025_v2

@SthPhoenix
Copy link
Author

Absolute links:
retinaface_mnet025_v1
retinaface_mnet025_v2

And just in case original R50 model:
retinaface_r50_v1

BTW, wouldn't you mind if I include part of your code in my InsightFace-REST repo for MXNet->ONNX->TensorRT convertion?

@zheshipinyinMc
Copy link
Owner

I will try these models. just cite them.

@zheshipinyinMc
Copy link
Owner

i found a bug,
In mxnet symbol, BN has fix_gamma, if fix_gamma is true, then set gamma to 1 and its gradient to 0, you can find this in mxnet API.
for example, in retinaface_mnet025_v1, the output is different from 'conv_3_dw_batchnorm', because fix_gamma in 'conv_3_dw_batchnorm' is true,but its value is 0.000007107922556315316(you can see weight by Netron). So forward onnx model its('conv_3_dw_batchnorm') gamma is 0.000007107922556315316, but forward mxnet model, actually its'conv_3_dw_batchnorm' gamma is 1.

@SthPhoenix
Copy link
Author

Thanks! I'll try to fix it.

@SthPhoenix
Copy link
Author

Still can't find how to fix it. Should I work with resulting ONNX, or somehow change gamma weights in MXNet graph?

@zheshipinyinMc
Copy link
Owner

I‘ll try to fix this.

@zheshipinyinMc
Copy link
Owner

I have upload fixed bn gamma models. @SthPhoenix

@SthPhoenix
Copy link
Author

Great work! Now both nets work as intended.
But I still can't understand how you fixed it, some example code would be much appreciated!

@zheshipinyinMc
Copy link
Owner

read params file, and change the value of gamma to 1.
here, some key code, later i will upload a new repo about how to modify json and params.
input_param = './retinaface_mnet025_v1/mnet10-0000.params' net_param = mx.nd.load(input_param) gamma = net_param['arg:'+ bn_name + '_gamma'].asnumpy() if fix_gamma == True: gamma *= 0 gamma += 1 net_param['arg:'+ bn_name + '_gamma'] = mx.nd.array(gamma) mx.nd.save(save_params_path,new_param)

@SthPhoenix
Copy link
Author

Oh, I get it now, thanks!

@SthPhoenix
Copy link
Author

Here's my code to fix MXNet model before export:

def mxnet_model_fix(input_symbol, input_params, write=True):
    names = []
    fix_gamma_layers = []

    with open(input_symbol, 'r') as _input_symbol:
        fixed_sym = json.load(_input_symbol)
        for e in fixed_sym['nodes']:
            if e['op'] == 'SoftmaxActivation':
                e['op'] = 'softmax'
                e['attrs'] = {"axis": "1"}
            # Fix for "Graph must be in single static assignment (SSA) form"
            if e['name'] in names:
                e['name'] = f"{e['name']}_1"
            names.append(e['name'])
            if e.get('attrs', {}).get('fix_gamma') == 'True' and e['name'].endswith('_gamma'):
                fix_gamma_layers.append(e['name'])
        _input_symbol.close()

    fixed_params = mxnet_fixgamma_params(input_params, layers=fix_gamma_layers)

    if write is True:
        mx.nd.save(input_params, fixed_params)
        with open(input_symbol, 'w') as sym_temp:
            json.dump(fixed_sym, sym_temp, indent=2)



def mxnet_fixgamma_params(input_param, layers):
    net_param = mx.nd.load(input_param)
    for layer in layers:
        name = f'arg:{layer}'
        gamma = net_param[name].asnumpy()
        gamma *= 0
        gamma += 1
        net_param[name] = mx.nd.array(gamma)
    return net_param

@zheshipinyinMc
Copy link
Owner

nice!

@Talgin
Copy link

Talgin commented Oct 29, 2020

Hi, thank you for shared codes and converted models, but mnet025_fix_gamma_v2.onnx model gives wrong landmarks and different head rectangle than gamma_v1 (I used the same code for postprocessing for gamma_v1 and gamma_v2). Please, check the resulting model, maybe I did something wrong.

@SthPhoenix
Copy link
Author

v1 and v2 models are different, and gives different results even in MXNet, v2 seems to have worse accuracy in tests

@Talgin
Copy link

Talgin commented Oct 29, 2020

tests

Oh sorry, I just tested the original mnet25_v2 in mxnet and the landmarks are also going haywire and head rectangle is different.

@Talgin
Copy link

Talgin commented Nov 2, 2020

Hi, I've tested the original mnet25_v1 and converted mnet025_fix_gamma_v1.onnx model, but they give different accuracy. Original model was able to find all faces on the photo, but converted model missed some people. P.S. pre and postprocessing is similar to original retinaface.py (except that we changed scales to calculate each axis to draw outputs on original image).

@SthPhoenix
Copy link
Author

SthPhoenix commented Nov 2, 2020

I haven't tested models provided by @zheshipinyinMc, I have converted models a bit different way.
Just in case, ensure that input image in both versions is resized to same dimensions, since in MXNet Retina can take any size of input, while in ONNX it require fixed size, same as during onnx creation. You can check onnx input size with Netron.

Also ensure that in both cases images have right channel order, either BGR or RGB, not sure which one is used by Retina. I have once lost many time debugging when missed this.

@zheshipinyinMc
Copy link
Owner

zheshipinyinMc commented Nov 4, 2020

onnx models in this repo, i have compared their ouput, onnx ouput is almost same with mxnet.
onnx test code: Retinaface/mxnet2onnx_demo.py/onnx_inferred_demo
mxnet test code: Retinaface/face_feature_demo.py
i just compared output,no preprocess and postprocess. @SthPhoenix @Talgin

@mohamadHN93
Copy link

onnx models in this repo, i have compared their ouput, onnx ouput is almost same with mxnet.
onnx test code: Retinaface/mxnet2onnx_demo.py/onnx_inferred_demo
mxnet test code: Retinaface/face_feature_demo.py
i just compared output,no preprocess and postprocess. @SthPhoenix @Talgin

Hi In the orginial version of retinaface the input shape is (3,112,112) but here is (3,640,640), can you provide the onnx version with (3,112,112) since the I got error when I run the onnx conversion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants