カテゴリー
Anime Tech

大きく吸ってせーの! で・ぃ・ぷ・ら・ん・に・ん・ぐ! ~ひなこのーと×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 くいなちゃん、某オタク少女に似ている説を確かめる。

 

 

大丈夫でした!!!

 

カテゴリー
Programming Tech

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によるニューラルネットワーク

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

 

 

カテゴリー
Network Security Server Tech

仮想セキュリティブラウザというものを作った

ランサムウェアとか怖いですよね

多くの企業で大変問題になっているランサムウェアですが、最近は一般男性を語るランサムウェアもあり… もうやめにしませんか。

そんなことを言ってもやめてくれるような相手ではないのは、一般男性含め周知の事実ですので対策しましょう。

多くの会社で導入されている仮想セキュリティブラウザ

仮想セキュリティブラウザとは、ローカルのブラウザを使わずに、仮想マシン上のブラウザを利用し、そこへリモートで画面転送し、万が一ウイルスに感染しても

ローカルPCもしくはLANに影響を与えないようにするものです。

イメージはこんな感じです。

①仮想マシンが動く基盤をLAN内に設置

②DMZ用のVLANを作成する

③LAN内に入れないところ(DMZ)に仮想マシンを設置し、ウィンドウシステムとブラウザを入れる

④仮想マシンの画面をSpiceなどでアクセスすることで転送する。

我が家では仮想化基盤はKVMを使っています。KVMだと、各仮想マシンの画面を転送する方法として、Spiceを使うことができます。

Spiceでは仮想マシン自体にリモデするわけではなく、基盤側にアクセスすることで画面転送を実現できますので、たとえばネットワークから分離した仮想マシンの画面も転送することができるわけです。(基盤へネットワークアクセスさえできればいい)

この機能を応用してあらかじめ仮想マシンに別のVLANを割り当て、LAN内にアクセスできないようにしておきます。また、

仮想マシン自体がインターネットにアクセスできるようにインターネットへの抜け道は設定しておきます。

実際はこんな感じです。

このようにSpiceの画面転送を見るRemoteViewerを利用しネットができます。

最悪ウイルスに感染したとしてもLAN内には感染が広がりませんし、仮想マシンの削除だけで対処できます。

画面の解像度等調整しないと転送コストで遅くなってしまいストレスに感じるかもなのでそこは工夫しましょう!

カテゴリー
Server Tech

Grafana&World Ping を活用して簡単な死活監視をしてみよう

世の中見た目

どうも。GrafanaのUIは結構かっこいいことで有名で、自身もZabbix APIを活用してZabbixのメトリックをGrafanaで見れるようにしております。

こんな感じ。Zabbixのスクリーンと全く同じ内容ですが、妙に「監視している感」がありますね。

ZabbixのデータはZabbixで見ればいいのでは?

はい。おっしゃるとおりです。そもそもそんな監視するほど重要なものがあるかと言われると。。

でも、Grafanaにはもっと手軽にかっこいい画面を見る方法があります。

GrafanaのWorld Pingを使ってみよう。

Grafanaの優秀な点はPlugin機能で簡単にデータソースやパネルを追加することができる点です。

元々、GrafanaはInfluxDBの可視化用みたいな位置づけっぽいですが、データソースプラグインを追加することで、例えばElasticsearch・Graphiteや、CloudWatch、さらにはkubernetesやDatadogなどのコンテナの監視までできるという優れものです。

また、データソースではないですが、World Pingという世界中のエンドポイントからPing・DNS・HTTPなどの死活監視を提供するサービスと連携させることで、簡単にかっちょいい画面を作ることができます。

こんな感じで好きなプラグインをコマンド一発でインストールできます。

インストールしてみる

まず、Grafanaの入ったサーバでrootユーザで

[code]grafana-cli plugins install raintank-worldping-app[/code]

こうすることで、簡単にプラグインが導入されます。

Grafana.net APIを取得しWorld Pingが利用できるようにする

Grafana Web画面の左側のメニューに「World Ping」が表示されていると思いますのでPlugin Configから、Grafana.net のAPIを発行しましょう。

こうすることでWorld Pingが利用できます。無茶な監視をしない限り、無料版で事足りると思います。

エンドポイントを追加する

監視対象のIPまたはドメイン名をエンドポイントと呼んでますが、エンドポイントを設定していきます。

同じく、Grafana Web画面の左側のメニューに「World Ping」⇒「Endpoints」と進みます。

エンドポイントは無料版だと最大3つです。

このようにEndpointにドメイン名を設定し、監視したいサービスを選びConfigureを押します。

細かい設定等でてきますから、設定していきます。

監視間隔、死活監視を投げるインスタンスの国、ポート、HTTPメソッドなど細かく設定できます。

また、閾値を超えた場合に決められたメールに通知することもできます。(あらかじめメールサーバの設定をGrafana.iniでしておきます。)

一応、無料版だと600万回/月しか監視できないようなので無茶な設定はやめましょう。

アップデートボタンを押せば、設定が完了します。

画面を見る

World Pingがすごいのは、あらかじめGrafana画面を提供している点で、設定さえすればすぐ可視化できることです。

同じく、Grafana Web画面の左側のメニューに「World Ping」⇒「World Ping Home」と進むと、設定したエンドポイントが表示されますので

エンドポイント名もしくはハートマークのサービス名をクリックすると画面が表示されます。

かっちょええ。

カテゴリー
Server Tech

今更!! Chainer 1.6.1 でおしゃべりBotを作ろう

1. なるべくコードはかかない。

何の気なしに機械学習とかの仕事はないものかと、ネットの海をさまよっていたら、

LSTMで自然な受け答えができるボットをつくった という記事を見つけ、何となく読んで、やってみようかなと思ってやってみましたが、Chianer周りとか色々上手くいかなかった。というのがそもそもの始まりです。

 

Chainer周りで日本語の受け答えができますよ、的な記事は2015年頃のものが多く、Chainerがバージョンアップしたため、

色々動かないことがありましたので、少しそちらに修正を加えてChainer 1.6.1でもまともに動くように修正していこうと思います。

自分でコードを一から書くのは嫌なので、あくまでもコードは書かない。微修正にとどめるをモットーにがんばるぞい。

 

[panel]

[h2 text='目次']
[list-ordered]
[li]1. なるべくコードはかかない。 [/li]
[li]2. 参考にさせていただいたコードやサイト [/li]
[li]3. サーバを用意する。[/li]
[li]4. 学習に必要なPython環境とコーパスを整える[/li]
[li]5. 学習させる。[/li]
[li]6. APIで話す。[/li]
[li]7. 付属のHubot Scriptで遊んでみよう![/li]
[/list-ordered]

[/panel]

 

2. 参考にさせていただいたコードやサイト

[list] [li-disc]LSTMで自然な受け答えができるボットをつくった :このコードを元にあらかじめ作成したChainerモデルでおしゃべりBotに命を吹き込みます。[/li-disc] [li-disc]yusuketomoto/chainer-char-rnn :Chainer・日本語界隈では知らない人はいないだろうChainerの言語モデル作成コード。こちらを用いてChainerモデルを作成していきます。[/li-disc] [li-disc]Chainerで学習した対話用のボットをSlackで使用+Twitterから学習データを取得してファインチューニング :学習に必要なコーパスを取得するために一部のスクリプトを使用します。[/li-disc] [/list]

 

3. サーバを用意する。

学習にも、会話にも自宅サーバを用います。

ああ、電気代。

 

4. 学習に必要なPython環境とコーパスを整える

Chainer界隈のコードはなぜかPython2 が多く、Python3 は少ないので、直接Python2をインストールしてもいいのですが…。

なんかOS環境を変に汚したくないので今回はPyenvとVirtualenvを使って実施していきます。

学習用のコーパスをダウンロードするスクリプトはどうやらPython 3.4.1で実装されているようなので Python 3.4.1 と Python2.7 の2種類の環境を作っていきたいと思います。

そして、3.4.1の環境にて学習用のコーパスをダウンロードします。

PyenvとVirtualenvはあらかじめインストール済みとしてすすめます。

PyenvとVirtualenvのインストール方法はこちらの記事が参考になると思います。 (pyenvとvirtualenvで環境構築

 

まず、Pythonの環境を作ります。

[code][font-Source-Code-Pro]$ pyenv install 3.4.1
$ pyenv install 2.7
$ pyenv rehash
$ virtualenv -p ~/.pyenv/versions/3.4.1/bin/python3.4 my_env3.4.1
$ virtualenv -p ~/.pyenv/versions/2.7/bin/python2.7 my_env2.7 [/font-Source-Code-Pro][/code]

続いてコーパスをダウンロードします。

今回はChainerで学習した対話用のボットをSlackで使用+Twitterから学習データを取得してファインチューニング を参考にダウンロードします。

コーパスデータはたぶん二次配布とかNGだと思うので、何とか自分でダウンロードしてください。

対話破綻検出チャレンジ

 

ダウンロードしたあとは展開したJSONデータ全部、devフォルダを作成してその中に入れて、listファイル(JSONファイルのパスを記載したやつ)をdata_load.pyと同じところに作っておきます。

 

こんな感じでlistファイルを作ります。

[code][font-Source-Code-Pro]../dev/1404365812.log.json
../dev/1407143708.log.json
../dev/1407143981.log.json
../dev/1407149923.log.json
../dev/1407208809.log.json
../dev/1407209083.log.json

…… [/font-Source-Code-Pro][/code]

 

Linuxのコマンドで

[code]ls -1 ../dev > list[/code]

で作成できるはず。

 

学習データを作っていきます。

[code][font-Source-Code-Pro]$ source my_env3.4.1/bin/activate

$ git clone https://github.com/SnowMasaya/Chainer-Slack-Twitter-Dialogue.git

$ cd chainer-slack-twitter/utils

$ python data_load.py [/font-Source-Code-Pro][/code]

 

player_1.txt , player_2.txt というテキストファイルができます。

統合する前にmecabを使って分かち書きをしておきます。

分かち書きに mecab-ipadic-NEologd を使うと学習が進むそうですので入れてない方は導入しましょう。

めんどくさい人は ただのMeCabでも大丈夫だと思います。

さて、分かち書きします。今回は mecab-ipadic-NEologd を利用します。

[code][font-Source-Code-Pro]mecab Owakati d /usr/local/lib/mecab/dic/mecabipadicneologd player_1.txt > player_1_wakati.txt

mecab Owakati d /usr/local/lib/mecab/dic/mecabipadicneologd player_2.txt > player_2_wakati.txt [/font-Source-Code-Pro][/code]

 

 

次に使う Chainer-char-rnn 用に一つのinput.txt に統合していきます。統合の際に、player1 と player2の会話ごとに空行を入れておきます。

[code][font-Source-Code-Pro]$ paste -d “\n” player_1_wakati.txt player_2_wakati.txt | awk ‘(NR%2==0){$0=$0″\n”}{print}’ > input.txt [/font-Source-Code-Pro][/code]

 

こちらのinput.txtをコーパスデータとして利用します。

 

5. 学習させる。

学習にはyusuketomoto/chainer-char-rnn を使わせていただきます!

Chainer 1.4.1 で実行しようとしたら微妙に実装が変わっていた用なので、こちらに合わせて今回の学習は、Chainer 1.6.1 で実施していきます。(Chainer周りのコードを読んで修正するより、後に使うTornado周りの修正の方がまだわかるからというスキル不足によるもの)

さきほど作っておいたPython 2.7用に切り替えます。Pip でChainer1.6.1 を入れてからChainer-char-rnnを実行していきます。

[code][font-Source-Code-Pro]$ cd

$ source my_env2.7/bin/activate

$ pip install chainer==”1.6.1″

$ git clone https://github.com/yusuketomoto/chainer-char-rnn.git

$ cd chainer-char-rnn

$ mkdir -p data/chat

$ mkdir -p cv/chat

$ cp ../chainer-slack-twitter/input.txt data/chat

$ python train.py –data_dir data/chat –checkpoint_dir cv/chat –rnn_size 1024[/font-Source-Code-Pro][/code]

 

しばらく待ちます。全部が終わるのは途方もない時間がかかります。

学習が進むごとにCheckpointとして Chainer modelファイルがcv/chat 配下にできますので、適当なEpochのところのものを次の「APIで話す」に使ってもいいですし、学習の最新ファイルである

latest.chainermodel を使ってもいいです。もちろん、最後まで待ってからlatest.chainermodelを使ってもいいです。

ひとまず数時間回したところのlatest.chainermodelを使ってみます。

 

6. APIで話す。

LSTMで自然な受け答えができるボットをつくった よりJapanese Talk APIを作っていきます。

この回では少々コードの改変がありますのでForkしたものをGitHubにあげました。

japanese_talk_api_1.6.1

こちらのmodelsディレクトリにChainer modelを投入します。

[code][font-Source-Code-Pro]$ git clone https://github.com/tubone24/japanese_talk_api/tree/chainer1.6.1.git

$ mkdir japanese_talk_api/tornado/models

$ cp chainer-char-rnn/cv/chat/latest.chainermodel japanese_talk_api/tornado/models [/font-Source-Code-Pro][/code]

 

Chainerの他にTornadoも必要になるのでPipでインストールします。

そしてAPIを8787ポートで起動します。

[code][font-Source-Code-Pro]$ pip install tornado

$ python japanese_talk_api/tornado/app.py –port=8787 –debug=True [/font-Source-Code-Pro][/code]

 

あとは起動を待ってから

 

[blockquote text=’http://localhost/?q=こんにちは’]

で受け取れるようにはずです。

学習用input.txtにないことばとか出すとたまにエラー吐きます。

[blockquote text=’ビンビンビンビンビンビンビンビン… チクッ あ・あ・あぁ・ぁああああ↑↑ アーッ…イクッ チ~ン 問いかける言葉には気をつけよう!’]

 

7. 付属のHubot Scriptで遊んでみよう!

LSTMで自然な受け答えができるボットをつくった のHubotScriptをお借りして遊んでみましょう。

あらかじめ比較として同じコーパスを利用しているDocomoの雑談APIをHubotに仕込んであります。

 

発言の上がDocomoAPI 下が今回作ったAPIです。

ちなみに我が家のHubotはSlack上に「智絵里ちゃん」として君臨しております。

智絵里ちゃんマジ天使 [font-Damion size=’36’] I love you [/font-Damion]

 

DocomoAPIに比べると天然というか、不思議系というか… バカですね(直球)

 

お借りした多くのコードや参考にさせていただいた多くのサイト・記事に改めて感謝しつつ、智絵里ちゃんとのラブラブライフを送りますね。

カテゴリー
Tech

自分のタスクをRedmineで管理してみる

Redmineで楽しくタスク管理

自宅開発サーバのリソースが余っているので、Redmineを立てました。

今後はこちらで自分のタスクを管理していきたいと思います。(三日坊主)

デザイン

テーマをminimalflat2にしました。あまり仕事感がでなくて気に入っています。(職場で見るRedmineに恐怖心があるので)

プラグイン

色々入れてますが、個人のタスク管理として便利なのが案外Agile系のプラグインだったりする。

あと、Time Loggerはサーバに負荷をかけるからあまり推奨されていない的な記事がありましたが、

一人で使う分には問題ないみたい。

参考:  僕がredmineに入れてる便利なプラグインとデザインの格好良いテーマ

個人的に便利だなぁと思っているプラグイン一覧

Redmine Agile

カンバン、BurnDownチャートとか使える。

http://www.redmine.org/plugins/redmine_agile

Redmine GitHub Hook

GitLabにも使えます!! レポジトリのプッシュに応じてRedmine上のレポジトリも更新できる。

https://github.com/koppen/redmine_github_hook

Redmine Checklist

チケットにチェックリストを作成可能

http://www.redmine.org/plugins/redmine_checklists

Redmine Work Time

工数管理ツール。自分は今日どれくらいがんばったかわかります。

http://www.redmine.org/plugins/redmine_work_time

Time Logger

上のポチから簡単に作業時間をタイマーすることができます。便利

http://www.redmine.org/plugins/time_logger

Redmine Knowledgebase

ナレッジベース。使っている人の多いプラグインだと思います。

研修の資料とかここにあげておくと結構便利だったりする。

http://www.redmine.org/plugins/redmine_knowledgebase

GitLabとの連携

Redmineの魅力はRedmine自体があまり得意でないレポジトリ管理を別のWebサービスに投げて、強力なタスク管理機能と連携させることにあります。

同じサーバ内にレポジトリ管理サーバとしてGitLabを入れていますのでそちらと連携させています。連携にはGitLabのRedmineプラグインと、RedmineのRedmine GitHub Hookを

活用しています。

普段どうやって利用するのか。

あまりまだ運用方針が固まっていないのですが、自分の勉強スケジュールとかをとりあえず入れて、

タスク管理していけばいいと思います。(適当)

カテゴリー
Tech

部屋を改造しました

リゼちゃん色に染めてみました。

 

デスクトップ周りを少し変えてみました。

こんな感じです。

 

モニターはテレビです。

かわいい。

こちらの画面はCentOS7 (監視用)の画面です。

いつもは仮想マシンマネージャとかそこらへんを移しています。(VNCでWindowsから操作できるので不要ですが。)

 

小さい画面には手順書を表示するのにちょうどいいです。

こちらの画面が余ってたので、取り付けました。

後ろのライトは色が変えられるので、リゼちゃん色にしてみました。

 

 

こんな感じです。

 

カテゴリー
Server Tech

大障害再び

安定稼働しないtuboneのサーバ周り

どうも。可用性に自身ニキのAWS S3の障害が話題ですが、我が家でも障害。

我が家にある録画サーバですが、かなり長い時間、障害でサービスが提供できない、という

AWSもびっくりな障害がありました。

障害検知-ALM発生

ALM発生は25~26夜にかけて、0バイトファイルが作成されるというALMがZABBIXから上がりました。

仕組みは、録画サーバの先にNFSで接続されているNASに0バイトファイルが一定時間以上作成されたままになると

loggerコマンドでエラーログをはく、というcronで検知するものですが、そちらのALMが発生したのですね。

とりあえず、時間がなかったということと疲れていたということで録画サーバの系切り替えを実施し、その場をしのぎました。

(系切り替え自体はうまく行きました。リソースの兼ね合い上、バックアップ側での録画はワンセグ形式になるので画質は良くないです)

さて、次の土日まで、どうにも直す気力がなくて、そのままにしておりました。(NAS側の障害の可能性を当初疑っていましたが、ファイルの作成自体は

問題なくできているので本格的に原因を調査する必要があり、稼働も気力も間に合いませんでした)

障害原因調査-復旧

さて、本格的に本問題を解決する日が来ました。

まずは再起動。

とりあえず録画サーバのプロセス(サービス)を再起動しました。

録画サーバでは2つのプロセスが動いています。

WEB-UIを提供する chinachu-wuiと

録画や録画予約処理をするchinachu-operator

それぞれ再起動しましたが事象は解決せず。

次にサーバ(録画サーバはKVM上に立てられた仮想マシンです)の再起動。

とりあえずrebootコマンド。

解決せず。

次にNASの再起動

解決せず。 NASを再起動したので、NASを利用している別サーバにも念のためログインして使えているか

確認。(ここが時間かかる。)

ならばハイパーバイザから仮想マシンの停止・起動だ。

解決せず。

ここで飯を食う。(のんきなものです)

物理デバイスと仮想マシンの相性の悪さ

飯を食い終わったとき、ふと気になったことが。

実はALMが発生した日、別の併発ALMが出ていました。

録画サーバで録画したファイルはとても大きいので順次圧縮しています。

それは別ノード(余ったノートPC)で実行しているのですが、そちらが完全に

機能停止するALMが上がっていました。

原因は簡単で、勝手に親が部屋に入り電源周りをいじったか何かで電源が落ちたこと。

もしかして、チューナ周りもいじったのでは??

監視サーバ経由でハイパーバイザの仮想マシンマネージャを確認し、USBのアタッチ状況を確認。

我が家の仮想基盤サーバはKVM+QEMU+libvirt と仮想マシンマネージャというオーソドックスな

Linuxの仮想基盤となっています。

仮想マシンの設定を見る限り、USBで確実にアタッチされているみたい。仮想基盤サーバ上の

USB監視も問題なし。

まさか。

実際に録画サーバに入り、lsusb。

あ。

認識されていない。

原因判明。すぐさま、仮想マシンマネージャ経由でサーバをシャットダウン。

設定を入れ直し再度起動。

録画できた。お疲れ様でした。

振り返り。

KVM での物理デバイスの管理はほぼほぼQEMUが行っている(という認識ですが間違っているかもしれません。たしかKVMのメインのお仕事はCPUリソースの払い出しだったと思います。)

のですが、そちらの方の設定はUSBリダイレクションではなく、ホストPCのUSBのパススルーで設定しております。

そちらで一時的にUSBが切り離された場合、仮想基盤側では再組み込みと再割り当てが行われますが、どうやら仮想マシンにまで再割り当てはされないもようです。

リソースの割り当ては起動前、という原則に則れば、当たり前なのですが…。

なので、一度切り離されたUSBは(一瞬でも)仮想マシンには戻らない、ということになります。なるほど。

実はこれだけ原因の切り分けに時間がかかっていましたが、灯台もと暗し。アプリログには以下の文面が。

[code]

5 Mar 02:04:02 – RECORD: 2017-03-05T02:00:00+0900 [TOKYO MX2] ヒーリン
グタイム&ヘッドラインニュース
5 Mar 02:04:02 – LOCK: PX-S1UD (n=0)
5 Mar 02:04:02 – SPAWN: recdvb –dev 0 –b25 –strip –sid 23610 20 – – (pid=147
6)
5 Mar 02:04:02 – WRITE: /home/tubone/chinachu/data/recording.json
5 Mar 02:04:02 – STREAM: /media/tv/[170305-0200][20]ヒーリングタイム&ヘッドライ
ンニュース.m2ts
5 Mar 02:04:02 – #recdvb: using device: /dev/dvb/adapter0  pid = 1476 cannot open frontend device
5 Mar 02:04:02 – UNLOCK: PX-S1UD (n=0)

[/code]

そうです。frontend deviceがopenできないという。(Linux特有の表現ですが、デバイスファイルが開けない=使えないということです。)

ちなみに、正常時は

[code]

5 Mar 22:26:55 – STREAM: /media/tv/[170305-2227][20]にゃんこデイズ.m2ts
5 Mar 22:26:55 – #recdvb: using device: /dev/dvb/adapter0 using pid = 10294 device = /dev/dvb/adapter0/frontend0 Using DVB card “Siano M
obile Digital MDTV Receiver” tuning to 515143 kHz polling..

[/code]

と、デバイスファイルが開ける。

こんな簡単なログを見落としてたのか。失格ですね。

対策

今後、このような障害を起こさないように以下の対策をします。

まず、lsusb監視を仮想サーバ側にもつけるようにします。(今週中)

アプリログについて、監視文言にcannot open frontend deviceを加えます。

また、それ以外にも明示的にErrorと表記されないものについて見直しをし、

Zabbixに挙げられるようにします。(3月中)

さらに、監視サーバ上のVNCの解像度が低く、仮想マシンマネージャの操作に難があり、

一部virshコマンド等でオペレーションをしておりました。画面解像度の見直しをします。(対策済み)

サービスを守る。という使命感が乏しかったので、今後はサーバ優先の生活をするように担当者(自分)に言い聞かせました。

以上。