カテゴリー
blog

Java SE8 Silverに合格しました

合格しました。

Javaの開発経験なんてないのでこれ以上は難しいです。

カテゴリー
blog

LaMetric Time でZabbix監視

ネットとつながる LED 時計

LaMetricを買いました。

 

かっこいい!

Gmailとか、天気とか、RSSとか受信してお知らせしてくれます!

 

Zabbixの監視用アプリ作ってみた。

LaMetricのデベロッパーサイトはこちら

 

自作のZabbix AlertスクリプトからLaMetricのアプリをPushすることで通知します。

AlertScriptはGitHubにアップしています。

 

 

こんな感じ。

 

アプリ自体は非公開なので、(Zabbixのアイコンは公開しました)自分で作ってみて下さい。

カテゴリー
blog

Google認定資格データ エンジニアに合格しました。

Google~

受けたら受かりました。

Google Certified Professional DataEngineer

GCPの基礎知識に加え機械学習系の知識が多く求められる認定資格だったと思います。

試験も手応えがあり、落ちたと思って結果送信ボタン押したら受かりました。

合格自体は8月にしましたが、Googleからジャージが届いたので写真を上げるついでに記事記載しました。

受けるに当たっていくつかポイントを上げるとしたら、TensorflowについてはEstimateAPIまで知らないと難しいです。

むかしTensorflow触ったから大丈夫という人は最新のTensorflowをもう一度触ってみるといいかもしれませんね。

あと、データベース。正直紛らわしい。

カテゴリー
blog

Python 3 エンジニア認定基礎試験受けました

合格しました。

よかったです。

モジュールの部分が50%(2問中1問ミス)で入出力に関しては0%(1問中1問ミス)でした。

試験の印象

試験内容は基礎的なものでしたが、Pythonの基礎的な知識がついてないと解ききれない問題という印象でした。(Javaとか経験あるから余裕、という感じではないです)

例外の部分など、試験を受けている身でも思わず「いい問題だなぁ」と感じましたね。

実務経験がある方でもある程度は基礎を復習してから受けた方がいいと思います。

公式テキストは Pythonチュートリアル-第3版 です!読みましょう!入門書というよりは中級者向けの基礎振り返り本なイメージがあります。(あぁ、こういうのあったね、的な)

あと、試験時間は余裕がありました。

にしても入出力で間違うとは…。ゴミですね。

今後の展望

とりあえず、Pythonもっと書けるようにします。

カテゴリー
blog

電源障害

UPSが落ちるとこうなる

たぶん監視者が一番いやな状況が目の前で起きたので。

うわあ。前にてきとーに作ったZabbixマップがおもしろい

こうやって見るとどこが悪いか一発でわかるなぁ。

カテゴリー
blog

Elasticsearchのクラスタ監視をZabbixでする

ZabbixでElasticsearchのクラスタを監視したい、したくない?

Elasticsearchのノードを先日1つ追加しましたので、ちょい傾向とかを確認しようと思いZabbixで監視できるテンプレートとかを作ってみました。

 

Elastic_zab

 

使い方

Zabbixには外部チェックという自作で用意したスクリプトをキックしてその実行結果を取得する機能があります。今回はそれを使ってみます。

 

シェルスクリプトをZabbixサーバに配置する

Elastic_zabに同梱しているelastic.shをZabbixサーバのexternalscriptsディレクトリに配置します。実行権限もZabbixユーザにします。

[code]

$ git clone https://github.com/tubone24/Elastic_zab

$  cp -p Elastic_zab/elastic.sh /usr/lib/zabbix/externalscripts/

$ chown zabbix. /usr/lib/zabbix/externalscripts/elastic.sh

$ chmod 751 /usr/lib/zabbix/externalscripts/elastic.sh

[/code]

 

Zabbixにテンプレートをインストールする

Zabbix画面の設定のテンプレートからelasticsearch_zab.xmlをインポートします。

 

うまくインストールできれば、テンプレート一覧にElastic clusterが出現します。

 

Elasticsearchのノードにテンプレートを当てる

Elasticsearchのノードにテンプレートを当てます。

 

合わせて、ElasticsearchのIPとポートをマクロで設定しておきます。

設定するマクロは以下の2つです。

  • {$ESIP} = ElasticsearchのIPもしくはDNSネームを設定します。
  • {$ESPORT} = Elasticsearchのポートを設定します。

 

監視する

うまく監視できるとこんなグラフができます。

 

おまけ Zabbixの予測関数を使ってみた

いくつかの監視アイテムはforecastやtimeleftといったZabbixの関数を利用しています。

予測は線形としています。

予測値はトリガー設定していないのでお好みでトリガーを設定するのもいいのではないでしょうか。

こんな感じで計算アイテムで簡単に実装できるのが魅力ですね。

 

 

カテゴリー
Anime

大きく吸ってせーの! で・ぃ・ぷ・ら・ん・に・ん・ぐ! ~ひなこのーと×Deep Learning~

くいなちゃんのかわいさで僕は満足です。

どうも。ひなこのーと、よかったです。かわいかったです。でも、ひなこのーとを見ているとき、いろんな人からこんなことを言われました。

ひなこのーとって、エロいごちうさじゃね?

はぁああああああん!?

可愛いという共通点は認めるし、ごちうさは女神の生まれ変わりだと思っているが、ひなこのーとはごちうさとは違うすばらしさがある!ということで、Deep Learningを使って以下のことをやってみたいと思います。

 

  1. きんいろDeepLearningご注文はDeep Learningですか? など、可愛いアニメは必ずDeep Learningの餌食になると思うので、「ひなこのーと」もDeep Learningやってみる。
  2. アニメひなこのーとの可愛い動画を読み込ませて、主要キャラの分類モデルを作成し、イラストを読み込ませて判定する。
  3. できあがったモデルでごちうさの画像を読み込ませて、ひなこのーとのキャラに分類されないことを確認する。

 

前提条件

[list] [li-disc]Python2.7(Anaconda3で仮想環境作成)[/li-disc] [li-disc]Windows 7[/li-disc] [li-disc]CPUオンリー[/li-disc] [/list]

 

ちょっとした考察

本当にひなこのーとと、ごちうさは似ているのか、雰囲気だけではないか、よく考えて欲しい。

ひなこのーと

ごちうさ

 

 

1. 「ひなこのーと」もDeep Learningやってみる。

 

下準備

Deep Learningの難しいところは、とにかく大量のトレーニングデータが必要になるところであります。

途方に暮れていたところ、すばらしいスクリプトがあったので使わせて頂きます。

Python、OpenCVで顔の検出(アニメ)

こちらのスクリプトをそのまま使ってひなこのーとの1~12話から顔という顔を切り抜こう!

その際、OpenCVによるアニメ顔検出ならlbpcascade_animeface.xml のすばらしい設定ファイルを活用します。このXMLは後々使いますので、その際また。

そして、切り抜いた顔をそれぞれのキャラごとにフォルダに移します。(手作業)

こんな感じ。 50×50の可愛い画像がたくさん!

データセットはそれぞれ

  • ひなこ 1164枚
  • くいな 678枚
  • まゆき 563枚
  • ゆあ 541枚
  • ちあき 536枚
  • その他 5493枚

です。少ない。。。

 

 

 

学習させる

ご注文はDeep Learningですか?では、Caffeを使っていますが、自分はChainerの方がなじみあるので、Chainerを使っていきます。

と言ってももう既に化物語で同じことをやっていた人がいたので、モデル定義と学習、予測のコードをお借りしました。

python: chainerを使って化物語キャラを認識させるよ! 〜part5.5 主要キャラで多値分類(改良編)〜

 

今回は、ひなこ・くいな・まゆき・ゆあ・ちあき・その他の計6つの分類になりますので、モデル定義等のパラメータのみ変更しています。

モデル定義

[code]

#coding:utf-8

import os

import chainer
from chainer import optimizers
import chainer.functions as F
import chainer.links as L
import chainer.serializers as S

import numpy as np

class clf_bake(chainer.Chain):
    def __init__(self):

        super(clf_bake, self).__init__(
            conv1 =  F.Convolution2D(3, 16, 5, pad=2),
            conv2 =  F.Convolution2D(16, 32, 5, pad=2),
            l3    =  F.Linear(6272, 256),
            l4    =  F.Linear(256, 6) #ここを6にしました
        )

    def clear(self):
        self.loss = None
        self.accuracy = None

    def forward(self, X_data, y_data, train=True):
        self.clear()
        X_data = chainer.Variable(np.asarray(X_data), volatile=not train)
        y_data = chainer.Variable(np.asarray(y_data), volatile=not train)
        h = F.max_pooling_2d(F.relu(self.conv1(X_data)), ksize = 5, stride = 2, pad =2)
        h = F.max_pooling_2d(F.relu(self.conv2(h)), ksize = 5, stride = 2, pad =2)
        h = F.dropout(F.relu(self.l3(h)), train=train)
        y = self.l4(h)
        return F.softmax_cross_entropy(y, y_data), F.accuracy(y, y_data)

[/code]

 

モデル定義に合わせて分類の数を変更し、画像の枚数に合わせて学習用、テスト用画像の枚数等を調整しました。

[code]

#coding: utf-8

import cv2
import os
import six
import datetime

import chainer
from chainer import optimizers
import chainer.functions as F
import chainer.links as L
import chainer.serializers as S
from clf_bake_model import clf_bake

import numpy as np

def getDataSet():

X_train = []
X_test = []
y_train = []
y_test = []

for i in range(0,6):
path = “dataset/”
if i == 0:

cutNum = 5493 # その他の画像数です。
cutNum2 = 5393 # 内100枚をテスト用にします。

elif i == 1:
cutNum = 1164 # ひなこの画像数です。
cutNum2 = 1139 # 内25枚をテスト用にします。

elif i == 2:
cutNum = 678 # くいなの画像数です。
cutNum2 = 653 # 内25枚をテスト用にします。

elif i == 3:
cutNum = 563 # まゆきの画像数です。
cutNum2 = 538 # 内25枚をテスト用にします。

elif i == 4:
cutNum = 541 # ゆあの画像数です。
cutNum2 = 516 # 内25枚をテスト用にします。

elif i == 5:
cutNum = 536 # ちあきの画像数です。
cutNum2 = 511 # 内25枚をテスト用にします。

imgList = os.listdir(path+str(i))
imgNum = len(imgList)
for j in range(cutNum):
imgSrc = cv2.imread(path+str(i)+”/”+imgList[j])

if imgSrc is None:continue
if j < cutNum2:
X_train.append(imgSrc)
y_train.append(i)
else:
X_test.append(imgSrc)
y_test.append(i)

return X_train,y_train,X_test,y_test

def train():

X_train,y_train,X_test,y_test = getDataSet()

X_train = np.array(X_train).astype(np.float32).reshape((len(X_train),3, 50, 50)) / 255
y_train = np.array(y_train).astype(np.int32)
X_test = np.array(X_test).astype(np.float32).reshape((len(X_test),3, 50, 50)) / 255
y_test = np.array(y_test).astype(np.int32)

model = clf_bake()
optimizer = optimizers.Adam()
optimizer.setup(model)

epochNum = 30
batchNum = 50
epoch = 1

while epoch <= epochNum:
print(“epoch: {}”.format(epoch))
print(datetime.datetime.now())

trainImgNum = len(y_train)
testImgNum = len(y_test)

sumAcr = 0
sumLoss = 0

perm = np.random.permutation(trainImgNum)

for i in six.moves.range(0, trainImgNum, batchNum):

X_batch = X_train[perm[i:i+batchNum]]
y_batch = y_train[perm[i:i+batchNum]]

optimizer.zero_grads()
loss, acc = model.forward(X_batch, y_batch)
loss.backward()
optimizer.update()

sumLoss += float(loss.data) * len(y_batch)
sumAcr += float(acc.data) * len(y_batch)
print(‘train mean loss={}, accuracy={}’.format(sumLoss / trainImgNum, sumAcr / trainImgNum))

sumAcr = 0
sumLoss = 0

for i in six.moves.range(0, testImgNum, batchNum):
X_batch = X_test[i:i+batchNum]
y_batch = y_test[i:i+batchNum]
loss, acc = model.forward(X_batch, y_batch, train=False)

sumLoss += float(loss.data) * len(y_batch)
sumAcr += float(acc.data) * len(y_batch)
print(‘test mean loss={}, accuracy={}’.format(
sumLoss / testImgNum, sumAcr / testImgNum))
epoch += 1

S.save_hdf5(‘model’+str(epoch+1), model)

[/code]

 

学習結果

[code]

(py27con) C:\Users\tubone\PycharmProjects\anime-learn>python train.py
epoch: 1
2017-07-16 21:40:03.060000
train mean loss=1.16183573621, accuracy=0.619771432281
test mean loss=1.05560781558, accuracy=0.506666666104
epoch: 2
2017-07-16 21:42:13.192000
train mean loss=0.800489272901, accuracy=0.69348571573
test mean loss=0.871727473206, accuracy=0.577777779765
epoch: 3
2017-07-16 21:44:23.290000
train mean loss=0.698785139833, accuracy=0.743085714408
test mean loss=0.780110951927, accuracy=0.631111116873
epoch: 4
2017-07-16 21:46:33.502000
train mean loss=0.597107084649, accuracy=0.786971424307
test mean loss=0.548737568988, accuracy=0.83111111323
epoch: 5
2017-07-16 21:48:44.037000
train mean loss=0.500077148761, accuracy=0.82479999406
test mean loss=0.480820135938, accuracy=0.857777780957
epoch: 6
2017-07-16 21:50:57.706000
train mean loss=0.451180534618, accuracy=0.841257137571
test mean loss=0.448005066978, accuracy=0.87555554178
epoch: 7
2017-07-16 21:53:09.992000
train mean loss=0.405994535514, accuracy=0.861028568063
test mean loss=0.472903796368, accuracy=0.835555553436
epoch: 8
2017-07-16 21:55:22.262000
train mean loss=0.358310819779, accuracy=0.87851428066
test mean loss=0.306394663122, accuracy=0.911111103164
epoch: 9
2017-07-16 21:57:34.985000
train mean loss=0.337241342791, accuracy=0.880799995831
test mean loss=0.308397501707, accuracy=0.902222216129
epoch: 10
2017-07-16 21:59:47.595000
train mean loss=0.324274266022, accuracy=0.886742852415
test mean loss=0.323723706934, accuracy=0.871111101574
epoch: 11
2017-07-16 22:01:59.865000
train mean loss=0.296059874466, accuracy=0.897142853737
test mean loss=0.390861597326, accuracy=0.848888880677
epoch: 12
2017-07-16 22:04:12.384000
train mean loss=0.28229231613, accuracy=0.900799994469
test mean loss=0.381249505613, accuracy=0.888888888889
epoch: 13
2017-07-16 22:06:25.189000
train mean loss=0.242525527115, accuracy=0.915771426473
test mean loss=0.304150695602, accuracy=0.906666656335
epoch: 14
2017-07-16 22:08:37.995000
train mean loss=0.231497560718, accuracy=0.919314283303
test mean loss=0.275258473224, accuracy=0.906666662958
epoch: 15
2017-07-16 22:10:50.532000
train mean loss=0.219778511652, accuracy=0.923199997629
test mean loss=0.354618171851, accuracy=0.91555554337
epoch: 16
2017-07-16 22:13:02.623000
train mean loss=0.218345963359, accuracy=0.926285712378
test mean loss=0.36049440172, accuracy=0.897777775923
epoch: 17
2017-07-16 22:15:15.105000
train mean loss=0.199432469181, accuracy=0.933599996226
test mean loss=0.403067363633, accuracy=0.87555554178
epoch: 18
2017-07-16 22:17:27.614000
train mean loss=0.188562800608, accuracy=0.936114283289
test mean loss=0.316384883391, accuracy=0.911111109787
epoch: 19
2017-07-16 22:19:40.506000
train mean loss=0.187215176012, accuracy=0.933028570243
test mean loss=0.360161377324, accuracy=0.906666676203
epoch: 20
2017-07-16 22:21:53.107000
train mean loss=0.165474589265, accuracy=0.94388571058
test mean loss=0.282101011939, accuracy=0.919999996821
epoch: 21
2017-07-16 22:24:05.521000
train mean loss=0.153822022751, accuracy=0.947999996117
test mean loss=0.33798650321, accuracy=0.919999996821
epoch: 22
2017-07-16 22:26:18.048000
train mean loss=0.140677581344, accuracy=0.952228568281
test mean loss=0.309250995517, accuracy=0.924444450272
epoch: 23
2017-07-16 22:28:30.608000
train mean loss=0.138967069973, accuracy=0.951314284801
test mean loss=0.488151417838, accuracy=0.871111101574
epoch: 24
2017-07-16 22:30:43.540000
train mean loss=0.150780805051, accuracy=0.945828568935
test mean loss=0.305154048734, accuracy=0.924444450272
epoch: 25
2017-07-16 22:32:55.811000
train mean loss=0.133075305953, accuracy=0.952799998692
test mean loss=0.421937998798, accuracy=0.906666662958
epoch: 26
2017-07-16 22:35:08.076000
train mean loss=0.119467954348, accuracy=0.954514285156
test mean loss=0.384507967366, accuracy=0.902222222752
epoch: 27
2017-07-16 22:37:20.527000
train mean loss=0.138162662153, accuracy=0.949028568949
test mean loss=0.317712697718, accuracy=0.928888883856
epoch: 28
2017-07-16 22:39:32.964000
train mean loss=0.114523774907, accuracy=0.961485714912
test mean loss=0.39709764719, accuracy=0.919999996821
epoch: 29
2017-07-16 22:41:45.211000
train mean loss=0.120365411943, accuracy=0.958171426228
test mean loss=0.379737239745, accuracy=0.93333334393
epoch: 30
2017-07-16 22:43:57.336000
train mean loss=0.110197391031, accuracy=0.958742856298
test mean loss=0.401306927204, accuracy=0.920000010067[/code]

計32エポックで学習終了です。

 

2.主要キャラの分類モデルを作成し、イラストを読み込ませて判定する。

 

予測用のコードも以下からお借りしています。

python: chainerを使って化物語キャラを認識させるよ! 〜part5.5 主要キャラで多値分類(改良編)〜

 

[code]

# -*- coding: utf-8 -*-
#!/usr/bin/env python
import sys

import numpy as np
import six
import cv2
import os


import chainer
from chainer import computational_graph as c
import chainer.functions as F
import chainer.serializers as S

from chainer import optimizers

from clf_bake_model import clf_bake


model = clf_bake()
S.load_hdf5('./model32', model) # 32モデルだったので。
#model = pickle.load(open('model30','rb'))

chara_name = ['Unknown', "Hinako","Kuina","Mayuki","Yua","Chiaki"]

def forward(x_data):
    x = chainer.Variable(x_data, volatile=False)
    h = F.max_pooling_2d(F.relu(model.conv1(x)), ksize = 5, stride = 2, pad =2)
    h = F.max_pooling_2d(F.relu(model.conv2(h)), ksize = 5, stride = 2, pad =2)
    h = F.dropout(F.relu(model.l3(h)), train=False)
    y = model.l4(h)

    return y

def detect(image, cascade_file = "./lbpcascade_animeface.xml"): # アニメ顔抽出時使ったXMLを指定
    if not os.path.isfile(cascade_file):
        raise RuntimeError("%s: not found" % cascade_file)

    cascade = cv2.CascadeClassifier(cascade_file)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.equalizeHist(gray)

    faces = cascade.detectMultiScale(gray,
                                     scaleFactor = 1.1,
                                     minNeighbors = 1,
                                     minSize = (20, 20))

    print(faces)

    return faces

def recognition(image, faces):
    face_images = []

    for (x, y, w, h) in faces:
        dst = image[y:y+h, x:x+w]
        dst = cv2.resize(dst, (50, 50))
        face_images.append(dst)

    face_images = np.array(face_images).astype(np.float32).reshape((len(face_images),3, 50, 50)) / 255

    #face_images = cuda.to_gpu(face_images)

    return forward(face_images) , image

def draw_result(image, faces, result):

    count = 0
    for (x, y, w, h) in faces:
        classNum = 0
        result_data = result.data[count]
        classNum = result_data.argmax()
        recognized_class = chara_name[result_data.argmax()]
        font = cv2.FONT_HERSHEY_TRIPLEX # 名前を入れたいので、OpenCVのFont機能を使います。
        font_size = 1.1
        if classNum == 0:
                cv2.rectangle(image, (x, y), (x+w, y+h), (255,255,3), 3)
                cv2.putText(image, chara_name[0], (x,y), font, font_size,
                            (255, 255, 3)) # 重ねたい画像を選択し、フォントサイズ等を指定
        elif classNum == 1:
                cv2.rectangle(image, (x, y), (x+w, y+h), (0,0,255), 3)
                cv2.putText(image, chara_name[1], (x,y), font, font_size,
                            (0, 0, 255))
        elif classNum == 2:
                cv2.rectangle(image, (x, y), (x+w, y+h),  (255,0,0), 3)
                cv2.putText(image, chara_name[2], (x,y), font, font_size,
                            (255, 0, 0))
        elif classNum == 3:
                cv2.rectangle(image, (x, y), (x+w, y+h), (255,255,255), 3)
                cv2.putText(image, chara_name[3], (x,y), font, font_size,
                            (255, 255, 255))
        elif classNum == 4:
                cv2.rectangle(image, (x, y), (x+w, y+h), (255,0,255), 3)
                cv2.putText(image, chara_name[4], (x,y), font, font_size,
                            (255, 0, 255))
        elif classNum == 5:
                cv2.rectangle(image, (x, y), (x+w, y+h), (0,255,255), 3)
                cv2.putText(image, chara_name[5], (x,y), font, font_size,
                            (255, 128, 255))

        count+=1

    return image

#ファイル読み込み
img = cv2.imread("test.jpg")

faces = detect(img)

result, image = recognition(img, faces)

image = draw_result(image, faces, result)
cv2.imwrite('out.png',image)

[/code]

 

実際、読み込ませる

実際読み込ませてみたものがこちら。

  • 水色はUnknown
  • 赤がひなこ
  • 青がくいな
  • 白がまゆき
  • 紫がゆあ
  • オレンジがちあき

です。

大家さんだけがUnknownとなってしまいました。。。

データ量が少なかったためでしょうね。

 

3. できあがったモデルでごちうさの画像を読み込ませて、ひなこのーとのキャラに分類されないことを確認する。

いよいよオーラスです。これをやるためにつくったモデルです。

さっそく読み込ませて見ます。

 

 

むむっ。ココアさんがひなこに、シャロちゃんがまゆちゃんと認識されているではないか。

ココアさんとひなこ、なんか似ているように感じなくもなくもない?????

フルール・ド・ラパンの制服と、まゆちゃんの私服が似ているというのはあるが、髪色で判断しているわけではないよな??

 

金髪で判断しているという可能性がぬぐいきれないので。これでもくらえ!きんモザ&ごちうさのコラボじゃあああ。

 

 

金髪で判断しているというわけではなかった。

それにしてもココアさん=ひなこは覆らないな。

 

絵のタッチを変えてみる

こうなったら徹底討論じゃあ。絵のタッチを変えてどうなるか試してみましょう。

 

 

[fontsize class=’xxxl’] ココア、お前だったのか!! (結論)[/fontsize]

 

おまけ1 ひなこのーともイラストで認識させてみる。

 

どうやら、くいなちゃんの認識率が一番いい。くいなちゃんかわいいからね。

 

おまけ2 くいなちゃん、某オタク少女に似ている説を確かめる。

 

 

大丈夫でした!!!

 

カテゴリー
blog

R言語を使って、サポートベクターとかニューラルネットとかを比較してみる(kddcup99編)

機械学習で彼女を作ろうとかふまじめなことはやめよう!

どうも。最近暑くてどうにもやる気がでませんが、そんなとき、めんどくさいことを機械がやってくれればなと思うわけです。

最近(とは言ってもだいぶ成熟した分野ですが)流行の機械学習を勉強することによって、明るい未来を作ろうということを考えるわけです。

前回はおしゃべり彼女を作りましたので、今回はまじめにセキュリティ系のネタをやっていこうかと思います。

 

データセットを用意しよう

データセットは以下のものを使います。

KDD Cup 1999 Data

国際会議SIGKDDの1999年のデータマイニングコンペデータだそうで、そのときの侵入検知データはセキュリティ界隈ではかなり有名だそうです。私は最近まで知りませんでした。恥ずかしい。

このデータはかなり膨大なので、今回はフルデータを10%抽出したkddcup.data_10_percentをさらに学習データと評価データにわけて実験します。

今回は通常の通信と、いくつかの攻撃手法とを分類します。

 

たまにはR言語を使ってみよう

R言語と聞くとじんま疹が出る生物系の学生も多いと思いますが、きちんとPythonとかでプログラミングするよりは簡単だと思います。無料だし。まぁSPSSとかの方がずっと簡単ですが。

 

分類にはサポートベクターマシン(SVM)

機械学習のパターン認識(分類)にはサポートベクターマシン(SVM)がいいと言われています。SVM自体は比較的古い手法ですが、汎化性能を高める工夫がしっかりしている点で非常に未学習データの認識が優れていると言われています。

R言語ではKernlabというパッケージにSVMがあります。

 

実際にやってみた(C-SVM)

 

データを読み込む

CSV形式のデータですのでReadCSVで読み込み、データ型を再定義した後、攻撃手法をざっくりとした分類に分けます。

最後のカラムのLabelが攻撃手法を定義したものですが、量が多いので、ここを参考に4つの攻撃手法に分けておきます。5クラス分類問題となります。

[list] [li-disc]DOS[/li-disc] [li-disc]R2L(リモートからの不正ログイン試み)[/li-disc] [li-disc]U2R(Root権限奪取)[/li-disc][li-disc]Probe(調査)[/li-disc] [/list]

 

[code]# CSVとして読み込み

> kddcup <- read_csv(“~/Downloads/kdd.ics.uci.edu/databases/kddcup99/kddcup.data_10_percent”, header=F)

# ヘッダーをつける

> colnames(kddcup)<-c(“duration”,”protocol_type”,”service”,”flag”,”src_bytes”,”dst_bytes”,”land”,”wrong_fragment”,”urgent”,”hot”,”num_failed_logins”,”logged_in”,”num_compromised”,”root_shell”,”su_attempted”,”num_root”,”num_file_creations”,”num_shells”,”num_access_files”,”num_outbound_cmds”,”is_host_login”,”is_guest_login”,”count”,”srv_count”,”serror_rate”,”srv_serror_rate”,”rerror_rate”,”srv_rerror_rate”,”same_srv_rate”,”diff_srv_rate”,”srv_diff_host_rate”,”dst_host_count”,”dst_host_srv_count”,”dst_host_same_srv_rate”,”dst_host_diff_srv_rate”,”dst_host_same_src_port_rate”,”dst_host_srv_diff_host_rate”,”dst_host_serror_rate”,”dst_host_srv_serror_rate”,”dst_host_rerror_rate”,”dst_host_srv_rerror_rate”,”label”)

# データを整える

> kddcup$duration = as.numeric(as.character(kddcup$duration))
> kddcup$protocol_type = factor(kddcup$protocol_type)
> kddcup$service = factor(kddcup$service)
> kddcup$flag = factor(kddcup$flag)
> kddcup$src_bytes = as.numeric(as.character(kddcup$src_bytes))
> kddcup$dst_bytes = as.numeric(as.character(kddcup$dst_bytes))
> kddcup$land = factor(kddcup$land)
> kddcup$wrong_fragment = as.numeric(as.character(kddcup$wrong_fragment))
> kddcup$urgent = as.numeric(as.character(kddcup$urgent))
> kddcup$hot = as.numeric(as.character(kddcup$hot))
> kddcup$num_failed_logins = as.numeric(as.character(kddcup$num_failed_logins))
> kddcup$logged_in = factor(kddcup$logged_in)
> kddcup$num_compromised = as.numeric(as.character(kddcup$num_compromised))
> kddcup$root_shell = factor(kddcup$root_shell)
> kddcup$su_attempted = factor(kddcup$su_attempted)
> kddcup$num_root = as.numeric(as.character(kddcup$num_root))
> kddcup$num_file_creations = as.numeric(as.character(kddcup$num_file_creations))
> kddcup$num_shells = as.numeric(as.character(kddcup$num_shells))
> kddcup$num_access_files = as.numeric(as.character(kddcup$num_access_files))
> kddcup$is_guest_login = factor(kddcup$is_guest_login)
> kddcup$count = as.numeric(as.character(kddcup$count))
> kddcup$srv_count = as.numeric(as.character(kddcup$srv_count))
> kddcup$serror_rate = as.numeric(as.character(kddcup$serror_rate))
> kddcup$srv_serror_rate = as.numeric(as.character(kddcup$srv_serror_rate))
> kddcup$rerror_rate = as.numeric(as.character(kddcup$rerror_rate))
> kddcup$srv_rerror_rate = as.numeric(as.character(kddcup$srv_rerror_rate))
> kddcup$same_srv_rate = as.numeric(as.character(kddcup$same_srv_rate))
> kddcup$diff_srv_rate = as.numeric(as.character(kddcup$diff_srv_rate))
> kddcup$srv_diff_host_rate = as.numeric(as.character(kddcup$srv_diff_host_rate))
> kddcup$dst_host_count = as.numeric(as.character(kddcup$dst_host_count))
> kddcup$dst_host_srv_count = as.numeric(as.character(kddcup$dst_host_srv_count))
> kddcup$dst_host_same_srv_rate = as.numeric(as.character(kddcup$dst_host_same_srv_rate))
> kddcup$dst_host_diff_srv_rate = as.numeric(as.character(kddcup$dst_host_diff_srv_rate))
> kddcup$dst_host_same_src_port_rate = as.numeric(as.character(kddcup$dst_host_same_src_port_rate))
> kddcup$dst_host_srv_diff_host_rate = as.numeric(as.character(kddcup$dst_host_srv_diff_host_rate))
> kddcup$dst_host_serror_rate = as.numeric(as.character(kddcup$dst_host_serror_rate))
> kddcup$dst_host_srv_serror_rate = as.numeric(as.character(kddcup$dst_host_srv_serror_rate))
> kddcup$dst_host_rerror_rate = as.numeric(as.character(kddcup$dst_host_rerror_rate))
> kddcup$dst_host_srv_rerror_rate = as.numeric(as.character(kddcup$dst_host_srv_rerror_rate))
> kddcup$label = as.character(kddcup$label)

# 攻撃手法をまとめる

> kddcup$label[kddcup$label == “ipsweep.”] = “probe”
> kddcup$label[kddcup$label == “portsweep.”] = “probe”
> kddcup$label[kddcup$label == “nmap.”] = “probe”
> kddcup$label[kddcup$label == “satan.”] = “probe”
> kddcup$label[kddcup$label == “buffer_overflow.”] = “u2r”
> kddcup$label[kddcup$label == “loadmodule.”] = “u2r”
> kddcup$label[kddcup$label == “perl.”] = “u2r”
> kddcup$label[kddcup$label == “rootkit.”] = “u2r”
> kddcup$label[kddcup$label == “back.”] = “dos”
> kddcup$label[kddcup$label == “land.”] = “dos”
> kddcup$label[kddcup$label == “neptune.”] = “dos”
> kddcup$label[kddcup$label == “pod.”] = “dos”
> kddcup$label[kddcup$label == “smurf.”] = “dos”
> kddcup$label[kddcup$label == “teardrop.”] = “dos”
> kddcup$label[kddcup$label == “ftp_write.”] = “r2l”
> kddcup$label[kddcup$label == “guess_passwd.”] = “r2l”
> kddcup$label[kddcup$label == “imap.”] = “r2l”
> kddcup$label[kddcup$label == “multihop.”] = “r2l”
> kddcup$label[kddcup$label == “phf.”] = “r2l”
> kddcup$label[kddcup$label == “spy.”] = “r2l”
> kddcup$label[kddcup$label == “warezclient.”] = “r2l”
> kddcup$label[kddcup$label == “warezmaster.”] = “r2l”
> kddcup$label[kddcup$label == “normal.”] = “normal”
> kddcup$label = as.factor(kddcup$label)

# 学習データと評価データを分ける(7:3)

> rowdata<-nrow(kddcup)
> random_ids<-sample(rowdata,rowdata*0.7)
> kddcup_train<-kddcup[random_ids, ]
> kddcup_pre<-kddcup[-random_ids, ]

[/code]

 

SVMで学習させる

[code]# 学習

> kddcup_svm<-ksvm(label ~., data=kddcup_train)

> kddcup_svm

# 結果

Support Vector Machine object of class “ksvm”

SV type: C-svc (classification)
parameter : cost C = 1

Gaussian Radial Basis kernel function.
Hyperparameter : sigma = 0.000103739702263078

Number of Support Vectors : 8239

Objective Function Value : -329.9296 -738.1392 -65.7569 -28.2657 -670.0012 -175.8475 -32.3014 -70.8226 -27.5727 -27.7096
Training error : 0.001939

[/code]

Training errorを確認すると、まずまず学習できているみたいです。さすが。

 

評価する

[code]> result_predict<-predict(kddcup_svm, kddcup_pre)
> table(result_predict,kddcup_pre$label)

result_predict dos normal probe r2l u2r
dos 195344 22 160 0 0
normal 108 48781 141 40 28
probe 96 40 1724 0 0
r2l 0 13 0 511 0
u2r 0 0 0 0 3[/code]

 

表でまとめます

[table class=’striped’] [thead] [th text=’result_prediction’] [th text=’dos’] [th text=’normal’] [th text=’probe’] [th text=’r2l’] [th text=’u2r’][th text=’適合率’][/thead] [tr] [td text=’dos’] [td text=’195344′] [td text=’22’] [td text=’160′][td text=’0′][td text=’0′][td text=’99.9%’][/tr] [tr] [td text=’normal’] [td text=’108′] [td text=’48781′] [td text=’141′][td text=’40’][td text=’28’][td text=’99.3%’][/tr] [tr] [td text=’probe’] [td text=’96’] [td text=’40’] [td text=’1724′][td text=’0′][td text=’0′][td text=’92.7%’] [/tr] [tr] [td text=’r2l’] [td text=’0′] [td text=’13’] [td text=’0′][td text=’511′][td text=’0′][td text=’97.5%’] [/tr] [tr] [td text=’u2r’] [td text=’0′] [td text=’0′] [td text=’0′][td text=’0′][td text=’3′][td text=’100%’] [/tr] [tr] [td text=’再現率’] [td text=’99.9%’] [td text=’99.8%’] [td text=’85.1%’][td text=’92.7%’][td text= ‘9.7%’ ][td text=’99.7%’] [/tr] [/table]

縦が予測結果で、横が実際のラベルです。総じて上手くいきました。ただ、U2Rの精度が低いことが気になります。そもそもデータが少なく学習があまり上手くいっていないのでしょうか。

 

実際にやってみた(C-SVMでクロスバリデーション)

クロスバリデーション(交差検証)は学習データをいくつかのデータに分け、1つの塊を評価用にそれ以外を学習用とし全ての場合を尽くすように学習を進め、汎化性能を上げる手法です。例えば、

  1. 全データをA・B・Cの3つに分けます。
  2. A・Bを学習データとして学習し、Cを用いて評価します。
  3. 次にB・Cを学習データとし、Aを用いて評価します。
  4. 次にC・Aを学習データとし、Bを用いて評価します。
  5. それぞれの結果からもっともよい結果をモデルとして採用します。

 

こうすることで少ないデータでも汎化性能を上げることができるというものです。当然、分割したデータでそれぞれ学習させるので時間はかかります。

今回はデータ量も多いので3つに分割して実施します。(K-folds法) 通常は10分割にすることが一般的で、データ量が少ない場合はleave-one-out 交差検証とかも使われます。

学習させる(C-SVM closs=3)

[code]# closs=3で3つに分割して学習

> kddcup_svm<-ksvm(label ~., data=kddcup_train, cross=3)

> kddcup_svm

Support Vector Machine object of class “ksvm”

SV type: C-svc (classification)
parameter : cost C = 1

Gaussian Radial Basis kernel function.
Hyperparameter : sigma = 9.3825289054228e-05

Number of Support Vectors : 9664

Objective Function Value : -435.7988 -1029.419 -65.9252 -38.3732 -854.7929 -212.3627 -49.4105 -74.7773 -37.6926 -34.5452
Training error : 0.001888
Cross validation error : 0.002689

[/code]

Cross validation errorは上がってしまいました。ただし、クロスバリデーションを用いないときと比べ学習に用いるデータが少ないため、学習の収束は低くでてしまうのは仕方ありません。

むしろ、収束しきらないところでも高精度を叩き出すことが目的でもありますし。

 

評価する

[code]> result_predict<-predict(kddcup_svm, kddcup_pre)
> table(result_predict,kddcup_pre$label)

result_predict dos normal probe r2l u2r
dos 117643 7 85 0 0
normal 58 28821 95 23 12
probe 53 19 1058 0 0
r2l 0 6 0 324 0
u2r 0 0 0 0 3

# 誤差率を計算してみる

> 1-sum(diag(kddcup_table))/sum(kddcup_table)
[1] 0.00241554

[/code]

 

表でまとめます

[table class=’striped’] [thead] [th text=’result_prediction’] [th text=’dos’] [th text=’normal’] [th text=’probe’] [th text=’r2l’] [th text=’u2r’][th text=’適合率’][/thead] [tr] [td text=’dos’] [td text=’117643′] [td text=’7′] [td text=’85’][td text=’0′][td text=’0′][td text=’99.9%’][/tr] [tr] [td text=’normal’] [td text=’58’] [td text=’28821′] [td text=’95’][td text=’23’][td text=’12’][td text=’99.4%’][/tr] [tr] [td text=’probe’] [td text=’53’] [td text=’19’] [td text=’1058′][td text=’0′][td text=’0′][td text=’93.6%’] [/tr] [tr] [td text=’r2l’] [td text=’0′] [td text=’6′] [td text=’0′][td text=’324′][td text=’0′][td text=’98.2%’] [/tr] [tr] [td text=’u2r’] [td text=’0′] [td text=’0′] [td text=’0′][td text=’0′][td text=’3′][td text=’100%’] [/tr] [tr] [td text=’再現率’] [td text=’99.9%’] [td text=’99.9%’] [td text=’85.5%’][td text=’93.4%’][td text= ‘20%’ ][td text=’99.8%’] [/tr] [/table]

ほんの少しですが精度が上がった気がします。

 

ニューラルネットでもやってみます(nnet)

比較のためにニューラルネットでもやってみます。R言語ではnnetというパッケージでニューラルネットが使えます。

隠れ層のユニット数は出力結果のラベル数を考慮し、5としてます。(3で実施したら、ラベルが全部でませんでした。)

学習させる(nnnet)

[code]# パッケージインストール&適応

> install.packages( “nnet” )

> library( nnet )

# 隠れ層のユニット数5、ランダム値範囲-0.1~0.1、減衰5e-4で実施

> kddcup_nnet <- nnet(label~., size=5, data=kddcup_train, rang = .1, decay = 5e-4, maxit = 3000)
# weights: 615
initial value 575217.442435
iter 10 value 74350.753004
iter 20 value 39017.507761
iter 30 value 33989.403391
iter 40 value 30099.250316
iter 50 value 27641.918258
iter 60 value 24688.366217
iter 70 value 23909.225741
iter 80 value 22006.056620
iter 90 value 21385.374653
iter 100 value 20640.355978
iter 110 value 19443.652176
iter 120 value 17966.682333
iter 130 value 17561.847075
iter 140 value 17298.101203
iter 150 value 16746.291929
iter 160 value 16219.714301
iter 170 value 15885.755704
iter 180 value 14769.847387
iter 190 value 14277.103879
iter 200 value 13651.371989
iter 210 value 12878.412456
iter 220 value 12637.064141
iter 230 value 11873.795106
iter 240 value 10919.945647
iter 250 value 9574.787432
iter 260 value 8064.989190
iter 270 value 7261.795869
iter 280 value 5941.270340
iter 290 value 4788.910803
iter 300 value 4263.836429
iter 310 value 4077.903774
iter 320 value 4035.943916
iter 330 value 3953.874037
iter 340 value 3927.603041
iter 350 value 3850.554389
iter 360 value 3690.449366
iter 370 value 3679.445537
iter 380 value 3660.072147
iter 390 value 3654.366314
iter 400 value 3649.497562
iter 410 value 3613.612850
iter 420 value 3546.881873
iter 430 value 3466.460679
iter 440 value 3332.472239
iter 450 value 3202.713314
iter 460 value 3192.588930
iter 470 value 3169.223153
iter 480 value 3097.055361
iter 490 value 2897.312752
iter 500 value 2595.342208
iter 510 value 2323.495624
iter 520 value 2160.486970
iter 530 value 2068.124473
iter 540 value 1986.553216
iter 550 value 1917.448970
iter 560 value 1848.341606
iter 570 value 1826.934175
iter 580 value 1817.437531
iter 590 value 1783.570324
iter 600 value 1749.888183
iter 610 value 1727.915109
iter 620 value 1724.945680
iter 630 value 1712.222157
iter 640 value 1709.191769
iter 650 value 1702.575583
iter 660 value 1689.403803
iter 670 value 1687.694131
iter 680 value 1685.270318
iter 690 value 1684.377098
iter 700 value 1684.111195
iter 710 value 1682.717637
iter 720 value 1682.526618
iter 720 value 1682.526604
iter 730 value 1682.082587
iter 730 value 1682.082587
final value 1682.081493
converged

[/code]

評価する

[code]# TypeはClassで

> kddcup_nnet_pre <- predict(kddcup_nnet, kddcup_pre, type=”class”)
> table(kddcup_nnet_pre,kddcup_pre$label)

kddcup_nnet_pre dos normal probe r2l u2r
dos 117326 7 3 4 3
normal 3 29315 11 57 7
probe 2 0 1164 0 0
r2l 1 11 0 289 1
u2r 0 1 0 0 2

# 誤差率を評価する
> kddcup_table_pre <- table(kddcup_nnet_pre,kddcup_pre$label)
> 1-sum(diag(kddcup_table_pre))/sum(kddcup_table_pre)
[1] 0.0007489525
[/code]

 

表でまとめます

[table class=’striped’] [thead] [th text=’result_prediction’] [th text=’dos’] [th text=’normal’] [th text=’probe’] [th text=’r2l’] [th text=’u2r’][th text=’適合率’][/thead] [tr] [td text=’dos’] [td text=’117326′] [td text=’7′] [td text=’3′][td text=’4′][td text=’3′][td text=’99.99…%’][/tr] [tr] [td text=’normal’] [td text=’3′] [td text=’29315′] [td text=’11’][td text=’57’][td text=’7′][td text=’99.7%’][/tr] [tr] [td text=’probe’] [td text=’2′] [td text=’0′] [td text=’1164′][td text=’0′][td text=’0′][td text=’99.8%’] [/tr] [tr] [td text=’r2l’] [td text=’1′] [td text=’11’] [td text=’0′][td text=’289′][td text=’1′][td text=’95.7%’] [/tr] [tr] [td text=’u2r’] [td text=’0′] [td text=’1′] [td text=’0′][td text=’0′][td text=’2′][td text=’66.7%’] [/tr] [tr] [td text=’再現率’] [td text=’99.99…%’] [td text=’99.9%’] [td text=’98.8%’][td text=’82.6%’][td text= ‘15.4%’ ][td text=’99.9%’] [/tr] [/table]

 

精度はクロスバリデーションを用いたC-SVMより上がりました。

 

おまけ それぞれのノードの重みを確認する

生態学のデータ解析 – ニューラルネット を参考にニューラルネットのノードを可視化してみます。

[code]> source(“http://hosho.ees.hokudai.ac.jp/~kubo/log/2007/img07/plot.nn.txt”)
> plot.nn(kddcup_nnet)[/code]

 

 

おお~。可視化するとすごいっすね。

 

結論

パターン認識にはやはり古典的ではありますが、SVMは単純なパラメータでもかなりの精度を叩き出しました。さらに学習データが十分だと思ってもクロスバリデーションでほんの少し精度を向上することができました。

それ以上に精度を出せたのはニューラルネットとなりました。ある程度データ量があれば、強力な分類精度を叩き出しますね。

 

参考文献

SVMで天気予報

【caret】R で SVM を学ぶ【Grid-Search】

Rでnnetを試してみる

RとWEKAによるニューラルネットワーク

生態学のデータ解析 – ニューラルネット