MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
Normalization2Layer.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using MyCaffe.basecode;
6using MyCaffe.common;
7using MyCaffe.fillers;
8using MyCaffe.param;
9using MyCaffe.param.ssd;
10
11namespace MyCaffe.layers.ssd
12{
22 public class Normalization2Layer<T> : Layer<T>
23 {
24 Blob<T> m_blobNorm;
25 Blob<T> m_blobSumChannelMultiplier;
26 Blob<T> m_blobSumSpatialMultiplier;
27 Blob<T> m_blobBuffer;
28 Blob<T> m_blobBufferChannel;
29 Blob<T> m_blobBufferSpatial;
30 bool m_bAcrossSpatial;
31 bool m_bChannelShared;
32 float m_fEps;
33
47 : base(cuda, log, p)
48 {
49 m_type = LayerParameter.LayerType.NORMALIZATION2;
50 m_blobNorm = new Blob<T>(cuda, log, false);
51 m_blobNorm.Name = m_param.name + " norm";
52 m_blobSumChannelMultiplier = new Blob<T>(cuda, log, false);
53 m_blobSumChannelMultiplier.Name = m_param.name + " sum_chan_mult";
54 m_blobSumSpatialMultiplier = new Blob<T>(cuda, log, false);
55 m_blobSumSpatialMultiplier.Name = m_param.name + " sum_spat_mult";
56 m_blobBuffer = new Blob<T>(cuda, log, false);
57 m_blobBuffer.Name = m_param.name + " buffer";
58 m_blobBufferChannel = new Blob<T>(cuda, log, false);
59 m_blobBufferChannel.Name = m_param.name + " buffer_chan";
60 m_blobBufferSpatial = new Blob<T>(cuda, log, false);
61 m_blobBufferSpatial.Name = m_param.name + " buffer_spat";
62 }
63
65 protected override void dispose()
66 {
67 m_blobNorm.Dispose();
68 m_blobSumChannelMultiplier.Dispose();
69 m_blobSumSpatialMultiplier.Dispose();
70 m_blobBuffer.Dispose();
71 m_blobBufferChannel.Dispose();
72 m_blobBufferSpatial.Dispose();
73 base.dispose();
74 }
75
77 protected override void setup_internal_blobs(BlobCollection<T> col)
78 {
79 if (col.Count > 0)
80 return;
81
82 col.Add(m_blobNorm);
83 col.Add(m_blobSumChannelMultiplier);
84 col.Add(m_blobSumSpatialMultiplier);
85 col.Add(m_blobBuffer);
86 col.Add(m_blobBufferChannel);
87 col.Add(m_blobBufferSpatial);
88 }
89
93 public override int ExactNumBottomBlobs
94 {
95 get { return 1; }
96 }
97
101 public override int ExactNumTopBlobs
102 {
103 get { return 1; }
104 }
105
111 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
112 {
113 m_log.CHECK_GE(colBottom[0].num_axes, 2, "The bottom(0) must have >= 2 axes.");
114 m_blobBuffer.Reshape(1, colBottom[0].channels, colBottom[0].height, colBottom[0].width);
115 m_blobBufferChannel.Reshape(1, colBottom[0].channels, 1, 1);
116 m_blobBufferSpatial.Reshape(1, 1, colBottom[0].height, colBottom[0].width);
117
119 m_bAcrossSpatial = norm_param.across_spatial;
120
121 if (m_bAcrossSpatial)
122 m_blobNorm.Reshape(colBottom[0].num, 1, 1, 1);
123 else
124 m_blobNorm.Reshape(colBottom[0].num, 1, colBottom[0].height, colBottom[0].width);
125
126 m_fEps = norm_param.eps;
127
128 int nChannels = colBottom[0].channels;
129 int nSpatialDim = colBottom[0].width * colBottom[0].height;
130
131 m_blobSumChannelMultiplier.Reshape(1, nChannels, 1, 1);
132 m_blobSumChannelMultiplier.SetData(1);
133
134 m_blobSumSpatialMultiplier.Reshape(1, 1, colBottom[0].height, colBottom[0].width);
135 m_blobSumSpatialMultiplier.SetData(1);
136
137 m_bChannelShared = norm_param.channel_shared;
138
139 if (m_colBlobs.Count > 0)
140 {
141 m_log.WriteLine("Skipping parameter initialization.");
142 }
143 else
144 {
145 Blob<T> blobScale = new Blob<T>(m_cuda, m_log);
146 blobScale.Name = m_param.name + " scale";
147 List<int> rgShape = new List<int>();
148
149 if (!m_bChannelShared)
150 rgShape.Add(nChannels);
151
152 blobScale.Reshape(rgShape);
153 Filler<T> filler = Filler<T>.Create(m_cuda, m_log, norm_param.scale_filler);
154 filler.Fill(blobScale);
155
156 m_colBlobs.Add(blobScale);
157 }
158
159 if (m_bChannelShared)
160 m_log.CHECK_EQ(m_colBlobs[0].count(), 1, "Scale size is inconsistent with prototxt config.");
161 else
162 m_log.CHECK_EQ(m_colBlobs[0].count(), nChannels, "Scale size is inconsistent with prototxt config.");
163
164 m_rgbParamPropagateDown[0] = true;
165 }
166
172 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
173 {
174 m_log.CHECK_GE(colBottom[0].num_axes, 2, "Number of axes of bottom blob must be >= 2.");
175 colTop[0].ReshapeLike(colBottom[0]);
176 m_blobBuffer.Reshape(1, colBottom[0].channels, colBottom[0].height, colBottom[0].width);
177
178 if (!m_bAcrossSpatial)
179 m_blobNorm.Reshape(colBottom[0].num, 1, colBottom[0].height, colBottom[0].width);
180
181 int nSpatialDim = colBottom[0].height * colBottom[0].width;
182
183 if (nSpatialDim != m_blobSumSpatialMultiplier.count())
184 {
185 m_blobSumSpatialMultiplier.Reshape(1, 1, colBottom[0].height, colBottom[0].width);
186 m_blobSumSpatialMultiplier.SetData(1);
187 m_blobBufferSpatial.ReshapeLike(m_blobSumSpatialMultiplier);
188 }
189 }
190
198 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
199 {
200 long hBottomData = colBottom[0].gpu_data;
201 long hTopData = colTop[0].mutable_gpu_data;
202 long hBufferData = m_blobBuffer.mutable_gpu_data;
203 long hScale = 0;
204 long hSumChannelMultiplier = m_blobSumChannelMultiplier.gpu_data;
205 long hNormData = 0;
206 T[] rgNormData = null;
207 T[] rgScale = null;
208
209 if (m_bAcrossSpatial)
210 {
211 // Need to index it.
212 rgNormData = m_blobNorm.mutable_cpu_data;
213 }
214 else
215 {
216 hNormData = m_blobNorm.mutable_gpu_data;
217 // Add eps to avoid overflow.
218 m_blobNorm.SetData(m_fEps);
219 }
220
221 if (m_bChannelShared)
222 rgScale = m_colBlobs[0].mutable_cpu_data;
223 else
224 hScale = m_colBlobs[0].gpu_data;
225
226 int nNum = colBottom[0].num;
227 int nDim = colBottom[0].count() / nNum;
228 int nSpatialDim = colBottom[0].height * colBottom[0].width;
229 int nChannels = colBottom[0].channels;
230 int nNormDataOffset = 0;
231 int nBottomOffset = 0;
232 int nTopOffset = 0;
233
234 for (int n = 0; n < nNum; n++)
235 {
236 m_cuda.powx(nDim, hBottomData, 2.0, hBufferData, nBottomOffset, 0);
237
238 if (m_bAcrossSpatial)
239 {
240 double dfNormSqr = Utility.ConvertVal<T>(m_blobBuffer.asum_data());
241 dfNormSqr += m_fEps; // Add eps to avoid overflow.
242 double dfNorm = Math.Pow(dfNormSqr, 0.5);
243 m_cuda.scale(nDim, Utility.ConvertVal<T>(1.0 / dfNorm), hBottomData, hTopData, nBottomOffset, nTopOffset);
244 rgNormData[n] = Utility.ConvertVal<T>(dfNorm);
245 }
246 else
247 {
248 // compute norm
249 m_cuda.gemv(true, nChannels, nSpatialDim, m_tOne, hBufferData, hSumChannelMultiplier, m_tOne, hNormData, 0, 0, nNormDataOffset);
250 m_cuda.powx(nSpatialDim, hNormData, 0.5, hNormData, nNormDataOffset, nNormDataOffset);
251
252 // Scale the layer.
253 m_cuda.divbsx(nDim, hBottomData, nBottomOffset, hNormData, nNormDataOffset, nChannels, nSpatialDim, false, hTopData, nTopOffset);
254 nNormDataOffset += nSpatialDim;
255 }
256
257 // Scale the output
258 if (m_bChannelShared)
259 {
260 m_cuda.scal(nDim, rgScale[0], hTopData, nTopOffset);
261 }
262 else
263 {
264 m_cuda.mulbsx(nDim, hTopData, nTopOffset, hScale, 0, nChannels, nSpatialDim, true, hTopData, nTopOffset);
265 }
266
267 nBottomOffset += nDim;
268 nTopOffset += nDim;
269 }
270
271 if (rgNormData != null)
272 m_blobNorm.mutable_cpu_data = rgNormData;
273 }
274
283 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
284 {
285 long hTopDiff = colTop[0].gpu_diff;
286 long hTopData = colTop[0].gpu_data;
287 long hBottomData = colBottom[0].gpu_data;
288 long hBottomDiff = colBottom[0].mutable_gpu_diff;
289 long hBufferData = m_blobBuffer.mutable_gpu_data;
290 long hScale = 0;
291 long hBufferChannel = m_blobBufferChannel.mutable_gpu_data;
292 long hBufferSpatial = m_blobBufferSpatial.mutable_gpu_data;
293 long hSumChannelMultiplier = m_blobSumChannelMultiplier.gpu_data;
294 long hSumSpatialMultiplier = m_blobSumSpatialMultiplier.gpu_data;
295 long hNormData = 0;
296 double dfScale = 0;
297 double[] rgNormData = null;
298
299 if (m_bAcrossSpatial)
300 {
301 // Need to index it.
302 rgNormData = Utility.ConvertVec<T>(m_blobNorm.mutable_cpu_data);
303 }
304 else
305 {
306 hNormData = m_blobNorm.mutable_gpu_data;
307 }
308
309 if (m_bChannelShared)
310 dfScale = Utility.ConvertVal<T>(m_colBlobs[0].GetData(0));
311 else
312 hScale = m_colBlobs[0].mutable_gpu_data;
313
314 int nCount = colTop[0].count();
315 int nNum = colTop[0].num;
316 int nDim = nCount / nNum;
317 int nSpatialDim = colTop[0].height * colTop[0].width;
318 int nChannels = colTop[0].channels;
319
320 // Propagate to param
322 {
323 if (m_bChannelShared)
324 {
325 double dfScaleDiff = Utility.ConvertVal<T>(m_colBlobs[0].GetDiff(0));
326 double dfA = Utility.ConvertVal<T>(m_cuda.dot(nCount, hTopData, hTopDiff));
327
328 dfScaleDiff += (dfA / dfScale);
329 m_colBlobs[0].SetDiff(dfScaleDiff, 0);
330 }
331 else
332 {
333 long hScaleDiff = m_colBlobs[0].mutable_gpu_diff;
334
335 for (int n = 0; n < nNum; n++)
336 {
337 // Compute A
338 m_cuda.mul(nDim, hTopData, hTopDiff, hBufferData, n * nDim, n * nDim, 0);
339 m_cuda.gemv(false, nChannels, nSpatialDim, m_tOne, hBufferData, hSumSpatialMultiplier, m_tZero, hBufferChannel);
340
341 // Store A / scale[i] in bufferdata temporarily.
342 m_cuda.div(nChannels, hBufferChannel, hScale, hBufferChannel);
343 m_cuda.add(nChannels, hBufferChannel, hScaleDiff, hScaleDiff);
344 }
345 }
346 }
347
348 // Propagate to bottom
349 if (rgbPropagateDown[0])
350 {
351 int nBottomDataOffset = 0;
352 int nBottomDiffOffset = 0;
353 int nTopDiffOffset = 0;
354 int nNormDataOffset = 0;
355
356 for (int n = 0; n < nNum; n++)
357 {
358 if (m_bAcrossSpatial)
359 {
360 double dfA = Utility.ConvertVal<T>(m_cuda.dot(nDim, hBottomData, hTopDiff, nBottomDataOffset, nTopDiffOffset));
361 double dfScale1 = dfA / rgNormData[n] / rgNormData[n];
362 m_cuda.scale(nDim, Utility.ConvertVal<T>(dfScale1), hBottomData, hBottomDiff, nBottomDataOffset, nBottomDiffOffset);
363 m_cuda.sub(nDim, hTopDiff, hBottomDiff, hBottomDiff, nTopDiffOffset, nBottomDiffOffset, nBottomDiffOffset);
364
365 dfScale1 = 1.0 / rgNormData[n];
366 m_cuda.scale(nDim, Utility.ConvertVal<T>(dfScale1), hBottomDiff, hBottomDiff, nBottomDiffOffset, nBottomDiffOffset);
367 }
368 else
369 {
370 // dot product between bottom_data and top_diff
371 m_cuda.mul(nDim, hBottomData, hTopDiff, hBufferData, nBottomDataOffset, nTopDiffOffset, 0);
372 m_cuda.gemv(true, nChannels, nSpatialDim, m_tOne, hBufferData, hSumChannelMultiplier, m_tZero, hBufferSpatial);
373
374 // scale bottom diff
375 m_cuda.mulbsx(nDim, hBottomData, nBottomDataOffset, hBufferSpatial, 0, nChannels, nSpatialDim, false, hBottomDiff, nBottomDiffOffset);
376
377 // divide by square of norm
378 m_cuda.powx(nSpatialDim, hNormData, 2.0, hBufferSpatial);
379 m_cuda.divbsx(nDim, hBottomDiff, nBottomDiffOffset, hBufferSpatial, 0, nChannels, nSpatialDim, false, hBottomDiff, nBottomDiffOffset);
380 m_cuda.sub(nDim, hTopDiff, hBottomDiff, hBottomDiff, nTopDiffOffset, nBottomDiffOffset, nBottomDiffOffset);
381
382 // divide by norm
383 m_cuda.divbsx(nDim, hBottomDiff, nBottomDiffOffset, hNormData, nNormDataOffset, nChannels, nSpatialDim, false, hBottomDiff, nBottomDiffOffset);
384 nNormDataOffset += nSpatialDim;
385 }
386
387 // Scale the diff
388 if (m_bChannelShared)
389 m_cuda.scal(nDim, dfScale, hBottomDiff, nBottomDiffOffset);
390 else
391 m_cuda.mulbsx(nDim, hBottomDiff, nBottomDiffOffset, hScale, 0, nChannels, nSpatialDim, true, hBottomDiff, nBottomDiffOffset);
392
393 nBottomDataOffset += nDim;
394 nBottomDiffOffset += nDim;
395 nTopDiffOffset += nDim;
396 }
397 }
398 }
399 }
400}
The Log class provides general output in text form.
Definition: Log.cs:13
void WriteLine(string str, bool bOverrideEnabled=false, bool bHeader=false, bool bError=false, bool bDisable=false)
Write a line of output.
Definition: Log.cs:80
void CHECK_EQ(double df1, double df2, string str)
Test whether one number is equal to another.
Definition: Log.cs:239
void CHECK_GE(double df1, double df2, string str)
Test whether one number is greater than or equal to another.
Definition: Log.cs:287
The Utility class provides general utility funtions.
Definition: Utility.cs:35
static double[] ConvertVec(float[] rgf)
Convert an array of float to an array of generics.
Definition: Utility.cs:550
The BlobCollection contains a list of Blobs.
void Add(Blob< T > b)
Add a new Blob to the collection.
int Count
Returns the number of items in the collection.
void ReshapeLike(BlobCollection< T > src)
Reshapes all blobs in the collection to the sizes of the source.
The Blob is the main holder of data that moves through the Layers of the Net.
Definition: Blob.cs:25
void SetData(T[] rgData, int nCount=-1, bool bSetCount=true)
Sets a number of items within the Blob's data.
Definition: Blob.cs:1922
long mutable_gpu_data
Returns the data GPU handle used by the CudaDnn connection.
Definition: Blob.cs:1487
void Reshape(int nNum, int nChannels, int nHeight, int nWidth, bool? bUseHalfSize=null)
DEPRECIATED; use
Definition: Blob.cs:442
T asum_data()
Compute the sum of absolute values (L1 norm) of the data.
Definition: Blob.cs:1706
int count()
Returns the total number of items in the Blob.
Definition: Blob.cs:739
void ReshapeLike(Blob< T > b, bool? bUseHalfSize=null)
Reshape this Blob to have the same shape as another Blob.
Definition: Blob.cs:648
string Name
Get/set the name of the Blob.
Definition: Blob.cs:2184
virtual void Dispose(bool bDisposing)
Releases all resources used by the Blob (including both GPU and Host).
Definition: Blob.cs:402
long gpu_data
Returns the data GPU handle used by the CudaDnn connection.
Definition: Blob.cs:1479
The CudaDnn object is the main interface to the Low-Level Cuda C++ DLL.
Definition: CudaDnn.cs:969
Abstract Filler class used to fill blobs with values.
Definition: Filler.cs:19
void Fill(Blob< T > b)
Fill the blob with values based on the actual filler used.
Definition: Filler.cs:50
static Filler< T > Create(CudaDnn< T > cuda, Log log, FillerParameter p)
Create a new Filler instance.
Definition: Filler.cs:79
An interface for the units of computation which can be composed into a Net.
Definition: Layer.cs:31
Log m_log
Specifies the Log for output.
Definition: Layer.cs:43
LayerParameter m_param
Specifies the LayerParameter describing the Layer.
Definition: Layer.cs:47
T m_tZero
Specifies a generic type equal to 0.0.
Definition: Layer.cs:76
T m_tOne
Specifies a generic type equal to 1.0.
Definition: Layer.cs:72
CudaDnn< T > m_cuda
Specifies the CudaDnn connection to Cuda.
Definition: Layer.cs:39
LayerParameter.LayerType m_type
Specifies the Layer type.
Definition: Layer.cs:35
LayerParameter layer_param
Returns the LayerParameter for this Layer.
Definition: Layer.cs:899
BlobCollection< T > m_colBlobs
Specifies the learnable parameter Blobs of the Layer.
Definition: Layer.cs:55
DictionaryMap< bool > m_rgbParamPropagateDown
Specifies whether or not to compute the learnable diff of each parameter Blob.
Definition: Layer.cs:63
The Normalization2Layer performs normalization used by the SSD algorithm. This layer is initialized w...
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
override void LayerSetUp(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Setup the layer.
override void dispose()
Releases all GPU and host resources used by the Layer.
override int ExactNumBottomBlobs
Returns the exact number of required bottom (input) Blobs: data
override int ExactNumTopBlobs
Returns the exact number of required top (output) Blobs: norm
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t the inputs.
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation.
override void setup_internal_blobs(BlobCollection< T > col)
Derivative layers should add all internal blobws to the 'col' provided.
Normalization2Layer(CudaDnn< T > cuda, Log log, LayerParameter p)
The Normalization2Layer constructor.
Specifies the base parameter for all layers.
Normalization2Parameter normalization2_param
Returns the parameter set when initialized with LayerType.NORMALIZATION2
string name
Specifies the name of this LayerParameter.
LayerType
Specifies the layer type.
Specifies the parameters for the Normalization2Layer used in SSD.
float eps
Specifies the epsilon for not dividing by zero while normalizing variance.
FillerParameter scale_filler
Specifies the filler for the initial value of scale, default is 1.0 for all.
bool channel_shared
Specifies whether or not the scale parameters are shared across channels.
bool across_spatial
Specifies to normalize across the spatial dimensions.
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
Definition: Annotation.cs:12
The MyCaffe.common namespace contains common MyCaffe classes.
Definition: BatchInput.cs:8
The MyCaffe.fillers namespace contains all fillers including the Filler class.
The MyCaffe.layers.ssd namespace contains all Single-Shot MultiBox (SSD) related layers.
Definition: LayerFactory.cs:19
The MyCaffe.param.ssd namespace contains all SSD related parameter objects that correspond to the nat...
The MyCaffe.param namespace contains parameters used to create models.
The MyCaffe namespace contains the main body of MyCaffe code that closesly tracks the C++ Caffe open-...
Definition: Annotation.cs:12