In [1]:
require 'ruby_brain'
require 'nyaplot'
org_stderr = $stderr
$stderr = File.open(File::NULL, "w")
org_stdout = $stdout
$stdout = File.open(File::NULL, "w")


Out[1]:
#<File:/dev/null>

In this example, we tray to make a network which imitate a wave form.

Currently RubyBrain has shigmoid as the activation function. Output layer also can has only sigmoid. In the result, the network can only treat 0~1 outpus.

So, we prepare a function which produces values whithin 0~1 for this example.

Define X is range $0 .. (2*\pi)$ with step $0.1$


In [2]:
X = (0..1).step(0.01).to_a


Out[2]:
[0.0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35000000000000003, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41000000000000003, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47000000000000003, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.5700000000000001, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.6900000000000001, 0.7000000000000001, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.8200000000000001, 0.8300000000000001, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.9400000000000001, 0.9500000000000001, 0.96, 0.97, 0.98, 0.99, 1.0]

Set

$(0.75 * sin(x*2*\pi) + 0.15 * cos(5*\pi – 0.023) + 1) / 2$

to Y_IDEAL

and use Y_IDEAL + (random noise) for Y


In [3]:
Y_IDEAL = X.map {|x| (0.75 * Math.sin(x*2*Math::PI) - 0.2 * Math.cos(5*x*2*Math::PI - 0.023) + 1) / 2} 
Y = [Y_IDEAL, Array.new(X.size) {rand(-0.05..0.05)}].transpose.map {|e| e.inject(:+)}


Out[3]:
[0.40552972386823233, 0.4774905499906632, 0.46219024504515543, 0.49408772854706584, 0.5511014641648844, 0.5830607265235062, 0.6290909985528079, 0.7188366408926009, 0.7464502651167544, 0.7570660940515662, 0.8487802767323701, 0.8048638528562673, 0.8781999845775225, 0.8350774438331358, 0.8231075782014501, 0.8205059962114565, 0.7620703948059987, 0.7592930665178563, 0.7564538805783714, 0.7718808660785458, 0.7939093724782238, 0.7241579038424741, 0.7556405318869907, 0.783810615332835, 0.8146499203453131, 0.9079803254799771, 0.8609454155246148, 0.963374223298478, 0.953686722421743, 0.9423887091039158, 0.9586439428093037, 0.9007886717482598, 0.8955021053214614, 0.9019821644047896, 0.8086460470276943, 0.8185435115568951, 0.7927944294792918, 0.7413519001413804, 0.6947676161553855, 0.6612751665879212, 0.6504900333096678, 0.5568179391111076, 0.6171380642298777, 0.5603384907700707, 0.5760947029063451, 0.5844655117589066, 0.6711066378344058, 0.5841094333299761, 0.5794228773540913, 0.5832987506533194, 0.5501273323962572, 0.6012162864215608, 0.5261450973336963, 0.4587469523684175, 0.4553581842601778, 0.37634597984408674, 0.31052441243765166, 0.2690342620110815, 0.2536487272472072, 0.24769930022299474, 0.17983166212931287, 0.12805859422706325, 0.11537112023884277, 0.21125790572283304, 0.16186838744714038, 0.16132579127049282, 0.2444294667072354, 0.19538817632744343, 0.24132425605822755, 0.22265883054824356, 0.2636831443649561, 0.26362289739592015, 0.2222927083908854, 0.17811329085234903, 0.12732948899046037, 0.16354600102188116, 0.13097407719532192, 0.06720693291100473, 0.05812709756878874, 0.01542796780553005, 0.07579910093602107, 0.07597297165054914, 0.057527311423150096, 0.08270797348892969, 0.10655437450419285, 0.23844271322818672, 0.2668974483956788, 0.2526080180629122, 0.36733263194408383, 0.3199785178151612, 0.3481489425022125, 0.4350143793173079, 0.37639065262225435, 0.3603462039844907, 0.34573400064588994, 0.4343252944140983, 0.3526295334202674, 0.3255975274840675, 0.3246599727949182, 0.3813989077499905, 0.36205386878698165]

Following graph shows X, Y_IDEAL and Y


In [4]:
plot1 = Nyaplot::Plot.new
y_ideal_line = plot1.add(:line, X, Y_IDEAL)
y_ideal_line.title('Y_IDEAL')
y_scatter = plot1.add(:scatter, X, Y)
y_scatter.title('Y')
y_scatter.color('rgb(43,140,190)')
plot1.legend(true)
plot1.show


Use this X for input and Y for output for the training of the network. The structure of the network is [1, 13, 6, 1].


In [5]:
a_network = RubyBrain::Network.new([1, 13, 6, 1])
a_network.init_network
a_network.learning_rate = 0.5
a_network.learn(X.map{|e| [e]}, Y.map{|e| [e]}, max_tra2ining_count=40000, tolerance=0.0004, monitoring_channels=[:best_params_training])


Out[5]:
#<File:best_weights_1470145958.yml (closed)>

You can review the trained network a_network with following code. Y_PREDICATED is the output corresponding to X


In [6]:
Y_PREDICATE = X.map{|e| [e]}.map {|a| a_network.get_forward_outputs(a).first}


Out[6]:
[0.3737866292325307, 0.4155508699326962, 0.4612227994051432, 0.510046222316126, 0.5607734887723744, 0.6116963934435019, 0.6608041726195469, 0.7060561912063408, 0.7456936081165836, 0.7784771369914162, 0.8037633916292516, 0.821410822089631, 0.831586492584581, 0.8345823617111626, 0.8307413200241917, 0.8205601443542602, 0.8049833967331003, 0.7858084350432145, 0.7659928349479052, 0.749589830496322, 0.7411587691845486, 0.7447336675059035, 0.7625310220377353, 0.7935930796595669, 0.8330121525085872, 0.873067538056558, 0.9065953289122177, 0.9300075375974213, 0.9432493802227251, 0.9475817667632656, 0.9436455216754961, 0.9308388250593038, 0.9080063638789239, 0.8751177181219204, 0.8346966936121065, 0.791409829361061, 0.7500728594939753, 0.7139692559515088, 0.6844888844303758, 0.6616316360791809, 0.6446489620789511, 0.6324921879080175, 0.6240459705698431, 0.6182210197904666, 0.6139740134240194, 0.6102956793165908, 0.6061871336344701, 0.6006329967575015, 0.5925754751648203, 0.5808950235422582, 0.5644105663702081, 0.5419267127836488, 0.5123759457604228, 0.4751183746737355, 0.43043144025293156, 0.38008020925535185, 0.32759650799188295, 0.2777575913555481, 0.2351886300617187, 0.20288571825862314, 0.1816714242970304, 0.17069750793984778, 0.16828296262253334, 0.17249611104525836, 0.18140743063906747, 0.19317928271401796, 0.20610461796094728, 0.2186044213693785, 0.22916435709398889, 0.23622278351873238, 0.23808013473390544, 0.23296469703376121, 0.2194239008812383, 0.1971133324075873, 0.1677002148212329, 0.13509396366268775, 0.10427568291398343, 0.07924563358074717, 0.06177808250062096, 0.05186721200466839, 0.04910661008352084, 0.05398370820118536, 0.06866668050121455, 0.09667948867577882, 0.14010814455355214, 0.19507285296341761, 0.2514040310494902, 0.2990186192456708, 0.3333385333302497, 0.354951345988609, 0.366768019225795, 0.3719392889242799, 0.3730100268641807, 0.37177787567756004, 0.36941386972406837, 0.36663471156418753, 0.3638523036599009, 0.3612843115758146, 0.35902970509799054, 0.35711797443189763, 0.3555401330418815]

The following graph shows X, Y_IDEAL, Y and Y_PREDICATED.

Looks good.


In [7]:
plot1 = Nyaplot::Plot.new
ideal_line = plot1.add(:line, X, Y_IDEAL)
ideal_line.title('Y_IDEAL')
training_scatter = plot1.add(:scatter, X, Y)
training_scatter.title('Y')
training_scatter.color('rgb(43,140,190)')
predicated_line = plot1.add(:line, X, Y_PREDICATE)
predicated_line.title("Y_PREDICATED")
predicated_line.color('#f85')
plot1.legend(true)
plot1.show