Erlang Mailing Lists

Author Message

<  Erlang  ~  Erlang and Neural Networks - Badmatch?

cosmixy
Posted: Tue Aug 05, 2008 5:50 pm Reply with quote
Joined: 05 Aug 2008 Posts: 3
I was going through this tut http://www.trapexit.org/Erlang_and_Neural_Networks.
Everything is going fine until I add the code for learning. Now I get a badmatch when a node tries to connect its output to more than one node.

When the second line here runs(in ann:run() )
Code:
   ann:connect(X1_pid, H1_pid),
   ann:connect(X1_pid, H2_pid),


I've used debugger and it happens on {Key, _} = Tup, with a badmatch only when a node connects its output more than once. Connecting output from different nodes to the input of one node works fine.
Code:
convert_to_keys(Tuple_list) ->
   lists:map(fun(Tup) ->
               {Key, _} = Tup,
               Key
            end,
            Tuple_list).


The prompt.
Code:
1> ann:run().
<0.47.0> output connected to <0.49.0>: [<0.49.0>]
<0.48.0> output connected to <0.49.0>: [<0.49.0>]
<0.49.0> inputs connected to <0.47.0>: [{<0.47.0>,0.5}]
<0.50.0> inputs connected to <0.47.0>: [{<0.47.0>,0.5}]
<0.51.0> inputs connected to <0.49.0>: [{<0.49.0>,0.5}]
<0.49.0> inputs connected to <0.48.0>: [{<0.48.0>,0.5},{<0.47.0>,0.5}]
<0.50.0> inputs connected to <0.48.0>: [{<0.48.0>,0.5},{<0.47.0>,0.5}]
<0.51.0> inputs connected to <0.50.0>: [{<0.50.0>,0.5},{<0.49.0>,0.5}]
<0.49.0> output connected to <0.51.0>: [<0.51.0>]
<0.50.0> output connected to <0.51.0>: [<0.51.0>]
{pass,1.3}

=ERROR REPORT==== 5-Aug-2008::10:51:08 ===
Error in process <0.47.0> with exit value: {{badmatch,<0.49.0>},[{ann,'-convert_to_keys/1-fun-0-',1},{ann,perceptron,3}]}


=ERROR REPORT==== 5-Aug-2008::10:51:08 ===
Error in process <0.48.0> with exit value: {{badmatch,<0.49.0>},[{ann,'-convert_to_keys/1-fun-0-',1},{ann,perceptron,3}]}


Here is the full code.
Code:

-module(ann).
-export([run/0, perceptron/3, connect/2]).

feed_forward(Func, Weights, Inputs) ->
   Func(dot_prod(Weights, Inputs)).

% like map, but with two lists instead.
vector_map(Func, [], []) ->
   [];
vector_map(Func, [Xh | Xt], [Yh | Yt]) ->
   [Func(Xh, Yh) | vector_map(Func, Xt, Yt)].

% Calculates the dot product of two lists
dot_prod(X, Y) ->
   lists:foldl(fun(E, Sum) -> E + Sum end, 0,
      vector_map(fun(Ex, Ey) -> Ex * Ey end, X, Y)).

perceptron(Weights, Inputs, Sensitivities) ->

   Sigmoid =    fun(X) ->
               1 / (1 + math:exp(-X))
            end,

   Sigmoid_deriv =   fun(X) ->
                  math:exp(-X) / (1 + math:exp(-2 * X))
               end,

   receive
      {learn, Backprop} ->
         Learning_rate = 0.5,

         % Calculate the correct sensitivities
         New_sensitivities = add_sensitivity(Sensitivities, Backprop),
         Output_value = feed_forward(Sigmoid, Weights, convert_to_values(Inputs)),
         Derv_value = feed_forward(Sigmoid_deriv, Weights, convert_to_values(Inputs)),
         Sensitivity = calculate_sensitivity(Backprop, Inputs, New_sensitivities,
                                    Output_value, Derv_value),
         io:format("(~w) New Sensitivities: ~w~n", [self(), New_sensitivities]),
         io:format("(~w) Calculated Sensitivity: ~w~n", [self(), Sensitivity]),

         % Adjust all the weights
         Weight_adjustments = lists:map(fun(Input) ->
                                       Learning_rate * Sensitivity * Input
                                 end,
                                 convert_to_values(Inputs)),
         New_weights = vector_map(fun(W, D) -> W + D end, Weights, Weight_adjustments),
         io:format("(~w) Adjusted Weights: ~w~n", [self(), Weights]),

         % propagate sensitivities and associated weights back to the previous layer
         vector_map(fun(Weight, Input_PID) ->
                        Input_PID ! {learn, {self(), Sensitivity * Weight}}
                  end,
                  New_weights,
                  convert_to_keys(Inputs)),
           
         perceptron(New_weights, Inputs, New_sensitivities);


      {stimulate, Input} ->
         New_inputs = replace_input(Inputs, Input),
         Output_value = feed_forward(Sigmoid, Weights, convert_to_values(New_inputs)),
         if Sensitivities =/= [] ->
               % My output's connected to at least one perceptron:
               lists:foreach(fun(Output_PID) ->
                              Output_PID ! {stimulate, {self(), Output_value}}
                           end,
                           convert_to_keys(Sensitivities));
            Sensitivities =:= [] ->
               % My output's connected to no one:
               io:format("~w outputs: ~w~n", [self(), Output_value]),
               % Call a trainer here instead and
               self() ! {learn, {self(), 1}}
         end,
         perceptron(Weights, New_inputs, Sensitivities);


      {connect_to_output, Receiver_PID} ->
         Combined_output = [Receiver_PID | convert_to_keys(Sensitivities)],
         io:format("~w output connected to ~w: ~w~n", [self(), Receiver_PID, Combined_output]),
         perceptron(Weights, Inputs, Combined_output);

      {connect_to_input, Sender_PID} ->
         Combined_input = [{Sender_PID, 0.5} | Inputs],
         io:format("~w inputs connected to ~w: ~w~n", [self(), Sender_PID, Combined_input]),
         perceptron([0.5 | Weights], Combined_input, convert_to_keys(Sensitivities));

      {pass, Input_value} ->
         lists:foreach(fun(Output_PID) ->
                        io:format("Stimulating ~w with ~w~n", [Output_PID, Input_value]),
                        Output_PID ! {stimulate, {self(), Input_value}}
                     end,
                     convert_to_keys(Sensitivities))
   end.

connect(Sender_PID,  Receiver_PID) ->
   Sender_PID ! {connect_to_output, Receiver_PID},
   Receiver_PID ! {connect_to_input, Sender_PID}.

replace_input(Inputs, Input) ->
   {Input_PID, _} = Input,
   lists:keyreplace(Input_PID, 1, Inputs, Input).

convert_to_values(Tuple_list) ->
   lists:map(fun(Tup) ->
               {_, Val} = Tup,
               Val
            end,
            Tuple_list).

convert_to_keys(Tuple_list) ->
   lists:map(fun(Tup) ->
               {Key, _} = Tup,
               Key
            end,
            Tuple_list).

% adds the propagating sensitivity to the Sensitivities Hash
add_sensitivity(Sensitivities, Backprop) when Sensitivities =/= [] ->
   replace_input(Sensitivities, Backprop);
add_sensitivity(Sensitivities, Backprop) when Sensitivities =:= [] ->
   [].

% Calculates the sensitivity of this particular node
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
   when Sensitivities =/= [], Inputs =:= [] -> % When the node is an input node:
      null;
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
   when Sensitivities =:= [], Inputs =/= [] -> % When the node is an output node:
      {_, Training_value} = Backprop,
      (Training_value - Output_value) * Derv_value;
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
   when Sensitivities =/= [], Inputs =/= [] -> % When the node is a hidden node:
   Derv_value * lists:foldl(fun(E, T) -> E + T end, 0, convert_to_values(Sensitivities)).

run() ->
   X1_pid = spawn(ann, perceptron, [[],[],[]]),
   X2_pid = spawn(ann, perceptron, [[],[],[]]),
   H1_pid = spawn(ann, perceptron, [[],[],[]]),
   H2_pid = spawn(ann, perceptron, [[],[],[]]),

   O_pid = spawn(ann, perceptron,  [[],[],[]]),

   % Connect input node X1 to hidden nodes H1 and H2
   ann:connect(X1_pid, H1_pid),
   ann:connect(X1_pid, H2_pid),
   
   % Connect input node X2 to hidden nodes H1 and H2
   ann:connect(X2_pid, H1_pid),
   ann:connect(X2_pid, H2_pid),

   % Connect input node H1 and H2 to output node O
   ann:connect(H1_pid, O_pid),
   ann:connect(H2_pid, O_pid),

   X1_pid ! {status},
   X2_pid ! {status},
   H1_pid ! {status},
   H2_pid ! {status},
   O_pid ! {status},

   X1_pid ! {pass, 1.8},
   X2_pid ! {pass, 1.3}.
View user's profile Send private message
cosmixy
Posted: Wed Aug 06, 2008 8:12 pm Reply with quote
Joined: 05 Aug 2008 Posts: 3
I have partially fixed the problem. A few instances of convert_to_values(Sensitivities) have been changed to just Sensitivities. That was causing Tup ({Key, _} = Tup) to be a single item rather than a 2 item tuple. Though I am still getting the error during the second layer of neurons which confuses me even more.

Code:
1> ann:run().
<0.47.0> output connected to <0.49.0>: [<0.49.0>]
<0.48.0> output connected to <0.49.0>: [<0.49.0>]
<0.49.0> inputs connected to <0.47.0>: [{<0.47.0>,0.5}]
<0.50.0> inputs connected to <0.47.0>: [{<0.47.0>,0.5}]
<0.51.0> inputs connected to <0.49.0>: [{<0.49.0>,0.5}]
<0.47.0> output connected to <0.50.0>: [<0.50.0>,<0.49.0>]
<0.48.0> output connected to <0.50.0>: [<0.50.0>,<0.49.0>]
<0.49.0> inputs connected to <0.48.0>: [{<0.48.0>,0.5},{<0.47.0>,0.5}]
<0.50.0> inputs connected to <0.48.0>: [{<0.48.0>,0.5},{<0.47.0>,0.5}]
<0.51.0> inputs connected to <0.50.0>: [{<0.50.0>,0.5},{<0.49.0>,0.5}]
Stimulating <0.50.0> with 1.8
Stimulating <0.50.0> with 1.3
<0.49.0> output connected to <0.51.0>: [<0.51.0>]
<0.50.0> output connected to <0.51.0>: [<0.51.0>]
Stimulating <0.49.0> with 1.8
Stimulating <0.49.0> with 1.3
{pass,1.3}

=ERROR REPORT==== 6-Aug-2008::12:57:38 ===
Error in process <0.50.0> with exit value: {{badmatch,<0.51.0>},[{ann,'-convert_to_keys/1-fun-0-',1},{ann,perceptron,3}]}


=ERROR REPORT==== 6-Aug-2008::12:57:38 ===
Error in process <0.49.0> with exit value: {{badmatch,<0.51.0>},[{ann,'-convert_to_keys/1-fun-0-',1},{ann,perceptron,3}]}
View user's profile Send private message
cosmixy
Posted: Sat Aug 09, 2008 8:07 pm Reply with quote
Joined: 05 Aug 2008 Posts: 3
Fixed. Convert_to_keys() wanted a list of two item tuples, before the second items were added to Sensitivities it was just a list. Added an atom as a placeholder to make a two it item tuple from the get go. Was an awfully simple fix =O
From:
Code:
{connect_to_output, Receiver_PID} ->
  Combined_output = [Receiver_PID | Sensitivities],

To:
Code:
{connect_to_output, Receiver_PID} ->
  Combined_output = [{Receiver_PID, n} | Sensitivities],
View user's profile Send private message

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum