-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathActivationBase.cs
178 lines (164 loc) · 6.82 KB
/
ActivationBase.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
171
172
173
174
175
176
177
178
using EasyMLCore.Extensions;
using EasyMLCore.MathTools;
using System;
namespace EasyMLCore.Activation
{
/// <summary>
/// Implements the base class of all activation classes.
/// </summary>
[Serializable]
public abstract class ActivationBase : SerializableObject
{
//Attribute properties
/// <summary>
/// Activation ID.
/// </summary>
public ActivationFnID ID { get; }
/// <summary>
/// Activation output range.
/// </summary>
public Interval OutputRange { get; }
//Protected constructor
protected ActivationBase(ActivationFnID identifier, Interval outputRange)
{
ID = identifier;
OutputRange = outputRange;
return;
}
//Properties
/// <summary>
/// Indicates whether activation and derivative computation requieres sums on whole layer (true) or single sum only (false).
/// </summary>
public virtual bool RequiresWholeLayerComputation { get { return false; } }
//Methods
/// <summary>
/// Computes an activation.
/// </summary>
/// <param name="sum">Summed activation input.</param>
/// <returns>Computed activation.</returns>
public abstract double Compute(double sum);
/// <summary>
/// Computes layer activations.
/// </summary>
/// <param name="sums">Summed activation inputs.</param>
/// <param name="sIdx">Start index within the sums.</param>
/// <param name="activations">Activations.</param>
/// <param name="aIdx">Start index within the activations.</param>
/// <param name="count">Number of layer neurons.</param>
public virtual void Compute(double[] sums, int sIdx, double[] activations, int aIdx, int count)
{
for (int i = 0; i < count; i++, sIdx++, aIdx++)
{
activations[aIdx] = Compute(sums[sIdx]);
}
return;
}
/// <summary>
/// Computes the derivative.
/// </summary>
/// <param name="sum">Summed activation input.</param>
/// <param name="activation">Computed activation.</param>
/// <returns>Computed derivative.</returns>
public abstract double ComputeDerivative(double sum, double activation);
/// <summary>
/// Computes layer activations and derivatives.
/// </summary>
/// <param name="sums">Summed inputs of the activations.</param>
/// <param name="sIdx">Start index within the sums.</param>
/// <param name="activations">Activations.</param>
/// <param name="aIdx">Start index within the activations.</param>
/// <param name="derivatives">Derivatives</param>
/// <param name="dIdx">Start index within the derivatives.</param>
/// <param name="count">Number of layer neurons.</param>
public virtual void Compute(double[] sums,
int sIdx,
double[] activations,
int aIdx,
double[] derivatives,
int dIdx,
int count
)
{
for (int i = 0; i < count; i++, sIdx++, aIdx++, dIdx++)
{
activations[aIdx] = Compute(sums[sIdx]);
derivatives[dIdx] = ComputeDerivative(sums[sIdx], activations[aIdx]);
}
return;
}
/// <summary>
/// Adjusts layer activations under specified dropout mode.
/// </summary>
/// <param name="mode">Dropout mode.</param>
/// <param name="dropoutP">The dropout probability.</param>
/// <param name="rand">Random generator to be used.</param>
/// <param name="switches">Node boolean switches.</param>
/// <param name="sIdx">Specifies the start index within the switches.</param>
/// <param name="activations">Activations.</param>
/// <param name="aIdx">Specifies the start index within the activations.</param>
/// <param name="derivatives">Derivatives (can be null).</param>
/// <param name="dIdx">Specifies the start index within the derivatives.</param>
/// <param name="count">Number of layer neurons.</param>
public virtual void Dropout(DropoutMode mode,
double dropoutP,
Random rand,
bool[] switches,
int sIdx,
double[] activations,
int aIdx,
double[] derivatives,
int dIdx,
int count
)
{
if (mode == DropoutMode.Bernoulli)
{
//Bernoulli gate
double enabledGateCoeff = 1d / (1d - dropoutP);
for (int i = 0; i < count; i++, sIdx++, aIdx++, dIdx++)
{
switches[sIdx] = rand.NextDouble() >= dropoutP;
if (!switches[sIdx])
{
activations[aIdx] = 0d;
if (derivatives != null)
{
derivatives[dIdx] = 0d;
}
}
else
{
activations[aIdx] *= enabledGateCoeff;
}
}
}
else
{
//Gaussian gate
for (int i = 0; i < count; i++, sIdx++, aIdx++)
{
switches[sIdx] = true;
activations[aIdx] *= rand.NextGaussianDouble(1d, Math.Sqrt(dropoutP / (1d - dropoutP)));
}
}
}
/// <summary>
/// Gets the standard deviation for layer weights initialization from the normal distribution.
/// </summary>
/// <param name="numOfInputNodes">Number of layer input nodes.</param>
/// <param name="numOfLayerNeurons">Number of layer neurons.</param>
public virtual double GetNormalInitWeightsStdDev(int numOfInputNodes, int numOfLayerNeurons)
{
//He-initialization. This covers most of ReLU like activation functions
return Math.Sqrt(2d / numOfInputNodes);
}
/// <summary>
/// Creates a clone.
/// </summary>
/// <returns>Clone of this activation function.</returns>
public ActivationBase Clone()
{
return ActivationFactory.CreateActivationFn(ID);
}
}//ActivationBase
}//Namespace