This repository has been archived on 2026-02-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tkDNN/include/tkDNN/Layer.h
T
2021-07-22 17:03:23 +02:00

724 lines
21 KiB
C++

#ifndef LAYER_H
#define LAYER_H
#include<iostream>
#include<vector>
#include "utils.h"
#include "Network.h"
namespace tk { namespace dnn {
enum layerType_t {
LAYER_INPUT,
LAYER_DENSE,
LAYER_CONV2D,
LAYER_DECONV2D,
LAYER_DEFORMCONV2D,
LAYER_LSTM,
LAYER_ACTIVATION,
LAYER_ACTIVATION_CRELU,
LAYER_ACTIVATION_LEAKY,
LAYER_ACTIVATION_MISH,
LAYER_ACTIVATION_LOGISTIC,
LAYER_FLATTEN,
LAYER_RESHAPE,
LAYER_RESIZE,
LAYER_MULADD,
LAYER_POOLING,
LAYER_SOFTMAX,
LAYER_ROUTE,
LAYER_REORG,
LAYER_SHORTCUT,
LAYER_UPSAMPLE,
LAYER_REGION,
LAYER_YOLO
};
#define TKDNN_BN_MIN_EPSILON 1e-5
/**
Simple layer Father class
*/
class Layer {
public:
Layer(Network *net);
virtual ~Layer();
virtual layerType_t getLayerType() = 0;
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData) {
std::cout<<"No infer action for this layer\n";
return NULL;
}
void setFinal() { this->final = true; }
dataDim_t input_dim, output_dim;
dnnType *dstData = nullptr; //where results will be putted
int id = 0;
bool final; //if the layer is the final one
uint n_params = 0;
uint feature_map_size = 0;
long unsigned MACC = 0;
std::string getLayerName() {
layerType_t type = getLayerType();
switch(type) {
case LAYER_INPUT: return "Input";
case LAYER_DENSE: return "Dense";
case LAYER_CONV2D: return "Conv2d";
case LAYER_DECONV2D: return "DeConv2d";
case LAYER_DEFORMCONV2D: return "DeformConv2d";
case LAYER_LSTM: return "LSTM";
case LAYER_ACTIVATION: return "Activation";
case LAYER_ACTIVATION_CRELU: return "ActivationCReLU";
case LAYER_ACTIVATION_LEAKY: return "ActivationLeaky";
case LAYER_ACTIVATION_MISH: return "ActivationMish";
case LAYER_ACTIVATION_LOGISTIC: return "ActivationLogistic";
case LAYER_FLATTEN: return "Flatten";
case LAYER_RESHAPE: return "Reshape";
case LAYER_RESIZE: return "Resize";
case LAYER_MULADD: return "MulAdd";
case LAYER_POOLING: return "Pooling";
case LAYER_SOFTMAX: return "Softmax";
case LAYER_ROUTE: return "Route";
case LAYER_REORG: return "Reorg";
case LAYER_SHORTCUT: return "Shortcut";
case LAYER_UPSAMPLE: return "Upsample";
case LAYER_REGION: return "Region";
case LAYER_YOLO: return "Yolo";
default: return "unknown";
}
}
protected:
Network *net;
cudnnTensorDescriptor_t srcTensorDesc, dstTensorDesc;
};
/**
Father class of all layer that need to load trained weights
*/
class LayerWgs : public Layer {
public:
LayerWgs(Network *net, int inputs, int outputs, int kh, int kw, int kt,
std::string fname_weights, bool batchnorm = false, bool additional_bias = false, bool deConv = false, int groups = 1);
virtual ~LayerWgs();
int inputs, outputs;
std::string weights_path;
dnnType *data_h, *data_d;
dnnType *bias_h, *bias_d;
// additional bias for DCN
bool additional_bias;
dnnType *bias2_h = nullptr, *bias2_d = nullptr;
//batchnorm
bool batchnorm;
dnnType *power_h = nullptr;
dnnType *scales_h = nullptr, *scales_d = nullptr;
dnnType *mean_h = nullptr, *mean_d = nullptr;
dnnType *variance_h = nullptr, *variance_d = nullptr;
//fp16
__half *data16_h = nullptr, *bias16_h = nullptr;
__half *data16_d = nullptr, *bias16_d = nullptr;
__half *bias216_h = nullptr, *bias216_d = nullptr;
__half *power16_h = nullptr, *power16_d = nullptr;
__half *scales16_h = nullptr, *scales16_d = nullptr;
__half *mean16_h = nullptr, *mean16_d = nullptr;
__half *variance16_h = nullptr, *variance16_d = nullptr;
void releaseHost(bool release32 = true, bool release16 = true) {
if(release32) {
if( data_h != nullptr) { delete [] data_h; data_h = nullptr; }
if( bias_h != nullptr) { delete [] bias_h; bias_h = nullptr; }
if( bias2_h != nullptr) { delete [] bias2_h; bias2_h = nullptr; }
if( scales_h != nullptr) { delete [] scales_h; scales_h = nullptr; }
if( mean_h != nullptr) { delete [] mean_h; mean_h = nullptr; }
if(variance_h != nullptr) { delete [] variance_h; variance_h = nullptr; }
if( power_h != nullptr) { delete [] power_h; power_h = nullptr; }
}
if(net->fp16 && release16) {
if( data16_h != nullptr) { delete [] data16_h; data16_h = nullptr; }
if( bias16_h != nullptr) { delete [] bias16_h; bias16_h = nullptr; }
if( bias216_h != nullptr) { delete [] bias216_h; bias216_h = nullptr; }
if( scales16_h != nullptr) { delete [] scales16_h; scales16_h = nullptr; }
if( mean16_h != nullptr) { delete [] mean16_h; mean16_h = nullptr; }
if(variance16_h != nullptr) { delete [] variance16_h; variance16_h = nullptr; }
if( power16_h != nullptr) { delete [] power16_h; power16_h = nullptr; }
}
}
void releaseDevice(bool release32 = true, bool release16 = true) {
if(release32) {
if( data_d != nullptr) { cudaFree( data_d); data_d = nullptr; }
if( bias_d != nullptr) { cudaFree( bias_d); bias_d = nullptr; }
if( bias2_d != nullptr) { cudaFree( bias2_d); bias2_d = nullptr; }
if( scales_d != nullptr) { cudaFree( scales_d); scales_d = nullptr; }
if( mean_d != nullptr) { cudaFree( mean_d); mean_d = nullptr; }
if(variance_d != nullptr) { cudaFree(variance_d); variance_d = nullptr; }
}
if(net->fp16 && release16) {
if( data16_d != nullptr) { cudaFree( data16_d); data16_d = nullptr; }
if( bias16_d != nullptr) { cudaFree( bias16_d); bias16_d = nullptr; }
if( bias216_d != nullptr) { cudaFree( bias216_d); bias216_d = nullptr; }
if( scales16_d != nullptr) { cudaFree( scales16_d); scales16_d = nullptr; }
if( mean16_d != nullptr) { cudaFree( mean16_d); mean16_d = nullptr; }
if(variance16_d != nullptr) { cudaFree(variance16_d); variance16_d = nullptr; }
if( power16_d != nullptr) { cudaFree( power16_d); power16_d = nullptr; }
}
}
};
/**
Input layer (it doesn't need weights)
*/
class Input : public Layer {
public:
Input(Network *net, dataDim_t &dim, dnnType* srcData) : Layer(net) {
input_dim = dim;
output_dim = dim;
dstData = srcData;
}
virtual ~Input() {}
virtual layerType_t getLayerType() { return LAYER_INPUT; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData) {
dim = output_dim;
return dstData;
}
};
/**
Dense (full interconnection) layer
*/
class Dense : public LayerWgs {
public:
Dense(Network *net, int out_ch, std::string fname_weights);
virtual ~Dense();
virtual layerType_t getLayerType() { return LAYER_DENSE; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
};
/**
Available activation functions
*/
typedef enum {
ACTIVATION_ELU = 100,
ACTIVATION_LEAKY = 101,
ACTIVATION_MISH = 102,
ACTIVATION_LOGISTIC = 103
} tkdnnActivationMode_t;
/**
Activation layer (it doesn't need weights)
*/
class Activation : public Layer {
public:
int act_mode;
float ceiling;
float slope;
Activation(Network *net, int act_mode, const float ceiling=0.0, const float slope=0.1);
virtual ~Activation();
virtual layerType_t getLayerType() {
if(act_mode == CUDNN_ACTIVATION_CLIPPED_RELU)
return LAYER_ACTIVATION_CRELU;
else if (act_mode == ACTIVATION_LEAKY)
return LAYER_ACTIVATION_LEAKY;
else if (act_mode == ACTIVATION_MISH)
return LAYER_ACTIVATION_MISH;
else if (act_mode == ACTIVATION_LOGISTIC)
return LAYER_ACTIVATION_LOGISTIC;
else
return LAYER_ACTIVATION;
};
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
protected:
cudnnActivationDescriptor_t activDesc;
};
/**
Convolutional 2D layer
WEIGHTS shape: OUTCH, INCH, KH, KW ...
BIAS shape: OUTCH
with BATCHNORM:
scales: OUTCH
means: OUTCH
variance: OUTCH
*/
class Conv2d : public LayerWgs {
public:
Conv2d( Network *net, int out_ch, int kernelH, int kernelW,
int strideH, int strideW, int paddingH, int paddingW,
std::string fname_weights, bool batchnorm = false, bool deConv = false, int groups = 1, bool additional_bias=false);
virtual ~Conv2d();
virtual layerType_t getLayerType() { return LAYER_CONV2D; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
int kernelH, kernelW, strideH, strideW, paddingH, paddingW;
bool deConv, additional_bias;
int groups;
protected:
cudnnFilterDescriptor_t filterDesc;
cudnnConvolutionDescriptor_t convDesc;
cudnnConvolutionFwdAlgoPerf_t algo;
cudnnConvolutionBwdDataAlgoPerf_t bwAlgo;
cudnnTensorDescriptor_t biasTensorDesc;
void initCUDNN(bool back = false);
void inferCUDNN(dnnType* srcData, bool back = false);
void* workSpace;
size_t ws_sizeInBytes;
};
/**
Bidirectional LSTM layer
ONLY BIDIRECTIONAL (TODO: more configurable)
currently implemented as 2 inferences: forward and backward (TODO: only 1 cudnn inference)
implementation info:
https://github.com/jiangnanhugo/seq2seq_cuda/blob/e4dbdcfa0517c972bfd4beea9f11a5233954093c/src/rnn.cpp
https://github.com/Jeffery-Song/mxnet-test/blob/aab666faad44011f7a67b527b5f6c960367d0422/src/operator/cudnn_rnn-inl.h
https://stackoverflow.com/a/38737941
https://colah.github.io/posts/2015-08-Understanding-LSTMs/
PARAMS (numlayers*2):
layer0:
( INCH, ? ) ???
( HIDDEN, ? ) ???
( HIDDEN * 8 ) ???
layer2:
( INCH, ? ) ???
( HIDDEN, ? ) ???
( HIDDEN * 8 ) ???
OUTPUT shape:
(N, C, 1, W) ---> LSTM(HIDDEN, returnSeq=True) ---> (N, 2*HIDDEN, 1, W) # W is seqLength
(N, C, 1, W) ---> LSTM(HIDDEN, returnSeq=False) ---> (N, 2*HIDDEN, 1, 1)
*/
class LSTM : public Layer {
public:
LSTM(Network *net, int hiddensize, bool returnSeq, std::string fname_weights);
virtual ~LSTM();
virtual layerType_t getLayerType() { return LAYER_LSTM; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
const bool bidirectional = true; /**> is the net bidir */
bool returnSeq = false; /**> if false return only the result of last timestamp */
int stateSize = 0; /**> number of hidden states */
int seqLen = 0; /**> number of timestamp */
int numLayers = 1; /**> number of internal layers */
protected:
cudnnRNNDescriptor_t rnnDesc;
cudnnDropoutDescriptor_t dropoutDesc;
dnnType *dropout_states_, *work_space_;
size_t workspace_byte_, dropout_byte_;
int workspace_size_, dropout_size_;
std::vector<cudnnTensorDescriptor_t> x_desc_vec_, y_desc_vec_;
cudnnTensorDescriptor_t hx_desc_, cx_desc_;
cudnnTensorDescriptor_t hy_desc_, cy_desc_;
dnnType *hx_ptr, *cx_ptr, *hy_ptr, *cy_ptr;
int stateDataDim;
cudnnFilterDescriptor_t w_desc_;
dnnType *w_ptr;
dnnType *w_h;
dnnType *wf_ptr, *wb_ptr; // params pointer forward and backward layer
// used during inference
dataDim_t one_output_dim; // output dim of as single inference
dnnType *srcF, *srcB; // input of single inference
dnnType *dstF, *dstB_NR, *dstB; // output of single inference, dstB_NR = dstB not reversed
};
/**
Convolutional 2D layer
*/
class DeConv2d : public Conv2d {
public:
DeConv2d( Network *net, int out_ch, int kernelH, int kernelW,
int strideH, int strideW, int paddingH, int paddingW,
std::string fname_weights, bool batchnorm = false, int groups = 1) :
Conv2d(net, out_ch, kernelH, kernelW, strideH, strideW, paddingH, paddingW, fname_weights, batchnorm, true, groups) {}
virtual ~DeConv2d() {}
virtual layerType_t getLayerType() { return LAYER_DECONV2D; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
};
/**
Deformable Convolutional 2d layer
*/
class DeformConv2d : public LayerWgs {
public:
DeformConv2d( Network *net, int out_ch, int deformable_group, int kernelH, int kernelW,
int strideH, int strideW, int paddingH, int paddingW,
std::string d_fname_weights, std::string fname_weights, bool batchnorm);
virtual ~DeformConv2d();
virtual layerType_t getLayerType() { return LAYER_DEFORMCONV2D; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
tk::dnn::Conv2d *preconv;
int out_ch;
int deformableGroup;
int kernelH, kernelW, strideH, strideW, paddingH, paddingW;
dnnType *ones_d1;
dnnType *ones_d2;
int chunk_dim;
dnnType *offset, *mask;
dnnType *output_conv;
cublasStatus_t stat;
cublasHandle_t handle;
protected:
cudnnTensorDescriptor_t biasTensorDesc;
void initCUDNN();
};
/**
Flatten layer
is actually a matrix transposition
*/
class Flatten : public Layer {
public:
Flatten(Network *net);
virtual ~Flatten();
virtual layerType_t getLayerType() { return LAYER_FLATTEN; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
};
/**
Reshape layer
*/
class Reshape : public Layer {
public:
Reshape(Network *net, dataDim_t new_dim);
virtual ~Reshape();
virtual layerType_t getLayerType() { return LAYER_RESHAPE; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
};
enum ResizeMode_t { NEAREST= 0,
LINEAR= 1};
/**
Resize layer
*/
class Resize : public Layer {
public:
Resize(Network *net, int scale_c, int scale_h, int scale_w, bool fixed=false, ResizeMode_t mode=NEAREST);
virtual ~Resize();
virtual layerType_t getLayerType() { return LAYER_RESIZE; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
ResizeMode_t mode;
};
/**
MulAdd layer
apply a multiplication and then an addition for each data
*/
class MulAdd : public Layer {
public:
MulAdd(Network *net, dnnType mul, dnnType add);
virtual ~MulAdd();
virtual layerType_t getLayerType() { return LAYER_MULADD; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
protected:
dnnType mul, add;
dnnType *add_vector;
};
/**
Available pooling functions (padding on tkDNN is not supported)
*/
typedef enum {
POOLING_MAX = 0,
POOLING_AVERAGE = 1, // count for average includes padded values
POOLING_AVERAGE_EXCLUDE_PADDING = 2, // count for average does not include padded values
POOLING_MAX_FIXEDSIZE = 100 // max pool darknet fashion
} tkdnnPoolingMode_t;
/**
Pooling layer
currently supported only 2d pooing (also on 3d input)
*/
class Pooling : public Layer {
public:
int winH, winW;
int strideH, strideW;
int paddingH, paddingW;
bool size;
tkdnnPoolingMode_t pool_mode;
Pooling(Network *net, int winH, int winW,
int strideH, int strideW,
int paddingH, int paddingW,
tkdnnPoolingMode_t pool_mode);
virtual ~Pooling();
virtual layerType_t getLayerType() { return LAYER_POOLING; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
protected:
cudnnPoolingDescriptor_t poolingDesc;
dnnType *tmpInputData, *tmpOutputData;
bool poolOn3d;
};
/**
Softmax layer
*/
class Softmax : public Layer {
public:
Softmax(Network *net, const tk::dnn::dataDim_t* dim=nullptr, const cudnnSoftmaxMode_t mode=CUDNN_SOFTMAX_MODE_CHANNEL);
virtual ~Softmax();
virtual layerType_t getLayerType() { return LAYER_SOFTMAX; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
dataDim_t dim;
cudnnSoftmaxMode_t mode;
};
/**
Route layer
Merge a list of layers
*/
class Route : public Layer {
public:
Route(Network *net, Layer **layers, int layers_n, int groups = 1, int group_id = 0);
virtual ~Route();
virtual layerType_t getLayerType() { return LAYER_ROUTE; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
public:
static const int MAX_LAYERS = 32;
Layer *layers[MAX_LAYERS]; //ids of layers to be merged
int layers_n; //number of layers
int groups;
int group_id;
};
/**
Reorg layer
Maintains same dimension but change C*H*W distribution
*/
class Reorg : public Layer {
public:
Reorg(Network *net, int stride);
virtual ~Reorg();
virtual layerType_t getLayerType() { return LAYER_REORG; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
int stride;
};
/**
Shortcut layer
sum with stride another layer
*/
class Shortcut : public Layer {
public:
Shortcut(Network *net, Layer *backLayer, bool mul=false);
virtual ~Shortcut();
virtual layerType_t getLayerType() { return LAYER_SHORTCUT; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
public:
Layer *backLayer;
bool mul = false;
};
/**
Upsample layer
Maintains same dimension but change C*H*W distribution
*/
class Upsample : public Layer {
public:
Upsample(Network *net, int stride);
virtual ~Upsample();
virtual layerType_t getLayerType() { return LAYER_UPSAMPLE; };
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
int stride;
bool reverse;
};
struct box {
int cl;
float x, y, w, h;
float prob;
std::vector<float> probs;
void print()
{
std::cout<<"x: "<<x<<"\ty: "<<y<<"\tw: "<<w<<"\th: "<<h<<"\tcl: "<<cl<<"\tprob: "<<prob<<std::endl;
}
};
struct sortable_bbox {
int index;
int cl;
float **probs;
};
struct box3D {
int cl;
std::vector<float> corners;
float prob;
void print()
{
std::cout<<"\tcl: "<<cl<<"\tprob: "<<prob<<"\tshape corners: "<<corners.size()<<std::endl;
}
};
/**
Yolo3 layer
*/
class Yolo : public Layer {
public:
struct box {
float x, y, w, h;
};
struct detection{
Yolo::box bbox;
int classes;
float *prob;
float *mask;
float objectness;
int sort_class;
};
enum nmsKind_t {GREEDY_NMS=0, DIOU_NMS=1};
Yolo(Network *net, int classes, int num, std::string fname_weights,int n_masks=3, float scale_xy=1, double nms_thresh=0.45, nmsKind_t nsm_kind=GREEDY_NMS, int new_coords=0);
virtual ~Yolo();
virtual layerType_t getLayerType() { return LAYER_YOLO; };
int classes, num, n_masks, new_coords;
dnnType *mask_h, *mask_d; //anchors
dnnType *bias_h, *bias_d; //anchors
float scaleXY;
double nms_thresh;
nmsKind_t nsm_kind;
std::vector<std::string> classesNames;
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
int computeDetections(Yolo::detection *dets, int &ndets, int netw, int neth, float thresh, int new_coords=0);
dnnType *predictions;
static const int MAX_DETECTIONS = 8192*2;
static Yolo::detection *allocateDetections(int nboxes, int classes);
static void mergeDetections(Yolo::detection *dets, int ndets, int classes, double nms_thresh=0.45, nmsKind_t nsm_kind=GREEDY_NMS);
};
/**
Region layer
*/
class Region : public Layer {
public:
Region(Network *net, int classes, int coords, int num);
virtual ~Region();
virtual layerType_t getLayerType() { return LAYER_REGION; };
int classes, coords, num;
virtual dnnType* infer(dataDim_t &dim, dnnType* srcData);
};
class RegionInterpret {
public:
RegionInterpret(dataDim_t input_dim, dataDim_t output_dim,
int classes, int coords, int num, float thresh, std::string fname_weights);
~RegionInterpret();
dataDim_t input_dim, output_dim;
dnnType *bias_h, *bias_d; //anchors
int classes, coords, num;
float thresh;
box *boxes;
float **probs;
sortable_bbox *s;
box res_boxes[256];
int res_boxes_n;
box get_region_box(float *x, float *biases, int n, int index, int i, int j, int w, int h, int stride);
void get_region_boxes( float *input, int w, int h, int netw, int neth, float thresh,
float **probs, box *boxes, int only_objectness,
int *map, float tree_thresh, int relative);
void correct_region_boxes(box *boxes, int n, int w, int h, int netw, int neth, int relative);
void interpretData(dnnType *data_h, int imageW = 0, int imageH = 0);
void showImageResult(dnnType *input_h);
static float box_iou(box a, box b);
};
}}
#endif //LAYER_H