tensorRT5.1.5.0実践EfficientNet+Pytorchの変換試行即ち精度テスト
2019.8.5参照EfficientNet-Pytorchに更新.
efficientnet_pytorchモジュール まとめ コンテンツ About EfficientNet About EfficientNet PyTorch Usage Onnx+EfficientNet実践 1.iterationのmodel だけ走った onnxファイル を作成する tensorRTで精度と時間 をテストする結果 pytorch蓄積 1. torch.max()メソッド 2. torchvision.transform 3.torch.squeeze()とtorch.unsqueeze()の使い方 4.データ読み出し MyDataset torch.utils.dataの学習 (1)class torch.utils.data.Dataset (2)class torch.utils.data.sample.Sampler(data_source) (3)class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, num_workers=0, collate_fn=, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None 5.torch.topk()
efficientnet_pytorchモジュール
dataset(Dataset):データをロードするデータセット、すなわち上述torch.utils.data.Dataseオブジェクト batch_size(int,optional):バッチごとに何個のサンプルがロードされますか.デフォルトは1 です. shuffle(bool,optional):「真」に設定と、epochごとにデータが乱れる.(デフォルト:False) sampler(Sampler,optional):データセットからサンプルを抽出するポリシーを定義し、サンプルSamplerオブジェクトを返します. batch_sampler(Sampler,optional):like sampler,but returns a batch of indices at a timeはサンプルを返す.とatch_size,shuffle,sampler,drop_last反発 num_workers(int,optional):データのロードに使用されるサブプロセスの数.0は、プライマリ・プロセスにデータがロードされることを示します.(デフォルト:0) collate_fn(callable,optional):サンプルリストをマージしてmini-batchを形成する.callable呼び出し可能オブジェクト pin_memory(bool,optional):Trueの場合、データ・ローダは、CUDA固定メモリにテンソルをコピーし、それらを返す. drop_Last(bool,optional):Trueに設定データセットサイズが一括サイズで割り切れない場合、最後の不完全なbatchが失われる(デフォルト:False). timeout(numeric,optional):正の値の場合、従業員からロットを収集するタイムアウト値です.常に非負であるべきだ.(デフォルト:0) worker_init_fn (callable, optional): If not None, this will be called on each worker subprocess with the worker id (an int in
torch.topk
torch.topk(input,k,dim=None,largest=True,sorted=True,out=None) -> (Tensor,LongTensor)
入力テンソルinputのk個の最大値を、与えられたdim次元に沿って返します.dimを指定しない場合、デフォルトはinputの最後の次元です.largestがFalseの場合、最小k個の値が返されます.
元の入力テンソルinputの測定要素の下付き記号であるメタグループ(values,indices)を返します.ブール値sortedを_に設定した場合True_,返されるk個の値がソートされることを確認します.
パラメータ:input(Tensor)–テンソルk(int)-「top-k」のk dim(int,optional)–ソートされた次元largest(bool,optional)–ブール値を入力し、最大値または最小値sorted(bool,optional)–ブール値を返し、戻り値がout(tuple,optional)–オプション出力テンソル(Tensor,LongTensor)output bufferをソートするかどうかを制御します.
文章の構造
efficientnet_pytorchモジュール
まとめ
pytorchにはefficientnet専用のネットモデルがあり、efficientnetに書かれています.pytorchモジュールにあります.モジュールはEfficientNetのop-for-opのpytorch実装を含み、プリトレーニングモデルと例も実装されている.このコードは簡単で、高度に拡張性があり、自分のプロジェクトに統合しやすい.現在達成可能な目的:(1)EfficientNetモデルをロードして訓練する(2)EfficientNetモデルを用いて分類または特徴抽出を行う(3)ImageNetまたは自分のピクチャセット上でEfficientNetが間もなく発売される機能を評価する:(1)簡単なコマンドを用いてImageNet上で新しいモデルを最初から訓練する(2)自分のデータセット上で迅速にEfficientNetをfinetuneする(3)製品レベルのEfficientNetを出力
内容
About EfficientNet
EfficientNetsは一連の画像分類モデルであり,state−of−artのaccuracyを実現したが,従来のモデルsmallerやfasterよりも優れている.著者らはAutoMLとCompound Scalingに基づいて開発されたEfficientNetsであり、まずAutoML Mobileフレームワークを用いてEfficientNet-B 0という移動規模ベースラインネットワーク(mobile-size baseline network)を開発した.次に,複合スケーリング法を用いてこのベースラインを拡張してEfficientNet−B 1〜B 7を得る.EfficientNetsはImageNet上で最も先進的な精度を実現し、効率は1桁向上した:高精度制度の下で、私たちのEfficientNet-B 7はImageNet上で66 Mパラメータと37 B FLOPSで最も先進的な84.4%前1/97.1%前5精度を実現し、CPU推理上で8.4倍小さく、6.1倍速く前より最も良いGpipeを実現した.中精度方式では,我々のEfficientNet−B 1はResNet−152より7.6倍小さく,CPU推論速度は5.7倍速く,同様のImageNet精度を有した.広く使用されているResNet−50と比較して、同様のFLOPS制約の下で、我々のEfficientNet−B 4は、前の1精度をResNet−50の76.3%から82.6%(+6.3%)に向上させた.
About EfficientNet PyTorch
EfficientNet PyTorchは、PyTorchによるEfficientNetの再実装である.元のTensorFlowと一致するため、TensorFlowチェックポイントから重みをロードしやすくなります.同時に、PyTorchをできるだけ簡単で、柔軟で、拡張性を実現することを目標としています.
Usage
EfficientNetのロードfrom efficientnet_pytorch import EfficientNet
model = EfficientNet.from_name('efficientnet-b0')
事前トレーニングEfficientNetのロードfrom efficientnet_pytorch import EfficientNet
model = EfficientNet.from_pretrained('efficientnet-b0')
Onnx+EfficientNet実践
すなわちefficientnet_を利用するpytorchモジュールが提供するネットワークモデルは、自分で訓練し、onnxに変換し、tensorRTのengineに変換し、最後にengineを直接使用して推定し、推定速度と精度を検出します.
1.iterationのモデルを1つだけ走った
データセット:自社の車両データセット、train:400万、test:2000モデルバージョン:efficientnet-b 0 num_classes:1852
onnxファイルの作成
固定の入力sizeを(224224)用torchとする.loadはモデルの重みをロードし、torchを使用することができる.onnx.Excport()メソッドをonnx形式のファイルに変換
tensorRTでの精度と時間のテスト
def main():
onnx_path='./onnx_file/0net_params_8_5.onnx'
engine_path="./trt_file/"+(onnx_path.split('/')[2]).split('.')[0]+".trt"
test_dir = './label_txt/val.txt'
num_classes=1852
img_size=224
# the mean value and std value is pre-calculated
valiTransform = transforms.Compose([
transforms.Resize((img_size,img_size)),
transforms.ToTensor(),
transforms.Normalize([0.3497724, 0.35888246, 0.37229323],[0.2726704, 0.2739602, 0.2761853])
])
test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
criterion = nn.CrossEntropyLoss().cuda() #
print("The length of test data set is %s"%(test_data.__len__()))
# initialize
sum_time=0
cls_num = num_classes
loss_sigma=0.0
conf_mat = np.zeros([cls_num, cls_num])
with get_engine(onnx_path,engine_path) as engine ,engine.create_execution_context() as context:
# because the input_size is fixed, the buffers should be allcated in advanced for all the data(img)
inputs_alloc, outputs_alloc, bindings, stream = common.allocate_buffers(engine)
for i,data in enumerate(test_loader):
# read the data
inputs,labels=data
inputs=inputs.numpy()
# get engine to inference
print("Reading engine from file {}".format(engine_path))
inputs_alloc[0].host = inputs
t_start=time.time()
trt_outputs = common.do_inference(context, bindings=bindings, inputs=inputs_alloc, outputs=outputs_alloc,stream=stream)
t_end=time.time()
t_time=t_end-t_start
sum_time += t_time
print('The {}th img, inference time : {}' .format(i, str(t_time)))
trt_outputs = np.array(trt_outputs)
outputs = torch.from_numpy(trt_outputs)
outputs.detach()
# loss
loss = criterion(outputs, labels)
loss_sigma += loss.item()
#
_, predicted = torch.max(outputs.data, 1)
#
for j in range(len(labels)):
cate_i = labels[j].cpu().numpy()
pre_i = predicted[j].cpu().numpy()
conf_mat[cate_i, pre_i] += 1.0
print('avg time: ' + str(sum_time / test_data.__len__()))
print('{} set Accuracy:{:.2%}'.format('test', conf_mat.trace() / conf_mat.sum()))
前処理と後処理ここで、numpyで直接処理して、いつも正しくないと書いて、サボってしまいました.後日穴をうめる
結果
たった1つのiterationを走ったモデルに
tensorRTを使用したengen:フィードフォワード時間:0.003499486 s精度:91.64%
pytorchでの:フィードフォワード時間:0.01249988 s精度:91.04%
pytorch蓄積
1. torch.max()メソッド
value, index=torch.max(tensor,num)
tensorは入力したtensor,numは操作の次元の2つの戻り値,valueは最大値,indexはインデックスである.eg: tensor=torch.randn(4,5)
value,index=torch.max(tensor,0)
tensor:tensor([[ 0.3045, -0.3509, 0.8248, 1.1156, -1.0433],
[ 1.0962, 0.8329, 1.0494, -0.7632, -0.2968],
[ 0.8749, 0.5894, -2.2095, -0.8238, -0.5258],
[ 1.5428, -0.2508, -0.8234, -0.9917, -1.2586]])
value: tensor([ 1.5428, 0.8329, 1.0494, 1.1156, -0.2968])
つまり、各カラムの最大値で計算し、インデックスindexを出力します.tensor([3, 1, 1, 0, 1])
次元を1にするとvalue,index=torch,max(tensor,1)
となり、行ごとの最大値とインデックスとなります.
2. torchvision.transform
ここでこのtorchvisionを学びました.Transform pytorchの画像前処理パッケージは、一般的にcomposeで複数のステップを統合します.eg: transform.Compose([transform.Resize((224,224)), transform.ToTensor, transform.Normalize(...)])
.
3.torch.squeeze()とtorch.unsqueeze()の使い方
データ次元をサブソルバまたは解凍します.torch.squeeze()という関数は主にデータの次元を圧縮し、次元数が1の次元を削除します.例えば、1行または1列のように、1行3列(1,3)の数が最初の次元数が1の次元を削除すると(3)行になります.squeeze(a)は,a中のすべてが1である次元を削除する.1でない次元は影響しません.a.squeeze(N)は、aで指定された次元数を1とした次元を削除する.もう一つの形式はb=torchです.squeeze(a,N)aで指定した次元数が1の次元を削除します.**torch.unsqueeze()**この関数は主にデータ次元を拡張します.指定された位置に次元数が1の次元を加算します.たとえば、元の3行のデータ(3)があり、0の位置に1次元を加算すると1行3列(1,3)になります.a.squeeze(N)は、aで指定された位置Nに次元数1を加算した次元である.もう一つの形式はb=torchです.squeeze(a,N)aは、aに指定された位置Nに次元数1を加算した次元である.
4.データ読み出し
私のコードに使いました test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
MyDataset
MyDatasetは独自に定義されたデータ構造でありtorchに継承される.utils.data.Dataset class MyDataset(Dataset):
def __init__(self,txt_path,transform=None,target_transform=None):
fh=open(txt_path,'r')
imgs=[]
for line in fh:
line=line.strip('
')
words=line.split()
path=words[0]
if (len(words)>2):
for i in range(1,len(words)-1):
path+=' '+words[i]
imgs.append((path,int(words[-1])))
self.imgs=imgs
self.transform=transform
self.target_transform=target_transform
def __getitem__(self,index):
fn,label=self.imgs[index]
img=Image.open(fn).convert('RGB')
if self.transform is not None:
img=self.transform(img)
return img,label
def __len__(self):
return len(self.imgs)
torch.utils.dataの勉強
torch.utils.Dataは主に3つのクラスを含む:pytorchは自由なデータ読み出し-torchを実現する.utils.dataの勉強
(1)class torch.utils.data.Dataset
データセットを作成します.getitem__(self,index)関数は、インデックス番号に基づいて画像とラベルを取得し、len_(self)関数を使用して、データセットの長さを取得します.
他のデータセットはそのサブクラスでなければなりません
(2)class torch.utils.data.sample.Sampler(data_source)
パラメータ:data_source(Dataset)-dataset to sample fromの役割:サンプラ、class torchを作成します.utils.data.sampler.SamplerはすべてのSamplerのベースクラスである、iter(self)関数は反復器を取得し、データセット要素のインデックスを反復し、len(self)法は反復器に含まれる要素の長さを返す.
(3)class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, num_workers=0, collate_fn=, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None
from efficientnet_pytorch import EfficientNet
model = EfficientNet.from_name('efficientnet-b0')
from efficientnet_pytorch import EfficientNet
model = EfficientNet.from_pretrained('efficientnet-b0')
すなわちefficientnet_を利用するpytorchモジュールが提供するネットワークモデルは、自分で訓練し、onnxに変換し、tensorRTのengineに変換し、最後にengineを直接使用して推定し、推定速度と精度を検出します.
1.iterationのモデルを1つだけ走った
データセット:自社の車両データセット、train:400万、test:2000モデルバージョン:efficientnet-b 0 num_classes:1852
onnxファイルの作成
固定の入力sizeを(224224)用torchとする.loadはモデルの重みをロードし、torchを使用することができる.onnx.Excport()メソッドをonnx形式のファイルに変換
tensorRTでの精度と時間のテスト
def main():
onnx_path='./onnx_file/0net_params_8_5.onnx'
engine_path="./trt_file/"+(onnx_path.split('/')[2]).split('.')[0]+".trt"
test_dir = './label_txt/val.txt'
num_classes=1852
img_size=224
# the mean value and std value is pre-calculated
valiTransform = transforms.Compose([
transforms.Resize((img_size,img_size)),
transforms.ToTensor(),
transforms.Normalize([0.3497724, 0.35888246, 0.37229323],[0.2726704, 0.2739602, 0.2761853])
])
test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
criterion = nn.CrossEntropyLoss().cuda() #
print("The length of test data set is %s"%(test_data.__len__()))
# initialize
sum_time=0
cls_num = num_classes
loss_sigma=0.0
conf_mat = np.zeros([cls_num, cls_num])
with get_engine(onnx_path,engine_path) as engine ,engine.create_execution_context() as context:
# because the input_size is fixed, the buffers should be allcated in advanced for all the data(img)
inputs_alloc, outputs_alloc, bindings, stream = common.allocate_buffers(engine)
for i,data in enumerate(test_loader):
# read the data
inputs,labels=data
inputs=inputs.numpy()
# get engine to inference
print("Reading engine from file {}".format(engine_path))
inputs_alloc[0].host = inputs
t_start=time.time()
trt_outputs = common.do_inference(context, bindings=bindings, inputs=inputs_alloc, outputs=outputs_alloc,stream=stream)
t_end=time.time()
t_time=t_end-t_start
sum_time += t_time
print('The {}th img, inference time : {}' .format(i, str(t_time)))
trt_outputs = np.array(trt_outputs)
outputs = torch.from_numpy(trt_outputs)
outputs.detach()
# loss
loss = criterion(outputs, labels)
loss_sigma += loss.item()
#
_, predicted = torch.max(outputs.data, 1)
#
for j in range(len(labels)):
cate_i = labels[j].cpu().numpy()
pre_i = predicted[j].cpu().numpy()
conf_mat[cate_i, pre_i] += 1.0
print('avg time: ' + str(sum_time / test_data.__len__()))
print('{} set Accuracy:{:.2%}'.format('test', conf_mat.trace() / conf_mat.sum()))
前処理と後処理ここで、numpyで直接処理して、いつも正しくないと書いて、サボってしまいました.後日穴をうめる
結果
たった1つのiterationを走ったモデルに
tensorRTを使用したengen:フィードフォワード時間:0.003499486 s精度:91.64%
pytorchでの:フィードフォワード時間:0.01249988 s精度:91.04%
pytorch蓄積
1. torch.max()メソッド
value, index=torch.max(tensor,num)
tensorは入力したtensor,numは操作の次元の2つの戻り値,valueは最大値,indexはインデックスである.eg: tensor=torch.randn(4,5)
value,index=torch.max(tensor,0)
tensor:tensor([[ 0.3045, -0.3509, 0.8248, 1.1156, -1.0433],
[ 1.0962, 0.8329, 1.0494, -0.7632, -0.2968],
[ 0.8749, 0.5894, -2.2095, -0.8238, -0.5258],
[ 1.5428, -0.2508, -0.8234, -0.9917, -1.2586]])
value: tensor([ 1.5428, 0.8329, 1.0494, 1.1156, -0.2968])
つまり、各カラムの最大値で計算し、インデックスindexを出力します.tensor([3, 1, 1, 0, 1])
次元を1にするとvalue,index=torch,max(tensor,1)
となり、行ごとの最大値とインデックスとなります.
2. torchvision.transform
ここでこのtorchvisionを学びました.Transform pytorchの画像前処理パッケージは、一般的にcomposeで複数のステップを統合します.eg: transform.Compose([transform.Resize((224,224)), transform.ToTensor, transform.Normalize(...)])
.
3.torch.squeeze()とtorch.unsqueeze()の使い方
データ次元をサブソルバまたは解凍します.torch.squeeze()という関数は主にデータの次元を圧縮し、次元数が1の次元を削除します.例えば、1行または1列のように、1行3列(1,3)の数が最初の次元数が1の次元を削除すると(3)行になります.squeeze(a)は,a中のすべてが1である次元を削除する.1でない次元は影響しません.a.squeeze(N)は、aで指定された次元数を1とした次元を削除する.もう一つの形式はb=torchです.squeeze(a,N)aで指定した次元数が1の次元を削除します.**torch.unsqueeze()**この関数は主にデータ次元を拡張します.指定された位置に次元数が1の次元を加算します.たとえば、元の3行のデータ(3)があり、0の位置に1次元を加算すると1行3列(1,3)になります.a.squeeze(N)は、aで指定された位置Nに次元数1を加算した次元である.もう一つの形式はb=torchです.squeeze(a,N)aは、aに指定された位置Nに次元数1を加算した次元である.
4.データ読み出し
私のコードに使いました test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
MyDataset
MyDatasetは独自に定義されたデータ構造でありtorchに継承される.utils.data.Dataset class MyDataset(Dataset):
def __init__(self,txt_path,transform=None,target_transform=None):
fh=open(txt_path,'r')
imgs=[]
for line in fh:
line=line.strip('
')
words=line.split()
path=words[0]
if (len(words)>2):
for i in range(1,len(words)-1):
path+=' '+words[i]
imgs.append((path,int(words[-1])))
self.imgs=imgs
self.transform=transform
self.target_transform=target_transform
def __getitem__(self,index):
fn,label=self.imgs[index]
img=Image.open(fn).convert('RGB')
if self.transform is not None:
img=self.transform(img)
return img,label
def __len__(self):
return len(self.imgs)
torch.utils.dataの勉強
torch.utils.Dataは主に3つのクラスを含む:pytorchは自由なデータ読み出し-torchを実現する.utils.dataの勉強
(1)class torch.utils.data.Dataset
データセットを作成します.getitem__(self,index)関数は、インデックス番号に基づいて画像とラベルを取得し、len_(self)関数を使用して、データセットの長さを取得します.
他のデータセットはそのサブクラスでなければなりません
(2)class torch.utils.data.sample.Sampler(data_source)
パラメータ:data_source(Dataset)-dataset to sample fromの役割:サンプラ、class torchを作成します.utils.data.sampler.SamplerはすべてのSamplerのベースクラスである、iter(self)関数は反復器を取得し、データセット要素のインデックスを反復し、len(self)法は反復器に含まれる要素の長さを返す.
(3)class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, num_workers=0, collate_fn=, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None
value, index=torch.max(tensor,num)
tensor=torch.randn(4,5)
value,index=torch.max(tensor,0)
tensor([[ 0.3045, -0.3509, 0.8248, 1.1156, -1.0433],
[ 1.0962, 0.8329, 1.0494, -0.7632, -0.2968],
[ 0.8749, 0.5894, -2.2095, -0.8238, -0.5258],
[ 1.5428, -0.2508, -0.8234, -0.9917, -1.2586]])
tensor([ 1.5428, 0.8329, 1.0494, 1.1156, -0.2968])
tensor([3, 1, 1, 0, 1])
transform.Compose([transform.Resize((224,224)), transform.ToTensor, transform.Normalize(...)])
test_data = MyDataset(txt_path=test_dir, transform=valiTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
class MyDataset(Dataset):
def __init__(self,txt_path,transform=None,target_transform=None):
fh=open(txt_path,'r')
imgs=[]
for line in fh:
line=line.strip('
')
words=line.split()
path=words[0]
if (len(words)>2):
for i in range(1,len(words)-1):
path+=' '+words[i]
imgs.append((path,int(words[-1])))
self.imgs=imgs
self.transform=transform
self.target_transform=target_transform
def __getitem__(self,index):
fn,label=self.imgs[index]
img=Image.open(fn).convert('RGB')
if self.transform is not None:
img=self.transform(img)
return img,label
def __len__(self):
return len(self.imgs)
[0, num_workers - 1]
) as input, after seeding and before data loading. (default: None). 5.torch.topk()
torch.topk
torch.topk(input,k,dim=None,largest=True,sorted=True,out=None) -> (Tensor,LongTensor)
入力テンソルinputのk個の最大値を、与えられたdim次元に沿って返します.dimを指定しない場合、デフォルトはinputの最後の次元です.largestがFalseの場合、最小k個の値が返されます.
元の入力テンソルinputの測定要素の下付き記号であるメタグループ(values,indices)を返します.ブール値sortedを_に設定した場合True_,返されるk個の値がソートされることを確認します.
パラメータ:input(Tensor)–テンソルk(int)-「top-k」のk dim(int,optional)–ソートされた次元largest(bool,optional)–ブール値を入力し、最大値または最小値sorted(bool,optional)–ブール値を返し、戻り値がout(tuple,optional)–オプション出力テンソル(Tensor,LongTensor)output bufferをソートするかどうかを制御します.