-
Notifications
You must be signed in to change notification settings - Fork 0
/
nn.c
186 lines (151 loc) · 5.99 KB
/
nn.c
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// Simple network that can learn XOR
// Feartures : sigmoid activation function, stochastic gradient descent, and mean square error fuction
// Activation function and its derivative
double sigmoid(double x) { return 1 / (1 + exp(-x)); }
double dSigmoid(double x) { return x * (1 - x); }
// Activation function and its derivative
double init_weight() { return ((double)rand())/((double)RAND_MAX); }
// Shuffle the dataset
void shuffle(int *array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
#define numInputs 2
#define numHiddenNodes 2
#define numOutputs 1
#define numTrainingSets 4
int main (void) {
const double lr = 0.1f;
double hiddenLayer[numHiddenNodes];
double outputLayer[numOutputs];
double hiddenLayerBias[numHiddenNodes];
double outputLayerBias[numOutputs];
double hiddenWeights[numInputs][numHiddenNodes];
double outputWeights[numHiddenNodes][numOutputs];
double training_inputs[numTrainingSets][numInputs] = {{0.0f,0.0f},
{1.0f,0.0f},
{0.0f,1.0f},
{1.0f,1.0f}};
double training_outputs[numTrainingSets][numOutputs] = {{0.0f},
{1.0f},
{1.0f},
{0.0f}};
for (int i=0; i<numInputs; i++) {
for (int j=0; j<numHiddenNodes; j++) {
hiddenWeights[i][j] = init_weight();
}
}
for (int i=0; i<numHiddenNodes; i++) {
hiddenLayerBias[i] = init_weight();
for (int j=0; j<numOutputs; j++) {
outputWeights[i][j] = init_weight();
}
}
for (int i=0; i<numOutputs; i++) {
outputLayerBias[i] = init_weight();
}
int trainingSetOrder[] = {0,1,2,3};
int numberOfEpochs = 10000;
// Train the neural network for a number of epochs
for(int epochs=0; epochs < numberOfEpochs; epochs++) {
// As per SGD, shuffle the order of the training set
shuffle(trainingSetOrder,numTrainingSets);
// Cycle through each of the training set elements
for (int x=0; x<numTrainingSets; x++) {
int i = trainingSetOrder[x];
// Forward pass
// Compute hidden layer activation
for (int j=0; j<numHiddenNodes; j++) {
double activation = hiddenLayerBias[j];
for (int k=0; k<numInputs; k++) {
activation += training_inputs[i][k] * hiddenWeights[k][j];
}
hiddenLayer[j] = sigmoid(activation);
}
// Compute output layer activation
for (int j=0; j<numOutputs; j++) {
double activation = outputLayerBias[j];
for (int k=0; k<numHiddenNodes; k++) {
activation += hiddenLayer[k] * outputWeights[k][j];
}
outputLayer[j] = sigmoid(activation);
}
// Print the results from forward pass
printf ("Input:%g Output:%g Expected Output: %g\n",
training_inputs[i][0], outputLayer[0],
training_outputs[i][0],
training_inputs[i][1]
);
// Backprop
// Compute change in output weights
double deltaOutput[numOutputs];
for (int j=0; j<numOutputs; j++) {
double errorOutput = (training_outputs[i][j] - outputLayer[j]);
deltaOutput[j] = errorOutput * dSigmoid(outputLayer[j]);
}
// Compute change in hidden weights
double deltaHidden[numHiddenNodes];
for (int j=0; j<numHiddenNodes; j++) {
double errorHidden = 0.0f;
for(int k=0; k<numOutputs; k++) {
errorHidden += deltaOutput[k] * outputWeights[j][k];
}
deltaHidden[j] = errorHidden * dSigmoid(hiddenLayer[j]);
}
// Apply change in output weights
for (int j=0; j<numOutputs; j++) {
outputLayerBias[j] += deltaOutput[j] * lr;
for (int k=0; k<numHiddenNodes; k++) {
outputWeights[k][j] += hiddenLayer[k] * deltaOutput[j] * lr;
}
}
// Apply change in hidden weights
for (int j=0; j<numHiddenNodes; j++) {
hiddenLayerBias[j] += deltaHidden[j] * lr;
for(int k=0; k<numInputs; k++) {
hiddenWeights[k][j] += training_inputs[i][k] * deltaHidden[j] * lr;
}
}
}
}
// Print final weights after training
fputs ("Final Hidden Weights\n[ ", stdout);
for (int j=0; j<numHiddenNodes; j++) {
fputs ("[ ", stdout);
for(int k=0; k<numInputs; k++) {
printf ("%f ", hiddenWeights[k][j]);
}
fputs ("] ", stdout);
}
fputs ("]\nFinal Hidden Biases\n[ ", stdout);
for (int j=0; j<numHiddenNodes; j++) {
printf ("%f ", hiddenLayerBias[j]);
}
fputs ("]\nFinal Output Weights", stdout);
for (int j=0; j<numOutputs; j++) {
fputs ("[ ", stdout);
for (int k=0; k<numHiddenNodes; k++) {
printf ("%f ", outputWeights[k][j]);
}
fputs ("]\n", stdout);
}
fputs ("Final Output Biases\n[ ", stdout);
for (int j=0; j<numOutputs; j++) {
printf ("%f ", outputLayerBias[j]);
}
fputs ("]\n", stdout);
return 0;
}