MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
KnnLayer.cs
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Linq;
5using System.Text;
6using MyCaffe.basecode;
7using MyCaffe.common;
8using MyCaffe.param;
9
10namespace MyCaffe.layers.beta
11{
34 public class KnnLayer<T> : Layer<T>
35 {
36 Blob<T> m_blobCompare;
37 int m_nBatchSize;
38 int m_nMaxBatches;
39 int m_nCurrentBatchIdx = 0;
40 int m_nNumOutput;
41 int m_nVectorDim = 0;
42 int m_nK = -1;
43 bool m_bBufferFull = false;
44 int m_nBatchDataCount = 0;
45
60 : base(cuda, log, p)
61 {
62 m_param = p;
64 m_nNumOutput = p.knn_param.num_output;
65 m_nK = p.knn_param.k;
66 m_nMaxBatches = p.knn_param.max_stored_batches;
67 m_blobCompare = new common.Blob<T>(m_cuda, m_log, false);
68 m_blobCompare.Name = m_param.name + " compare";
69 }
70
72 protected override void dispose()
73 {
74 dispose(ref m_blobCompare);
75 base.dispose();
76 }
77
79 protected override void setup_internal_blobs(BlobCollection<T> col)
80 {
81 if (col.Count > 0)
82 return;
83
84 col.Add(m_blobCompare);
85 }
86
90 public override int MinBottomBlobs
91 {
92 get { return 1; } // data (embeddings) - only in RUN mode
93 }
94
98 public override int MaxBottomBlobs
99 {
100 get { return 2; } // data (embeddings), label - only in TRAIN/TEST mode
101 }
102
106 public override int MinTopBlobs
107 {
108 get { return 1; }
109 }
110
116 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
117 {
118 if (m_phase == Phase.TEST || m_phase == Phase.TRAIN)
119 m_log.CHECK_EQ(2, colBottom.Count, "There should be two bottom items: data (embeddings) and labels.");
120
121 m_nBatchSize = colBottom[0].shape(0);
122
123 // Make sure to not have a diff so as to avoid
124 // being normalized or regularized in the
125 // ApplyUpdate.
126 Blob<T> blobInfo = new Blob<T>(m_cuda, m_log, false);
127 blobInfo.Name = m_param.name + " info";
128 blobInfo.Reshape(1, 1, 1, 1);
129 blobInfo.SetData(0, 0);
130 m_colBlobs.Add(blobInfo);
131
132 // Setup the weights where
133 // weight[0] stores the last 'max' batches and
134 // weight[1] stores the last 'max' labels
135 for (int i = 0; i < m_nMaxBatches; i++)
136 {
137 Blob<T> blobData = new Blob<T>(m_cuda, m_log, false);
138 blobData.Name = m_param.name + " data_" + i.ToString();
139 Blob<T> blobLabel = new Blob<T>(m_cuda, m_log, false);
140 blobLabel.Name = m_param.name + " label_" + i.ToString();
141 m_colBlobs.Add(blobData);
142 m_colBlobs.Add(blobLabel);
143 }
144
145 for (int i = 0; i < colBottom.Count; i++)
146 {
147 m_param.propagate_down.Add(false);
148 }
149 }
150
156 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
157 {
158 // Reshape the temp batch storage.
159 for (int i = 0; i < m_nMaxBatches; i++)
160 {
161 m_colBlobs[1 + (i * 2 + 0)].ReshapeLike(colBottom[0]);
162
163 if (colBottom.Count > 1)
164 m_colBlobs[1 + (i * 2 + 1)].ReshapeLike(colBottom[1]);
165 }
166
167 // Size the compare blob to one element int a single batch.
168 List<int> rgShape = Utility.Clone<int>(colBottom[0].shape());
169 rgShape[0] = 1;
170 m_blobCompare.Reshape(rgShape);
171 m_nVectorDim = m_blobCompare.count();
172
173 // Setup the outputs where each item has 'num_output' elements, one per class.
174 rgShape = new List<int>() { m_nBatchSize, m_nNumOutput, 1, 1 };
175 colTop[0].Reshape(rgShape);
176
177 m_nBatchDataCount = (m_bBufferFull) ? m_nMaxBatches : (m_nCurrentBatchIdx + 1);
178 }
179
189 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
190 {
191 if (m_phase == Phase.TRAIN || m_param.phase == Phase.TRAIN)
192 {
193 // Save the last 'max' items.
194 forward_save(colBottom, colTop);
195 return;
196 }
197
198 colTop[0].SetData(0);
199
200 // Find the label with the closest (smallest)
201 // averaged distance.
202 forward_test(colBottom, colTop);
203 }
204
215 protected void forward_test(BlobCollection<T> colBottom, BlobCollection<T> colTop)
216 {
217 float fDataCount = convertF(m_colBlobs[0].GetData(0));
218 int nDataCount = (int)fDataCount;
219
220 if (nDataCount == 0)
221 return;
222
223 m_log.CHECK_EQ(colBottom.Count, 2, "The KNN Layer is used for testing and expects both the 'data' and 'label' bottom items.");
224
225 Dictionary<int, List<Tuple<int, int>>> rgData = new Dictionary<int, List<Tuple<int, int>>>();
226 float[] rgFullSet = new float[m_nBatchSize * m_nNumOutput];
227
228 // Organize all stored data items by label.
229 for (int i = 0; i < nDataCount; i++)
230 {
231 Blob<T> blobLabel = m_colBlobs[1 + (i * 2 + 1)];
232 float[] rgLabels1 = convertF(blobLabel.update_cpu_data());
233
234 for (int j = 0; j < rgLabels1.Length; j++)
235 {
236 int nLabel = (int)rgLabels1[j];
237
238 if (!rgData.ContainsKey(nLabel))
239 rgData.Add(nLabel, new List<Tuple<int, int>>());
240
241 rgData[nLabel].Add(new Tuple<int, int>(i, j));
242 }
243 }
244
245 // Get the current set of labels.
246 float[] rgLabels = convertF(colBottom[1].update_cpu_data());
247 Stopwatch sw = new Stopwatch();
248
249 sw.Start();
250
251 // Calculate all distances between each item in the current bottom and those in the stored
252 // blobs 'weight' data (which are actually the last trained 'max' data items and labels).
253 for (int i = 0; i < m_nBatchSize; i++)
254 {
255 int nLabel = (int)rgLabels[i];
256 Dictionary<int, float> rgKDist = new Dictionary<int, float>();
257
258 foreach (KeyValuePair<int, List<Tuple<int, int>>> kvItem in rgData.OrderBy(p => p.Key))
259 {
260 List<float> rgDist = new List<float>();
261
262 foreach (Tuple<int, int> offset in kvItem.Value)
263 {
264 Blob<T> blobData = m_colBlobs[1 + (offset.Item1 * 2 + 0)];
265 m_cuda.sub(m_blobCompare.count(), colBottom[0].gpu_data, blobData.gpu_data, m_blobCompare.mutable_gpu_data, i * m_nVectorDim, offset.Item2 * m_nVectorDim);
266 float fDist1 = m_cuda.dot_float(m_blobCompare.count(), m_blobCompare.gpu_data, m_blobCompare.gpu_data);
267 float fDist = (float)Math.Sqrt(convertF(m_blobCompare.sumsq_data()));
268 rgDist.Add(fDist);
269 }
270
271 rgDist.Sort();
272 int k = (m_nK <= 0 || m_nK > rgDist.Count) ? rgDist.Count : m_nK;
273 float fTotal = 0;
274
275 for (int j = 0; j < k; j++)
276 {
277 fTotal += rgDist[j];
278 }
279
280 float fAveDist = fTotal / k;
281 rgKDist.Add(kvItem.Key, fAveDist);
282 }
283
284 List<KeyValuePair<int, float>> rgKDistSorted = rgKDist.OrderBy(p => p.Key).ToList();
285 float fMax = rgKDistSorted.Max(p => p.Value);
286 float fMin = rgKDistSorted.Min(p => p.Value);
287
288 for (int j = 0; j < rgKDistSorted.Count; j++)
289 {
290 float fVal = (rgKDistSorted[j].Value - fMin)/(fMax - fMin);
291 fVal = 1.0f - fVal; // invert so that max value is the shortest distance (softmax looks for max);
292 rgFullSet[i * m_nNumOutput + j] = fVal;
293 }
294
295 if (sw.Elapsed.TotalMilliseconds > 1000)
296 {
297 double dfPct = (double)i / (double)m_nBatchSize;
298 m_log.WriteLine("KNN testing cycle at " + dfPct.ToString("P") + "...");
299 sw.Restart();
300 }
301 }
302
303 colTop[0].mutable_cpu_data = convert(rgFullSet.ToArray());
304 }
305
306
316 protected bool forward_save(BlobCollection<T> colBottom, BlobCollection<T> colTop)
317 {
318 m_log.CHECK_EQ(2, colBottom.Count, "When training, the bottom must have both 'data' and 'labels'.");
319
320 if (m_nCurrentBatchIdx == m_nMaxBatches)
321 {
322 m_bBufferFull = true;
323 m_nCurrentBatchIdx = 0;
324 }
325
326 // Copy the data into the batch storage.
327 m_cuda.copy(colBottom[0].count(), colBottom[0].gpu_data, m_colBlobs[1 + (m_nCurrentBatchIdx * 2 + 0)].mutable_gpu_data);
328 m_cuda.copy(colBottom[1].count(), colBottom[1].gpu_data, m_colBlobs[1 + (m_nCurrentBatchIdx * 2 + 1)].mutable_gpu_data);
329 m_nCurrentBatchIdx++;
330
331 double dfCount = (m_bBufferFull) ? m_nMaxBatches : m_nCurrentBatchIdx;
332 m_colBlobs[0].SetData(dfCount, 0);
333
334 return m_bBufferFull;
335 }
336
338 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
339 {
340 if (rgbPropagateDown[0])
341 throw new NotImplementedException();
342 }
343 }
344}
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
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
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
string Name
Get/set the name of the Blob.
Definition: Blob.cs:2184
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
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
Phase m_phase
Specifies the Phase under which the Layer is run.
Definition: Layer.cs:51
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
BlobCollection< T > m_colBlobs
Specifies the learnable parameter Blobs of the Layer.
Definition: Layer.cs:55
override int MinBottomBlobs
Returns the minimum number of required bottom (intput) Blobs: data
Definition: KnnLayer.cs:91
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
Definition: KnnLayer.cs:156
override int MaxBottomBlobs
Returns the maximum number of required bottom (intput) Blobs: data, label
Definition: KnnLayer.cs:99
override void LayerSetUp(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Setup the layer.
Definition: KnnLayer.cs:116
void forward_test(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation, run during the Phase.TEST cycle to find the closest averaged distan...
Definition: KnnLayer.cs:215
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation.
Definition: KnnLayer.cs:189
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Not implemented - the KNN Layer does not perform backward.
Definition: KnnLayer.cs:338
override int MinTopBlobs
Returns the minimum number of required top (output) Blobs: knn
Definition: KnnLayer.cs:107
override void dispose()
Releases all GPU and host resources used by the Layer.
Definition: KnnLayer.cs:72
bool forward_save(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Save the data in the batch storage.
Definition: KnnLayer.cs:316
override void setup_internal_blobs(BlobCollection< T > col)
Derivative layers should add all internal blobws to the 'col' provided.
Definition: KnnLayer.cs:79
KnnLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
The KnnLayer constructor.
Definition: KnnLayer.cs:59
Specifies the base parameter for all layers.
string name
Specifies the name of this LayerParameter.
List< bool > propagate_down
Specifies whether or not the LayerParameter (or protions of) should be backpropagated.
KnnParameter knn_param
Returns the parameter set when initialized with LayerType.KNN
Phase phase
Specifies the Phase for which this LayerParameter is run.
LayerType
Specifies the layer type.
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
Definition: Annotation.cs:12
Phase
Defines the Phase under which to run a Net.
Definition: Interfaces.cs:61
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