百度关键收获:

// 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;
};

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐