【DeepLearning】PyTorchは損失関数(Loss Function)をどのようにカスタマイズしますか?

22122 ワード

変換元:https://www.zhihu.com/question/66988664
文書ディレクトリ
  • 1. 直接利用Tensorが提供するインタフェース
  • 2. PyTorchによるnumpy/scipy拡張
  • 3. PyTorchを書くC拡張
  • 1.torchを直接利用する.Tensorが提供するインタフェース
    カスタムlossのみが必要であるため、lossは1つ以上のTensorに対する混合計算と見なすことができ、例えば3元グループのLoss(Triplet Loss)を計算するには、(入力された3つの(anchor,positive,negative)テンソル次元がbatch_であると仮定する)テンソル次元がsize * 400)
    import torch
    import torch.nn as nn
    import torch.nn.functional as func
    class TripletLossFunc(nn.Module):
        def __init__(self, t1, t2, beta):
            super(TripletLossFunc, self).__init__()
            self.t1 = t1
            self.t2 = t2
            self.beta = beta
            return
    
        def forward(self, anchor, positive, negative):    
            matched = torch.pow(func.pairwise_distance(anchor, positive), 2)
            (func.pairwise_distance(anchor, positive), 2)
            part_1 = torch.clamp(matched - mismatched, min=self.t1)
            part_2 = torch.clamp(matched, min=self.t2)
            dist_hinge = part_1 + self.beta * part_2
            loss = torch.mean(dist_hinge)
            return loss
    

    図に示すように、init__()でスーパーパラメータを定義し、forward()で計算プロセスを定義すればよい.torchが提供するテンソル計算インタフェース(numpyとscipyも同様に使用できるが、感覚効率は低下する)を使用してcudaを呼び出すことができる(torchインタフェースまたはpython内蔵メソッドのみを使用することができる).つまり、インスタンス化オブジェクトの.cuda()メソッドを直接使用することができる.
    nnを受け継いだからModuleなので、このLossクラスはインスタンス化後に直接実行できます_call__()メソッド、つまり
    a = TripletLossFunc(...)
    loss = a(anchor, positive, negative)
    

    それでいいです.これが最初の方法です.
    2.PyTorchによるnumpy/scipy拡張
    もしあなたが細心の注意を払うなら、私がtorchを使っていることに気づきます.nn.functionalモジュールの関数ですが、問題が来ました.もし必要な計算がこのモジュールになかったらどうしますか.では、問題が来ました.もし必要な計算がこのモジュールになかったらどうしますか.公式サイトのチュートリアルはここです(公式サイトのチュートリアルは高速フーリエ変換をネットワークにカスタマイズし、操作を定義してlossで使用することもできます).https://pytorch.org/tutorials/advanced/numpy_extensions_tutorial.html必要な操作はほんの一歩です
    import torch
    from torch.autograd import Function
    from troch.autograd import Variable
    class OwnOp(Function):
        def forward(input_tensor):
            tensor = input_tensor.numpy()
            ...... #    numpy/scipy   
            result = ......
            return torch.Tensor(result)
        def backward(grad_output):
    

    forward()とbackward()の2つのメソッドを定義するだけでいいので、入力を先に呼び出す必要があります.numpy()メソッドは、返す値をtorchにする必要がある.Tensor.
    ここまで書くと、ほとんどのニーズを満たしていますが、もう一つの問題があります.もし私が計算する必要があるものがたくさんある(例えば、ピクセルレベルの計算が必要)か、複雑なものがあるか、numpy/scipyにこれらの操作がない場合はどうしますか.
    はい、それは最後の方法しかありませんが、C言語の基礎とCUDAプログラミングが必要です(MSRAにはCUDAを書く熟練した神がたくさんいるそうです)
    3.PyTorchのC拡張を書く
    うん....最近またこれに振り回されて、まだcuda 23333を学んで、これに対して、私は先に公式サイトの教程をあげます
    PyTorch C拡張https://pytorch.org/tutorials/advanced/cpp_extension.html#
    ある大神が書いたroi_poolingのC拡張ROI
    具体的には、基本的なC/CUDA演算を定義する必要があります
    /* triplest_cal.c */
    #include 
    #include 
    int triplet_cal_forward(...)
    {
        //     
    }
    int triplet_cal_backward(...)
    {
        //     
    }
     
      
    /* triplet_cal.h *?
    int triplet_cal_forward(...);
    int triplet_cal_backward(...);
    

    ここのファイル はモジュール と じでなければなりません. えば、モジュール はtriplet_です.cal、ファイル は の りです.そしてforward、backwardの2つの もこのフォーマットに わなければなりません.PyTorch がヘッダファイルを するためのParseを っているので、 する を います.
    Cudaも じようにtriplet_を する がありますcal_cuda.cとtriplet_cal_cuda.h cudaはcuda を する がある
    /* triplet_cal_kernel.cu */
    #ifdef __cplusplus
    extern "C"{
    #endif
    
    #include 
    #include 
    #include 
    #include "triplet_cal_kernel.h"
    }
    /*
        CUDA233333
    */
    

    その 、buildを する があります.py、この を してPyTorchに け れられるようにします( の はまだここまで いていないので、roi_poolingのものを23333 ってきました.このモジュール はroi_poolingと ばれています)
    import os
    import torch
    from torch.utils.ffi import create_extension
    
    sources = ['src/roi_pooling.c']
    headers = ['src/roi_pooling.h']
    definex = []
    with_cuda = False
    
    if torch.cuda.is_available():
        print('Including CUDA code.')
        sources += ['src/roi_pooling_cuda.c']
        headers += ['src/roi_pooling.cuda.h']
        defines += [('WITH_CUDA', None)]
        with_cuda = True
    
    this_file = os.path.dirname(os.path.realpath(__file__))
    print(this_file)
    extra_objects = ['src/cuda/roi_pooling.cu.o']
    extra_objects = [os.path.join(this_file, name) for fname in extra_objects]
    
    ffi = create_extension(
        '_ext.roi_pooling',
        headers=headers,
        sources=sources,
        define_macros=defines,
        relative_to = __file__,
        with_cuda=with_cuda
        extra_objects=extra_objects
    )
    
    if __name__ == '__main__'
        ffi.build()
    

    あと、やるべきことは2とあまり がないので、 び せばいいのですが、 び す に
    from _ext import roi_pooling
    

    にクラスを きます(メソッド2と にforwardとbackwardでroi_poolingを び せばいいです)








    アルファベットで :
    A B C D E F G H I J K L M N O P Q R S T U V W X Y Z その