評価関数の扱い - Shinichi0713/recommendation-ai GitHub Wiki

目的

評価関数を自作する場合に注意すべき点について確認する。

自作

torchの入力、出力による直接計算を行わず、一旦、別テンソルを構築して計算する

class EvaluateFunction(_WeightedLoss):
    def __init__(self, input_size):
        super().__init__(reduction='mean')
        self.input_size = input_size
        # self.rects = rects
        self.packer = newPacker(rotation=False)

    def forward(self, rects_input, length_predict):
        # packed_rectsの面積を計算する
        packed_area = torch.zeros((len(rects_input), 1))
        area_tenant = torch.zeros((len(rects_input), 1))
        for i in range(len(rects_input)):
            packed_area[i, :] = rects_input[i] * rects_input[i]
            # rectsの面積を計算する
            area_tenant[i, :] = length_predict[i] * length_predict[i]
        # 隙間の面積を計算する
        gap_area = torch.sum(torch.abs(area_tenant - packed_area))
        return gap_area

実験内容

モデルは、複数の四角形のデータを入力→面積の総和の平方根を予測するmodelを作る。
さっきに上げた評価関数でうまく学習が進むかについて確認する。

結果:
学習出来ました。
image

余談:
ちなみに、出力にReluをかけてたら全然、学習進みませんでした。。。 勾配が消失してたみたいです。

計算グラフが消失

入力を使った計算中に計算グラフが消失→勾配が計算されず、学習が進まない

通常

ロス計算後にgradを出力すると   image  

計算グラフが算出されているとgradが出力される
image  

自作で計算グラフ消失時

同じコードで、評価関数のみ別物の(計算グラフが切れた)場合

            outputs = model(inputs.to(model.device))
            outputs.retain_grad()
            # labels = labels.to(model.device)
            # loss = criterion(outputs, labels)
            
            loss = criterion(inputs, outputs.detach().cpu())
            loss.backward()
            print(outputs.grad)
            optimizer.step()

image

自作の評価関数の中で、inputの値をdetachかつcloneして、ロス値を計算した場合、計算グラフはどうなるでしょうか?

自作の評価関数の中で input の値を detach かつ clone してロス値を計算した場合、計算グラフはその input から切断されます。
これは、detach を使用することで、そのテンソルの計算グラフから切り離され、勾配計算が行われなくなるためです。

結論

自作評価関数を作成する場合、入力した値は直接ロスの値の計算に影響を及ぼすようにしないといけない。