• 实验项目5.1 深度学习算法与硬件加速器


    实验对CPU的修改不多,如果完全按照RISC-V的要求设计CPU,将mul归类为R-Type的话,改动较多。但是我们可以单独设计一跟op_mul电线,然后单独设计乘法指令。
    在这里插入图片描述

    乘法指令的实现,直接使用其提供的乘法部件即可:

    wire [31: 0] Result_MUL = RF_rdata1*RF_rdata2; 
    
    • 1
    随后在选数里增加一项MUL的指令:
    
    • 1
        assign RF_wdata = {32{op_shift}}&shift_result|
                          {32{op_J_Type}}&PC_4|
                          {32{op_lui}}&extend|
                          {32{op_auipc}}&(PC_temp+extend)|
                          {32{(op_I_Type|op_R_Type)&~op_shift}}&ALU_result|
                          {32{op_lw}}&load_word|
                          {32{op_lb }}& {{24{load_byte[7]}},load_byte}|
                          {32{op_lbu}}& {{24{1'b0}},load_byte}|
                          {32{op_lh}}& {{16{load_half[15]}},load_half}|
                          {32{op_lhu}}& {{16{1'b0}},load_half}|
                          {32{op_mul}}& Result_MUL
                          ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    并按照R-Type的指令设计,设计自动机的转移:

                `state_EX : begin
                    if(op_B_Type)
                        next_state = `state_IF;
                    else 
                        if(op_R_Type|op_I_Type|op_U_Type|op_J_Type|op_mul)
                            next_state = `state_WB;
                        else 
                            if(op_S_Type)
                                next_state = `state_ST;
                            else 
                                if(op_L_Type)
                                    next_state = `state_LD;
                                else 
                                    next_state= `state_EX; 
                end 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其次是DNN相关的代码:
    按照定义,需要设计几种中间变量:

        short bias;
        short num_out;//output
        short num_in;//input
        short y,x,ky,kx;
        short k_square=1+mul(weight_size.d2,weight_size.d3);
        short in_square=mul(input_fm_h,input_fm_w);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    bias指的是偏移量,存在 F i l t e r [ i ] [ 0 ] [ 0 ] Filter\left[i\right]\left[0\right]\left[0\right] Filter[i][0][0]位置。
    其次num_in和num_out分别是吗枚举读入的图片通道数和输出的特征图片通道数。
    x、y枚举的是当前图像处理的像素点位置,kx、ky指的是每一次卷积操作的时候卷积核的相对位置。
    k_square和in_square是计算下标的中间变量。
    在设计out的赋值时我发现,其赋值规律是顺序的,所以可以设计一个outoffset来计算位置。

        int out_offset=0;
        short bias_offset=mul(rd_size.d1,k_square); 
    
    • 1
    • 2

    在这里插入图片描述

    在第一重循环,枚举的是当前输出的通道数,在这一层可以计算bias的值。在第二层,枚举输入的通道数,随后枚举当前通道这张图片的像素点位置。在这种过程中,更据定义,需要增加当前图片间的步长Stride_X、Stride_Y。对于每个卷积核,其每个方块的由kx、ky两个块进行枚举。
    在这里由于存在边界填充,所以存在一个pad的偏移,于是在这里需要作差的得到iw和ih。随后求出当前的像素值和卷积的权重,随后便可以计算卷积后的结果,在这里中间变量需要用32位整数存储。
    在这里,值得注意的是16位定点数的符号位需要由32位定点数的符号位求出。最后,由于发现输出特征图的像素顺序是良序的,所以可以直接不断加1得到结果。
    另外一个比较重要的步骤是池化操作,池化操作本质是取最大值,所以实现起来比较简单。
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    池化操作的计算也就是找到对应像素点位置,然后比个大小就可以了。注意到这里最大值max的初始值是0x8000,这在16位定点数里表示最小值,因此一定会被更大的数所替换。
    硬件加速器就很简单了:

    #ifdef USE_HW_ACCEL
    void launch_hw_accel()
    {
        volatile int* gpio_start = (void*)(GPIO_START_ADDR);
        volatile int* gpio_done = (void*)(GPIO_DONE_ADDR);
        * gpio_start =(* gpio_start )|0x01;
        while(1){
            if((*(volatile char*)gpio_done)&0x01)break;
        }
        return;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    按照流程图,如果开始将对应位置低位赋值1,如果检测到结束位置低位赋值1就结束。

  • 相关阅读:
    决策树——预剪枝和后剪枝
    Qt扫盲-QListView理论总结
    MySQL基础操作
    TerraNoise for 3dMax插件教程
    MySQL 快速入门之第一章 账号管理、建库以及四大引擎
    Jenkins权限配置和构建VUE项目
    linux 安装docker
    DJYOS事件调度解析:事件、事件调度和线程调度关系
    php-fpm详解
    陕西秦创原创新驱动平台案例解读
  • 原文地址:https://blog.csdn.net/fcb_x/article/details/126524733