-
Notifications
You must be signed in to change notification settings - Fork 8
/
SubsamplingWeights.cs
170 lines (141 loc) · 6.88 KB
/
SubsamplingWeights.cs
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
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AdvancedOCR
{
class SubsamplingWeights : RectangularWeights
{
public SubsamplingWeights(int width, int height) : base(width, height, 1)
{
Weight = RandomWeight(width * height);
WeightStepSize = 0.0;
}
protected double Weight;
protected double WeightStepSize;
protected override void PropogateForward(RectangularStep downstream, int mapNumber)
{
RectangularStep upstream = downstream.Upstream[mapNumber];
int index = 0;
for (int y = 0; y < downstream.Height; y++)
{
for (int x = 0; x < downstream.Width; x++)
{
downstream.WeightedInputs[index++] += PropogateForward(upstream, x * Width, y * Height, mapNumber);
}
}
}
protected double PropogateForward(RectangularStep upstream, int upstreamX, int upstreamY, int mapNumber)
{
Debug.Assert(upstreamX + Width <= upstream.Width); // Check we are staying within the width limit of the step.
Debug.Assert(upstreamY + Height <= upstream.Height); // Check we are staying within the height limit of the step.
double result = Bias;
int upstreamIndex = (upstreamY * upstream.Width) + upstreamX;
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
result += upstream.Output[upstreamIndex] * Weight;
upstreamIndex += 1;
}
upstreamIndex += upstream.Width - Width;
}
return result;
}
protected override void StartPreTrainingCore()
{
base.StartPreTrainingCore();
WeightStepSize = 0.0;
}
protected override void PropogateUnitSecondDerivatives(RectangularStep downstream, int upstreamIndex)
{
RectangularStep upstream = downstream.Upstream[upstreamIndex];
for (int y = 0; y < downstream.Height; y++)
{
for (int x = 0; x < downstream.Width; x++)
{
EstimateWeightSecondDerivative(upstream, downstream, x, y);
}
}
}
protected void EstimateWeightSecondDerivative(RectangularStep upstream, RectangularStep downstream, int downstreamX, int downstreamY)
{
double weight2ndDerivative = 0;
int downstreamIndex = downstreamY * downstream.Width + downstreamX;
int upstreamIndex = (downstreamY * Height * upstream.Width) + downstreamX * Width;
double downstreamSecondDerivative = downstream.ErrorDerivative[downstreamIndex];
double upstreamSecondDerivative = Weight * Weight * downstreamSecondDerivative;
// This loop here is equivalent to the sigma in equation 19 in Gradient-Based Learning Applied to Document Recognition.
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
double upstreamState = upstream.Output[upstreamIndex];
// Here we calculate (d^2)Ej/(dWij)^2 by multiplying the 2nd derivative of E with respect to the sum of inputs, Ai
// by the state of Oi, the upstream unit, squared. Refer to Equation 25 in document.
// The summing happening here is described by equation 23.
weight2ndDerivative += downstreamSecondDerivative * upstreamState * upstreamState;
// This is implementing the last sigma of Equation 27.
// This propogates error second derivatives back to previous layer, but will need to be multiplied by the second derivative
// of the activation function at the previous layer.
upstream.ErrorDerivative[upstreamIndex] = upstreamSecondDerivative;
upstreamIndex += 1;
}
upstreamIndex += upstream.Width - Width;
}
WeightStepSize += weight2ndDerivative;
}
protected override void EstimateBiasSecondDerivative(RectangularStep downstream)
{
for (int i = 0; i < downstream.Length; i++)
{
// Calculating the sum of: second derivatives of error with respect to the bias weight.
// Note that the bias is implemented as an always-on Neuron with a (the same) weight to the outputs neurons.
BiasStepSize += downstream.ErrorDerivative[i] * 1.0 * 1.0;
}
}
protected override void CompletePreTrainingCore()
{
double sampleCount = (double)PreTrainingSamples;
// Divide each of the 2nd derivative sums by the number of samples used to make the estimation, then convert into step size.
BiasStepSize /= sampleCount;
WeightStepSize /= sampleCount;
System.Diagnostics.Debug.WriteLine("Weight Hkk = " + BiasStepSize + ", Bias Hkk = " + WeightStepSize + ".");
BiasStepSize = GlobalLearningRate / (GlobalMu + BiasStepSize);
WeightStepSize = GlobalLearningRate / (GlobalMu + WeightStepSize);
}
protected override void PropogateError(RectangularStep downstream, int mapNumber)
{
RectangularStep upstream = downstream.Upstream[mapNumber];
for (int y = 0; y < downstream.Height; y++)
{
for (int x = 0; x < downstream.Width; x++)
{
PropogateError(downstream, upstream, x, y);
}
}
}
protected void PropogateError(RectangularStep downstream, RectangularStep upstream, int downstreamX, int downstreamY)
{
int downstreamIndex = downstreamY * downstream.Width + downstreamX;
int upstreamIndex = (downstreamY * Height * upstream.Width) + downstreamX * Width;
double downstreamErrorDerivative = downstream.ErrorDerivative[downstreamIndex];
double upstreamError = Weight * downstreamErrorDerivative;
double weightError = 0.0;
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
upstream.ErrorDerivative[upstreamIndex] = upstreamError;
double weightErrorGradient = downstreamErrorDerivative * upstream.Output[upstreamIndex];
weightError += weightErrorGradient;
upstreamIndex += 1;
}
upstreamIndex += upstream.Width - Width;
}
Weight -= weightError * WeightStepSize;
}
}
}