基于CNN(LeNet)的垃圾分类(C语言实现)

2023-05-16

基于CNN(LeNet)的垃圾分类(C语言实现CNN算子)

  • 一、先使用python训练模型
  • 二、提取参数
    • 提取模型参数
    • 提取图片
  • 三、编写CNN算子
    • 在windows中实现
    • 在FPGA中实现,使用avalon接口


一、先使用python训练模型

具体步骤参考基于pytorch的MNIST数据集的四层CNN,测试准确率99.77%这篇文章,各种步骤我写的很详细,只需要将MNIST数据集换成垃圾分类的数据集,再调整一下参数就好了。

二、提取参数

提取模型参数

权重和偏置
我们需要提取每一个具有学习的参数的训练层的权重和偏置,我使用了两层卷积和两层全连接,就要提取两个卷积层的权重和偏置,两个全连接层的权重和偏置。

# Extraction_Parameter.py
#引入库
#引用需要用到的库
import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

#model
class CNNModel(nn.Module):
    def __init__(self):
        super(CNNModel, self).__init__()
        
        # Convolution layer 1
        self.conv1 = nn.Conv2d(in_channels = 3 , out_channels = 8, kernel_size = 3, stride = 1, padding = 0 )
        self.relu1 = nn.ReLU()
        self.maxpool1 = nn.MaxPool2d(kernel_size = 2, stride = 2)
        
        # Convolution layer 2
        self.conv2 = nn.Conv2d(in_channels =8 , out_channels = 16, kernel_size = 3, stride = 1, padding = 0 )
        self.relu2 = nn.ReLU()
        self.maxpool2 = nn.MaxPool2d(kernel_size = 2, stride = 2)
        
        # Fully-Connected layer 1
        self.fc1 = nn.Linear(400,40)
        
        # Fully-Connected layer 2
        self.fc2 = nn.Linear(40,4)
        
    
    def forward(self, x):
        # conv layer 1 的前向计算,3行代码
        out = self.conv1(x)
        #print(out.shape)
        out = self.relu1(out)
        out = self.maxpool1(out)
        #print(out.shape)
        
        # conv layer 2 的前向计算,3行代码
        out = self.conv2(out)
        #print(out.shape)
        out = self.relu2(out)
        out = self.maxpool2(out)
        #print(out.shape)
        
        #Flatten拉平操作
        out = out.view(out.size(0),-1)
        #print(out.shape)
        #FC layer的前向计算(2行代码)
        out = self.fc1(out)
        out = self.fc2(out)
  
        return F.log_softmax(out,dim = 1)


#实例化模型
network = CNNModel()

#加载模型
model_path = "model1.pth"
network.load_state_dict(torch.load(model_path, map_location = torch.device('cpu')))
#network.eval()

parm = {}
for name,parameters in network.state_dict().items():

    parm[name] = parameters.detach().numpy()
    print(name, parameters)

w1 = parm['conv1.weight']
b1 = parm['conv1.bias']
w2 = parm['conv2.weight']
b2 = parm['conv2.bias']

fc1_w = parm['fc1.weight']
fc1_b = parm['fc1.bias']
fc2_w = parm['fc2.weight']
fc2_b = parm['fc2.bias']

#print(type(w1))
#print(len(w1[0]))
#print(len(w1[0][0]))
#print(len(w1[0][0][0]))

#conv1_wb
with open("parameters1_wb.h","a") as f:
    print(type(w1))
    #new_str1 = str(np.transpose(w1).tolist())
    new_str1 = str(w1.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float conv1_weight[8][3][9] = {" + new_str3 + "};\n\n")
    print("第一层卷积的权重保存成功")
    f.close()

with open("parameters1_wb.h","a") as f:
    print(type(b1))
    #new_str1 = str(np.transpose(b1).tolist())
    new_str1 = str(b1.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float conv1_bias[8] = {" + new_str3 + "};\n\n")
    print("第一层卷积的偏置保存成功")
    f.close()

#conv2_wb
with open("parameters1_wb.h","a") as f:
    print(type(w2))
    #new_str1 = str(np.transpose(w2).tolist())
    new_str1 = str(w2.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float conv2_weight[16][8][9] = {" + new_str3 + "};\n\n")
    print("第二层卷积的权重保存成功")
    f.close()

with open("parameters1_wb.h","a") as f:
    print(type(b2))
    #new_str1 = str(np.transpose(b2).tolist())
    new_str1 = str(b2.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float conv2_bias[16] = {" + new_str3 + "};\n\n")
    print("第二层卷积的偏置保存成功")
    f.close()


#fc1_wb
with open("parameters1_wb.h","a") as f:
    print(type(fc1_w))
    new_str1 = str(np.transpose(fc1_w).tolist())
    #new_str1 = str(fc1_w.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float fc1_weight[" + str(400*40) + "] = {" + new_str3 + "};\n\n")
    print("第一层全连接的权重保存成功")
    f.close()

with open("parameters1_wb.h","a") as f:
    print(type(fc1_b))
    #new_str1 = str(np.transpose(fc1_b).tolist())
    new_str1 = str(fc1_b.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float fc1_bias[40] = {" + new_str3 + "};\n\n")
    print("第一层全连接的偏置保存成功")
    f.close()


#fc2_wb
with open("parameters1_wb.h","a") as f:
    print(type(fc2_w))
    new_str1 = str(np.transpose(fc2_w).tolist())
    #new_str1 = str(fc2_w.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float fc2_weight[" + str(40*4) + "] = {" + new_str3 + "};\n\n")
    print("第二层全连接的权重保存成功")
    f.close()

with open("parameters1_wb.h","a") as f:
    print(type(fc2_b))
    #new_str1 = str(np.transpose(fc2_b).tolist())
    new_str1 = str(fc2_b.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float fc2_bias[4] = {" + new_str3 + "};\n\n")
    print("第二层全连接的偏置保存成功")
    f.close()

提取成功后会得到一个parameters1_wb.h文件,如图所示
模型的权重和偏置

提取图片

将测试的图片同样提取为.h文件

# Extract_Image.py
from torchvision import transforms
import torch
import numpy as np
from PIL import Image
from itertools import chain

# 在训练模型时对图片进行怎样的预处理
# 在提取图片参数时需要先进行同样的处理再提取,不然维度数据对不上
data_transform = transforms.Compose(
    [transforms.ToTensor()
     #transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
     ])

img = Image.open("./test/Others1.jpg")#预测图片
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
img = img.numpy()
#img = img * (1.0/255.0)
#img = img.tolist()

print(img)

#参数提取
with open("pic1.h","a") as f:
    #new_str1 = str(np.transpose(img).tolist())
    new_str1 = str(img.tolist())
    new_str2 = new_str1.replace('[','')
    new_str3 = new_str2.replace(']','')
    f.write("float Others2" + "[3][28][28] = {" + new_str3 + "};\n\n")
    print("图片Others1参数读取完成")
    f.close()

提取的图片

三、编写CNN算子

在windows中实现

#include <stdio.h>
#include "parameters1_wb.h"
#include "pic1.h"

#define CONV_KERNEL_SIZE 3
#define POLL_KERNEL_SIZE 2
#define POLL_STRIDE 2

#define IMG_SIZE 28
#define CONV1_IN_KERNEL 3
#define CONV1_OUT_SIZZE 26
#define CONV1_OUT_KERNEL 8
#define POLL1_OUT_SIZE 13 

#define CONV2_OUT_KERNEL 16
#define CONV2_OUT_SIZE 11
#define POLL2_OUT_SIZE 5

#define FC_X 400    //16*5*5
#define FC1_OUT 40 
#define FC1_B 40

#define FC2_OUT 4 
#define FC2_B 4


int cnn_predict(float img[CONV1_IN_KERNEL][IMG_SIZE][IMG_SIZE],
                float conv1_w[CONV1_OUT_KERNEL][CONV1_IN_KERNEL][CONV_KERNEL_SIZE * CONV_KERNEL_SIZE],
                float conv1_b[CONV1_OUT_KERNEL],
                float conv2_w[CONV2_OUT_KERNEL][CONV1_OUT_KERNEL][CONV_KERNEL_SIZE * CONV_KERNEL_SIZE],
                float conv2_b[CONV2_OUT_KERNEL],
                float fc1_w[FC_X * FC1_OUT],
                float fc1_b[FC1_B],
                float fc2_w[FC1_OUT * FC2_OUT],
                float fc2_b[FC2_B])
{
    //---------------------------第一层卷积---------------------------//
    //in img size : 3*28*28  
    //out img size : 8*26*26
    printf("\n------------------------------------Conv1_out------------------------------------\n");
    int conv1_row, conv1_col, conv1_out_kernel, conv1_in_kernel, conv1_i, conv1_j;
    float temp;
    float conv1_out[CONV1_OUT_KERNEL][CONV1_OUT_SIZZE][CONV1_OUT_SIZZE] = {0.0};
    for(conv1_out_kernel = 0; conv1_out_kernel < CONV1_OUT_KERNEL; conv1_out_kernel++)
    {
        //行卷积
        for(conv1_row = 0; conv1_row < IMG_SIZE - CONV_KERNEL_SIZE + 1; conv1_row++)
        {
            //列卷积
            for(conv1_col = 0; conv1_col < IMG_SIZE - CONV_KERNEL_SIZE + 1; conv1_col++)
            {
                temp = 0.0;
                //多通道
                for(conv1_in_kernel = 0; conv1_in_kernel < CONV1_IN_KERNEL; conv1_in_kernel++)
                {   
                    //单点卷积计算
                    //temp = 0,.0;
                    for(conv1_i = 0; conv1_i < CONV_KERNEL_SIZE; conv1_i++)
                    {
                        for(conv1_j = 0; conv1_j < CONV_KERNEL_SIZE; conv1_j++)
                        {
                            float a = img[conv1_in_kernel][conv1_i + conv1_row][conv1_j + conv1_col];
                            float b = conv1_w[conv1_out_kernel][conv1_in_kernel][conv1_i * CONV_KERNEL_SIZE + conv1_j];
                            temp +=  a * b;
                        }
                    }
                }
                temp += conv1_b[conv1_out_kernel];//加偏置
                conv1_out[conv1_out_kernel][conv1_row][conv1_col] = temp > 0 ? temp : 0;//加激活
                printf("%f ",conv1_out[conv1_out_kernel][conv1_row][conv1_col]);
                if(conv1_col % 6 == 0)
                {
                    printf("\n");
                }
            }
        }
    }

    //---------------------------第一层池化---------------------------//
    //in img size : 8*26*26 
    //out img size : 8*13*13
    printf("\n------------------------------------Poll1_out------------------------------------\n");
    int poll1_kernel, poll1_row, poll1_col, poll1_i, poll1_j;
    float poll1_out[CONV1_OUT_KERNEL][POLL1_OUT_SIZE][POLL1_OUT_SIZE] = {0};
    for(poll1_kernel = 0; poll1_kernel < CONV1_OUT_KERNEL; poll1_kernel++)
    {
        //行池化
        for(poll1_row = 0; poll1_row < (CONV1_OUT_SIZZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll1_row++)
        {
            //列池化
            for(poll1_col = 0; poll1_col < (CONV1_OUT_SIZZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll1_col++)
            {
                temp = 0.0;
                //单点池化计算
                for(poll1_i = 0; poll1_i < POLL_KERNEL_SIZE; poll1_i++)
                {
                    for(poll1_j = 0; poll1_j < POLL_KERNEL_SIZE; poll1_j++)
                    {
                        temp = (conv1_out[poll1_kernel][poll1_i + poll1_row * POLL_STRIDE][poll1_j + poll1_col * POLL_STRIDE] > temp) ? 
                        conv1_out[poll1_kernel][poll1_i + poll1_row * POLL_STRIDE][poll1_j + poll1_col * POLL_STRIDE] : temp; 
                    }
                }
                poll1_out[poll1_kernel][poll1_row][poll1_col] = temp;
                printf("%f ",poll1_out[poll1_kernel][poll1_row][poll1_col]);
                if(poll1_col % 6 == 0)
                {
                    printf("\n");
                }
            }
        }
    }

    //---------------------------第二层卷积---------------------------//
    //in img size : 8*13*13 
    //out img size : 16*11*11
    printf("\n------------------------------------Conv2_out------------------------------------\n");
    int conv2_row, conv2_col, conv2_out_kernel, conv2_in_kernel, conv2_i, conv2_j;
    float conv2_out[CONV2_OUT_KERNEL][CONV2_OUT_SIZE][CONV2_OUT_SIZE] = {0.0};
    for(conv2_out_kernel = 0; conv2_out_kernel < CONV2_OUT_KERNEL; conv2_out_kernel++)
    {
        //行卷积
        for(conv2_row = 0; conv2_row < POLL1_OUT_SIZE - CONV_KERNEL_SIZE + 1; conv2_row++)
        {
            //列卷积
            for(conv2_col = 0; conv2_col < POLL1_OUT_SIZE - CONV_KERNEL_SIZE + 1; conv2_col++)
            {
                temp = 0.0;
                //多通道
                for(conv2_in_kernel = 0; conv2_in_kernel < CONV1_OUT_KERNEL; conv2_in_kernel++)
                {   
                    //单点卷积计算
                    //temp = 0,.0;
                    for(conv2_i = 0; conv2_i < CONV_KERNEL_SIZE; conv2_i++)
                    {
                        for(conv2_j = 0; conv2_j < CONV_KERNEL_SIZE; conv2_j++)
                        {
                            float a = poll1_out[conv2_in_kernel][conv2_i + conv2_row][conv2_j + conv2_col];
                            float b = conv2_w[conv2_out_kernel][conv2_in_kernel][conv2_i * CONV_KERNEL_SIZE + conv2_j];
                            temp +=  a * b;
                        }
                    }
                }
                temp += conv2_b[conv2_out_kernel];//加偏置
                conv2_out[conv2_out_kernel][conv2_row][conv2_col] = temp > 0 ? temp : 0;//加激活
                printf("%f ",conv2_out[conv2_out_kernel][conv2_row][conv2_col]);
                if(conv2_col % 6 == 0)
                {
                    printf("\n");
                }
            }
        }
    }

    //---------------------------第二层池化---------------------------//
    //in img size : 16*11*11
    //out img size : 16*5*5
    printf("\n------------------------------------Poll2_out------------------------------------\n");
    int poll2_kernel, poll2_row, poll2_col, poll2_i, poll2_j;
    float poll2_out[CONV2_OUT_KERNEL][POLL2_OUT_SIZE][POLL2_OUT_SIZE] = {0};
    for(poll2_kernel = 0; poll2_kernel < CONV2_OUT_KERNEL; poll2_kernel++)
    {
        //行池化
        for(poll2_row = 0; poll2_row < (CONV2_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll2_row++)
        {
            //列池化
            for(poll2_col = 0; poll2_col < (CONV2_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll2_col++)
            {
                temp = 0.0;
                //单点池化计算
                for(poll2_i = 0; poll2_i < POLL_KERNEL_SIZE; poll2_i++)
                {
                    for(poll2_j = 0; poll2_j < POLL_KERNEL_SIZE; poll2_j++)
                    {
                        temp = (conv2_out[poll2_kernel][poll2_i + poll2_row * POLL_STRIDE][poll2_j + poll2_col * POLL_STRIDE] > temp) ? 
                        conv2_out[poll2_kernel][poll2_i + poll2_row * POLL_STRIDE][poll2_j + poll2_col * POLL_STRIDE] : temp; 
                    }
                }
                poll2_out[poll2_kernel][poll2_row][poll2_col] = temp;
                printf("%f ",poll2_out[poll2_kernel][poll2_row][poll2_col]);
                if(poll2_col % 6 == 0)
                {
                    printf("\n");
                }
            }
        }
    }

    //---------------------------多维数组转一维---------------------------//
    //in img size : 16*5*5 3维
    //out img size : 400  1维
    printf("\n------------------------------------N to one------------------------------------\n");
    float out[FC_X] = {0.0};
    int i, j, k;
    for(k = 0; k < CONV2_OUT_KERNEL; k++)
    {
        for(i = 0; i < POLL2_OUT_SIZE; i++)
        {
            for(j = 0; j < POLL2_OUT_SIZE; j++)
            {
            //这个公式很重要,有时候由于硬件问题使用多维数组进行
            //运算会造成内存溢出,程序无法运行,这时就需要将所有的
            //数据都转换成一维数组进行运算,就需要用到这个公式
            //(通道数 - 1) * 行 * 列 + (行 - 1) * 行 + 列
            //16*5*5 = 400 = 15*5*5 + 4*5 + 5 
                out[k * POLL2_OUT_SIZE * POLL2_OUT_SIZE + i * POLL2_OUT_SIZE + j] = poll2_out[k][i][j];
                printf("%f ",out[k * POLL2_OUT_SIZE * POLL2_OUT_SIZE + i * POLL2_OUT_SIZE + j]);
            }
        }
    }

    //---------------------------第一层全连接---------------------------//
    //in img size : 400
    //out img size : 40
    printf("\n------------------------------------ FC1_OUT ------------------------------------\n");
    int fc1_i, fc1_j;
    float fc1_out[FC1_OUT] = {0.0};
    for(fc1_i = 0; fc1_i < FC1_OUT; fc1_i++)
    {
        temp = 0.0;
        for(fc1_j = 0; fc1_j < FC_X; fc1_j++)
        {
            temp += fc1_w[fc1_j * FC1_OUT + fc1_i] * out[fc1_j];
        }
        //加偏置
        temp +=  fc1_b[fc1_i];
        fc1_out[fc1_i] = temp;
        printf("  %f  ",fc1_out[fc1_i]);
        if(fc1_i % 8 == 0)
        {
            printf("\n");
        }
    }

    //---------------------------第二层全连接---------------------------//
    //in img size : 40
    //out img size : 4
    printf("\n------------------------------------ FC2_OUT ------------------------------------\n");
    int fc2_i, fc2_j;
    float fc2_out[FC2_OUT] = {0.0};
    for(fc2_i = 0; fc2_i < FC2_OUT; fc2_i++)
    {
        temp = 0.0;
        for(fc2_j = 0; fc2_j < FC1_OUT; fc2_j++)
        {
            temp += fc2_w[fc2_j * FC2_OUT + fc2_i] * fc1_out[fc2_j];
        }
        //加偏置
        temp +=  fc2_b[fc2_i];
        fc2_out[fc2_i] = temp;
        printf("  %f  ",fc2_out[fc2_i]);
        if(fc2_i % 8 == 0)
        {
            printf("\n");
        }
    }

    //---------------------------找出概率最大值的索引---------------------------//
    temp = 0.0;
    int ret;
    for(i = 0; i < FC2_OUT; i++ )
    {
        if(fc2_out[i] > temp)
        {
            temp = fc2_out[i];
            ret = i;
        }
    }
    //0: Hazardous;
    //1: Kitchen;
    //2: Others;
    //3: Recycled;
    return ret;
}

int cnn_test()
{
    int ret= 0;
    ret = cnn_predict(Others1,conv1_weight,conv1_bias,conv2_weight,conv2_bias,
                     fc1_weight,fc1_bias,fc2_weight,fc2_bias);
                     
    char class[][10] = {"Hazardous","Kitchen","Others","Recycled"};
    printf("\n input Others predict is: %s\n",class[ret]);
    return 0;
}

int main()
{
    cnn_test();
    return 0;
}

在FPGA中实现,使用avalon接口

由于FPGA内存限制,全部使用一维数据进行运算。

#include "HLS/hls.h"
#include "HLS/stdio.h"
#include "parameters_wb.h"
#include "pic.h"

#define CONV_KERNEL_SIZE 3
#define POLL_KERNEL_SIZE 2
#define POLL_STRIDE 2

#define IMG_SIZE 28
#define CONV1_IN_KERNEL 3
#define CONV1_OUT_SIZE 26
#define CONV1_OUT_KERNEL 8
#define POLL1_OUT_SIZE 13 

#define CONV2_OUT_KERNEL 16
#define CONV2_OUT_SIZE 11
#define POLL2_OUT_SIZE 5

#define FC_X 400    //16*5*5
#define FC1_OUT 40 
#define FC1_B 40

#define FC2_OUT 4 
#define FC2_B 4

hls_avalon_slave_component
component int one_dim_rubbish(
    hls_avalon_slave_memory_argument(3*28*28*sizeof(float)) float *in_img,
    hls_avalon_slave_memory_argument(8*3*3*3*sizeof(float)) float *conv1_w,
    hls_avalon_slave_memory_argument(8*sizeof(float)) float *conv1_b,
    hls_avalon_slave_memory_argument(16*8*3*3*sizeof(float)) float *conv2_w,
    hls_avalon_slave_memory_argument(16*sizeof(float)) float *conv2_b,
    hls_avalon_slave_memory_argument(16*5*5*40*sizeof(float)) float *fc1_w,
    hls_avalon_slave_memory_argument(40*sizeof(float)) float *fc1_b,
    hls_avalon_slave_memory_argument(40*4*sizeof(float)) float *fc2_w,
    hls_avalon_slave_memory_argument(4*sizeof(float)) float *fc2_b
)
{
    float out1[CONV1_IN_KERNEL * IMG_SIZE * IMG_SIZE];
    float out2[CONV1_OUT_KERNEL * CONV1_OUT_SIZE * CONV1_OUT_SIZE];
    //---------------------------第一层卷积---------------------------//
    //in img size : 3*28*28  
    //out img size : 8*26*26
    //printf("\n------------------------------------Conv1_out------------------------------------\n");
    int conv1_row, conv1_col, conv1_out_kernel, conv1_in_kernel, conv1_i, conv1_j;
    float temp;
    for(conv1_out_kernel = 0; conv1_out_kernel < CONV1_OUT_KERNEL; conv1_out_kernel++)
    {
        //行卷积
        for(conv1_row = 0; conv1_row < IMG_SIZE - CONV_KERNEL_SIZE + 1; conv1_row++)
        {
            //列卷积
            for(conv1_col = 0; conv1_col < IMG_SIZE - CONV_KERNEL_SIZE + 1; conv1_col++)
            {
                temp = 0.0;
                //多通道
                for(conv1_in_kernel = 0; conv1_in_kernel < CONV1_IN_KERNEL; conv1_in_kernel++)
                {   
                    //单点卷积计算
                    //temp = 0,.0;
                    for(conv1_i = 0; conv1_i < CONV_KERNEL_SIZE; conv1_i++)
                    {
                        for(conv1_j = 0; conv1_j < CONV_KERNEL_SIZE; conv1_j++)
                        {
                            //通道数 * 行 * 列 + (行 - 1) * 行 + 列
                            float a = in_img[conv1_in_kernel * IMG_SIZE * IMG_SIZE + 
                                             (conv1_i + conv1_row) * IMG_SIZE + 
                                             conv1_j + conv1_col];
                            float b = conv1_w[conv1_out_kernel * CONV1_IN_KERNEL * CONV_KERNEL_SIZE * CONV_KERNEL_SIZE +
                                              conv1_in_kernel * CONV_KERNEL_SIZE * CONV_KERNEL_SIZE + 
                                              conv1_i * CONV_KERNEL_SIZE + 
                                              conv1_j];
                            temp +=  a * b;
                        }
                    }
                }
                temp += conv1_b[conv1_out_kernel];//加偏置
                out2[conv1_out_kernel * CONV1_OUT_SIZE * CONV1_OUT_SIZE +
                     conv1_row * CONV1_OUT_SIZE + 
                     conv1_col] = temp > 0 ? temp : 0;
            }
        }
    }

    //---------------------------第一层池化---------------------------//
    //in img size : 8*26*26 
    //out img size : 8*13*13
    //printf("\n------------------------------------Poll1_out------------------------------------\n");
    int poll1_kernel, poll1_row, poll1_col, poll1_i, poll1_j;
    for(poll1_kernel = 0; poll1_kernel < CONV1_OUT_KERNEL; poll1_kernel++)
    {
        //行池化
        for(poll1_row = 0; poll1_row < (CONV1_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll1_row++)
        {
            //列池化
            for(poll1_col = 0; poll1_col < (CONV1_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll1_col++)
            {
                temp = 0.0;
                //单点池化计算
                for(poll1_i = 0; poll1_i < POLL_KERNEL_SIZE; poll1_i++)
                {
                    for(poll1_j = 0; poll1_j < POLL_KERNEL_SIZE; poll1_j++)
                    { 
                        temp = (out2[poll1_kernel * CONV1_OUT_SIZE * CONV1_OUT_SIZE + 
                                     (poll1_i + poll1_row * POLL_STRIDE) * CONV1_OUT_SIZE + 
                                     poll1_j + poll1_col * POLL_STRIDE] > temp) ? 
                                out2[poll1_kernel * CONV1_OUT_SIZE * CONV1_OUT_SIZE + 
                                     (poll1_i + poll1_row * POLL_STRIDE) * CONV1_OUT_SIZE + 
                                     poll1_j + poll1_col * POLL_STRIDE] : temp; 
                    }
                }
                out1[poll1_kernel * POLL1_OUT_SIZE * POLL1_OUT_SIZE + 
                     poll1_row * POLL1_OUT_SIZE + 
                     poll1_col] = temp;
            }
        }
    }

    //---------------------------第二层卷积---------------------------//
    //in img size : 8*13*13 
    //out img size : 16*11*11
    int i;
    for(i = 0; i < CONV1_OUT_KERNEL * CONV1_OUT_SIZE * CONV1_OUT_SIZE; i++)
    {
        out2[i] = 0;
    }
    //printf("\n------------------------------------Conv2_out------------------------------------\n");
    int conv2_row, conv2_col, conv2_out_kernel, conv2_in_kernel, conv2_i, conv2_j;
    for(conv2_out_kernel = 0; conv2_out_kernel < CONV2_OUT_KERNEL; conv2_out_kernel++)
    {
        //行卷积
        for(conv2_row = 0; conv2_row < POLL1_OUT_SIZE - CONV_KERNEL_SIZE + 1; conv2_row++)
        {
            //列卷积
            for(conv2_col = 0; conv2_col < POLL1_OUT_SIZE - CONV_KERNEL_SIZE + 1; conv2_col++)
            {
                temp = 0.0;
                //多通道
                for(conv2_in_kernel = 0; conv2_in_kernel < CONV1_OUT_KERNEL; conv2_in_kernel++)
                {   
                    //单点卷积计算
                    //temp = 0,.0;
                    for(conv2_i = 0; conv2_i < CONV_KERNEL_SIZE; conv2_i++)
                    {
                        for(conv2_j = 0; conv2_j < CONV_KERNEL_SIZE; conv2_j++)
                        {
                            float a = out1[conv2_in_kernel * POLL1_OUT_SIZE * POLL1_OUT_SIZE + 
                                           (conv2_i + conv2_row) * POLL1_OUT_SIZE + 
                                           conv2_j + conv2_col];
                            float b = conv2_w[conv2_out_kernel * CONV1_OUT_KERNEL * CONV_KERNEL_SIZE * CONV_KERNEL_SIZE + 
                                              conv2_in_kernel * CONV_KERNEL_SIZE * CONV_KERNEL_SIZE + 
                                              conv2_i * CONV_KERNEL_SIZE + 
                                              conv2_j];
                            temp += a * b;
                        }
                    }
                }
                temp += conv2_b[conv2_out_kernel];//加偏置
                out2[conv2_out_kernel * CONV2_OUT_SIZE * CONV2_OUT_SIZE + 
                     conv2_row * CONV2_OUT_SIZE + 
                     conv2_col] = temp > 0 ? temp : 0;
            }
        }
    }

    //---------------------------第二层池化---------------------------//
    //in img size : 16*11*11
    //out img size : 16*5*5
    for(i = 0; i < CONV1_IN_KERNEL * IMG_SIZE * IMG_SIZE; i++)
    {
        out1[i] = 0;
    }
    //printf("\n------------------------------------Poll2_out------------------------------------\n");
    int poll2_kernel, poll2_row, poll2_col, poll2_i, poll2_j;
    for(poll2_kernel = 0; poll2_kernel < CONV2_OUT_KERNEL; poll2_kernel++)
    {
        //行池化
        for(poll2_row = 0; poll2_row < (CONV2_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll2_row++)
        {
            //列池化
            for(poll2_col = 0; poll2_col < (CONV2_OUT_SIZE - POLL_KERNEL_SIZE)/POLL_STRIDE + 1; poll2_col++)
            {
                temp = 0.0;
                //单点池化计算
                for(poll2_i = 0; poll2_i < POLL_KERNEL_SIZE; poll2_i++)
                {
                    for(poll2_j = 0; poll2_j < POLL_KERNEL_SIZE; poll2_j++)
                    {
                        temp = (out2[poll2_kernel * CONV2_OUT_SIZE * CONV2_OUT_SIZE + 
                                     (poll2_i + poll2_row * POLL_STRIDE) * CONV2_OUT_SIZE + 
                                     poll2_j + poll2_col * POLL_STRIDE] > temp) ? 
                                out2[poll2_kernel * CONV2_OUT_SIZE * CONV2_OUT_SIZE + 
                                     (poll2_i + poll2_row * POLL_STRIDE) * CONV2_OUT_SIZE + 
                                     poll2_j + poll2_col * POLL_STRIDE] : temp; 
                    }
                }
                out1[poll2_kernel * POLL2_OUT_SIZE * POLL2_OUT_SIZE + 
                     poll2_row * POLL2_OUT_SIZE + 
                     poll2_col] = temp;
            }
        }
    }

    //---------------------------第一层全连接---------------------------//
    //in img size : 400
    //out img size : 40
    for(i = 0; i < CONV1_OUT_KERNEL * CONV1_OUT_SIZE * CONV1_OUT_SIZE; i++)
    {
        out2[i] = 0;
    }
    //printf("\n------------------------------------ FC1_OUT ------------------------------------\n");
    int fc1_i, fc1_j;
    for(fc1_i = 0; fc1_i < FC1_OUT; fc1_i++)
    {
        temp = 0.0;
        for(fc1_j = 0; fc1_j < FC_X; fc1_j++)
        {
            temp += fc1_w[fc1_j * FC1_OUT + fc1_i] * out1[fc1_j];
        }
        //加偏置
        temp +=  fc1_b[fc1_i];
        out2[fc1_i] = temp;
    }

    //---------------------------第二层全连接---------------------------//
    //in img size : 40
    //out img size : 4
    for(i = 0; i < CONV1_IN_KERNEL * IMG_SIZE * IMG_SIZE; i++)
    {
        out1[i] = 0;
    }
    //printf("\n------------------------------------ FC2_OUT ------------------------------------\n");
    int fc2_i, fc2_j;
    for(fc2_i = 0; fc2_i < FC2_OUT; fc2_i++)
    {
        temp = 0.0;
        for(fc2_j = 0; fc2_j < FC1_OUT; fc2_j++)
        {
            temp += fc2_w[fc2_j * FC2_OUT + fc2_i] * out2[fc2_j];
        }
        //加偏置
        temp +=  fc2_b[fc2_i];
        out1[fc2_i] = temp;
    }

    //---------------------------找出概率最大值的索引---------------------------//
    temp = 0.0;
    int ret;
    for(i = 0; i < FC2_OUT; i++ )
    {
        if(out1[i] > temp)
        {
            temp = out1[i];
            ret = i;
        }
    }
    //0: Hazardous;
    //1: Kitchen;
    //2: Others;
    //3: Recycled;
    return ret;
}

int main()
{
    int ret;
    #if 1
    ret = one_dim_rubbish(Others1,conv1_weight,conv1_bias,conv2_weight,conv2_bias,fc1_weight,fc1_bias,fc2_weight,fc2_bias);
    char const *input_img[] = {"Hazardous1","Hazardous2","Kitchen1","Kitchen2","Others1","Others2","Recycled1","Recycled2"};
    char const *classes[] = {"Hazardous","Kitchen","Others","Recycled"};
    printf("\n input %s \t predict is: %s\n",input_img[4],classes[ret]);
    #else 
    float *imgx[] = {Hazardous1, Hazardous2, Kitchen1, Kitchen2,
					  Others1, Others2, Recycled1, Recycled2};
    char const *input_img[] = {"Hazardous1","Hazardous2","Kitchen1","Kitchen2","Others1","Others2","Recycled1","Recycled2"};                   
    for(int i = 0; i < 8; i++)
    {
        ret = conv_connect(imgx[i],conv1_weight,conv1_bias,conv2_weight,conv2_bias,fc1_weight,fc1_bias,fc2_weight,fc2_bias);
        char const *classes[] = {"Hazardous","Kitchen","Others","Recycled"};
        printf("\n input %s \t predict is: %s\n",input_img[i],classes[ret]);
    }
    #endif
    return 0;
}

FPGA编译代码main.c

/*
 * main.c
 *
 *  Created on: 2021年10月21日
 *      Author: eye
 */
//gcc标准头文件
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

//HPS厂家提供的底层定义头文件
#define soc_cv_av //开发端Cyclone V系列

#include "hwlib.h"
#include "socal/socal.h"
#include "socal/hps.h"

//与用户具体的HPS 应用系统相关的硬件描述头文件
#include "hps_0.h"
#include "conv.h"

//接口定义区
#define HW_REGS_BASE (ALT_STM_OFST)		//HPS外设地址段基地址
#define HW_REGS_SPAN (0x04000000)		//HPS外设地址段地址空间64MB大小
#define HW_REGS_MASK (HW_REGS_SPAN - 1) //HPS外设地址段地址掩码

//接口定义(结构体的方式)
typedef struct{
	volatile float *img;
	volatile float *c1_w;
	volatile float *c1_b;
	volatile float *c2_w;
	volatile float *c2_b;
	volatile float *f1_w;
	volatile float *f1_b;
	volatile float *f2_w;
	volatile float *f2_b;
}fc_port_def;

fc_port_def my_fc_port;

typedef struct{
	volatile long long busy;
	volatile long long start;
	volatile long long irq_en;
	volatile long long done;
	volatile long long result;
}fc_ctrl_def;

fc_ctrl_def *my_fc_ctrl;

const float *imgx[8] = {Hazardous1, Hazardous2, Kitchen1, Kitchen2,
						Others1, Others2, Recycled1, Recycled2};
const char *input_img[] = {"Hazardous1","Hazardous2","Kitchen1","Kitchen2","Others1","Others2","Recycled1","Recycled2"};
const char *classes[] = {"Hazardous","Kitchen","Others","Recycled"};

int fc_init(void *virtual_base)
{
	void *fc_ctrl_addr;
	fc_ctrl_addr = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_CRA_BASE) & (unsigned long)(HW_REGS_MASK));
	//接口映射
	my_fc_ctrl = (fc_port_def *)fc_ctrl_addr;
	my_fc_ctrl->start = 0x0;

	my_fc_port.img = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_IN_IMG_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.c1_w = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_CONV1_W_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.c1_b = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_CONV1_B_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.c2_w = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_CONV2_W_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.c2_b = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_CONV2_B_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.f1_w = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_FC1_W_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.f1_b = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_FC1_B_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.f2_w = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_FC2_W_BASE) & (unsigned long)(HW_REGS_MASK));
	my_fc_port.f2_b = virtual_base + ((unsigned long)(ALT_LWFPGASLVS_OFST + RUBBISH_0_ONE_DIM_RUBBISH_INTERNAL_INST_AVS_FC2_B_BASE) & (unsigned long)(HW_REGS_MASK));

	//加载权重参数、偏置参数
	memcpy(my_fc_port.c1_w,conv1_weight,8*3*3*3*sizeof(float));
	memcpy(my_fc_port.c1_b,conv1_bias,8*sizeof(float));
	memcpy(my_fc_port.c2_w,conv2_weight,16*8*3*3*sizeof(float));
	memcpy(my_fc_port.c2_b,conv2_bias,16*sizeof(float));
	memcpy(my_fc_port.f1_w,fc1_weight,400*40*sizeof(float));
	memcpy(my_fc_port.f1_b,fc1_bias,40*sizeof(float));
	memcpy(my_fc_port.f2_w,fc2_weight,40*4*sizeof(float));
	memcpy(my_fc_port.f2_b,fc2_bias,4*sizeof(float));

	return 0;
}

//主函数
int main()
{
	int fd,ret;
	int i;
	void *virtual_base;
	float time_s,time_ns,time_ms;
	struct timespec ts1,ts2;
	clock_t start,finish;
	float win_runtime;

	//1.打开mmu open()
	fd = open("/dev/mem",(O_RDWR | O_SYNC));
	if(fd == (-1))
	{
		printf("Error:could not open\"/dev/mem\"...\n");
		return 1;
	}
	//2.虚拟地址映射 mmap()
	virtual_base = mmap(NULL,HW_REGS_SPAN,(PROT_READ | PROT_WRITE),MAP_SHARED,fd,HW_REGS_BASE);
	//3.定义初始化函数()
	fc_init(virtual_base);
	//4.操作阶段
	while(1)
	{
		for(i = 0; i < 8; i++)
		{
			start = clock();//windows 运行时间
			ret = conv(imgx[i],conv1_weight,conv1_bias,conv2_weight,conv2_bias,fc1_weight,fc1_bias,fc2_weight,fc2_bias);
			finish = clock();

			win_runtime = (float)(finish - start)*1000/CLOCKS_PER_SEC;

			memcpy(my_fc_port.img,imgx[i],3*28*28*sizeof(float));
			clock_gettime(CLOCK_MONOTONIC,&ts1); //执行推理开始的时间
			my_fc_ctrl->start = 0x01;

			while((my_fc_ctrl->done & 0x02) == 0 );
			my_fc_ctrl->start = 0x0;

			clock_gettime(CLOCK_MONOTONIC,&ts2); //执行推理结束的时间
			time_ns = ts2.tv_nsec - ts1.tv_nsec;
			time_s = ts2.tv_sec - ts1.tv_sec;
			time_ms = time_ns / 1000000 + time_s*1000;

			//0: Hazardous
			//1: Kitchen
			//2: Others
			//3: Recycled

			printf("\n windows: running time:%.6f \t FPGA: running time:%.6f \n ",win_runtime, time_ms);
			printf("\n input is: %s \n",input_img[i]);
			printf("\n Windows predict is: %s \t FPGA predict is: %s \n\n",classes[ret], classes[my_fc_ctrl->result]);
		}
		break;
	}

	//5.取消虚拟地址映射,munmap()
	if(munmap(virtual_base, HW_REGS_SPAN) != 0)
	{
		printf("Error:munmap is failed...\n");
		close(fd);
		return 1;
	}
	//6.关闭 close()
	close(fd);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于CNN(LeNet)的垃圾分类(C语言实现) 的相关文章

  • Fuzzy C-Means Clustering(模糊C均值)

    别看了 有错的 我懒得改了 强推https www bilibili com video BV18J411a7yY t 61 591 看完你还不会那我也没办法了 算法原理 模糊c 均值聚类算法 fuzzy c means algorithm
  • Last-Modified / If-Modified-Since / ETag / If-None-Match 的区别

    看一圈全都是 Last Modified和HTTP IF MODIFIED SINCE只判断资源的最后修改时间 xff0c 而ETags和If None Match可以是资源任何的属性 我 好像说了什么又好像什么也没说 修改 资源的任何属性
  • 计算机网络安全(通信机密性、完整性、数字签名、公钥认证、SSL)

    1 提供通信机密性 1 1 RSA RSA有两个互相关联的部分 xff1a 公钥和私钥的选择加密和解密算法 为了生成RSA的公钥和私钥 xff0c Bob执行如下步骤 xff1a 选择两个大素数 p p p 和 q
  • 网卡出现“Windows 仍在设置此设备的类配置。 (代码 56)“

    原因 xff1a vmware惹的祸 1 下载cclean修复注册表 xff08 尝试无效 cclean下载网址 2 键盘按win 43 r xff0c 弹出运行窗口 xff0c 输入 redegit xff0c 进入注册表 xff0c 删
  • datax实现mysql数据同步到oracle

    一 mysql数据同步到oracle 注意 xff1a mysql不区分大小写 xff0c 但是oracle严格区分大小写 xff0c 并且oracle的库名 表名和字段名要用大写 xff0c 如果用的小写需要添加双引号说明 job set
  • 在gazebo仿真环境下对相机和激光雷达的标定

    相机和激光雷达的标定主要是为了得到两者之间的参数 xff0c 包括相机的内参和雷达到相机的外参 这样便可以完成点云到图像的投影 xff0c 从而完成信息融合 实际上gazebo中这些参数都是真值 xff0c 是不需要标定的 xff1a 相机
  • 深度学习模型过拟合问题解决办法

    深度学习模型过拟合问题解决办法 模型过拟合 xff08 如果训练集上精度比测试集上精度高很多 xff0c 说明发生了过拟合 xff09 如上图所示拟合曲线 1 图一的拟合较为简单 xff0c 不能很好的反应出变化关系 xff0c 欠拟合 2
  • strchr()函数

    如果需要对字符串中的单个字符进行查找 xff0c 那么应该使用 strchr 或 strrchr 函数 其中 xff0c strchr 函数原型的一般格式如下 xff1a char strchr const char s int c 它表示
  • MapReduce之Map阶段

    MapReduce阶段分为map xff0c shuffle xff0c reduce map进行数据的映射 xff0c 就是数据结构的转换 xff0c shuffle是一种内存缓冲 xff0c 同时对map后的数据分区 排序 reduce
  • 嵌入式开发常用的三种通信协议串口通信、SPI和IIC

    常用的三种通信协议串口通信 SPI和IIC 文章目录 常用的三种通信协议串口通信 SPI和IIC一 通信分类1 1 同步通信和异步通信1 2 单工通信 半双工通信和全双工通信1 3 串行通信与并行通信 二 串口通信2 1 UART2 2 R
  • HTML 解决css缓存

    span class token operator lt span link rel span class token operator 61 span span class token string 34 stylesheet 34 sp
  • Ubuntu18.04安装Nvidia显卡驱动教程

    0 前期准备 禁用BIOS的secure boot xff0c 即disable它 xff0c 如果不关闭 xff0c 使用第三方源安装显卡驱动会安装后不能使用 1 禁用nouveau 1 创建文件 xff0c 如果没有下载vim编辑器 x
  • VINS之estimator节点小结

    VINS的核心节点 xff0c 包括VIO的初始化过程 紧耦合的非线性化过程 边缘化处理过程 主要流程步骤 1 主函数线程 订阅了四个topic xff0c 分别调用回调函数 xff1b 创建了13个话题发布器 xff1b 开辟了一个VIO
  • 基于布谷鸟搜索算法的函数寻优算法

    文章目录 一 理论基础1 算法原理2 算法流程图 二 Matlab代码三 参考文献 一 理论基础 1 算法原理 布谷鸟采用一种特殊的寄生宿主巢穴的方式孕育繁殖 它将孵育的蛋置入寄生宿主的巢穴 xff0c 让寄生宿主孵化布谷鸟蛋 由于布谷鸟幼
  • 基于逐维反向学习的动态适应布谷鸟算法

    文章目录 一 理论基础1 布谷鸟搜索算法2 DA DOCS算法 xff08 1 xff09 逐维反向学习策略 xff08 2 xff09 动态适应 xff08 3 xff09 DA DOCS算法流程 二 实验与结果分析三 参考文献 一 理论
  • SMPL学习笔记

    文章目录 前言一 SMPL概述1 形状参数 beta 2 姿态参数
  • 多协议BGP-----MPBGP

    MPBGP是在BGP 4 基础上的扩展 xff0c 分为三种 xff1a ipv4 ipv4 ipv6 ipv6 ipv6 ipv4 ipv4 ipv6 本文主要介绍 xff1a ipv6 ipv4 xff08 在 建立ipv6 的BGP邻
  • __asm void MSR_MSP(uint32_t addr) 提示:error:expected '(' after 'asm'

    SYSTEM sys sys c 33 7 error expected 39 39 before 39 void 39 ASM void MSR MSP u32 addr 在STM32中的sys c文件编译报出这个错误时 xff1a AS
  • LTL线性时序逻辑

    https blog csdn net yuniruchujian article details 106213848https www docin com p 506137477 html
  • 强化学习资料

    强化学习资料 莫烦学习资料 莫烦学习资料 https mofanpy com bilibili视频资料 xff1a https www bilibili com video BV13W411Y75P from 61 search amp s

随机推荐

  • apollo学习

    知乎王方浩 https zhuanlan zhihu com p 52521739 csdn https blog csdn net u013914471 type 61 blog bilibili 忠厚老实的老王 https space
  • 求解离散黎卡提矩阵代数方程

    离散代数黎卡提方程求解 1 黎卡提方程 在LQR最优控制中 xff0c 有连续时间最优控制 xff0c 即LQR xff0c 也有离散时间最优控制DLQR xff0c 则在求解中一定会遇到解连续时间黎卡提方程和离散时间黎卡提方程的问题 xf
  • 基于运动学模型的无人机模型预测控制(MPC)-2

    基于无人机自身模型的模型预测控制 无约束情况 1 模型建立 无人机运动学模型 xff1a x
  • 一阶低通滤波器-连续转离散

    一阶低通滤波器 1 一阶连续低通滤波器 y s r
  • 汽车动力学模型

    1 动力学模型 在纵向时 xff0c 可能还会受到纵向空气阻力 xff0c 前轮滚动阻力 xff0c 后轮滚动阻力 xff0c 坡道重力分量等
  • PX4飞控源码及解析

    源码地址 xff1a https github com 987419640 Firmware 解析 xff1a https dev px4 io zh concept architecture html
  • Hadoop:简介和安装

    Hadoop简介 Hadoop项目由多个子项目组成 与其他项目不同 xff0c 这个项目更像一个生态系统 其中 xff0c 核心项目包括HDFS MapReduce框架 YARN和ZooKeeper HDFS是一个符合Hadoop要求的分布
  • centos6.x如何安装docker

    1 curl Lks https yum spaceduck org kernel ml aufs kernel ml aufs repo gt etc yum repos d kernel ml aufs repo 2 yum remov
  • c#开发Windows桌面程序,支持触摸屏

    这是一段由new bing聊天机器人提供的代码 xff0c 我没有测试是否能正常运行 xff0c 请谨慎使用 我是这样提问的 xff1a 我想用c 开发一款Windows桌面程序 xff0c 这个程序支持触摸屏 xff0c 这个程序打开后要
  • 七. (《Java核心技术》读书笔记+重点整理系列)异常处理、断言和日志

    目录 异常分类抛出异常捕获异常断言记录日志调试技巧PS 异常分类
  • IAR for ARM 无法烧写

    一直用的IDE都是Keil xff0c 最近需要用到的一款芯片只有IAR这一种环境可以从Demo里直接用 xff0c 所以用到了IAR xff0c 但发现自己装好了IAR xff08 版本8 32 1 xff09 并破解后 xff0c 编绎
  • ADC采集的数据通过串口进行发送 (2)

    1 xff09 在RIDE板子上调通的基础上 xff0c 硬件替代成CJ 575板 在后面步骤中并开始将代码中的硬件配置部分给对应成CJ 575板子的ARM9芯片的配置 2 xff09 将ADC CHANNEL和ADC CHANNEL MO
  • 相机成像模型、内参矩阵、外参矩阵

    相机针孔成像模型 基本的小孔成像过程 xff1a X坐标系是针孔所在坐标系 xff0c Y坐标系为成像平面坐标系 xff0c P为空间一点 xff0c 小孔成像使得P点在图像平面上呈现了一个倒立的像 xff0c 俯视图如下 xff1a 由三
  • YUM安装nginx

    想在 Alibaba Cloud Linux 3 2104 64位 CentOS 系统上安装 Nginx xff0c 你得先去添加一个资源库 xff0c 像这样 xff1a vim etc yum repos d nginx repo 使用
  • PX4固件在Gazebo下进行SITL仿真自己的包时遇到MODE: Unsupported FCU问题

    在运行别人的的px4代码时 xff0c 比如一个包Base control中 xff0c 终端提示了MODE Unsupported FCU xff0c 该错误主要是因为端口不正确 xff0c mavros没能正确的连接到px4固件 xff
  • 学习OpenCV在SFM系统的使用

    文章目录 OpenCV构建SFM模型SFM的概念从一对图像估计相机运动使用丰富特征描述符的点匹配利用光流进行点匹配寻找相机矩阵场景重建从多个场景重建重构的细化使用PCL可视化3D点云使用实例代码 本文是翻译自经典书籍Mastering OP
  • ROS无人机自主飞行(数传与串口)与PX4配置问题

    ROS无人机自主飞行与PX4配置问题 文中引用均为参考 xff0c 部分内容转载 xff01 特感谢提供了参考 xff01 PX4的配置 首先需要对PX4烧写固件 xff0c 版本问题上其实没有很多区别 xff0c 目前我所用的最新版本 1
  • js 如何删除对象整的key值

    采用delete进行删除 js 的delete可以根据key删除对象中的元素 var obj 61 定义一个对象 obj a 61 1 obj b 61 2 delete obj 39 a 39 打印obj b 2 delete a b 打
  • MSCKF-VIO源码框架及C++知识点总结

    MSCKF VIO源码框架及C 43 43 知识点总结 摘要MSCKF VIO程序架构前端前端流程图函数功能解读前端各主要函数模块耗时分析 后端后端流程图函数功能解读后端各主要函数模块耗时分析 运行过程分析 ROS里的信息流图C 43 43
  • 基于CNN(LeNet)的垃圾分类(C语言实现)

    基于CNN xff08 LeNet xff09 的垃圾分类 xff08 C语言实现CNN算子 xff09 一 先使用python训练模型二 提取参数提取模型参数提取图片 三 编写CNN算子在windows中实现在FPGA中实现 xff0c