MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
AccuracyLayer.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using MyCaffe.basecode;
6using MyCaffe.common;
7using MyCaffe.param;
8
9namespace MyCaffe.layers
10{
20 public class AccuracyLayer<T> : Layer<T>
21 {
22 int m_nLabelAxis;
23 int m_nOuterNum;
24 int m_nInnerNum;
25 int m_nTopK;
26 int? m_nIgnoreLabel = null;
27 Blob<T> m_blobNumsBuffer;
28 Blob<T> m_blobAccData;
29 bool m_bDirectLabels = false;
30 bool m_bEnableSimpleAccuracy = false;
31 bool m_bEnableLastElementOnly = false;
32
45 : base(cuda, log, p)
46 {
48 m_blobNumsBuffer = new Blob<T>(cuda, log, false);
49 m_blobAccData = new Blob<T>(cuda, log);
50 }
51
53 protected override void dispose()
54 {
55 m_blobNumsBuffer.Dispose();
56 base.dispose();
57 }
58
62 public override int ExactNumBottomBlobs
63 {
64 get { return 2; }
65 }
66
70 public override int MinTopBlobs
71 {
72 get { return 1; }
73 }
74
78 public override int MaxTopBlobs
79 {
80 get { return 2; }
81 }
82
88 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
89 {
90 m_bEnableSimpleAccuracy = m_param.accuracy_param.enable_simple_accuracy;
91 m_bEnableLastElementOnly = m_param.accuracy_param.enable_last_element_only;
92
93 if (!m_bEnableSimpleAccuracy && m_bEnableLastElementOnly)
94 m_log.WriteLine("WARNING: The accuracy layer currently only supports last element accuracy when using the simple accuracy.");
95
96 m_nTopK = (int)m_param.accuracy_param.top_k;
97 m_nIgnoreLabel = null;
99 {
100 if (m_bEnableSimpleAccuracy && m_param.accuracy_param.ignore_labels.Count > 1)
101 m_log.WriteLine("WARNING: The accuracy layer currently only supports a single ignore label.");
102 m_nIgnoreLabel = m_param.accuracy_param.ignore_labels[0];
103 }
104
105 if (m_bEnableSimpleAccuracy && m_nTopK > 1)
106 {
107 m_log.WriteLine("WARNING: The accuracy layer currently only supports top_k = 1 for simple accuracy.");
108 m_nTopK = 1;
109 }
110
111 m_bDirectLabels = false;
112 }
113
119 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
120 {
121 m_log.CHECK_LE(m_nTopK, colBottom[0].count() / colBottom[1].count(), "top_k must be less than or equal to the number of classes.");
122
123 m_nLabelAxis = colBottom[0].CanonicalAxisIndex(m_param.accuracy_param.axis);
124 m_nOuterNum = colBottom[0].count(0, m_nLabelAxis);
125 m_nInnerNum = colBottom[0].count(m_nLabelAxis + 1);
126 int nLabelDim = m_nOuterNum * m_nInnerNum;
127
128 if (m_param.accuracy_param.axis == 0 && nLabelDim == 1)
129 {
130 if (!m_bDirectLabels)
131 m_log.WriteLine("WARNING: Using direct label comparisons where a label is expected in each item (e.g. no Softmax used).");
132 m_bDirectLabels = true;
133 }
134 else
135 {
136 m_log.CHECK_EQ(m_nOuterNum * m_nInnerNum, colBottom[1].count(), "Number of labels must match number of predictions; e.g., if label axis = 1 and prediction shape is (N, C, H, W), label count (number of labels) must be N*H*W, with integer values in {0, 1, ..., C=1}.");
137 }
138
139 List<int> rgTopShape = new List<int>(); // Accuracy is a scalar; 0 axes.
140 colTop[0].Reshape(rgTopShape);
141 colTop[0].type = BLOB_TYPE.ACCURACY;
142
143 if (colTop.Count > 1)
144 {
145 // Per-class accuracy is a vector; 1 axes.
146 List<int> rgTopShapePerClass = new List<int>() { colBottom[0].shape(m_nLabelAxis) };
147 colTop[1].Reshape(rgTopShapePerClass);
148 m_blobNumsBuffer.Reshape(rgTopShapePerClass);
149 }
150
151 if (m_bEnableSimpleAccuracy)
152 m_blobAccData.Reshape(m_nOuterNum, 1, 1, 1);
153 }
154
182 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
183 {
184 // Currently using cpu version for gpu version fails in the auto tests.
185 if (m_bEnableSimpleAccuracy)
186 forward_gpu(colBottom, colTop);
187 else if (m_bDirectLabels)
188 forward_cpu_direct(colBottom, colTop);
189 else
190 forward_cpu(colBottom, colTop);
191 }
192
222 protected void forward_gpu(BlobCollection<T> colBottom, BlobCollection<T> colTop)
223 {
224 int nDim = colBottom[0].count() / m_nOuterNum;
225 int? nIgnoreLabel = null;
227 {
229 nIgnoreLabel = m_param.accuracy_param.ignore_labels[0];
231 m_log.WriteLine("WARNING: Only the first ignore label recognized when using the simple accuracy layer.");
232 }
233
234 m_cuda.accuracy_fwd(colBottom[0].count(), m_nOuterNum, nDim, colBottom[0].gpu_data, colBottom[1].gpu_data, m_blobAccData.mutable_gpu_data, m_blobAccData.mutable_gpu_diff, nIgnoreLabel, m_bEnableLastElementOnly, colBottom[0].num);
235
236 float fAccCount = m_cuda.asum_float(m_blobAccData.count(), m_blobAccData.gpu_data);
237 float fTotalCount = m_cuda.asum_float(m_blobAccData.count(), m_blobAccData.gpu_diff);
238 float fAccuracy = (fTotalCount == 0) ? 0 : fAccCount / fTotalCount;
239
240 colTop[0].SetData(fAccuracy, 0);
241 }
242
270 protected void forward_cpu(BlobCollection<T> colBottom, BlobCollection<T> colTop)
271 {
272 if (typeof(T) == typeof(double))
273 forward_cpuD(colBottom, colTop);
274 else
275 forward_cpuF(colBottom, colTop);
276 }
277
278 private void forward_cpuD(BlobCollection<T> colBottom, BlobCollection<T> colTop)
279 {
280 double dfAccuracy = 0;
281 double[] rgBottomData = convertD(colBottom[0].update_cpu_data());
282 double[] rgBottomLabel = convertD(colBottom[1].update_cpu_data());
283 int nDim = colBottom[0].count() / m_nOuterNum;
284 int nNumLabels = colBottom[0].shape(m_nLabelAxis);
285 double[] rgNumsBuffer = null;
286 double[] rgTopLabel = null;
287
288 if (colTop.Count > 1)
289 {
290 m_blobNumsBuffer.SetData(0.0);
291 colTop[1].SetData(0.0);
292 rgTopLabel = convertD(colTop[1].mutable_cpu_data);
293 rgNumsBuffer = convertD(m_blobNumsBuffer.update_cpu_data());
294 }
295
296 int nCount = 0;
297 bool bNanDetected = false;
298
299 for (int i = 0; i < m_nOuterNum; i++)
300 {
301 for (int j = 0; j < m_nInnerNum; j++)
302 {
303 int nLabelValue = (int)rgBottomLabel[i * m_nInnerNum + j];
304
305 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabelValue)
306 continue;
307
308 m_log.CHECK_GE(nLabelValue, 0, "The lable value must be >= 0.");
309 m_log.CHECK_LT(nLabelValue, nNumLabels, "The label value must be < " + nNumLabels.ToString() + ". Make sure that the prototxt 'num_outputs' setting is > the highest label number.");
310
311 if (colTop.Count > 1)
312 rgNumsBuffer[nLabelValue]++;
313
314 double prob_of_true_class = rgBottomData[i * nDim
315 + nLabelValue * m_nInnerNum
316 + j];
317 int num_better_predictions = -1; // true_class also counts as 'better'
318 // Top-k accuracy
319 for (int k = 0; k < nNumLabels && num_better_predictions < m_nTopK; k++)
320 {
321 double dfVal = rgBottomData[i * nDim + k * m_nInnerNum + j];
322
323 if (double.IsNaN(dfVal) || double.IsInfinity(dfVal))
324 bNanDetected = true;
325 else if (dfVal >= prob_of_true_class)
326 num_better_predictions += 1;
327 }
328
329 // Check if true label is in top_k predictions
330 if (num_better_predictions != -1 && num_better_predictions < m_nTopK)
331 {
332 dfAccuracy += 1.0;
333
334 if (colTop.Count > 1)
335 rgTopLabel[nLabelValue] += 1.0;
336 }
337
338 nCount++;
339 }
340 }
341
342 if (bNanDetected)
343 m_log.WriteLine("WARNING: NAN/INF detected in output!");
344
345 // m_log.WriteLine("Accuracy: " + dfAccuracy.ToString());
346 dfAccuracy = (nCount == 0) ? 0 : (dfAccuracy / nCount);
347 colTop[0].SetData(dfAccuracy, 0);
348 colTop[0].Tag = m_param.accuracy_param.top_k;
349
350 if (colTop.Count > 1)
351 {
352 for (int i = 0; i < colTop[1].count(); i++)
353 {
354 double dfVal = 0.0;
355
356 if (rgNumsBuffer[i] != 0)
357 dfVal = rgTopLabel[i] / rgNumsBuffer[i];
358
359 rgTopLabel[i] = dfVal;
360 }
361
362 colTop[1].mutable_cpu_data = convert(rgTopLabel);
363 }
364
365 // Accuracy layer should not be used as a loss function.
366 }
367
368 private void forward_cpuF(BlobCollection<T> colBottom, BlobCollection<T> colTop)
369 {
370 float dfAccuracy = 0;
371 float[] rgBottomData = convertF(colBottom[0].update_cpu_data());
372 float[] rgBottomLabel = convertF(colBottom[1].update_cpu_data());
373 int nDim = colBottom[0].count() / m_nOuterNum;
374 int nNumLabels = colBottom[0].shape(m_nLabelAxis);
375 float[] rgNumsBuffer = null;
376 float[] rgTopLabel = null;
377
378 if (colTop.Count > 1)
379 {
380 m_blobNumsBuffer.SetData(0.0);
381 colTop[1].SetData(0.0);
382 rgTopLabel = convertF(colTop[1].mutable_cpu_data);
383 rgNumsBuffer = convertF(m_blobNumsBuffer.update_cpu_data());
384 }
385
386 int nCount = 0;
387 bool bNanDetected = false;
388
389 for (int i = 0; i < m_nOuterNum; i++)
390 {
391 for (int j = 0; j < m_nInnerNum; j++)
392 {
393 int nLabelValue = (int)rgBottomLabel[i * m_nInnerNum + j];
394
395 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabelValue)
396 continue;
397
398 m_log.CHECK_GE(nLabelValue, 0, "The lable value must be >= 0.");
399 m_log.CHECK_LT(nLabelValue, nNumLabels, "The label value must be < " + nNumLabels.ToString() + ". Make sure that the prototxt 'num_outputs' setting is > the highest label number.");
400
401 if (colTop.Count > 1)
402 rgNumsBuffer[nLabelValue]++;
403
404 double prob_of_true_class = rgBottomData[i * nDim
405 + nLabelValue * m_nInnerNum
406 + j];
407 int num_better_predictions = -1; // true_class also counts as 'better'
408 // Top-k accuracy
409 for (int k = 0; k < nNumLabels && num_better_predictions < m_nTopK; k++)
410 {
411 double dfVal = rgBottomData[i * nDim + k * m_nInnerNum + j];
412
413 if (double.IsNaN(dfVal) || double.IsInfinity(dfVal))
414 bNanDetected = true;
415 else if (dfVal >= prob_of_true_class)
416 num_better_predictions += 1;
417 }
418
419 // Check if true label is in top_k predictions
420 if (num_better_predictions != -1 && num_better_predictions < m_nTopK)
421 {
422 dfAccuracy += 1.0f;
423
424 if (colTop.Count > 1)
425 rgTopLabel[nLabelValue] += 1.0f;
426 }
427
428 nCount++;
429 }
430 }
431
432 if (bNanDetected)
433 m_log.WriteLine("WARNING: NAN/INF detected in output!");
434
435 // m_log.WriteLine("Accuracy: " + dfAccuracy.ToString());
436 dfAccuracy = (nCount == 0) ? 0 : (dfAccuracy / nCount);
437 colTop[0].SetData(dfAccuracy, 0);
438 colTop[0].Tag = m_param.accuracy_param.top_k;
439
440 if (colTop.Count > 1)
441 {
442 for (int i = 0; i < colTop[1].count(); i++)
443 {
444 float dfVal = 0.0f;
445
446 if (rgNumsBuffer[i] != 0)
447 dfVal = rgTopLabel[i] / rgNumsBuffer[i];
448
449 rgTopLabel[i] = dfVal;
450 }
451
452 colTop[1].mutable_cpu_data = convert(rgTopLabel);
453 }
454
455 // Accuracy layer should not be used as a loss function.
456 }
457
483 {
484 double dfAccuracy = 0;
485 double[] rgBottomData = convertD(colBottom[0].update_cpu_data());
486 double[] rgBottomLabel = convertD(colBottom[1].update_cpu_data());
487 int nNumLabels = colBottom[0].num;
488 int nNumMatches = 0;
489 bool bNanDetected = false;
490
491 for (int i = 0; i < nNumLabels; i++)
492 {
493 double dfDiff = Math.Abs(rgBottomData[i] - rgBottomLabel[i]);
494 if (dfDiff < 0.00001)
495 nNumMatches++;
496 }
497
498 if (bNanDetected)
499 m_log.WriteLine("WARNING: NAN/INF detected in output!");
500
501 dfAccuracy = (double)nNumMatches / (double)nNumLabels;
502 colTop[0].SetData(dfAccuracy, 0);
503 colTop[0].Tag = m_param.accuracy_param.top_k;
504
505 if (colTop.Count > 1)
506 colTop[1].SetData(0);
507
508 // Accuracy layer should not be used as a loss function.
509 }
510
512 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
513 {
514 if (rgbPropagateDown[0])
515 throw new NotImplementedException();
516 }
517 }
518}
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_LE(double df1, double df2, string str)
Test whether one number is less than or equal to another.
Definition: Log.cs:263
void CHECK_GE(double df1, double df2, string str)
Test whether one number is greater than or equal to another.
Definition: Log.cs:287
void CHECK_LT(double df1, double df2, string str)
Test whether one number is less than another.
Definition: Log.cs:275
The BlobCollection contains a list of Blobs.
void SetData(double df)
Set all blob data to the value specified.
int Count
Returns the number of items in the collection.
void Reshape(int[] rgShape)
Reshapes all blobs in the collection to the given shape.
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_diff
Returns the diff GPU handle used by the CudaDnn connection.
Definition: Blob.cs:1555
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[] update_cpu_data()
Update the CPU data by transferring the GPU data over to the Host.
Definition: Blob.cs:1470
int count()
Returns the total number of items in the Blob.
Definition: Blob.cs:739
long gpu_diff
Returns the diff GPU handle used by the CudaDnn connection.
Definition: Blob.cs:1541
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
The AccuracyLayer computes the classification accuracy for a one-of-many classification task....
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Not implemented – AccuracyLayer cannot be used as a loss.
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.
void forward_gpu(BlobCollection< T > colBottom, BlobCollection< T > colTop)
The simple accuracy calculates the total accuracy across all predictions using an argmax comparison w...
void forward_cpu(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Forward compuation.
AccuracyLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
Constructor.
override int MaxTopBlobs
Returns the maximum number of top blobs: accuracy, labels
override int ExactNumBottomBlobs
Returns the number of bottom blobs used: predicted, label
void forward_cpu_direct(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Forward compuation.
override int MinTopBlobs
Returns the minimum number of top blobs: accuracy
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Forward compuation.
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
void convert(BlobCollection< T > col)
Convert a collection of blobs from / to half size.
Definition: Layer.cs:535
float convertF(T df)
Converts a generic to a float value.
Definition: Layer.cs:1359
double convertD(T df)
Converts a generic to a double value.
Definition: Layer.cs:1349
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
uint top_k
When computing accuracy, count as correct by comparing the true label to the top_k scoring classes....
List< int > ignore_labels
If specified, ignore instances with the given label(s).
int axis
The 'label' axis of the prediction blob, whos argmax corresponds to the predicted label – may be nega...
bool enable_simple_accuracy
Enables a simple accuracy calculation where the argmax is compared with the actual.
bool enable_last_element_only
When computing accuracy, only count the last element of the prediction blob.
Specifies the base parameter for all layers.
AccuracyParameter accuracy_param
Returns the parameter set when initialized with LayerType.ACCURACY
LayerType
Specifies the layer type.
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
BLOB_TYPE
Defines the tpe of data held by a given Blob.
Definition: Interfaces.cs:62
The MyCaffe.layers namespace contains all layers that have a solidified code base,...
Definition: LayerFactory.cs:15
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