MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
InfogainLossLayer.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{
24 public class InfogainLossLayer<T> : LossLayer<T>
25 {
26 // The internal SoftmaxLayer used to map predictions to a distribution.
27 SoftmaxLayer<T> m_softmaxLayer;
28 // Stores the output probability preductions from the SoftmaxLayer.
29 Blob<T> m_blobProb = null;
30 // Bottom vector holder used in the call to the underlying SoftmaxLayer::Forward
31 BlobCollection<T> m_colSoftmaxBottomVec = new BlobCollection<T>();
32 // Top vector holder used in the call to the underlying SoftmaxLayer::Forward
33 BlobCollection<T> m_colSoftmaxTopVec = new BlobCollection<T>();
34 // The infogain blob.
35 Blob<T> m_blobInfoGain = null;
36 // Cache holding the rows sums of H.
37 Blob<T> m_blobSumRowsOfH = null;
38 // The optional lable indicating that an instance should be ignored.
39 int? m_nIgnoreLabel = null;
40 int m_nInfogainAxis = 0;
41 int m_nNumLabels = 0;
42
57 : base(cuda, log, p)
58 {
59 m_type = LayerParameter.LayerType.INFOGAIN_LOSS;
60
61 m_blobProb = new Blob<T>(m_cuda, m_log);
62 m_blobProb.Name = m_param.name + " prob";
63 m_blobInfoGain = new Blob<T>(m_cuda, m_log);
64 m_blobInfoGain.Name = m_param.name + " infogain";
65 m_blobSumRowsOfH = new Blob<T>(m_cuda, m_log);
66 m_blobSumRowsOfH.Name = m_param.name + " sum rows of H";
67 }
68
70 protected override void dispose()
71 {
72 base.dispose();
73
74 if (m_blobInfoGain != null)
75 {
76 m_blobInfoGain.Dispose();
77 m_blobInfoGain = null;
78 }
79
80 if (m_blobProb != null)
81 {
82 m_blobProb.Dispose();
83 m_blobProb = null;
84 }
85
86 if (m_blobSumRowsOfH != null)
87 {
88 m_blobSumRowsOfH.Dispose();
89 m_blobSumRowsOfH = null;
90 }
91 }
92
94 protected override void setup_internal_blobs(BlobCollection<T> col)
95 {
96 if (col.Count > 0)
97 return;
98
99 col.Add(m_blobInfoGain);
100 col.Add(m_blobProb);
101 col.Add(m_blobSumRowsOfH);
102 }
103
109 public override int ExactNumBottomBlobs
110 {
111 get { return -1; }
112 }
113
117 public override int MinBottomBlobs
118 {
119 get { return 2; }
120 }
121
125 public override int MaxBottomBlobs
126 {
127 get { return 3; }
128 }
129
134 public override int ExactNumTopBlobs
135 {
136 get { return -1; }
137 }
138
142 public override int MinTopBlobs
143 {
144 get { return 1; }
145 }
146
150 public override int MaxTopBlobs
151 {
152 get { return 2; }
153 }
154
159 protected virtual void sum_rows_of_H(Blob<T> blobH)
160 {
161 m_log.CHECK_EQ(blobH.count(), m_nNumLabels * m_nNumLabels, "H must be " + m_nNumLabels.ToString() + " x " + m_nNumLabels.ToString());
162 float[] rgInfogainMat = convertF(blobH.update_cpu_data());
163 float[] rgSum = convertF(m_blobSumRowsOfH.mutable_cpu_data);
164
165 for (int row = 0; row < m_nNumLabels; row++)
166 {
167 rgSum[row] = 0;
168
169 for (int col = 0; col < m_nNumLabels; col++)
170 {
171 rgSum[row] += rgInfogainMat[row * m_nNumLabels + col];
172 }
173 }
174
175 m_blobSumRowsOfH.mutable_cpu_data = convert(rgSum);
176 }
177
183 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
184 {
185 base.LayerSetUp(colBottom, colTop);
186
187 // Internal softmax layer.
188 LayerParameter softmax_param = new LayerParameter(LayerParameter.LayerType.SOFTMAX);
190 softmax_param.loss_weight.Clear();
191 softmax_param.loss_weight.Add(1);
192 m_softmaxLayer = new SoftmaxLayer<T>(m_cuda, m_log, softmax_param);
193 m_colSoftmaxBottomVec.Clear();
194 m_colSoftmaxBottomVec.Add(colBottom[0]);
195 m_colSoftmaxTopVec.Clear();
196 m_colSoftmaxTopVec.Add(m_blobProb);
197 m_softmaxLayer.Setup(m_colSoftmaxBottomVec, m_colSoftmaxTopVec);
198
199 // ignore label.
200 m_nIgnoreLabel = m_param.loss_param.ignore_label;
201
202 // matrix H
203 if (colBottom.Count < 3)
204 {
205 m_log.CHECK(m_param.infogain_loss_param.source != null, "Infogain matrix source must be specified.");
206 PersistCaffe<T> persist = new PersistCaffe<T>(m_log, true);
208 m_blobInfoGain.FromProto(blobProto);
209 }
210 }
211
217 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
218 {
219 base.Reshape(colBottom, colTop);
220
221 m_softmaxLayer.Reshape(m_colSoftmaxBottomVec, m_colSoftmaxTopVec);
222 m_nInfogainAxis = colBottom[0].CanonicalAxisIndex(m_param.infogain_loss_param.axis);
223 m_nOuterNum = colBottom[0].count(0, m_nInfogainAxis);
224 m_nInnerNum = colBottom[0].count(m_nInfogainAxis + 1);
225
226 m_log.CHECK_EQ(m_nOuterNum * m_nInnerNum, colBottom[1].count(), "Number of labels must match the number of predictions; e.g., if infogain_axis == 1 and predictions shape is (N, C, H, W), label count (number of labels) must be N*H*W, with integer values in {0, 1, ..., C-1}.");
227 m_nNumLabels = colBottom[0].shape(m_nInfogainAxis);
228
229 Blob<T> blobInfoGain = null;
230
231 if (colBottom.Count < 3)
232 blobInfoGain = m_blobInfoGain;
233 else
234 blobInfoGain = colBottom[2];
235
236 m_log.CHECK_EQ(blobInfoGain.count(), m_nNumLabels * m_nNumLabels, "The infogain count must equal 'num_labels' * 'num_labels'.");
237 m_blobSumRowsOfH.Reshape(new List<int>() { m_nNumLabels });
238 if (colBottom.Count == 2)
239 {
240 // H is provided as a parameter and will not change. Sum rows once.
241 sum_rows_of_H(blobInfoGain);
242 }
243 if (colTop.Count >= 2)
244 {
245 // softmax output.
246 colTop[1].ReshapeLike(colBottom[0]);
247 }
248 }
249
280 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
281 {
282 // The forward pass computes the softmax prob values.
283 m_softmaxLayer.Forward(m_colSoftmaxBottomVec, m_colSoftmaxTopVec);
284
285 Blob<T> blobInfoGain = (colBottom.Count < 3) ? m_blobInfoGain : colBottom[2];
286 int nCount = 0;
287 int nLabel = -1;
288 double dfLoss = 0;
289 double dfProb = 0;
290 double dfProbLog = 0;
291 double dfVal;
292
293 if (typeof(T) == typeof(double))
294 {
295 double[] rgProbData = (double[])Convert.ChangeType(m_blobProb.update_cpu_data(), typeof(double[]));
296 double[] rgBottomLabel = (double[])Convert.ChangeType(colBottom[1].update_cpu_data(), typeof(double[]));
297 double[] rgInfoGainMat = (double[])Convert.ChangeType(blobInfoGain.update_cpu_data(), typeof(double[]));
298
299 for (int i = 0; i < m_nOuterNum; i++)
300 {
301 for (int j = 0; j < m_nInnerNum; j++)
302 {
303 nLabel = (int)rgBottomLabel[i * m_nInnerNum + j];
304 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabel)
305 continue;
306
307 m_log.CHECK_GE(nLabel, 0, "The label should be greater than or equal to 0.");
308 m_log.CHECK_LT(nLabel, m_nNumLabels, "The label should be less than the number of labels '" + m_nNumLabels.ToString() + "'");
309
310 for (int l = 0; l < m_nNumLabels; l++)
311 {
312 dfProb = Math.Max(rgProbData[i * m_nInnerNum * m_nNumLabels + l * m_nInnerNum + j], kLOG_THRESHOLD);
313 dfProbLog = Math.Log(dfProb);
314 dfVal = rgInfoGainMat[nLabel * m_nNumLabels + l] * dfProbLog;
315 dfLoss -= dfVal;
316 }
317
318 nCount++;
319 }
320 }
321 }
322 else
323 {
324 float[] rgProbData = (float[])Convert.ChangeType(m_blobProb.update_cpu_data(), typeof(float[]));
325 float[] rgBottomLabel = (float[])Convert.ChangeType(colBottom[1].update_cpu_data(), typeof(float[]));
326 float[] rgInfoGainMat = (float[])Convert.ChangeType(blobInfoGain.update_cpu_data(), typeof(float[]));
327
328 for (int i = 0; i < m_nOuterNum; i++)
329 {
330 for (int j = 0; j < m_nInnerNum; j++)
331 {
332 nLabel = (int)rgBottomLabel[i * m_nInnerNum + j];
333 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabel)
334 continue;
335
336 m_log.CHECK_GE(nLabel, 0, "The label should be greater than or equal to 0.");
337 m_log.CHECK_LT(nLabel, m_nNumLabels, "The label should be less than the number of labels '" + m_nNumLabels.ToString() + "'");
338
339 for (int l = 0; l < m_nNumLabels; l++)
340 {
341 dfProb = Math.Max(rgProbData[i * m_nInnerNum * m_nNumLabels + l * m_nInnerNum + j], kLOG_THRESHOLD);
342 dfProbLog = Math.Log(dfProb);
343 dfVal = rgInfoGainMat[nLabel * m_nNumLabels + l] * dfProbLog;
344 dfLoss -= dfVal;
345 }
346
347 nCount++;
348 }
349 }
350 }
351
352 double dfNormalizer = get_normalizer(m_normalization, nCount);
353 double dfNormalizedLoss = dfLoss / dfNormalizer;
354 colTop[0].SetData(dfNormalizedLoss, 0);
355
356 if (colTop.Count == 2)
357 colTop[1].ShareData(m_blobProb);
358 }
359
393 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
394 {
395 if (rgbPropagateDown[1])
396 m_log.FAIL(type.ToString() + " Layer cannot backpropagate to label inputs.");
397
398 if (rgbPropagateDown.Count > 2 && rgbPropagateDown[2])
399 m_log.FAIL(type.ToString() + " Layer cannot backpropagate to infogain inputs.");
400
401 if (rgbPropagateDown[0])
402 {
403 Blob<T> blobInfoGainMat = m_blobInfoGain;
404 int nDim = colBottom[0].count() / m_nOuterNum;
405 int nCount = 0;
406 int nLabelValue = 0;
407
408 if (colBottom.Count >= 3)
409 {
410 blobInfoGainMat = colBottom[2];
411 // H is provided as a 'bottom' and might change so sum rows every time.
412 sum_rows_of_H(colBottom[2]);
413 }
414
415 if (typeof(T) == typeof(double))
416 {
417 double[] rgProbData = (double[])Convert.ChangeType(m_blobProb.update_cpu_data(), typeof(double[]));
418 double[] rgBottomLabel = (double[])Convert.ChangeType(colBottom[1].update_cpu_data(), typeof(double[]));
419 double[] rgInfoGainMat = (double[])Convert.ChangeType(blobInfoGainMat.update_cpu_data(), typeof(double[]));
420 double[] rgSumsRowsH = (double[])Convert.ChangeType(m_blobSumRowsOfH.update_cpu_data(), typeof(double[]));
421 double[] rgBottomDiff = (double[])Convert.ChangeType(colBottom[0].mutable_cpu_diff, typeof(double[]));
422
423 for (int i=0; i<m_nOuterNum; i++)
424 {
425 for (int j=0; j<m_nInnerNum; j++)
426 {
427 nLabelValue = (int)rgBottomLabel[i * m_nInnerNum + j];
428
429 m_log.CHECK_GE(nLabelValue, 0, "The label should be greater than or equal to 0.");
430 m_log.CHECK_LT(nLabelValue, m_nNumLabels, "The label should be less than the number of labels '" + m_nNumLabels.ToString() + "'");
431
432 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabelValue)
433 {
434 for (int l = 0; l < m_nNumLabels; l++)
435 {
436 rgBottomDiff[i * nDim + l * m_nInnerNum + j] = 0;
437 }
438 }
439 else
440 {
441 for (int l = 0; l < m_nNumLabels; l++)
442 {
443 int nIdx = i * nDim + l * m_nInnerNum + j;
444 rgBottomDiff[nIdx] = rgProbData[nIdx] * rgSumsRowsH[nLabelValue] - rgInfoGainMat[nLabelValue * m_nNumLabels + l];
445 }
446
447 nCount++;
448 }
449 }
450 }
451
452 colBottom[0].mutable_cpu_diff = convert(rgBottomDiff);
453 }
454 else
455 {
456 float[] rgProbData = (float[])Convert.ChangeType(m_blobProb.update_cpu_data(), typeof(float[]));
457 float[] rgBottomLabel = (float[])Convert.ChangeType(colBottom[1].update_cpu_data(), typeof(float[]));
458 float[] rgInfoGainMat = (float[])Convert.ChangeType(blobInfoGainMat.update_cpu_data(), typeof(float[]));
459 float[] rgSumsRowsH = (float[])Convert.ChangeType(m_blobSumRowsOfH.update_cpu_data(), typeof(float[]));
460 float[] rgBottomDiff = (float[])Convert.ChangeType(colBottom[0].mutable_cpu_diff, typeof(float[]));
461
462 for (int i = 0; i < m_nOuterNum; i++)
463 {
464 for (int j = 0; j < m_nInnerNum; j++)
465 {
466 nLabelValue = (int)rgBottomLabel[i * m_nInnerNum + j];
467
468 m_log.CHECK_GE(nLabelValue, 0, "The label should be greater than or equal to 0.");
469 m_log.CHECK_LT(nLabelValue, m_nNumLabels, "The label should be less than the number of labels '" + m_nNumLabels.ToString() + "'");
470
471 if (m_nIgnoreLabel.HasValue && m_nIgnoreLabel.Value == nLabelValue)
472 {
473 for (int l = 0; l < m_nNumLabels; l++)
474 {
475 rgBottomDiff[i * nDim + l * m_nInnerNum + j] = 0;
476 }
477 }
478 else
479 {
480 for (int l = 0; l < m_nNumLabels; l++)
481 {
482 int nIdx = i * nDim + l * m_nInnerNum + j;
483 rgBottomDiff[nIdx] = rgProbData[nIdx] * rgSumsRowsH[nLabelValue] - rgInfoGainMat[nLabelValue * m_nNumLabels + l];
484 }
485
486 nCount++;
487 }
488 }
489 }
490
491 colBottom[0].mutable_cpu_diff = convert(rgBottomDiff);
492 }
493
494 // Scale the gradient
495 double dfNormalizer = get_normalizer(m_normalization, nCount);
496 double dfLossWeight = convertD(colTop[0].GetDiff(0)) / dfNormalizer;
497 m_cuda.scal(colBottom[0].count(), dfLossWeight, colBottom[0].mutable_gpu_diff);
498 }
499 }
500 }
501}
The Log class provides general output in text form.
Definition: Log.cs:13
void CHECK(bool b, string str)
Test a flag for true.
Definition: Log.cs:227
void FAIL(string str)
Causes a failure which throws an exception with the desciptive text.
Definition: Log.cs:394
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
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 Add(Blob< T > b)
Add a new Blob to the collection.
void SetData(double df)
Set all blob data to the value specified.
int Count
Returns the number of items in the collection.
void Clear(bool bDispose=false)
Remove all items from 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
T[] mutable_cpu_data
Get data from the GPU and bring it over to the host, or Set data from the Host and send it over to th...
Definition: Blob.cs:1461
void Reshape(int nNum, int nChannels, int nHeight, int nWidth, bool? bUseHalfSize=null)
DEPRECIATED; use
Definition: Blob.cs:442
void FromProto(BlobProto bp, bool bReshape=true)
Create a new Blob from a given BlobProto.
Definition: Blob.cs:1589
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
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
The CudaDnn object is the main interface to the Low-Level Cuda C++ DLL.
Definition: CudaDnn.cs:969
The PersistCaffe class is used to load and save weight files in the .caffemodel format.
Definition: PersistCaffe.cs:20
BlobProto LoadBlobProto(byte[] rg, int nFieldId)
The LoadBlobProto function loads a BlobProto from a proto buffer.
The InforgainLossLayer is a generalization of SoftmaxWithLossLayer that takes an 'information gain' (...
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the infogain loss error gradient w.r.t the predictions.
override int ExactNumBottomBlobs
InfogainLossLayer takes 2-3 bottom blobs; if there are 3 the third should be the infogain matrix....
virtual void sum_rows_of_H(Blob< T > blobH)
Fill m_blobSumRowsOfH according to matrix H.
override void setup_internal_blobs(BlobCollection< T > col)
Derivative layers should add all internal blobws to the 'col' provided.
override int MaxBottomBlobs
Returns the maximum number of required bottom (intput) Blobs: pred, label, matrix
override int MaxTopBlobs
Returns the maximum number of requried top (output) Blobs: infogain, softmax
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 MinBottomBlobs
Returns the minimum number of required bottom (intput) Blobs: pred, label
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
The forward computation.
override int MinTopBlobs
Returns the minimum number of required top (output) Blobs: infogain
InfogainLossLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
The InfogainLossLayer constructor.
override int ExactNumTopBlobs
InfogainLossLayer computes softmax probability internally. optional second 'top' outputs the sofmax p...
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
LayerParameter.LayerType type
Returns the LayerType of this Layer.
Definition: Layer.cs:927
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
The LossLayer provides an interface for Layer's that take two blobs as input – usually (1) prediction...
Definition: LossLayer.cs:23
const double kLOG_THRESHOLD
Specifies the minimum threshold for loss values.
Definition: LossLayer.cs:27
int m_nOuterNum
Specifies the outer num, such as the batch count (e.g. count(0, axis)). Each derivative class must se...
Definition: LossLayer.cs:39
int m_nInnerNum
Specifies the inner num, such as the channel + height + width (e.g. count(axis + 1))....
Definition: LossLayer.cs:43
virtual double get_normalizer(LossParameter.NormalizationMode normalization_mode, int nValidCount)
Returns the normalizer used to normalize the loss.
Definition: LossLayer.cs:92
LossParameter.NormalizationMode m_normalization
Specifies the normalization mode used to normalize the loss.
Definition: LossLayer.cs:35
The SoftmaxLayer computes the softmax function. This layer is initialized with the MyCaffe....
Definition: SoftmaxLayer.cs:24
The BlobProto contains the descripion of a blob.
Definition: BlobProto.cs:15
string source
Specifies the infogain matrix source.
int axis
[optional, default = 1] Specifies the axis of the probability.
Specifies the base parameter for all layers.
string name
Specifies the name of this LayerParameter.
List< double > loss_weight
Specifies the loss weight.
SoftmaxParameter softmax_param
Returns the parameter set when initialized with LayerType.SOFTMAX
LayerType
Specifies the layer type.
override string ToString()
Returns a string representation of the LayerParameter.
InfogainLossParameter infogain_loss_param
Returns the parameter set when initialized with LayerType.INFOGAIN_LOSS
LossParameter loss_param
Returns the parameter set when initialized with LayerType.LOSS
int? ignore_label
If specified, the ignore instances with the given label.
int axis
The axis along which to perform the softmax – may be negative to index from the end (e....
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.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