Python
MachineLearning
異常検知
PyTorch
MetricLearning


Deep Metric Learning

Metric Learning自体は,画像などのデータからある計量(マハラノビス距離やコサイン類似度など)を抽出し,その近さでクラスタリングを行うような手法です.そしてDeep Metric Learningは,従来のMetric Learningの距離の定義や抽出部分をDNNに丸投げしたものです.

識別モデルのように識別境界を引くことで分類するモデルとは性質が異なるので,異常検知の文脈などでよく使用される技術です.

今回はこの技術を使用し,犬と猫の分類を行います.


実験

Deep Metric Learningを用いて,異常検知を行います.

犬猫の2値分類で猫を正常,犬を異常として分類を行います.

今回の実験は2つのLossについて行います.

- Triplet Loss

- Angular Loss


DMLにおけるLoss

詳細はこの記事を参照してください.

Deep Metric Learning サーベイ

今回はTriplet Loss,Angular Lossの比較を行います.

まずはじめに実装をあげて,その後に実験結果を示します.

Lossの検討では,Triplet Samplingを用います.そのためN-pair Samplingをしたい場合,Lossのコードは少し書き直す必要があることに注意してください.


Triplet Loss


losses.py

class TripletLoss(nn.Module):

def __init__(self, margin=0.2):
super(TripletLoss, self).__init__()
self.margin = margin

def forward(self, a, p, n):
loss = torch.norm(a - p, p=2, dim=1) - torch.norm(a - n, p=2, dim=1) + self.margin
return F.relu(loss).mean()



Angular Loss


losses.py

class TripletAngularLoss(nn.Module):

def __init__(self, alpha=45, in_degree=True, margin=0.2):
super(TripletAngularLoss, self).__init__()
self.margin = margin
if in_degree:
alpha = np.deg2rad(alpha)
self.tan_alpha = np.tan(alpha) ** 2

def forward(self, a, p, n):
c = (a + p) / 2
loss = torch.norm(a - p, p=2, dim=1) - 4*self.tan_alpha*torch.norm(n - c, p=2, dim=1) + self.margin
return F.relu(loss).mean()



Triplet Sampler


datasets.py

class TripletSampler(Dataset):

def __init__(self, inputs, targets):
self.inputs = inputs
self.targets = targets

def __len__(self):
return len(self.targets)

def __getitem__(self, idx):
x = self.inputs[idx]
t = self.targets[idx]
xp_idx = np.random.choice(np.where(self.targets == t)[0])
xn_idx = np.random.choice(np.where(self.targets != t)[0])
xp = self.inputs[xp_idx]
xn = self.inputs[xn_idx]
return x, xp, xn, t


エンコーダにはpretrained ResNet18を用いて,その後ろに100次元の出力を持つ全結合層を1つつけたモデルを使用します.


学習条件


  • Optimizer: MomentumSGD


    • lr = 0.001

    • momentum = 0.9

    • weight_decay = 1e-4



  • batch_size = 32

  • n_epochs = 30


タスク

OxfordのPet Datasetを用いて画像分類を行います.

異常検知タスクと仮定し,正常データを猫,異常データを犬とします.

訓練用データ

- 正常の猫画像が1896枚

- 異常の犬画像が406枚

テストデータ

- 正常の猫画像が370枚

- 異常の犬画像が3363枚


学習結果

t-SNEを用いて2次元にplotした結果が以下の画像です.

まずこれがTriplet Sampling + Triplet Loss.

正常データである猫が紫,異常データである犬が黄色でプロットされています.

正常データを集めることには成功していますが,異常データをうまく分離できていないように見えます.

triplet.png

そしてこちらがTriplet Sampling + Angular Loss.

こちらは比較的奇麗に分離できていることがわかります.

-302.png

t-SNEによる可視化だけでなく,KMeansによるクラスタリングも行ってみました.

テストデータをsklearnのStratifiedKFoldを用いて交差検証した結果がこちらです.

ちなみに先ほども述べたとおり,テストデータでは正常データが少数派,異常データが多数派です.

こう見るとTriplet Lossは正常データに比較的ひっぱられがちですが,Angular Lossは異常データをきれいに分離できているというような結果になりました.(f値からみるとTriplet Lossの方がいいので状況により一概には言えませんが)

Triplet Loss
Angular Loss

Accuracy
0.719
0.760

F1 score
0.837
0.758


まとめ

今回はTriplet LossとAngular Lossの比較をしてみました.

t-SNEもKMeansもどちらも見方のひとつでしかないのですが,今回の実験ではAngular Lossが非常に良い結果を示しました

以上,

ご覧いただきありがとうございました.