cuDNN C++ 实现 Dropout:原理与代码实战(二,成功,感谢deepseek与百度)
百度关键收获:
// 5. 查询 Reserve Space 大小 (用于存储 Mask)
size_t reserveSize;
CHECK_CUDNN(cudnnDropoutGetReserveSpaceSize(xDesc, &reserveSize)); // 分配 Reserve Space 内存 (GPU)
void *d_reserveSpace;
cudaMalloc(&d_reserveSpace, reserveSize);
。。。。。。
CHECK_CUDNN(cudnnDropoutForward(handle, dropoutDesc, xDesc, d_x, yDesc, d_y, d_reserveSpace, reserveSize)); // --- 执行反向传播 --- // 假设 d_dy 已经被上一层的反向传播填充好了梯度值 // 这里仅演示调用接口
CHECK_CUDNN(cudnnDropoutBackward( handle, // cuDNN handle
dropoutDesc, // 与前向传播相同的 dropout 描述符
yDesc, // dy 的描述符 (通常与 dx 形状相同)
d_dy, // 输出梯度 (来自上一层)
xDesc, // dx 的描述符
d_dx, // 输入梯度 (结果写入这里)
d_reserveSpace, // 必须与前向传播使用的 reserveSpace 指针完全一致
reserveSize // reserveSpace 的大小 ));
下面是我封装的dropout类,就这么实现了:
class Dropout :public Layer {
public:
Dropout(cudnnHandle_t& handle, int n, int c, int h, int w) :_handle(handle), _n(n), _c(c), _h(h), _w(w) {
//描述子初始化
cudnnCreateTensorDescriptor(&_input_desc);
cudnnCreateTensorDescriptor(&_output_desc);
cudnnCreateDropoutDescriptor(&dropout_desc);
//描述子设置
cudnnSetTensor4dDescriptor(_input_desc, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, _n, _c, _h, _w);
cudnnSetTensor4dDescriptor(_output_desc, CUDNN_TENSOR_NCHW, CUDNN_DATA_FLOAT, _n, _c, _h, _w);
// 获取保存随机数状态所需内存大小
cudnnDropoutGetStatesSize(handle, &states_size);
// 分配状态内存
cudaMalloc(&states, states_size);
// 初始化 Dropout 描述符
cudnnSetDropoutDescriptor(dropout_desc, handle, dropout_prob,
states, states_size, seed);
// 5. 查询 Reserve Space 大小 (用于存储 Mask)
cudnnDropoutGetReserveSpaceSize(_input_desc, &reserveSize);
// 分配 Reserve Space 内存 (GPU)
cudaMalloc(&d_reserveSpace, reserveSize);//在deepseek的基础上,成功的关键
//分配GPU内存
cudaMalloc(&_output, sizeof(float) * _n * _c * _h * _w);
cudaMalloc(&_grad_input, sizeof(float) * _n * _c * _h * _w);
}
void forward(float* input)override {
_input = input;
// 7. 执行前向 Dropout
cudnnDropoutForward(_handle, dropout_desc, _input_desc, _input,
_output_desc, _output, d_reserveSpace, reserveSize);//在deepseek的基础上,成功的关键
}
void forward2(float* input)override {
_input = input;//推理forward函数,这个很容易处理,否则测试不出成绩!202609052303
//forward(_input);//推理不要这个forward
}
void backward(float* grad_output)override {
// 13. 执行反向 Dropout
// 注意:必须复用前向的 dropout_desc 和 states,保证掩码一致
cudnnDropoutBackward(_handle, dropout_desc, _output_desc, grad_output,
_input_desc, _grad_input, d_reserveSpace, reserveSize);//在deepseek的基础上,成功的关键
}
int getname() override { return 10; }
float* get_output()override { return _output; }
float* get_grad_input()override { return _grad_input; }
void update(float lr) override {}
~Dropout() {
cudaFree(_output);
cudaFree(_grad_input);
cudaFree(d_reserveSpace);
cudaFree(states);
cudnnDestroyTensorDescriptor(_input_desc);
cudnnDestroyTensorDescriptor(_output_desc);
cudnnDestroyDropoutDescriptor(dropout_desc);
}
private:
float* _input;
float* _output;
float* _grad_input;
int _n, _c, _h, _w;
cudnnHandle_t& _handle;
cudnnTensorDescriptor_t _input_desc;//输入(同时也是输出)张量的描述子
cudnnTensorDescriptor_t _output_desc;
// 6. 创建 Dropout 描述符并设置参数
cudnnDropoutDescriptor_t dropout_desc;
float dropout_prob = 0.2f; // 丢弃概率
unsigned long long seed = 2024ULL; // 随机种子
void* states;
size_t states_size = 0;
size_t reserveSize;
void* d_reserveSpace;
};
更多推荐


所有评论(0)