1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
-module(ann).
-export([
connect/2,
dot_prod/2,
feed_forward/3,
perceptron/3,
replace_input/2,
sigmoid/1,
run/0
]).
sigmoid(X) ->
1 / (1 + math:exp(-X)).
sigmoid_deriv(X) ->
math:exp(-X) / ((1 + math:exp(-X)) * (1 + math:exp(-X))).
dot_prod(X, Y) ->
lists:foldl(fun({A, B}, Sum) -> A * B + Sum end, 0, lists:zip(X, Y)).
feed_forward(F, Weights, Inputs) ->
F(dot_prod(Weights, Inputs)).
connect(Sender_PID, Receiver_PID) ->
Sender_PID ! {connect_to_output, {Receiver_PID, 0.0}},
Receiver_PID ! {connect_to_input, {Sender_PID, 0.5}}.
replace_input(Inputs, Input) ->
lists:keyreplace(element(1, Input), 1, Inputs, Input).
convert_to_keys(Tuple_list) ->
lists:map(fun(Tup) -> element(1, Tup) end, Tuple_list).
convert_to_values(Tuple_list) ->
lists:map(fun(Tup) -> element(2, Tup) end, Tuple_list).
vector_map(F, X, Y) -> lists:map(fun(A) -> F(element(1,A), element(2,A)) end, lists:zip(X, Y)).
add_sensitivity(Sensitivities, Backprop) when Sensitivities =/= [] ->
replace_input(Sensitivities, Backprop);
add_sensitivity(Sensitivities, Backprop) when Sensitivities =:= [] ->
[].
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
when Sensitivities =/= [], Inputs =:= [] ->
null;
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
when Sensitivities =:= [], Inputs =/= [] ->
{_, Training_value} = Backprop,
(Training_value - Output_value) * Derv_value;
calculate_sensitivity(Backprop, Inputs, Sensitivities, Output_value, Derv_value)
when Sensitivities =/= [], Inputs =/= [] ->
Derv_value * lists:foldl(fun(E, T) -> E + T end, 0, convert_to_values(Sensitivities)).
perceptron(Weights, Inputs, Sensitivities) ->
receive
{learn, Backprop} ->
Learning_rate = 0.5,
New_sensitivities = add_sensitivity(Sensitivities, Backprop),
Output_value = feed_forward(fun(X) -> sigmoid(X) end, Weights, convert_to_values(Inputs)),
Derv_value = feed_forward(fun(X) -> sigmoid_deriv(X) end, 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]),
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]),
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 = feed_forward(fun(X)-> sigmoid(X) end, Weights, convert_to_values(New_inputs)),
if
Sensitivities =/= [] ->
lists:foreach(fun(Output_PID) ->
Output_PID ! {stimulate, {self(), Output}}
end,
convert_to_keys(Sensitivities));
Sensitivities =:= [] ->
io:format("~n~w outputs: ~w", [self(), Output]),
self() ! {learn, {self(), 1}}
end,
perceptron(Weights, New_inputs, Sensitivities);
{connect_to_output, Sensitivity} ->
Combined_output = [Sensitivity | Sensitivities],
io:format("~w output connected to ~w: ~w~n", [self(), element(1, Sensitivity), Combined_output]),
perceptron(Weights, Inputs, Combined_output);
{connect_to_input, Sensitivity} ->
Combined_input = [Sensitivity | Inputs],
io:format("~w input connected from ~w: ~w~n", [self(), element(1, Sensitivity), Combined_input]),
perceptron([0.5 | Weights], Combined_input, Sensitivities);
{status} ->
io:format("Status of Node(~w)~n W: ~w~n I: ~w~n S: ~w~n", [self(), Weights, Inputs, Sensitivities]),
perceptron(Weights, Inputs, 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)),
perceptron(Weights, Inputs, Sensitivities)
end.
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, [[],[],[]]),
ann:connect(X1_pid, H1_pid),
ann:connect(X1_pid, H2_pid),
ann:connect(X2_pid, H1_pid),
ann:connect(X2_pid, H2_pid),
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}.
|