人工データを使ってPylearn2でDBMを試してみた

  • 39
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Pylearn2を使ってDeep Learningしてみました。
まともなデータを使ってテストはしていないし、まともなアウトプットが出ていないので、"ふ〜ん、Pylearn2ってこんな感じか"、っていうPylearn2の雰囲気をつかむ目的で読んで頂けますと助かります。

Pylearn2のインストール

とりあえず公式のドキュメントを参考にしてください。
theanoのバージョンによってはエラーが出るため、その場合は下のstackoverflowを参考にして下さい。

参考資料

とりあえず、下のコンピュータビジョン最先端ガイド6を一読して、Deep Learning Tutorialsを読みつつtheanoで実装しながら動かすと、なんとなくDeep Learningが理解できると思います。ちなみに私はなんとなくしか理解できていません。。
theanoでの実装についてはsinhrksさんのブログに手法のわかりやすい解説付きポストがありますので、学習コストを下げてくれると思います。
それと、株式会社知能情報システムさんのTheano入門も非常に参考になると思います。合わせてご一読頂くことをおすすめ致します。

やったこと

  1. binary教師なし人工データの発生
  2. DBMのtraining
  3. 作成したDBMの結果表示

参考コード

試行錯誤感を出すためにコメントアウトは意図的に残しています。見づらくて申し訳ありませんが、ご了承下さい。

人口データの発生

toy_train.csvとtoy_train.pkl(Pylearn2のserial objectとして保存)を作成し、保存します。

create_toy_dataset.py
import numpy
from pylearn2.datasets import DenseDesignMatrix
from pylearn2.utils import serial

class ToyDataset(DenseDesignMatrix):
    def __init__(self):
        rng = numpy.random.RandomState(seed=42)
        data = numpy.array( [rng.randint(0,2,200) for _ in range(1000)] )
        self.data = data
        super(ToyDataset, self).__init__(X=data) #, y=self.y)

def main():
    train = ToyDataset()
    train.use_design_loc('./toy_train_design.npy')
    rng = numpy.random.RandomState(seed=42)

    train_csv_path = './toy_train.csv'
    train_pkl_path = './toy_train.pkl'
    data = numpy.array( [rng.randint(0,2,200) for _ in range(1000)] ,dtype=numpy.int)
    numpy.savetxt(train_csv_path, data, delimiter=',',fmt='%d')
    serial.save(train_pkl_path, train)

if __name__ == '__main__':
    main()

Pylearn2設定用yamlファイル

csvファイルを直接読んで動かそうと思ったんですが、うまく動かなかったので、pklファイルを読んで使用します。
CSVDatasetのdelimiterはdefaultではカンマとなっています。numpy.savetxtでdelimiterを指定していない場合は、yamlファイルのCSVDataset内でdelimiterを半角スペースに書き換えて下さい。
またlabelがない場合はexpect_labels: False、ヘッダーがない場合はexpect_headers: Falseを記述して下さい。
詳細は公式ドキュメントを参考にして頂きたく。
データを自作する場合のデータ構造などにつては、pylearn2 入門したい編が参考になります。
見ての通り係数は適当に設定していますので、参考にしないでください。
Deep Learningの実践についてはをA Practical Guide to Training Redstricted Boltzmann Machineを要約したRBMから考えるDeep Learning ~黒魔術を添えて~が参考になると思います。
あと、個人的にmomentumについてDropoutの実装と重みの正則化が参考になりました。

grbm_dbm.yaml
!obj:pylearn2.train.Train {
    dataset: &data !obj:pylearn2.datasets.binarizer.Binarizer {
        raw: &raw_train !pkl: "toy_train.pkl",
    },
    #dataset: &train !obj:pylearn2.datasets.csv_dataset.CSVDataset {
    #    path: %(path)s,
    #    start: %(start)i,
    #    stop: %(stop)i,
    #    expect_labels: False,
    #    expect_headers: False
    #},
    model: !obj:pylearn2.models.dbm.DBM {
        batch_size: %(batch_size)i,
        niter: 5,
        visible_layer: !obj:pylearn2.models.dbm.BinaryVector {
            nvis: %(nvis)i,
            bias_from_marginals: *raw_train,
        },
        hidden_layers: [
                 !obj:pylearn2.models.dbm.BinaryVectorMaxPool {
                     layer_name: 'h1',
                     detector_layer_dim: %(detector_layer_dim1)i,
                     pool_size: 1,
                     irange: .05,
                     init_bias: -2.,
                 },
                 !obj:pylearn2.models.dbm.BinaryVectorMaxPool {
                     layer_name: 'h2',
                     detector_layer_dim: %(detector_layer_dim2)i,
                     pool_size: 1,
                     irange: .05,
                     init_bias: -2.,
                 },
                 !obj:pylearn2.models.dbm.BinaryVectorMaxPool {
                     layer_name: 'y',
                     detector_layer_dim: %(detector_layer_dim3)i,
                     pool_size: 1,
                     irange: .05,
                     init_bias: -2.,
                 }
                 #!obj:pylearn2.models.dbm.Softmax {
                 #    layer_name: 'y',
                 #    max_col_norm: 1.9365,
                 #    #supervised: False,
                 #    n_classes: 10,
                 #    irange: .05,
                 #}
        ],
    },
    algorithm: !obj:pylearn2.training_algorithms.sgd.SGD {
        learning_rate: .05,
        learning_rule: !obj:pylearn2.training_algorithms.learning_rule.Momentum {
            init_momentum: .5,
        },
        monitoring_batches: %(monitoring_batches)i,
        monitoring_dataset: { 'train': *data
                              #'test': !obj:pylearn2.datasets.csv_dataset.CSVDataset {
                              #          path: %(path)s,
                              #          start: %(test_start)i,
                              #          stop: %(test_stop)i,
                              #          expect_labels: False,
                              #          expect_headers: False
                              #},
                            },
        cost: !obj:pylearn2.costs.cost.SumOfCosts {
            costs: [
                !obj:pylearn2.costs.dbm.VariationalPCD {
                    num_chains: 100,
                    num_gibbs_steps: 5
                },
                !obj:pylearn2.costs.dbm.WeightDecay {
                    coeffs: [.0001, .0001, .0001]
                },
                !obj:pylearn2.costs.dbm.TorontoSparsity {
                    targets: [.2, .2, .2],
                    coeffs: [.001, .001, .001],
                }
            ],
        },
        termination_criterion: !obj:pylearn2.termination_criteria.EpochCounter { max_epochs: %(max_epochs)i },
        update_callbacks: [
            !obj:pylearn2.training_algorithms.sgd.ExponentialDecay {
                decay_factor: 1.000015,
                min_lr: .000001
            }
        ]
    },
    extensions: [
        !obj:pylearn2.training_algorithms.learning_rule.MomentumAdjustor {
            final_momentum: .9,
            start: 5,
            saturate: 6
        }
    ],
    save_path: "%(save_path)s/grbm_dbm.pkl",
    save_freq: 1
}

training

ToyDataset classをpylearn2のdatasetに置いておかないとエラーが出るのですが、training用のソースに直接書いても問題なく動くようですので、(意味もなく)下のコードに記述があります。

train_dbm.py
import os

from nose.plugins.skip import SkipTest
from theano import config

import pylearn2
from pylearn2.datasets import DenseDesignMatrix
from pylearn2.testing import skip
from pylearn2.testing import no_debug_mode
from pylearn2.utils.serial import load_train_file
from pylearn2.config import yaml_parse

class ToyDataset(DenseDesignMatrix):
    def __init__(self):
        rng = numpy.random.RandomState(seed=42)
        data = numpy.array( [rng.randint(0,200,200) for _ in range(1000)] )
        super(ToyDataset, self).__init__(X=data)#, y=self.y)

@no_debug_mode
def train_yaml(yaml_file):
    train = yaml_parse.load(yaml_file)
    train.main_loop()

def train(yaml_file_path, save_path):
    yaml = open("{0}/grbm_dbm.yaml".format(yaml_file_path), 'r').read()
    hyper_params = {'batch_size': 100,
                    'nvis': 200,
                    'detector_layer_dim1': 300,
                    'detector_layer_dim2': 300,
                    'detector_layer_dim3': 10,
                    'monitoring_batches': 10,
                    'max_epochs': 100,
                    'save_path': save_path}
    yaml = yaml % (hyper_params)
    train_yaml(yaml)

def train_dbm():
    skip.skip_if_no_data()
    yaml_file_path = '.'
    save_path = '.'
    train(yaml_file_path, save_path)

if __name__ == '__main__':
    train_dbm()

学習結果の表示

dbm_result.py
import numpy as np
import pickle
import sys
import theano
from pylearn2.space import VectorSpace
from pylearn2.datasets import DenseDesignMatrix

class ToyDataset(DenseDesignMatrix):
    def __init__(self):
        rng = numpy.random.RandomState(seed=42)
        data = numpy.array( [rng.randint(0,2,200) for _ in range(1000)] )
        super(ToyDataset, self).__init__(X=data)#, y=self.y)

def simulate(inputs, model):
    print dir(model)
    space = VectorSpace(inputs.shape[1])
    X = space.get_theano_batch()
    q = model.mf(space.format_as(X, model.get_input_space()))
    f = theano.function([X], q[-1])
    result = []
    batch_size = 100
    for x in xrange(0, len(inputs), batch_size):
        result.extend(f(inputs[x:x + batch_size]))
        print "len:", len(result)
        print result[0]
    return result

def countCorrectResults(outputs):
    correct = 0;
    for output in outputs:
        for out_vec in output:
            print np.argmax(out_vec)

def score(dataset, model):
    outputs = simulate(dataset.X, model)
    countCorrectResults(outputs)

model = pickle.load(open('grbm_dbm.pkl')) #学習後のモデル
test_data = pickle.load(open('toy_train.pkl')) #学習に使用したデータ
score(test_data, model)

上のコードを動かした結果、全てのデータでindex6で確率値がmaxになるという意味不明の結果が帰ってきましたw
何かがおかしい、というか何か根本的に間違ってそうな気もします。。

コメント

githubにはあるけどPylearn2のドキュメントには記載がないモジュールなどもあり、まともに動かすのは結構しんどいな、、というのが感想です。
Pylearn2はドキュメント整備が追いついてないとは思うのですが、手法の概要などが記載されているものもあるので、自分の知らない手法で効率の良さそうなモノがないかドキュメントでザッと見て、気になった手法の論文を読んでみる、という使い方をすれば効率的に学習が出来そうな気がしています。(気がしているだけです。。)

上でやったこと以外にも、アホな事をやっていまして、教師なしのRBMをMLPで動かせないかやってみたりしました。が、MLPは教師ありしか受け付けない模様です(monitering時にエラーが出ます。)。

お手数ですが間違いがありましたらご指摘いただけますと助かります。