MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
SoftmaxLayer.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
11{
23 public class SoftmaxLayer<T> : Layer<T>
24 {
25 int m_nOuterNum;
26 int m_nInnerNum;
27 int m_nSoftmaxAxis;
28 Blob<T> m_blobScale;
29 SOFTMAX_ALGORITHM m_algorithm = SOFTMAX_ALGORITHM.DEFAULT;
30 SOFTMAX_MODE m_mode = SOFTMAX_MODE.CHANNEL;
31 List<int> m_rgScaleDims = null;
32
33 long m_hCudnn = 0;
34 long m_hBottomDesc = 0;
35 long m_hTopDesc = 0;
36
49 : base(cuda, log, p)
50 {
52 m_blobScale = new Blob<T>(cuda, log);
53 m_blobScale.Name = m_param.name + " scale";
54
56 }
57
59 protected override void dispose()
60 {
61 if (m_hCudnn != 0)
62 {
63 m_cuda.FreeCuDNN(m_hCudnn);
64 m_hCudnn = 0;
65 }
66
67 if (m_hBottomDesc != 0)
68 {
69 m_cuda.FreeTensorDesc(m_hBottomDesc);
70 m_hBottomDesc = 0;
71 }
72
73 if (m_hTopDesc != 0)
74 {
75 m_cuda.FreeTensorDesc(m_hTopDesc);
76 m_hTopDesc = 0;
77 }
78
79 m_blobScale.Dispose();
80 base.dispose();
81 }
82
84 protected override void setup_internal_blobs(BlobCollection<T> col)
85 {
86 if (col.Count > 0)
87 return;
88
90 {
91 col.Add(m_blobScale);
92 }
93 }
94
98 public override int MinBottomBlobs
99 {
100 get { return 1; }
101 }
102
106 public override int MaxBottomBlobs
107 {
108 get { return 2; }
109 }
110
114 public override int ExactNumTopBlobs
115 {
116 get { return 1; }
117 }
118
124 public override void LayerSetUp(BlobCollection<T> colBottom, BlobCollection<T> colTop)
125 {
126 m_algorithm = m_param.softmax_param.algorithm;
128 {
129 if (m_algorithm != SOFTMAX_ALGORITHM.ACCURATE)
130 m_log.WriteLine("WARNING: SoftmaxLayer: Caffe mode does not support the ACCURATE algorithm, the default FAST algorithm will be used instead.");
131 }
132
134 return;
135
136 // Initialize cuDNN
137 m_hCudnn = m_cuda.CreateCuDNN();
138 m_hBottomDesc = m_cuda.CreateTensorDesc();
139 m_hTopDesc = m_cuda.CreateTensorDesc();
140 }
141
147 public override void Reshape(BlobCollection<T> colBottom, BlobCollection<T> colTop)
148 {
149 m_nSoftmaxAxis = colBottom[0].CanonicalAxisIndex(m_param.softmax_param.axis);
150
151 if (m_phase == Phase.TRAIN && m_param.softmax_param.algorithm_train.HasValue)
152 m_algorithm = m_param.softmax_param.algorithm_train.Value;
153
154 colTop[0].ReshapeLike(colBottom[0]);
155
156 m_nOuterNum = colBottom[0].count(0, m_nSoftmaxAxis);
157 m_nInnerNum = colBottom[0].count(m_nSoftmaxAxis + 1);
158
160 {
161 shareLayerBlob(m_blobScale, colBottom[0].shape());
162 m_blobScale.ReshapeLike(colBottom[0]);
163
164 m_rgScaleDims = Utility.Clone<int>(colBottom[0].shape());
165 m_rgScaleDims[m_nSoftmaxAxis] = 1;
166
167 m_blobScale.Reshape(m_rgScaleDims);
168
169 return;
170 }
171
172 int nN = m_nOuterNum;
173 int nK = colBottom[0].shape(m_nSoftmaxAxis);
174 int nH = m_nInnerNum;
175 int nW = 1;
176
177 if (nH == 1 && nW == 1)
178 m_mode = SOFTMAX_MODE.INSTANCE;
179
180 m_cuda.SetTensorDesc(m_hBottomDesc, nN, nK, nH, nW);
181 m_cuda.SetTensorDesc(m_hTopDesc, nN, nK, nH, nW);
182 }
183
193 protected override void forward(BlobCollection<T> colBottom, BlobCollection<T> colTop)
194 {
196 forward_cuda(colBottom, colTop);
197 else
198 forward_cudnn(colBottom, colTop);
199 }
200
213 protected override void backward(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
214 {
216 backward_cuda(colTop, rgbPropagateDown, colBottom);
217 else
218 backward_cudnn(colTop, rgbPropagateDown, colBottom);
219 }
220
230 protected void forward_cuda(BlobCollection<T> colBottom, BlobCollection<T> colTop)
231 {
232 long hBottomData = colBottom[0].gpu_data;
233 long hTopData = colTop[0].mutable_gpu_data;
234 long hScaleData = m_blobScale.mutable_gpu_data;
235 long hScaleDiff = m_blobScale.mutable_gpu_diff;
236 int nCount = colBottom[0].count();
237 int nChannels = colTop[0].shape(m_nSoftmaxAxis);
238
239 m_cuda.copy(nCount, hBottomData, hTopData);
240
241 // We need to subtract the max to avoid numerical issues, compute the exp
242 // and then normalize.
243 // c = x.max(dim=axis)
244 m_cuda.channel_max(m_nOuterNum * m_nInnerNum, m_nOuterNum, nChannels, m_nInnerNum, hTopData, hScaleData);
245
246 // Subtract c
247 // xm = x - c (along each channel)
248 m_cuda.channel_sub(nCount, m_nOuterNum, nChannels, m_nInnerNum, hScaleData, hTopData);
249
250 // exponentiate
251 // exp_x = exp(xm)
252 m_cuda.exp(nCount, hTopData, hTopData);
253
254 // Sum across each channel after exp
255 // exp_sum = exp_x.sum(dim=axis)
256 m_cuda.channel_sum(m_nOuterNum * m_nInnerNum, m_nOuterNum, nChannels, m_nInnerNum, hTopData, hScaleDiff);
257
259 {
260 // exp_log = exp_sum.log()
261 m_cuda.log(m_nOuterNum * m_nInnerNum, hScaleDiff, hScaleDiff);
262 // log_z = c + exp_log
263 m_cuda.add(m_nOuterNum * m_nInnerNum, hScaleData, hScaleDiff, hScaleData);
264 // sm = x - log_z
265 m_cuda.copy(nCount, hBottomData, hTopData);
266 m_cuda.channel_sub(nCount, m_nOuterNum, nChannels, m_nInnerNum, hScaleData, hTopData);
267 }
268 else
269 {
270 // divide
271 m_cuda.channel_div(nCount, m_nOuterNum, nChannels, m_nInnerNum, hScaleDiff, hTopData);
272 }
273 }
274
275
288 protected void backward_cuda(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
289 {
290 long hTopDiff = colTop[0].gpu_diff;
291 long hTopData = colTop[0].gpu_data;
292 long hBottomDiff = colBottom[0].mutable_gpu_diff;
293 long hScaleData = m_blobScale.mutable_gpu_data;
294 int nCount = colTop[0].count();
295 int nChannels = colTop[0].shape(m_nSoftmaxAxis);
296
298 {
299 // sumgy = sum channel diff
300 m_blobScale.Reshape(m_rgScaleDims);
301 m_cuda.channel_sum(nCount, m_nOuterNum, nChannels, m_nInnerNum, hTopDiff, m_blobScale.mutable_gpu_diff);
302
303 // expy = exp(y)
304 m_cuda.exp(nCount, hTopData, hBottomDiff);
305
306 // Fill the expy values across each channel.
307 m_blobScale.ReshapeLike(colBottom[0]);
308 m_cuda.channel_fillfrom(nCount, m_nOuterNum, 1, nChannels, m_blobScale.gpu_diff, m_blobScale.mutable_gpu_data, DIR.FWD);
309
310 // expy * sumgy
311 m_cuda.mul(nCount, hBottomDiff, m_blobScale.gpu_data, hBottomDiff);
312 m_blobScale.Reshape(m_rgScaleDims);
313
314 // grad = gy - (expy * sumgy)
315 m_cuda.sub(nCount, hTopDiff, hBottomDiff, hBottomDiff);
316 }
317 else
318 {
319 m_cuda.copy(nCount, hTopDiff, hBottomDiff);
320
321 // Compute inner1d(top_diff, top_data) and subtract them from the bottom diff.
322 m_cuda.channel_dot(m_nOuterNum * m_nInnerNum, m_nOuterNum, nChannels, m_nInnerNum, hTopDiff, hTopData, hScaleData);
323 m_cuda.channel_sub(nCount, m_nOuterNum, nChannels, m_nInnerNum, hScaleData, hBottomDiff);
324
325 // elementwise multiplication
326 m_cuda.mul(nCount, hBottomDiff, hTopData, hBottomDiff);
327 }
328 }
329
339 protected void forward_cudnn(BlobCollection<T> colBottom, BlobCollection<T> colTop)
340 {
341 long hBottomData = colBottom[0].gpu_data;
342 long hTopData = colTop[0].mutable_gpu_data;
343
344 m_cuda.SoftmaxForward(m_hCudnn, m_algorithm, m_mode, m_tOne, m_hBottomDesc, hBottomData, m_tZero, m_hTopDesc, hTopData);
345 }
346
359 protected void backward_cudnn(BlobCollection<T> colTop, List<bool> rgbPropagateDown, BlobCollection<T> colBottom)
360 {
361 long hTopData = colTop[0].gpu_data;
362 long hTopDiff = colTop[0].gpu_diff;
363 long hBottomData = colBottom[0].gpu_data;
364 long hBottomDiff = colBottom[0].mutable_gpu_diff;
365
366 m_cuda.SoftmaxBackward(m_hCudnn, m_algorithm, m_mode, m_tOne, m_hTopDesc, hTopData, m_hTopDesc, hTopDiff, m_tZero, m_hBottomDesc, hBottomDiff);
367 }
368 }
369}
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
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.
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
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 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
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
bool shareLayerBlob(Blob< T > b, List< int > rgMinShape)
Attempts to share a Layer Blob if another parameter Blob with the same name and acceptable size is fo...
Definition: Layer.cs:1170
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
BlobCollection< T > m_colInternalBlobs
Specifies internal blobs used by the layer.
Definition: Layer.cs:59
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
The SoftmaxLayer computes the softmax function. This layer is initialized with the MyCaffe....
Definition: SoftmaxLayer.cs:24
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the bottom (input) and top (output) blobs.
override int MinBottomBlobs
Returns the minimum number of bottom blobs (input) Blobs: input.
Definition: SoftmaxLayer.cs:99
override void LayerSetUp(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Setup the layer to run in either Engine.CAFFE or Engine.CUDNN mode.
void forward_cuda(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation using the Engine.CAFFE mode.
override void dispose()
Releases all GPU and host resources used by the Layer.
Definition: SoftmaxLayer.cs:59
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t the inputs using either the Engine.CAFFE or Engine....
SoftmaxLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
The SoftmaxLayer constructor.
Definition: SoftmaxLayer.cs:48
override int ExactNumTopBlobs
Returns the exact number of required top (output) Blobs: softmax
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation using either the Engine.CAFFE or Engine.CUDNN mode.
override void setup_internal_blobs(BlobCollection< T > col)
Derivative layers should add all internal blobws to the 'col' provided.
Definition: SoftmaxLayer.cs:84
void backward_cudnn(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t the inputs using either the Engine.CUDNN.
void forward_cudnn(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Computes the forward calculation using the Engine.CUDNN mode.
void backward_cuda(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t the inputs using either the Engine.CAFFE.
override int MaxBottomBlobs
Returns the maximum number of bottom blobs (input) Blobs: input, target (ignored)
Specifies whether to use the NVIDIA cuDnn version or Caffe version of a given forward/backward operat...
Engine engine
Specifies the Engine in use.
Engine
Defines the type of engine to use.
Specifies the base parameter for all layers.
string name
Specifies the name of this LayerParameter.
SoftmaxParameter softmax_param
Returns the parameter set when initialized with LayerType.SOFTMAX
LayerType
Specifies the layer type.
SOFTMAX_ALGORITHM algorithm
Specifies the softmax algorithm to use during the running and testing.
bool useCudnn()
Queries whether or not to use NVIDIA's cuDnn. Softmax uses cuDNN as the default.
SOFTMAX_ALGORITHM? algorithm_train
Optionally, specifies the softmax algorithm to use during the training phase, when null,...
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
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
DIR
Defines the direction of data flow.
Definition: CudaDnn.cs:22
SOFTMAX_MODE
Specifies the SOFTMAX mode to use.
Definition: CudaDnn.cs:724
SOFTMAX_ALGORITHM
Specifies the SOFTMAX algorithm to use.
Definition: CudaDnn.cs:701
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