tensorRT5.1.5.0実践EfficientNet+Pytorchの変換試行即ち精度テスト

29756 ワード

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モジュール


    まとめ


    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

  • 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 [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をソートするかどうかを制御します.