MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
TripletLossLayer.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using MyCaffe.basecode;
6using MyCaffe.common;
7using MyCaffe.param;
8
10{
41 public class TripletLossLayer<T> : LossLayer<T>
42 {
43 Blob<T> m_blobDiffAP;
44 Blob<T> m_blobDiffSqAP;
45 Blob<T> m_blobDistSqAP;
46 Blob<T> m_blobDiffAN;
47 Blob<T> m_blobDiffSqAN;
48 Blob<T> m_blobDistSqAN;
49 Blob<T> m_blobDiffPN;
50 Blob<T> m_blobSumVec;
51 Blob<T> m_blobLossVec;
52 Blob<T> m_blobWork;
53 Blob<T> m_blobPreGenTargetsPos;
54 Blob<T> m_blobPreGenTargetsNeg;
55 double m_dfAlpha;
56
65 : base(cuda, log, p)
66 {
67 m_type = LayerParameter.LayerType.TRIPLET_LOSS;
68
69 m_blobDiffAP = new Blob<T>(m_cuda, m_log);
70 m_blobDiffAP.Name = m_param.name + ".positive delta";
71
72 m_blobDiffSqAP = new Blob<T>(m_cuda, m_log, false);
73 m_blobDiffSqAP.Name = m_param.name + ".positive delta sq";
74
75 m_blobDistSqAP = new Blob<T>(m_cuda, m_log, false);
76 m_blobDistSqAP.Name = m_param.name + ".positive dist sq";
77
78 m_blobDiffAN = new Blob<T>(m_cuda, m_log);
79 m_blobDiffAN.Name = m_param.name + ".negative delta";
80
81 m_blobDiffSqAN = new Blob<T>(m_cuda, m_log, false);
82 m_blobDiffSqAN.Name = m_param.name + ".negative delta sq";
83
84 m_blobDistSqAN = new Blob<T>(m_cuda, m_log, false);
85 m_blobDistSqAN.Name = m_param.name + ".negative dist sq";
86
87 m_blobDiffPN = new Blob<T>(m_cuda, m_log);
88 m_blobDiffPN.Name = m_param.name + ".pos/neg delta";
89
90 m_blobSumVec = new Blob<T>(m_cuda, m_log, false);
91 m_blobSumVec.Name = m_param.name + ".summer vec";
92
93 m_blobLossVec = new Blob<T>(m_cuda, m_log, false);
94 m_blobLossVec.Name = m_param.name + ".loss vec";
95
96 m_blobWork = new Blob<T>(m_cuda, m_log);
97 m_blobWork.Name = m_param.name + ".work";
98 }
99
101 protected override void dispose()
102 {
103 if (m_blobDiffAP != null)
104 {
105 m_blobDiffAP.Dispose();
106 m_blobDiffAP = null;
107 }
108
109 if (m_blobDiffSqAP != null)
110 {
111 m_blobDiffSqAP.Dispose();
112 m_blobDiffSqAP = null;
113 }
114
115 if (m_blobDistSqAP != null)
116 {
117 m_blobDistSqAP.Dispose();
118 m_blobDistSqAP = null;
119 }
120
121 if (m_blobDiffAN != null)
122 {
123 m_blobDiffAN.Dispose();
124 m_blobDiffAN = null;
125 }
126
127 if (m_blobDiffSqAN != null)
128 {
129 m_blobDiffSqAN.Dispose();
130 m_blobDiffSqAN = null;
131 }
132
133 if (m_blobDistSqAN != null)
134 {
135 m_blobDistSqAN.Dispose();
136 m_blobDistSqAN = null;
137 }
138
139 if (m_blobDiffPN != null)
140 {
141 m_blobDiffPN.Dispose();
142 m_blobDiffPN = null;
143 }
144
145 if (m_blobSumVec != null)
146 {
147 m_blobSumVec.Dispose();
148 m_blobSumVec = null;
149 }
150
151 if (m_blobLossVec != null)
152 {
153 m_blobLossVec.Dispose();
154 m_blobLossVec = null;
155 }
156
157 if (m_blobWork != null)
158 {
159 m_blobWork.Dispose();
160 m_blobWork = null;
161 }
162
163 if (m_blobPreGenTargetsPos != null)
164 {
165 m_blobPreGenTargetsPos.Dispose();
166 m_blobPreGenTargetsPos = null;
167 }
168
169 if (m_blobPreGenTargetsNeg != null)
170 {
171 m_blobPreGenTargetsNeg.Dispose();
172 m_blobPreGenTargetsNeg = null;
173 }
174
175 base.dispose();
176 }
177
179 protected override void setup_internal_blobs(BlobCollection<T> col)
180 {
181 if (col.Count > 0)
182 return;
183
184 col.Add(m_blobDiffAP);
185 col.Add(m_blobDiffSqAP);
186 col.Add(m_blobDistSqAP);
187 col.Add(m_blobDiffAN);
188 col.Add(m_blobDiffSqAN);
189 col.Add(m_blobDistSqAN);
190 col.Add(m_blobDiffPN);
191 col.Add(m_blobSumVec);
192 col.Add(m_blobLossVec);
193 col.Add(m_blobWork);
194
195 if (m_blobPreGenTargetsPos != null)
196 col.Add(m_blobPreGenTargetsPos);
197
198 if (m_blobPreGenTargetsNeg != null)
199 col.Add(m_blobPreGenTargetsNeg);
200 }
201
205 public override int ExactNumBottomBlobs
206 {
207 get { return -1; }
208 }
209
213 public override int MinBottomBlobs
214 {
215 get { return 4; } // anchor, positive, negative, label
216 }
217
221 public override int MaxBottomBlobs
222 {
223 get { return 5; } // anchor, positive, negative, label, cetroids (from decode layer)
224 }
225
229 public override int ExactNumTopBlobs
230 {
231 get { return 1; }
232 }
233
239 public override bool AllowForceBackward(int nBottomIdx)
240 {
241 if (nBottomIdx <= 2)
242 return true;
243
244 return false;
245 }
246
252 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
253 {
254 base.LayerSetUp(colBottom, colTop);
255 m_dfAlpha = m_param.triplet_loss_param.alpha;
256
257 // If the fifth bottom exists (the centroids) initialize the pregen targets.
258 if (colBottom.Count == 5)
259 {
260 m_blobPreGenTargetsNeg = new Blob<T>(m_cuda, m_log, false);
261 m_blobPreGenTargetsNeg.Name = "pregen neg";
262 m_blobPreGenTargetsPos = new Blob<T>(m_cuda, m_log);
263 m_blobPreGenTargetsPos.Name = "pregen pos";
264 }
265 }
266
272 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
273 {
274 base.Reshape(colBottom, colTop);
275
276 m_log.CHECK(Utility.Compare<int>(colBottom[0].shape(), colBottom[1].shape()), "Inputs must have the same dimension.");
277 m_log.CHECK(Utility.Compare<int>(colBottom[0].shape(), colBottom[2].shape()), "Inputs must have the same dimension.");
278
279 m_blobDiffAP.ReshapeLike(colBottom[0]);
280 m_blobDiffSqAP.ReshapeLike(colBottom[0]);
281 m_blobDiffAN.ReshapeLike(colBottom[0]);
282 m_blobDiffSqAN.ReshapeLike(colBottom[0]);
283 m_blobDiffPN.ReshapeLike(colBottom[0]);
284 m_blobLossVec.ReshapeLike(colBottom[0]);
285
286 int nNum = colBottom[0].num;
287 int nDim = colBottom[0].count(1);
288 m_blobSumVec.Reshape(nDim, 1, 1, 1);
289 m_blobSumVec.SetData(1.0);
290
291 m_blobWork.Reshape(nNum, 1, 1, 1);
292 m_blobWork.SetData(0.0);
293
294 m_blobDistSqAP.ReshapeLike(m_blobWork);
295 m_blobDistSqAN.ReshapeLike(m_blobWork);
296
297 List<int> rgLossShape = new List<int>(); // Loss layers output a scalar, 0 axes.
298 colTop[0].Reshape(rgLossShape);
299
300 if (m_blobPreGenTargetsNeg != null)
301 m_blobPreGenTargetsNeg.ReshapeLike(colBottom[0]);
302
303 if (m_blobPreGenTargetsPos != null)
304 m_blobPreGenTargetsPos.ReshapeLike(colBottom[0]);
305 }
306
314 public void loadPreGenTargets(Blob<T> lbl, Blob<T> tgt, Blob<T> tgtNeg, Blob<T> tgtPos)
315 {
316 float[] rgLabels = convertF(lbl.update_cpu_data());
317 int nLblDim = lbl.count(1);
318 int nLblNum = tgt.num;
319 int nNum = lbl.num;
320 int nDim = tgt.count(1);
321 Random rand = new Random();
322 List<int> rgLabelVals = new List<int>();
323 Dictionary<int, List<int>> rgrgLabelSel = new Dictionary<int, List<int>>();
324
325 for (int i = 0; i < tgt.num; i++)
326 {
327 rgLabelVals.Add(i + m_param.triplet_loss_param.pregen_label_start);
328 rgrgLabelSel.Add(i + m_param.triplet_loss_param.pregen_label_start, new List<int>());
329 }
330
331 m_log.CHECK_EQ(nNum, tgtNeg.num, "The neg targets have an incorrect num!");
332 m_log.CHECK_EQ(nNum, tgtPos.num, "The pos targets have an incorrect num!");
333 m_log.CHECK_EQ(nDim, tgtNeg.count(1), "The neg targets have an incorrect dim!");
334 m_log.CHECK_EQ(nDim, tgtPos.count(1), "The pos targets have an incorrect dim!");
335
336 for (int i = 0; i < nNum; i++)
337 {
338 int nLabel = (int)rgLabels[i * nLblDim];
339
340
341 // Copy the positive to match the anchor label.
342 m_cuda.copy(nDim, tgt.gpu_data, tgtPos.mutable_gpu_data, nLabel * nDim, i * nDim);
343
344 // Copy the negative to NOT match the anchor label.
345 if (rgrgLabelSel[nLabel].Count == 0)
346 {
347 for (int l = 0; l < rgLabelVals.Count; l++)
348 {
349 if (rgLabelVals[l] != nLabel)
350 rgrgLabelSel[nLabel].Add(rgLabelVals[l]);
351 }
352 }
353
354 int nLabelIdx = rand.Next(rgrgLabelSel[nLabel].Count);
355 int nLabelX = rgrgLabelSel[nLabel][nLabelIdx];
356 rgrgLabelSel[nLabel].Remove(nLabelX);
357
358 m_cuda.copy(nDim, tgt.gpu_data, tgtNeg.mutable_gpu_data, nLabelX * nDim, i * nDim);
359 }
360 }
361
379 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
380 {
381 m_log.CHECK_GE(colBottom.Count, 4, "The bottom must have at least 4 items: anchor, positives, negatives and label.");
382 int nCount = colBottom[0].count();
383 int nNum = colBottom[0].num;
384 int nDim = colBottom[0].count(1);
385 long hAnchor = colBottom[0].gpu_data;
386 long hPositive = colBottom[1].gpu_data;
387 long hNegative = colBottom[2].gpu_data;
388
389
390 m_blobWork.Reshape(nNum, 1, 1, 1);
391
392 m_log.CHECK_EQ(colBottom.Count, 4, "Currently, external targts such as centroids are not supported.");
393 //if (colBottom.Count == 5)
394 // loadPreGenTargets(colBottom[3], colBottom[4], m_blobPreGenTargetsNeg, m_blobPreGenTargetsPos);
395
396 m_cuda.sub(nCount, hAnchor, hPositive, m_blobDiffAP.mutable_gpu_data); // a_i - p_i
397 m_cuda.sub(nCount, hAnchor, hNegative, m_blobDiffAN.mutable_gpu_data); // a_i - n_i
398
399 m_cuda.powx(nCount, m_blobDiffAP.gpu_data, 2.0, m_blobDiffSqAP.mutable_gpu_data); // (a_i - p_i)^2
400 m_cuda.gemv(false, nNum, nDim, 1.0, m_blobDiffSqAP.gpu_data, m_blobSumVec.gpu_data, 0.0, m_blobDistSqAP.mutable_gpu_data); // \Sum (a_i - p_i)^2
401
402 m_cuda.powx(nCount, m_blobDiffAN.gpu_data, 2.0, m_blobDiffSqAN.mutable_gpu_data); // (a_i - p_i)^2
403 m_cuda.gemv(false, nNum, nDim, 1.0, m_blobDiffSqAN.gpu_data, m_blobSumVec.gpu_data, 0.0, m_blobDistSqAN.mutable_gpu_data); // \Sum (a_i - p_i)^2
404
405 double dfMargin = m_dfAlpha;
406
407 m_cuda.sub(nNum, m_blobDistSqAP.gpu_data, m_blobDistSqAN.gpu_data, m_blobWork.mutable_gpu_data);
408 m_cuda.add_scalar(nNum, dfMargin, m_blobWork.mutable_gpu_data);
409 m_cuda.set_bounds(nNum, 0, float.MaxValue, m_blobWork.mutable_gpu_data);
410 m_cuda.copy_expand(nCount, nNum, nDim, m_blobWork.gpu_data, m_blobLossVec.mutable_gpu_data);
411 m_cuda.sign(nCount, m_blobLossVec.gpu_data, m_blobLossVec.mutable_gpu_data);
412
413 double dfLoss = m_cuda.asum_double(nNum, m_blobWork.gpu_data);
414 dfLoss /= (nNum * 2.0);
415 colTop[0].SetData(dfLoss, 0);
416 }
417
434 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
435 {
436 int nCount = colBottom[0].count();
437 int nNum = colBottom[0].num;
438 double dfDiff = convertD(colTop[0].GetDiff(0));
439 double dfAlpha = dfDiff / (double)nNum;
440 long hAnchor = colBottom[0].gpu_data;
441 long hPositive = colBottom[1].gpu_data;
442 long hNegative = colBottom[2].gpu_data;
443
444 m_blobLossVec.scale_data(dfAlpha);
445
446 if (rgbPropagateDown[0])
447 {
448 m_cuda.sub(nCount, hNegative, hPositive, m_blobDiffPN.mutable_gpu_diff);
449 m_cuda.mul(nCount, m_blobLossVec.gpu_data, m_blobDiffPN.gpu_diff, colBottom[0].mutable_gpu_diff);
450 }
451
452 if (rgbPropagateDown[1])
453 {
454 m_cuda.sub(nCount, hPositive, hAnchor, m_blobDiffAP.mutable_gpu_diff);
455 m_cuda.mul(nCount, m_blobLossVec.gpu_data, m_blobDiffAP.gpu_diff, colBottom[1].mutable_gpu_diff);
456 }
457
458 if (rgbPropagateDown[2])
459 {
460 m_cuda.sub(nCount, hAnchor, hNegative, m_blobDiffAN.mutable_gpu_diff);
461 m_cuda.mul(nCount, m_blobLossVec.gpu_data, m_blobDiffAN.gpu_diff, colBottom[2].mutable_gpu_diff);
462 }
463 }
464 }
465}
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 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
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 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
void scale_data(double df)
Scale the data by a scaling factor.
Definition: Blob.cs:1754
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
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
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
int num
DEPRECIATED; legacy shape accessor num: use shape(0) instead.
Definition: Blob.cs:792
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
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
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
TripletLoss Layer - this is the triplet loss layer used to calculate the triplet loss and gradients u...
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t the inputs.
TripletLossLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
The TripletLossLayer constructor.
override void LayerSetUp(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Setup the layer.
override int ExactNumBottomBlobs
Returns the exact number of bottom blobs which are variable so -1 is returned.
override int MinBottomBlobs
Returns the minimum number of bottom blobs: anchor, positive, negative, label
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
override bool AllowForceBackward(int nBottomIdx)
Returns true for all but the labels, for we want the loss value to be propagated back.
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 bottom blobs: anchor, positive, negative, label, centroids (from decode...
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation.
override int ExactNumTopBlobs
Returns the exact number of required top (output) Blobs: loss
void loadPreGenTargets(Blob< T > lbl, Blob< T > tgt, Blob< T > tgtNeg, Blob< T > tgtPos)
Loads the pre-gen targets, only made public for testing.
override void dispose()
Releases all GPU and host resources used by the Layer.
Specifies the base parameter for all layers.
string name
Specifies the name of this LayerParameter.
TripletLossParameter triplet_loss_param
Returns the parameter set when initialized with LayerType.TRIPLET_LOSS
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
The MyCaffe.layers.beta namespace contains all beta stage layers.
Definition: LayerFactory.cs:9
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