기계 학습×웹 앱 진단: 다층 퍼셉트론으로 CAPTCHA를 인식한다(Chainer편)

지난번은 전체 스크래치로 다층 퍼셉트론을 구현하고 CAPTCHA 이미지를 인식하려고 시도했습니다.
이번에는 「 Chainer 」를 사용해 같은 것을 해 본다.

덧붙여 「scikit-neuralnetwork」에서도 다층 퍼셉트론을 실장할 수 있지만, 이 검증은 또 기회로 한다.

아젠다



0. 구현 코드
1. 해보자
2. 정리
3. 참고 문헌

0. 구현 코드



아래 하나의 파이썬 코드 만 사용.
전회에 비해 매우 코드량이 적어지고 있다.

mlp.py
#!/usr/bin/env python
#coding:utf-8
import os
import gzip, pickle
import pylab
import numpy as np
from chainer import Variable, FunctionSet, optimizers
import chainer.functions as F

# 学習データのロード
def train_data_read(file_path):
        # 学習データ(MNISTの手書き文字)のロード
        f = gzip.open(file_path, 'rb')
        train, valid, test = pickle.load(f)
        f.close()

        return (train[0], train[1], train[0].shape[0])

# ニューラルネットワーク(多層パーセプトロン)の処理
def forward(x_data, y_data, train=True):
    x = Variable(x_data)
    t = Variable(y_data)

    # 活性化関数に正規化線形関数(ReLU)を使用
    # 汎化性能向上のためにドロップアウトを使用
    h1 = F.dropout(F.relu(model.l1(x)),  train=train)
    h2 = F.dropout(F.relu(model.l2(h1)), train=train)
    y = model.l3(h2)

    # 誤差関数に交差エントロピーを使用
    return F.softmax_cross_entropy(y, t)

# データの予測
def predict(x_test):
    x = Variable(x_test)

    # 活性化関数に正規化線形関数(ReLU)を使用
    # 汎化性能向上のためにドロップアウトを使用
    h1 = F.dropout(F.relu(model.l1(x)))
    h2 = F.dropout(F.relu(model.l2(h1)))
    y = model.l3(h2)

    return np.argmax(y.data)

if __name__ == "__main__":
    # 識別対象のCAPTCHA画像が格納されているファイルパスを定義
    captcha_path = 'C:\MNIST\captcha\captcha0'

    # 訓練用データ(MNIST)のファイルパスを定義
    train_data_path = os.path.join('C:\\MNIST', 'mnist.pkl.gz')

    # 正解ラベルの定義(結果表示用)
    answerLabel = [0, 1, 4, 6, 7, 9]

    # 予測対象データ(CAPTCHA画像)の取得
    # 画像データを784次元のベクトルに変換
    # RGB毎の配列からR要素のみを抽出(次元削減)
    img_captcha = []
    analize_data = []
    captcha_files = os.listdir(captcha_path)
    for file in captcha_files:
        img_captcha = pylab.imread(os.path.join(captcha_path,file))
        img_captcha_r = img_captcha[:, :, 0]
        #img_captcha_r = img_captcha[:, :]
        img_captcha_Array = np.asarray(img_captcha_r)
        d_captcha = img_captcha_Array.shape[0] * img_captcha_Array.shape[1]
        img_captcha_wide = img_captcha_Array.reshape(1, d_captcha)
        analize_data.append(img_captcha_wide)

    # 訓練データの取得
    x_train, y_train, length = train_data_read(train_data_path)
    x_train = x_train.astype(np.float32)
    y_train = y_train.astype(np.int32)

    # ニューラルネットワークの構築
    # 入力層=784(28*28)、中間層=300、出力層=10(0~9)
    model = FunctionSet(l1=F.Linear(784, 300),
                        l2=F.Linear(300, 300),
                        l3=F.Linear(300, 10))

    # 確率的勾配降下法(SGD)で学習する際のバッチサイズ
    # 10~100程度とすることが多いが、最も結果が良かった100とした。
    batchsize = 100

    # 学習の繰り返し回数
    # 5回の学習で精度が95%を超えたため、5回とした。
    learning_loop = 5

    # SGDの設定
    optimizer = optimizers.Adam()
    optimizer.setup(model.collect_parameters())

    # 学習
    N = 50000
    for epoch in range(1, learning_loop+1):

        # 学習データの順番をランダムにする
        perm = np.random.permutation(N)

        # 0〜Nまでのデータをバッチサイズに区切って学習する
        for i in range(0, N, batchsize):
            x_batch = x_train[perm[i:i+batchsize]]
            y_batch = y_train[perm[i:i+batchsize]]

            # 重みの初期化
            optimizer.zero_grads()

            # フィードフォワードさせて誤差を算出
            error = forward(x_batch, y_batch)

            # バックプロパゲーションで勾配を算出
            error.backward()

            # 重みを更新
            optimizer.update()

    # CAPTCHAデータの予測
    ok = 0
    for i in range(len(analize_data)):
        # 認識対象データを1個ずつ読み込む
        x = analize_data[i].astype(np.float32)

        # 認識対象の正解データを1個ずつ読み込む
        y = answerLabel[i]

        # CAPTCHAデータの予測
        answer = predict(x)

        # 予測値と正解データを標準出力する
        print("No.{0:d} : predict => {1:d} , answer = > {2:d}".format(i, answer, int(y)))

        # 予測値と正解データが一致している場合、ok(正解)を1インクリメントする
        if int(y) == answer:
            ok += 1

    # ok(正解)の数と認識対象データ数を基に正解率を標準出力する
    print("{0:05d} / {1:05d} = {2:3.2f}%".format(ok, len(analize_data), 100*ok/len(analize_data)))

피드 포워드나 백프로파게이션, 확률적 그라디언트 강하법(SGD)이나 드롭아웃 등의 테크닉이 매우 간이한 코드로 실현할 수 있다.

얼마나 멋진 도서관이야!

1. 해보자



조속히 이것을 사용해 CAPTCHA의 인식을 해 본다.

우선은 첫 번째 지금부터.


첫 번째 예측 결과
No.0 : predict => 0 , answer = > 0
No.1 : predict => 1 , answer = > 1
No.2 : predict => 4 , answer = > 4
No.3 : predict => 6 , answer = > 6
No.4 : predict => 7 , answer = > 7
No.5 : predict => 9 , answer = > 9
00006 / 00006 = 100.00%

정답률은 100%.
이것은 지난번과 다르지 않다.

다음은 두 번째 이것이다.


두 번째 예측 결과
No.0 : predict => 0 , answer = > 0
No.1 : predict => 1 , answer = > 1
No.2 : predict => 6 , answer = > 4
No.3 : predict => 8 , answer = > 6
No.4 : predict => 8 , answer = > 7
No.5 : predict => 9 , answer = > 9
00003 / 00006 = 50.00%

정답률은 50%.
전회는 33.33%였으므로, 개선되고 있는 것을 알 수 있다.

2. 정리



Chainer를 사용하여 숫자 이미지의 인식을 시도했습니다.
전회보다 정답률이 개선되고 있다.

학습 횟수를 늘리면 더욱 정답률은 올라갈 것으로 보이지만, 전회도 쓴 것처럼 학습 데이터를 궁리하지 않는 것은 근본 해결이 되지 않는다.

오히려 이번 검증에서 특필해야 할 것은, 매우 간이한 코드로 다층 퍼셉트론을 실장할 수 있어 게다가 정답률을 개선할 수 있었을 것이다.

앞으로 Chainer와 Deap을 사용하여 Neuroevolution을 구현하고 웹 응용 프로그램의 자동 크롤러를 개발하려고합니다.

3. 참고 문헌


  • 심층 학습
  • 【기계 학습】딥 러닝 프레임워크 Chainer를 시험하면서 해설해 본다.
  • Chainer Official Document

  • 이상

    좋은 웹페이지 즐겨찾기