とある大学生の勉強メモ

Python, C#, UWP, WPF, 心理実験関連の開発備忘録

学習したモデルの推論結果がnullになる MaskRCNN(Pytorch),onnxruntime

推論を行ったとき結果がnullとなるケースが多々ある. 今回PreTrainedのresnetをonnx exportし,onnx runtimeで推論すると結果が返るが, pytorchで学習を進めたモデルをexportした場合,推論結果がnullとなった際の備忘録.

結論

画像を配列にしたとき正規化を行えば推論結果が返るようになった.

input_image = cv2.imread(file_path)/255

序論

推論時はモデルの入出力の型に注意しなくてはいけない. 今回画像をTensorFloat配列に変換しモデルに入力する.

UWPにonnxモデルを取り込むとcode generatorが自動でラッパーファイルをonnx_model_name.csで生成する.
その際にInputの方をImageFeatureValueまたはTensorFloatにすると思うが,
入力配列の中身の値が0~255で構成されているならばImageFeatureValue,0~1ならTensorFloatを用いれば良い(と思う).
余談だが配列の中身の値が-1~1の範囲を求めるならば,onnxexportの際にtorch.randnを用いる.

modelのexportと推論

学習後のモデルをonnx exportする.
(BatchNorm層のあるモデルでもtorchの最新版であれば対応しています)

import torch
import torchvision
model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)
x = torch.rand(1,3,2048, 1084,device=torch.device("cpu"))
torch.onnx.export(model.cpu(), x, 
                  "detection_resnet_op11.onnx",
                  export_params=True,#モデルに訓練した重みも保存するか否か
                  verbose=False, #変換の途中経過を見るかどうか
                  opset_version = 11)

上記のように学習済みのResnet50であれば,onnx sessionで推論した画像をcv2で読み込んでInputに指定すれば結果が返る.
今回はtrain_one_epoch(model, optimizer, data_loader, device, epoch, print_freq=100)後のmodelだと推論結果がnullになった.

そこでevaluate(model.cpu(), data_loader_test, device=device)の際にモデルに入力される画像の中身を確認した.
model(images)で推論されているのだが,そのimagesをprint
・Resnet
f:id:amakazeryu:20220115115359p:plain

・自前データセットでの学習後の推論
f:id:amakazeryu:20220115115532p:plain

ここで自分の愚に気付く!!
画像を正規化すれば解決しました.
以下推論コード

# Writer : Yu Yamaoka
import onnxruntime
import numpy as np
import torch
import cv2

#モデルの読み込み
onnx_session = onnxruntime.InferenceSession(model_path)# ex:) model_path = "model.onnx"

#入力画像の用意
input_image = cv2.imread(file_name) # file_name = "picture.png"
input_image = input_image/255 #正規化(笑)
input_image = input_image.transpose(2, 1, 0).astype('float32') #モデルのInputの型と合うように転置すればいいです
input_image = input_image.reshape(1,3,2048, 1084)#Ajust model input shape

#モデルへのInputとOutputを規定
input_name = onnx_session.get_inputs()[0].name#NetronでInputの名前を確認してもいい.
output_name = onnx_session.get_outputs()[1].name#欲しい出力を決める,Netronで確認するのが楽.

#推論
result = onnx_session.run([output_name], {input_name: input_image})

#推論結果整形
result = np.array(result).squeeze()
print(result)

本日はここまでです.お疲れ様でした.