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となる.