回転・鏡像反転用のデータ拡張用コード Train-Valid分けコード
自分用
画像Pathを指定するとデータ拡張してくれるコードと,
画像群フォルダのPathを指定するとValidとTrainの2つに分けてくれるコード.
下記を使うのが一般的かもしれないが........ albumentations.ai
from glob import glob import random import os import shutil #指定したデータセットPATHの中にTrainフォルダとValidフォルダを作り,VALID_Ratioで指定した量で分ける def Split_Train_Valid(DatasetFolderPath, filetype = ".png", VALID_RATIO = 0.2): """ Args: DatasetFolderPath (string): filetype (str, optional): 画像の型. Defaults to ".png". VALID_RATIO (float, optional): 検証用のデータ数割合. Defaults to 0.2. """ files = glob(os.path.join(DatasetFolderPath, "*" + filetype)) random.shuffle(files) VALID_DATA_NUM = int(len(files) * VALID_RATIO) #make dir Train_Dir = os.path.join(DatasetFolderPath, "Train") Valid_Dir = os.path.join(DatasetFolderPath, "Valid") if os.path.exists(Train_Dir)==False: os.mkdir(Train_Dir) if os.path.exists(Valid_Dir)==False: os.mkdir(Valid_Dir) #copy file for i, file in enumerate(files): if i<=VALID_DATA_NUM: shutil.copy2(file, Valid_Dir) else: shutil.copy2(file, Train_Dir)
#Writer : Yu Yamaoka #回転と鏡像で8倍水増し用のコード import cv2 def Augment_ByRotationMirror(ImageFilePath, filetype = ".png"): #every 90 degree rotation * mirror = 4 times * 2times = 8times(MAX) img = cv2.imread(ImageFilePath) width, height, _ = img.shape #Mirror mirror_img = cv2.flip(img, 1) cv2.imwrite(ImageFilePath.replace(filetype,"") + "_mirror" + filetype, mirror_img) #If width and height is NOT equal, can't do aug by 90 and 270 rot. img_180 = cv2.rotate(img, cv2.ROTATE_180) cv2.imwrite(ImageFilePath.replace(filetype,"")+"_180" + filetype, img_180) cv2.imwrite(ImageFilePath.replace(filetype,"") + "_180mirror.png", cv2.flip(img_180, 1)) if(width == height): img_90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) cv2.imwrite(ImageFilePath.replace(filetype,"")+"_90" + filetype, img_90) cv2.imwrite(ImageFilePath.replace(filetype,"") + "_90mirror" + filetype, cv2.flip(img_90, 1)) img_270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) cv2.imwrite(ImageFilePath.replace(filetype,"")+"_270" + filetype, img_270) cv2.imwrite(ImageFilePath.replace(filetype,"") + "_270mirror" + filetype, cv2.flip(img_270, 1))
SSH WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
Docker pull→run→exit→psからID取得してexec
自分用です.
Docker Image検索リンクから欲しいImageをPull
$ docker images
からREPOSITORYとTAGの部分を探して下記を埋める. -vの<directory_in_server>マウント場所を指定. pはポート番号で使っていないやつを選ぶ.
$ docker run -it --rm \ --gpus '"device=<GPU_ID>"' \ -p 8000:8000 \ -v <directory_in_server>:/workspace \ REPOSITORY:TAG
(docker)$ exit
で抜けてから,
$ docker ps
で立ち上がっているCONTAINER ID確認,
$ docker exec -it CONTAINER ID /bin/bash
でもう一度は入れる.
学習したモデルの推論結果が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
・自前データセットでの学習後の推論
ここで自分の愚に気付く!!
画像を正規化すれば解決しました.
以下推論コード
# 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)
本日はここまでです.お疲れ様でした.
Pytorchで学習・保存したonnx(format version6,opset=11)をVisual Studio2019(C#)のUWPで読み込む
備忘録.
Pytorchで学習したモデルをtorch.onnx.exportで保存後,Visual Studioでmodel Outputが返ってくるまでのお話.
環境:
Windows 10 2004 (OSビルド 19041.1052)
onnx opset =11
onnx format version = 6
Visual Studio 2019(UWP)
CUDA : 10.0
cuDNN : 7.4.1
torch 1.8.1 + cu102
torchvision 0.9.1+cu102
onnxの保存
色々とハマる点がある.
・ModelのInput
・opsetの指定
・Model,InputをCPU上で扱うかGPU上で扱うか
今回モデルの入力にはカラー画像を用いたので,縦横(width*heightピクセル)の画像をinputにし,modelはcpu()上に乗せ,opsetは11でexportした.cuda()にすればGPUで使えるようになるが,Inputとmodelは同じハードウェア上で用いなければErrorを吐かれるので注意.
import torch input = torch.rand(1, 3, width, height) torch.onnx.export(model.cpu(), input, "model_name.onnx", opset_version = 11)
ひとまずこのonnxをNetronで確認してみよう. ここまで確認できればonnx出力はお終い.
モデルのラッパーファイル作成
色々と沼るポイントにモデルのインターフェースを合わせる(InputとOutputを合わせる)作業がある.こちらをショートカットさせてくれるのがWindows Machine Learning Code Generatorである.
ツールバーの拡張機能から,インストールして用いるのが手っ取り早い.
自分が半日死んだポイントはVisual StudioのプロジェクトファイルのPath問題である.一応参考リンクを.
さて,ラッパーファイルであるmodel_name.csがVisual Studio上に無事出来上がったら覗こう.
とりあえずInputとOutputを見る.
using System; using System.Collections.Generic; using System.Threading.Tasks; using Windows.Media; using Windows.Storage; using Windows.Storage.Streams; using Windows.AI.MachineLearning; namespace MNIST_Demo { public sealed class mrcnn_0702Input { public TensorFloat images; // shape(1,3,width, height) } public sealed class mrcnn_0702Output { public TensorFloat output3550; // shape(-1,4) public TensorInt64Bit output3213; // shape(-1) public TensorFloat output3211; // shape(-1) public TensorFloat output3788; // shape(0,1,width, height) }
変更ポイントは主に二つ.Inputの型をイメージに,opset=11を読み込めるようにMicrosoft.AI version≧1.8.0を使うこと.
//using Windows.AI.MachineLearning; using Microsoft.AI.MachineLearning;
public sealed class mrcnn_0702Input { //public TensorFloat images; // shape(1,3,2448,1920) public ImageFeatureValue images; // shape(1,3,2448,1920) }
とまあ公開できる情報は現状ここまで.具体的なコードはオープンにできないが,時間が経ったらできるかもしれない. 引っかかるポイントをクリアさせられていたら嬉しい.
"ModelGenがNull" UWP(C#,Visual Studio2019)でopset≧10,format version≧6のonnxモデルを読み込むときの対処
環境
Windows10 2004 OSビルド19041,1052
onnx opset = 11
onnx format version = 6
Visual Studio 2019
問題
Pytorchで作成したonnxをVisual Studio(C#)で動かすチュートリアルを試していた.
こちらのWindows-Machine-Learning-master\Samples\Tutorial Samples\MLNET and Windows ML
が今回の主人公である.
実行すると, NullReferenceExceptionを頂戴したときのおはなし.
調べると読み込んだはずのModelがNullとなっている.
理由はonnxを作成したときのformat versionとopsetの違いである.
NugetのライブラリやOSのバージョンによっては対応していないopsetとformat versionがある.
こちらのエラーメッセージもvisual studio2019のコンソールに表示される筈.
WinRT Failed to load model with error: Unknown model file format version.
解決策
NugetパッケージでMicrosoft.AI.MachineLearning 1.8.0を入れて,
MainPagexaml.csとMNIST.cs(モデルのラッパーファイル)の両方で,
using Windows.AI.MachineLearningをコメントアウトし,
using Microsoft.AI.MachineLearning;を入れる.
Windows.AIとMicrosoft.AIは各種変数の名前が同じなので競合します.
ですのでwindowsの方を消しましょう.
補足
onnxの各バージョンの確認をするにはこちらのNetronを使うのが手っ取り早い github.com
モデルを読み込んだら赤丸でopsetとformat versionをチェックできる
確認欄は下図のかんじ.
こちらのformat versionと,Importsのai.onnx v○○の○○がopsetに相当している.
MLNET and Windows ML にあるonnxモデルは となっており,opset=9,format version = 6で,windows.AIでは読み込めない.
UWPの知見と人材が少なすぎて泣けてくる.
Windows Machine Learning Code GeneratorでAssetに追加したonnxファイルからcsファイルが生成されないことの解決策
環境
・Windows OS 1803以降
・Windows10 SDK 10.0.17763.0以降
・Windows Machine Learning Code Generator (VS2019 version)
・Visual studio 2019以降
問題
Assetにonnxファイルを入れても,csファイルが生成されない.
プロパティをコンテンツにしても駄目.
解決策
プロジェクトの保存場所にアルファベット以外の文字が入っている場合,ジェネレーターが起動しない. したがってCドライブ直下などに置けばonnxの取り込みと同時にcsファイルが生成される.
そしてAssetにonnxを入れると自動生成される.
以上.
このバグで半日溶けたので,同じ悩みを持った人がいたら救いになって欲しい.
アメリカに開発中心があると,こういったバグになかなか気付けないものですね.