2using System.Collections.Generic;
34 List<int> m_rgShapeMask;
61 Blob<T> m_blobAttnScoresAllHeads;
62 Blob<T> m_blobAttnOutputAllHeads;
66 List<int> m_rgShape =
new List<int>(4);
79 m_blobQ =
new Blob<T>(cuda, log);
81 m_blobK =
new Blob<T>(cuda, log);
83 m_blobV =
new Blob<T>(cuda, log);
85 m_blobIpQ =
new Blob<T>(cuda, log);
87 m_blobIpK =
new Blob<T>(cuda, log);
89 m_blobIpV =
new Blob<T>(cuda, log);
91 m_blobMask =
new Blob<T>(cuda, log,
false);
93 m_blobIpVfull =
new Blob<T>(cuda, log);
94 m_blobIpVfull.
Name = p.
name +
".ipvfull";
95 m_blobIpQt =
new Blob<T>(cuda, log);
97 m_blobIpKt =
new Blob<T>(cuda, log);
99 m_blobIpKt1 =
new Blob<T>(cuda, log);
100 m_blobIpKt1.
Name = p.
name +
".ipkt1";
101 m_blobIpVt =
new Blob<T>(cuda, log);
103 m_blobAttnScores1 =
new Blob<T>(cuda, log);
104 m_blobAttnScores1.
Name = p.
name +
".attn_scores";
105 m_blobAttnScoresAllHeads =
new Blob<T>(cuda, log);
106 m_blobAttnScoresAllHeads.
Name = p.
name +
".attn_scr_allhd";
107 m_blobAttnOutputAllHeads =
new Blob<T>(cuda, log);
108 m_blobAttnOutputAllHeads.
Name = p.
name +
".attn_out_allhd";
109 m_blobWork =
new Blob<T>(cuda, log);
128 dispose(ref m_blobAttnScores1);
129 dispose(ref m_blobAttnScoresAllHeads);
130 dispose(ref m_blobAttnOutputAllHeads);
154 col.
Add(m_blobIpVfull);
157 col.
Add(m_blobIpKt1);
159 col.
Add(m_blobAttnScores1);
160 col.
Add(m_blobAttnScoresAllHeads);
161 col.
Add(m_blobAttnOutputAllHeads);
197 private void reshapeRepeat(
Blob<T> b, List<int> rgShape,
int nRepeat)
200 m_rgShape.AddRange(rgShape);
201 m_rgShape[3] *= nRepeat;
205 private void reshapeFwd(
Blob<T> b,
int nNumHeads, List<int> rgShape =
null)
212 m_rgShape.Add(rgShape[0]);
213 m_rgShape.Add(rgShape[1]);
214 m_rgShape.Add(nNumHeads);
215 m_rgShape.Add(rgShape[2] / nNumHeads);
219 private void reshapeBwd(
Blob<T> b,
int nNumHeads, List<int> rgShape =
null)
226 m_rgShape.Add(rgShape[0]);
227 m_rgShape.Add(rgShape[1]);
228 m_rgShape.Add(rgShape[2] * rgShape[3]);
232 private void reshapeSansHead(
Blob<T> b, List<int> rgShape)
235 m_rgShape.AddRange(rgShape);
236 m_rgShape.RemoveAt(1);
240 private void calculateChannelMeanAcrossChannelsFwd(
Blob<T> bBtm,
Blob<T> bTop)
244 int nSpatialDim = bBtm.
count(2);
245 int nSpatialDimDst = bTop.
count(1);
248 m_log.
CHECK_EQ(nSpatialDim, bTop.
count(1),
"Both src and dst must have the same spatial dim.");
253 for (
int i = 0; i < nC; i++)
262 private void calculateChannelMeanAcrossChannelsBwd(
Blob<T> bBtm,
Blob<T> bTop)
266 int nSpatialDim = bBtm.
count(2);
269 m_log.
CHECK_EQ(nSpatialDim, bTop.
count(1),
"Both src and dst must have the same spatial dim.");
273 for (
int i = 0; i < nC; i++)
281 private void generate_mask(
Blob<T> mask)
284 m_rgShape.Add(m_nNumFut);
285 m_rgShape.Add(m_nNumFut + m_nNumHist);
288 int nRow = m_nNumFut + m_nNumHist;
289 int nOutSeqLen = m_nNumFut;
290 float[] rgData =
new float[mask.
count()];
292 for (
int i = 0; i < m_nNumFut; i++)
294 for (
int j = 0; j < m_nNumHist + nOutSeqLen; j++)
296 int nIdx = i * nRow + j;
298 if (j > m_nNumHist && j-m_nNumHist > i)
314 m_log.
CHECK_EQ(colBottom.
Count, 1,
"When using self-attention, there should only be one bottom.");
316 m_log.
CHECK_EQ(colBottom.
Count, 3,
"When not using self-attention, there should be three bottom values: q, k, v");
320 m_nAllHeadsDim = m_nNumHeads * m_nDModel;
321 m_dfScale = 1.0 / Math.Sqrt(m_nDModel);
323 m_log.
CHECK(colBottom.
Count == 1 || colBottom.
Count == 4,
"The bottom count must be 1 (input ->q,k,v, mask generated) or 4 for q,k,q,mask");
326 m_log.
CHECK_GT(m_nNumFut, 0,
"The number of future steps must be greater than zero.");
328 m_log.
CHECK_GT(m_nNumHist, 0,
"The number of historical steps must be greater than zero.");
329 m_log.
CHECK_EQ(m_nNumFut + m_nNumHist, colBottom[0].channels,
"The number of future + historical steps must equal the bottom(0).channels.");
330 m_log.
CHECK_EQ(m_nNumHist % m_nNumFut, 0,
"The historical steps must be a multiple of the future steps! For example, historical steps = 90 and future steps = 30.");
331 m_nBlocks = (m_nNumHist + m_nNumFut) / m_nNumFut;
333 if (colBottom.
Count == 1)
334 generate_mask(m_blobMask);
338 if (m_ipQLayer ==
null)
352 if (colBottom.
Count == 1)
355 m_rgShape.Add(colBottom[0].num);
356 m_rgShape.Add(m_nNumFut);
357 m_rgShape.Add(colBottom[0].count(2));
365 addBtmTop(m_blobQ, m_blobIpQ);
366 m_ipQLayer.
Setup(m_colBtm, m_colTop);
370 if (m_ipKLayer ==
null)
385 addBtmTop(m_blobK, m_blobIpK);
386 m_ipKLayer.
Setup(m_colBtm, m_colTop);
390 if (m_ipVLayer ==
null)
404 addBtmTop(m_blobV, m_blobIpV);
405 m_ipVLayer.
Setup(m_colBtm, m_colTop);
410 if (m_transpose ==
null)
416 reshapeFwd(m_blobIpQ, m_nNumHeads);
417 reshapeFwd(m_blobIpK, m_nNumHeads);
418 reshapeFwd(m_blobIpV, m_nNumHeads);
419 reshapeRepeat(m_blobIpVfull, m_blobIpV.
shape(), m_nNumHeads);
426 addBtmTop(m_blobIpQ, m_blobIpQt);
427 m_transpose.
Setup(m_colBtm, m_colTop);
428 addBtmTop(m_blobIpK, m_blobIpKt);
429 m_transpose.
Setup(m_colBtm, m_colTop);
430 addBtmTop(m_blobIpVfull, m_blobIpVt);
431 m_transpose.
Setup(m_colBtm, m_colTop);
435 if (m_blobIpKt1.
count() == 0)
437 List<int> rgShape =
Utility.Clone<
int>(m_blobIpKt.
shape());
438 int nTemp = rgShape[2];
439 rgShape[2] = rgShape[3];
443 m_blobAttnScores1.
MatMul(m_blobIpQt, m_blobIpKt1,
true);
447 if (m_softmax ==
null)
454 addBtmTop(m_blobAttnScores1, m_blobAttnScoresAllHeads);
455 m_softmax.
Setup(m_colBtm, m_colTop);
457 m_blobAttnOutputAllHeads.
MatMul(m_blobAttnScoresAllHeads, m_blobIpVt,
true);
460 if (m_ipOutLayer ==
null)
473 reshapeSansHead(colTop[1], m_blobAttnOutputAllHeads.
shape());
474 reshapeSansHead(colTop[2], m_blobAttnScoresAllHeads.
shape());
476 addBtmTop(colTop[1], colTop[0]);
477 m_ipOutLayer.
Setup(m_colBtm, m_colTop);
494 bool bShapeQDirty = m_rgShapeQ ==
null || !colBottom[0].CompareShape(m_rgShapeQ);
495 bool bShapeKDirty = (colBottom.
Count == 1) ? bShapeQDirty : m_rgShapeK ==
null || !colBottom[1].CompareShape(m_rgShapeK);
496 bool bShapeVDirty = (colBottom.
Count == 1) ? bShapeQDirty : m_rgShapeV ==
null || !colBottom[2].CompareShape(m_rgShapeV);
497 bool bShapeMaskDirty =
false;
499 m_rgShapeQ =
Utility.Clone<
int>(colBottom[0].shape());
500 m_rgShapeK = m_rgShapeQ;
501 m_rgShapeV = m_rgShapeQ;
503 if (colBottom.
Count > 1)
504 m_rgShapeK =
Utility.Clone<
int>(colBottom[1].shape());
505 if (colBottom.
Count > 2)
506 m_rgShapeV =
Utility.Clone<
int>(colBottom[2].shape());
508 if (colBottom.
Count > 3)
510 bShapeMaskDirty = m_rgShapeMask ==
null || !colBottom[3].CompareShape(m_rgShapeMask);
511 m_rgShapeMask =
Utility.Clone<
int>(colBottom[3].shape());
514 if (bShapeQDirty || bShapeKDirty || bShapeVDirty || bShapeMaskDirty)
530 if (colBottom.
Count == 1)
533 m_rgShape.Add(colBottom[0].num);
534 m_rgShape.Add(m_nNumFut);
535 m_rgShape.Add(colBottom[0].count(2));
543 addBtmTop(m_blobQ, m_blobIpQ);
544 m_ipQLayer.
Reshape(m_colBtm, m_colTop);
547 addBtmTop(m_blobK, m_blobIpK);
548 m_ipKLayer.
Reshape(m_colBtm, m_colTop);
551 addBtmTop(m_blobV, m_blobIpV);
552 m_ipVLayer.
Reshape(m_colBtm, m_colTop);
558 reshapeFwd(m_blobIpQ, m_nNumHeads);
559 reshapeFwd(m_blobIpK, m_nNumHeads);
560 reshapeFwd(m_blobIpV, m_nNumHeads);
561 reshapeRepeat(m_blobIpVfull, m_blobIpV.
shape(), m_nNumHeads);
563 addBtmTop(m_blobIpQ, m_blobIpQt);
564 m_transpose.
Reshape(m_colBtm, m_colTop);
566 addBtmTop(m_blobIpK, m_blobIpKt);
567 m_transpose.
Reshape(m_colBtm, m_colTop);
569 addBtmTop(m_blobIpVfull, m_blobIpVt);
570 m_transpose.
Reshape(m_colBtm, m_colTop);
572 List<int> rgShape =
Utility.Clone<
int>(m_blobIpKt.
shape());
573 int nTemp = rgShape[2];
574 rgShape[2] = rgShape[3];
578 m_blobAttnScores1.
MatMul(m_blobIpQt, m_blobIpKt1,
true);
580 addBtmTop(m_blobAttnScores1, m_blobAttnScoresAllHeads);
581 m_softmax.
Reshape(m_colBtm, m_colTop);
583 colTop[1].MatMul(m_blobAttnScoresAllHeads, m_blobIpVt,
true);
586 reshapeSansHead(colTop[1], m_blobAttnOutputAllHeads.
shape());
587 reshapeSansHead(colTop[2], m_blobAttnScoresAllHeads.
shape());
590 addBtmTop(colTop[1], colTop[0]);
591 m_ipOutLayer.
Reshape(m_colBtm, m_colTop);
594 private void copy_to_q_fwd(
int nCount,
Blob<T> bBtm,
Blob<T> bTop)
600 int nOuterNum = bBtm.
num;
601 int nChannels = m_nBlocks;
611 private void copy_to_q_bwd(
int nCount,
Blob<T> bBtm,
Blob<T> bTop)
617 int nOuterNum = bBtm.
num;
618 int nChannels = m_nBlocks;
642 copy_to_q_fwd(colBottom.
Count, colBottom[0], m_blobQ);
644 addBtmTop(m_blobQ, m_blobIpQ);
645 m_ipQLayer.
Forward(m_colBtm, m_colTop);
647 m_blobK.
CopyFrom((colBottom.
Count == 1) ? colBottom[0] : colBottom[1]);
649 addBtmTop(m_blobK, m_blobIpK);
650 m_ipKLayer.
Forward(m_colBtm, m_colTop);
652 m_blobV.
CopyFrom((colBottom.
Count == 1) ? colBottom[0] : colBottom[2]);
654 addBtmTop(m_blobV, m_blobIpV);
655 m_ipVLayer.
Forward(m_colBtm, m_colTop);
661 reshapeFwd(m_blobIpQ, m_nNumHeads);
662 reshapeFwd(m_blobIpK, m_nNumHeads);
663 reshapeFwd(m_blobIpV, m_nNumHeads);
664 reshapeRepeat(m_blobIpVfull, m_blobIpV.
shape(), m_nNumHeads);
667 int nInnerNum = m_blobIpV.
count(2);
668 for (
int i = 0; i < m_nNumHeads; i++)
678 addBtmTop(m_blobIpQ, m_blobIpQt);
679 m_transpose.
Forward(m_colBtm, m_colTop);
681 addBtmTop(m_blobIpK, m_blobIpKt);
682 m_transpose.
Forward(m_colBtm, m_colTop);
684 addBtmTop(m_blobIpVfull, m_blobIpVt);
685 m_transpose.
Forward(m_colBtm, m_colTop);
693 m_blobAttnScores1.
MatMul(m_blobIpQt, m_blobIpKt1,
true);
698 if (m_blobMask !=
null)
708 addBtmTop(m_blobAttnScores1, m_blobAttnScoresAllHeads);
709 m_softmax.
Forward(m_colBtm, m_colTop);
712 m_blobAttnOutputAllHeads.
MatMul(m_blobAttnScoresAllHeads, m_blobIpVt,
true);
719 calculateChannelMeanAcrossChannelsFwd(m_blobAttnOutputAllHeads, colTop[1]);
720 calculateChannelMeanAcrossChannelsFwd(m_blobAttnScoresAllHeads, colTop[2]);
723 addBtmTop(colTop[1], colTop[0]);
724 m_ipOutLayer.
Forward(m_colBtm, m_colTop);
744 addBtmTop(colTop[1], colTop[0]);
745 m_ipOutLayer.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
748 calculateChannelMeanAcrossChannelsBwd(m_blobAttnOutputAllHeads, colTop[1]);
755 m_blobAttnOutputAllHeads.
MatMulGrad(m_blobAttnScoresAllHeads, m_blobIpVt, m_blobWork);
758 addBtmTop(m_blobAttnScores1, m_blobAttnScoresAllHeads);
759 m_softmax.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
762 m_blobAttnScores1.
MatMulGrad(m_blobIpQt, m_blobIpKt1, m_blobWork, m_dfScale);
769 addBtmTop(m_blobIpQ, m_blobIpQt);
770 m_transpose.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
772 addBtmTop(m_blobIpK, m_blobIpKt);
773 m_transpose.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
775 addBtmTop(m_blobIpVfull, m_blobIpVt);
776 m_transpose.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
781 int nOuterNum = m_blobIpVfull.
count(0, 2);
784 for (
int i = 1; i < m_nNumHeads; i++)
793 reshapeBwd(m_blobIpQ, m_nNumHeads);
794 reshapeBwd(m_blobIpK, m_nNumHeads);
795 reshapeBwd(m_blobIpV, m_nNumHeads);
798 addBtmTop(m_blobQ, m_blobIpQ);
799 m_ipQLayer.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
801 addBtmTop(m_blobK, m_blobIpK);
802 m_ipKLayer.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
804 addBtmTop(m_blobV, m_blobIpV);
805 m_ipVLayer.
Backward(m_colTop, rgbPropagateDown, m_colBtm);
807 if (colBottom.
Count == 1)
810 copy_to_q_bwd(colBottom.
Count, colBottom[0], m_blobQ);
811 m_cuda.add(colBottom[0].count(), colBottom[0].gpu_diff, m_blobK.
gpu_diff, colBottom[0].mutable_gpu_diff);
812 m_cuda.add(colBottom[0].count(), colBottom[0].gpu_diff, m_blobV.
gpu_diff, colBottom[0].mutable_gpu_diff);
816 colBottom[0].
CopyFrom(m_blobQ,
true);
817 colBottom[1].
CopyFrom(m_blobK,
true);
818 colBottom[2].
CopyFrom(m_blobV,
true);
The Log class provides general output in text form.
void CHECK(bool b, string str)
Test a flag for true.
void CHECK_EQ(double df1, double df2, string str)
Test whether one number is equal to another.
void CHECK_GT(double df1, double df2, string str)
Test whether one number is greater than another.
The Utility class provides general utility funtions.
The BlobCollection contains a list of Blobs.
void Add(Blob< T > b)
Add a new Blob to the collection.
void SetDiff(double df)
Set all blob diff 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 CopyFrom(BlobCollection< T > bSrc, bool bCopyDiff=false)
Copy the data or diff from another BlobCollection into this one.
The Blob is the main holder of data that moves through the Layers of the Net.
int channels
DEPRECIATED; legacy shape accessor channels: use shape(1) instead.
void SetData(T[] rgData, int nCount=-1, bool bSetCount=true)
Sets a number of items within the Blob's data.
void ShareData(Blob< T > b)
Set the data to point to the data of the other blob – useful in Layers which simply perform a copy in...
void MatMul(Blob< T > blobA, Blob< T > blobB, bool bReshape=false, bool bTransA=false, bool bTransB=false, double dfScale=1.0, bool bADiff=false, bool bBDiff=false, bool bCDiff=false)
MatMul blobA with blobB and place the result in this blob (e.g. this = matmul(A, B))....
void MatMulGrad(Blob< T > blobA, Blob< T > blobB, Blob< T > blobWork, double dfScale=1.0)
Calculates and propagates the gradient for blobA and BlobB given the input gradient in this blob's di...
long mutable_gpu_diff
Returns the diff GPU handle used by the CudaDnn connection.
long mutable_gpu_data
Returns the data GPU handle used by the CudaDnn connection.
void CopyFromAndTransposeHeightWidth(Blob< T > blobSrc, bool bCopyDiff=false, bool bUseCuda=true)
Copy from a source Blob and transpose the height and width of the copy.
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...
void Reshape(int nNum, int nChannels, int nHeight, int nWidth, bool? bUseHalfSize=null)
DEPRECIATED; use
void CopyFrom(Blob< T > src, int nSrcOffset, int nDstOffset, int nCount, bool bCopyData, bool bCopyDiff)
Copy from a source Blob.
void scale_data(double df)
Scale the data by a scaling factor.
int width
DEPRECIATED; legacy shape accessor width: use shape(3) instead.
List< int > shape()
Returns an array where each element contains the shape of an axis of the Blob.
int count()
Returns the total number of items in the Blob.
void ReshapeLike(Blob< T > b, bool? bUseHalfSize=null)
Reshape this Blob to have the same shape as another Blob.
string Name
Get/set the name of the Blob.
long gpu_diff
Returns the diff GPU handle used by the CudaDnn connection.
void scale_diff(double df)
Scale the diff by a scaling factor.
void SetDiff(double dfVal, int nIdx=-1)
Either sets all of the diff items in the Blob to a given value, or alternatively only sets a single i...
int num
DEPRECIATED; legacy shape accessor num: use shape(0) instead.
long gpu_data
Returns the data GPU handle used by the CudaDnn connection.
The CudaDnn object is the main interface to the Low-Level Cuda C++ DLL.
An interface for the units of computation which can be composed into a Net.
Log m_log
Specifies the Log for output.
LayerParameter m_param
Specifies the LayerParameter describing the Layer.
void convert(BlobCollection< T > col)
Convert a collection of blobs from / to half size.
void Backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Given the top Blob error gradients, compute the bottom Blob error gradients.
double Forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Given the bottom (input) Blobs, this function computes the top (output) Blobs and the loss.
abstract void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Adjust the shapes of top blobs and internal buffers to accomodate the shapes of the bottom blobs.
CudaDnn< T > m_cuda
Specifies the CudaDnn connection to Cuda.
void Setup(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Implements common Layer setup functionality.
static Layer< T > Create(CudaDnn< T > cuda, Log log, LayerParameter p, CancelEvent evtCancel, IXDatabaseBase db=null, TransferInput trxinput=null)
Create a new Layer based on the LayerParameter.
LayerParameter.LayerType m_type
Specifies the Layer type.
BlobCollection< T > blobs
Returns the collection of learnable parameter Blobs for the Layer.
LayerParameter convertLayerParam(LayerParameter pChild, LayerParameter pParent)
Called to convert a parent LayerParameterEx, used in blob sharing, with a child layer parameter.
The MultiHeadAttentionInterpLayer implements the Multi-head Attention Interpretive Layer
override void dispose()
Releases all GPU and host resources used by the Layer.
override int MaxBottomBlobs
Returns the max number of required bottom (input) Blobs: q, k, v, mask
override void setup_internal_blobs(BlobCollection< T > col)
Derivative layers should add all internal blobws to the 'col' provided.
override void forward(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Forward computation
override void backward(BlobCollection< T > colTop, List< bool > rgbPropagateDown, BlobCollection< T > colBottom)
Computes the error gradient w.r.t. the stacked embedding numeric and categorical value inputs.
override void LayerSetUp(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Setup the layer.
override bool reshapeNeeded(BlobCollection< T > colBottom, BlobCollection< T > colTop, bool bReset=false)
Determines if a reshape is needed or not.
override void Reshape(BlobCollection< T > colBottom, BlobCollection< T > colTop)
Reshape the top (output) blobs.
override int MinBottomBlobs
Returns the min number of required bottom (input) Blobs: input -> q,k,v, mask is generated
MultiHeadAttentionInterpLayer(CudaDnn< T > cuda, Log log, LayerParameter p)
The constructor.
override int ExactNumTopBlobs
Returns the exact number of required top (output) Blobs: y, attn_out, attn_scores
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.
double sigma_init
Specifies the initialization value for the sigma weight and sigma bias used when 'enable_noise' = tru...
FillerParameter weight_filler
The filler for the weights.
int axis
Specifies the first axis to be lumped into a single inner product computation; all preceding axes are...
bool enable_noise
Enable/disable noise in the inner-product layer (default = false).
double bias_grad_scale
Specifies a scaling value applied to the bias mutliplier and then unapplied after calculating the bia...
FillerParameter bias_filler
The filler for the bias.
uint num_output
The number of outputs for the layer.
bool bias_term
Whether to have bias terms or not.
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
MultiHeadAttentionInterpParameter multihead_attention_interp_param
Returns the parameter set when initialized with LayerType.MULTIHEAD_ATTENTION_INTERP
InnerProductParameter inner_product_param
Returns the parameter set when initialized with LayerType.INNERPRODUCT
TransposeParameter transpose_param
Returns the parameter set when initialized with LayerType.TRANSPOSE
LayerType
Specifies the layer type.
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.
The MyCaffe.common namespace contains common MyCaffe classes.
DIR
Defines the direction of data flow.
BLOB_TYPE
Defines the tpe of data held by a given Blob.
The MyCaffe.layers.tft namespace contains all TFT related layers.
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-...