/* BPTT-Lernalgoritmus fuer rekurrentes Elman Netzwerk mit einem */ /* Eingang, einem Ausgangsneuron und N versteckten Neuronen */ #define MAXLENGTH 255 /* maximale Laenge einer Sequenz */ #define N 10 /* Groesse der versteckten Schicht */ synapse bptt_input_link: std_synapse { input: real in, delta_in; output: real out; private: real w, dw; real buf[MAXLENGTH]; public methods: void init(void) { w = rrand(-0.1, 0.1); dw = 0; } void forward(int counter) { out = in * w; buf[counter] = in; } void backward(int counter) { dw = dw + delta_in * buf[counter]; } void update_weights(real eta) { w = w + eta * dw; dw = 0; } } synapse bptt_link: bptt_input_link { output: real delta_out; public methods: void backward(int counter) { dw = dw + delta_in * buf[counter]; delta_out = delta_in * w; } } neuron output_neuron: std_neuron { input: real_vector u; real teach; output: real y, delta_out; real square_error; private: real bias, dbias; real buf[MAXLENGTH]; public methods: void init(void) { bias = rrand(-0.1,0.1); dbias = 0; } void update(int count) { y = reduce(+,u) + bias; buf[count] = (teach-y); } void learn(int count) { delta_out = buf[count]; dbias = dbias + delta_out; square_error = delta_out * delta_out; } void update_bias(real eta) { bias = bias + eta * dbias; dbias = 0; } } neuron bptt_neuron: output_neuron { input: real_vector v, delta_in, delta_in_loop; private: real buf[MAXLENGTH]; real x; public methods: void update(int counter) {/* Erzeugt in der Vorwaertsphase die neue Ausgabe y des Neurons und speichert fuer jedes Zeichen eines Musters die Ableitung der Aktivierung x des Neurons */ x = reduce(+, u) + reduce(+, v) + bias ; y = sigmoid(x); buf[counter] = derived_sigmoid(x); } void learn(int counter) { delta_out = (reduce(+, delta_in_loop) + reduce(+, delta_in)) * buf[counter]; dbias = dbias + delta_out; } void set_neuron_output_zero(void) { y = 0; delta_out = 0; } } neuron input_node: std_neuron { input: real_vector next; real u; output: real y; public methods: void loop(void) { y = reduce(?>,next); } void load(void) { y = u; } } network bptt: std_network { input: real node.u; output: real layer2.y; private: bptt_neuron layer1[N]; /* Versteckte Schicht (sigmoide Neuronen) */ output_neuron layer2[1]; /* Ausgangsschicht (lineare Neuronen) */ input_node node[1]; /* Eingangsknoten (einfacher Schalter) */ bptt_input_link input_net = {full, node, layer1, /* Versorgt Netz mit */ in=node.y, out=layer1.u, /* externen Eingaben */ delta_in=layer1.delta_out}; bptt_link recurrent_net = {full, layer1, layer1, /* Rueckkopplung */ in=src.y, out=dest.v, delta_in=dest.delta_out, delta_out=src.delta_in_loop}; bptt_link output_net = {full, layer1, layer2, in=layer1.y, out=layer2.u, delta_in=layer2.delta_out, delta_out=layer1.delta_in}; wire teach_net = {full, node, layer2, /* Leitet Lehrersignal */ in=node.y, out=layer2.teach}; /* an Ausgabeschicht */ wire loop_net = {full, layer2, node, /* Leitet Ausgang */ in=layer2.y, out=node.next}; /* an Eingangsknoten */ public methods: void init(void) { int eof; input_net.init(); recurrent_net.init(); output_net.init(); layer1.init(); layer2.init(); } real learn(real eta) { int count, eof, random_length, length; real total_error; /****** Die einzelnen Zeichen einer Sequenz *************/ /****** nacheinander einlesen und vorwaerts *************/ /****** durch das Netz schicken *************/ length = get_nopat(); random_length=irand(10,length); count = 0; total_error = 0; layer1.set_neuron_output_zero(); eof = read_inputs_first(); node.load(); while ((eof != -1) && (count < random_length) && (count < MAXLENGTH)){ input_net.forward(count); recurrent_net.forward(count); layer1.update(count); output_net.forward(count); eof = read_inputs_next(); node.load(); teach_net.forward(); layer2.update(count); count = count + 1; } /**** Hier beginnt die Rueckwaertsphase, d.h. es werden ***/ /**** die dw fuer das Muster berechnet ***/ while (count > 0) { count = count - 1; layer2.learn(count); total_error = total_error + reduce(+,layer2.square_error); output_net.backward(count); layer1.learn(count); input_net.backward(count); recurrent_net.backward(count); } /***** Nachdem nun ein Muster vollstaendig abgearbeitet ***/ /***** wurde, werden jetzt die Gewichte aktualisiert ***/ output_net.update_weights(eta); input_net.update_weights(eta); recurrent_net.update_weights(eta); layer2.update_bias(eta); layer1.update_bias(eta); return(total_error); } void predict(int init_length, int num) { int count, eof; count = 0; layer1.set_neuron_output_zero(); eof = read_inputs_first(); /* zunachst init_length Werte dem Netz pr\"asentieren ... */ while ((eof != -1) && (count < init_length) && (count < MAXLENGTH)) { node.load(); input_net.forward(count); recurrent_net.forward(count); layer1.update(count); output_net.forward(count); layer2.update(count); write_outputs(); /* schreibt Ausgabe in Ergebnisdatei */ count = count + 1; eof = read_inputs_next(); } count = 0; /* dann num weitere Werte prognostizieren ... */ while (count < num) { loop_net.forward(); node.loop(); input_net.forward(0); recurrent_net.forward(0); layer1.update(0); output_net.forward(0); layer2.update(0); write_outputs(); /* schreibt Prognose in Ergebnisdatei */ count = count + 1; } } }