PyBrainのテスト 2

PyBrainでbuildNetwork関数を使わずにネットワークをつくる方法. バイアスパラメータを入れるには,BiasUnitを作って各レイヤーにつなげる必要がある.

例によってXORを学習させる.

from pybrain.datasets import SupervisedDataSet
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.structure import (FeedForwardNetwork,
                               LinearLayer,
                               SigmoidLayer,
                               FullConnection)
from pybrain.structure.modules.biasunit import BiasUnit

# Build a network
network = FeedForwardNetwork()
input_layer = LinearLayer(2)
hidden_layer = SigmoidLayer(2)
output_layer = SigmoidLayer(1)
bias = BiasUnit()

network.addInputModule(input_layer)
network.addModule(hidden_layer)
network.addOutputModule(output_layer)
network.addModule(bias)

conn_I2H = FullConnection(input_layer, hidden_layer)
conn_B2H = FullConnection(bias, hidden_layer)
conn_H2O = FullConnection(hidden_layer, output_layer)
conn_B2O = FullConnection(bias, output_layer)

network.addConnection(conn_I2H)
network.addConnection(conn_B2H)
network.addConnection(conn_H2O)
network.addConnection(conn_B2O)

network.sortModules()

# Set teaching signals
target = SupervisedDataSet(2, 1)
target.addSample([0, 0], [0])
target.addSample([0, 1], [1])
target.addSample([1, 0], [1])
target.addSample([1, 1], [0])

def print_weight(conns):
    for conn in conns:
        print conn
        for i in range(len(conn)):
            print conn.whichBuffers(i), conn.params[i]

# Training
for i in range(100000):
    trainer = BackpropTrainer(network, target)
    error = trainer.train()
    if i % 1000 == 0:
        print i, error

print_weight([conn_I2H, conn_B2H, conn_H2O, conn_B2O])

print "f(0, 0) = %f" % network.activate([0, 0])
print "f(0, 1) = %f" % network.activate([0, 1])
print "f(1, 0) = %f" % network.activate([1, 0])
print "f(1, 1) = %f" % network.activate([1, 1])

この場合も初期条件によっては収束しない場合がある.以下はうまく行った場合の結果.

<FullConnection 'FullConnection-6': 'LinearLayer-4' -> 'SigmoidLayer-11'>
(0, 0) -5.15370157608  <= 隠れユニット0の入力ユニット0への重み
(1, 0) 4.83424768504   <= 隠れユニット0の入力ユニット1への重み
(0, 1) 5.54148979423   <= 隠れユニット1の入力ユニット0への重み
(1, 1) -5.50558291046  <= 隠れユニット1の入力ユニット1への重み
<FullConnection 'FullConnection-8': 'BiasUnit-5' -> 'SigmoidLayer-11'>
(0, 0) -2.69438557779  <= 隠れユニット0のバイアス
(0, 1) -3.20939710879  <= 隠れユニット1のバイアス
<FullConnection 'FullConnection-7': 'SigmoidLayer-11' -> 'SigmoidLayer-12'>
(0, 0) 7.61858298153  <= 出力ユニットの隠れユニット0への重み
(1, 0) 7.52633889547  <= 出力ユニットの隠れユニット1への重み
<FullConnection 'FullConnection-9': 'BiasUnit-5' -> 'SigmoidLayer-12'>
(0, 0) -3.73169289793 <= 出力ユニットのバイアス
f(0, 0) = 0.049394
f(0, 1) = 0.956312
f(1, 0) = 0.958175
f(1, 1) = 0.044246

sigmoid(3) ≒ 1, sigmoid(-3) ≒ 0なので,各ユニットは入力に対して以下のような動きをする.

隠れユニット0 hidden0(x, y) = 1 if y > x else 0
隠れユニット1 hidden1(x, y) = 1 if x > y else 0
出力ユニット out(x, y) = 1 if x > 0 or y > 0 else 0

入力値が(0, 0)(1, 1)だと隠れユニットがともに0になるので,出力は0となる.
入力値が(1, 0)(0, 1)だと隠れユニットのどちらかが1になるので,出力は1となる.