異常検知

数少ない画像(正常画像:500、異常画像:10)をうまく分類する方法を検討する。
FashionMNIST画像を使用する。
正常画像としてスニーカー画像500枚
異常画像としてブーツ画像10枚

データの準備

今回はグレー画像をカラーに変換して使用する。

import cv2
import random
import mxnet as mx
from mxnet.gluon import data

train_data = data.vision.datasets.FashionMNIST(train=True)

Sneaker = []
for each_data, label in train_data:
    if label==7:
        img = cv2.cvtColor(each_data.asnumpy(), cv2.COLOR_GRAY2RGB)
        Sneaker.append(mx.nd.array(img))
Sneaker = random.sample(Sneaker, 500)

mx.nd.save('Sneaker', Sneaker)

Boot = []
for each_data, label in train_data:
    if label==9:
        img = cv2.cvtColor(each_data.asnumpy(), cv2.COLOR_GRAY2RGB)
        Boot.append(mx.nd.array(img))
Boot = random.sample(Boot, 10)

mx.nd.save('Boot', Boot)


test_data = data.vision.datasets.FashionMNIST(train=False)

test_Sneaker = []
for each_data, label in test_data:
    if label==7:
        img = cv2.cvtColor(each_data.asnumpy(), cv2.COLOR_GRAY2RGB)
        test_Sneaker.append(mx.nd.array(img))

mx.nd.save('test_Sneaker', test_Sneaker)

test_Boot = []
for each_data, label in test_data:
    if label==9:
        img = cv2.cvtColor(each_data.asnumpy(), cv2.COLOR_GRAY2RGB)
        test_Boot.append(mx.nd.array(img))

mx.nd.save('test_Boot', test_Boot)

単純なクラス分類を試してみる

  • コード
import numpy as np 
import mxnet as mx
from mxnet import autograd, gluon
from mxnet.gluon import nn, data
from mxnet.gluon.data.vision import transforms
from gluoncv.model_zoo import get_model

jitter_param = 0.4
lighting_param = 0.1
transform_train = transforms.Compose([
    transforms.Resize(224),
    transforms.RandomFlipLeftRight(),
    transforms.RandomColorJitter(brightness=jitter_param, contrast=jitter_param,
                                 saturation=jitter_param),
    transforms.RandomLighting(lighting_param),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

transform_test = transforms.Compose([
    transforms.Resize(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

train_data = mx.nd.load('Sneaker') + mx.nd.load('Boot')
train_label = [0]*500 + [1]*10

train_dataset = data.dataset.ArrayDataset(train_data, train_label)
train_data = data.DataLoader(
    train_dataset.transform_first(transform_train), 
    batch_size=32,
    shuffle=True)

test_data = mx.nd.load('test_Sneaker') + mx.nd.load('test_Boot')
test_label = [0]*1000 + [1]*1000

test_dataset = data.dataset.ArrayDataset(test_data, test_label)
test_data = data.DataLoader(
    test_dataset.transform_first(transform_test), 
    batch_size=32,
    shuffle=False)

finetune_net = get_model('mobilenet1.0', pretrained=True, root='MobileNet')

with finetune_net.name_scope():
    finetune_net.output = nn.Dense(2)
finetune_net.output.initialize(mx.init.Xavier())
finetune_net.hybridize()

def evaluate_accuracy(dataloader, net):
    sample_n = 0
    acc = 0
    for batch in dataloader:
        data = batch[0]
        label = batch[1].asnumpy().astype('int32')
        output = net(data)
        predictions = np.argmax(output.asnumpy(), axis=1).astype('int32')
        sample_n += data.shape[0]
        acc += sum(predictions==label)
    return acc / sample_n

trainer = gluon.Trainer(finetune_net.collect_params(), 'adam')
Loss = gluon.loss.SoftmaxCrossEntropyLoss()

epoch = 10

print('start training...')

for epoch in range(1, epoch + 1):
    for batch in train_data:
        data = batch[0]
        label = batch[1]
        with autograd.record():
            output = finetune_net(data)
            loss = Loss(output, label)
            loss.backward()
        trainer.step(data.shape[0])

    train_acc = evaluate_accuracy(train_data, finetune_net)
    test_acc = evaluate_accuracy(test_data, finetune_net)
    
    print('{:<2} epoch train_acc = {:<10,.5f} test_acc = {:<10,.5f}'.format(epoch, train_acc, test_acc))

    finetune_net.save_parameters('finetune_%d.params'%epoch)
  • 結果
1  epoch train_acc = 0.21765    test_acc = 0.56150
2  epoch train_acc = 0.99608    test_acc = 0.79000
3  epoch train_acc = 0.99804    test_acc = 0.88500
4  epoch train_acc = 1.00000    test_acc = 0.81750
5  epoch train_acc = 0.99608    test_acc = 0.89800
6  epoch train_acc = 1.00000    test_acc = 0.87300
7  epoch train_acc = 1.00000    test_acc = 0.87100
8  epoch train_acc = 1.00000    test_acc = 0.87100
9  epoch train_acc = 1.00000    test_acc = 0.76400
10 epoch train_acc = 1.00000    test_acc = 0.78600
  • 結果を図示するコード
import numpy as np 
import mxnet as mx
from mxnet.gluon import nn, data
from mxnet.gluon.data.vision import transforms
from gluoncv.model_zoo import get_model

transform_test = transforms.Compose([
    transforms.Resize(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

train_data = mx.nd.load('Sneaker') + mx.nd.load('Boot')
train_label = [0]*500 + [1]*10

train_dataset = data.dataset.ArrayDataset(train_data, train_label)
train_data = data.DataLoader(
    train_dataset.transform_first(transform_test), 
    batch_size=32,
    shuffle=False)

test_data = mx.nd.load('test_Sneaker') + mx.nd.load('test_Boot')
test_label = [0]*1000 + [1]*1000

test_dataset = data.dataset.ArrayDataset(test_data, test_label)
test_data = data.DataLoader(
    test_dataset.transform_first(transform_test), 
    batch_size=32,
    shuffle=False)

finetune_net = get_model('mobilenet1.0', pretrained=False, root='MobileNet')

with finetune_net.name_scope():
    finetune_net.output = nn.Dense(2)
finetune_net.load_parameters('finetune_5.params')
finetune_net.hybridize()

train_result = []
for batch in train_data:
    output = finetune_net.features(batch[0])
    train_result.append(output)

train_x = mx.nd.concat(*train_result, dim=0)

test_result = []
for batch in test_data:
    output = finetune_net.features(batch[0])
    test_result.append(output)

test_x = mx.nd.concat(*test_result, dim=0)

from sklearn.manifold import TSNE
train_result = TSNE(n_components=2).fit_transform(train_x.asnumpy())
test_result = TSNE(n_components=2).fit_transform(test_x.asnumpy())

#結果を散布図にして表示
import matplotlib.pyplot as plt

plt.scatter(train_result[:,0], train_result[:,1], c = train_label, cmap='bwr')
plt.show()

plt.scatter(test_result[:,0], test_result[:,1], c = test_label, cmap='bwr')
plt.show()
  • 結果の図示

f:id:touch-sp:20190903172409p:plain
f:id:touch-sp:20190903172425p:plain
上が訓練データ、下がテストデータ
訓練データでは異常画像が十分分類されており、これ以上の改善は望めないことがわかる。

ここからが本題

(書きかけ)