工作小计- RGB相关算子实现

项目中的模型一直都是直接操作NV12的yuv格式数据,这次的模型只支持RGB格式的输入,正好来自己实现对应的算子。
这里记录一下对应算子的实现过程,主要涉及到NV12到RGB的变换,RGB的crop/resize操作,对于数据的Norm/ToFloat操作,调整Layout等等。

cu文件是要nvcc来进行编译的,但是其头文件可以供外部的cpp文件调用,另外这里的核函数并没有涉及到stream的考虑,因为这个涉及到之后的性能优化环节,要有先来后到。实际stream也就是在核函数调用前的<<<>>>中传入stream而已,然后之后要跟着同步stream的操作。与函数实现逻辑无关。

cuda_transformation.cu

在这里实现真正的核函数,

NV12toRGB

在这里插入图片描述

这里的坑点在于 BT.601/709 FULL/非FULL的yuv格式,如果出了差错会导致图像看起来色度不对,遇到过的问题就是红色很不明显,原因就是转换公式写的有问题。

__global__ void NV12toRGB(uint8_t *yuv, uint8_t *rgb, int width,
                          int height) {
  const int nv_start = width * height;
  int i, j, nv_index = 0;
  uint8_t y, u, v;
  int r, g, b;

  j = blockIdx.x * blockDim.x + threadIdx.x;
  i = blockIdx.y * blockDim.y + threadIdx.y;

  if (i >= height || j >= width)
    return;

  nv_index = i / 2 * width + j - j % 2;

  int rgb_index = i * width + j;

  y = yuv[rgb_index];
  u = yuv[nv_start + nv_index];
  v = yuv[nv_start + nv_index + 1];

  r = y + (140 * (v - 128)) / 100;                         // r
  g = y - (34 * (u - 128)) / 100 - (71 * (v - 128)) / 100; // g
  b = y + (177 * (u - 128)) / 100;                         // b

  if (r > 255)
    r = 255;
  if (g > 255)
    g = 255;
  if (b > 255)
    b = 255;
  if (r < 0)
    r = 0;
  if (g < 0)
    g = 0;
  if (b < 0)
    b = 0;

  rgb[rgb_index * 3 + 0] = b;
  rgb[rgb_index * 3 + 1] = g;
  rgb[rgb_index * 3 + 2] = r;
}

int cudaNV12toRGB(uint8_t *input, uint8_t *output, size_t width,
                  size_t height) {
  if (!input || !output)
    return cudaErrorInvalidDevicePointer;

  const dim3 blockDim(32, 32, 1);
  const dim3 gridDim((width + blockDim.x - 1) / blockDim.x,
                     (height + blockDim.y - 1) / blockDim.y, 1);
  NV12toRGB<<<gridDim, blockDim>>>(input, output, width, height);
  return cudaDeviceSynchronize();
}

RGBBilinearResize

__global__ void RGBBilinearResize(uint8_t *input, uint8_t *output,
                                  int inputWidth, int inputHeight,
                                  int outputWidth, int outputHeight) {
  // 计算线程的全局索引
  int x = blockIdx.x * blockDim.x + threadIdx.x;
  int y = blockIdx.y * blockDim.y + threadIdx.y;

  if (x >= outputWidth || y >= outputHeight)
    return;

  // gx,gy是相对于resize后的图中的点,这里计算对应的原图中的浮点位置,确定要从哪里采样
  float gx = ((float)x) / outputWidth * (inputWidth - 1);
  float gy = ((float)y) / outputHeight * (inputHeight - 1);

  // 对应的整数位置及其偏移量
  int gxi = (int)gx;
  int gyi = (int)gy;
  float dx = gx - gxi;
  float dy = gy - gyi;

  // 读取四个最近的像素值
  uint8_t topLeft[3] = {input[(gyi * inputWidth + gxi) * 3 + 0],
                              input[(gyi * inputWidth + gxi) * 3 + 1],
                              input[(gyi * inputWidth + gxi) * 3 + 2]};
  uint8_t topRight[3] = {input[(gyi * inputWidth + gxi + 1) * 3 + 0],
                               input[(gyi * inputWidth + gxi + 1) * 3 + 1],
                               input[(gyi * inputWidth + gxi + 1) * 3 + 2]};
  uint8_t bottomLeft[3] = {input[((gyi + 1) * inputWidth + gxi) * 3 + 0],
                                 input[((gyi + 1) * inputWidth + gxi) * 3 + 1],
                                 input[((gyi + 1) * inputWidth + gxi) * 3 + 2]};
  uint8_t bottomRight[3] = {
      input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 0],
      input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 1],
      input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 2]};

  // 对每个通道进行双线性插值
  for (int i = 0; i < 3; i++) {
    float top = topLeft[i] * (1 - dx) + topRight[i] * dx;
    float bottom = bottomLeft[i] * (1 - dx) + bottomRight[i] * dx;
    output[(y * outputWidth + x) * 3 + i] = top * (1 - dy) + bottom * dy;
  }
}

int cudaRGBBilinearResize(uint8_t *input, uint8_t *output, size_t width,
                          size_t height, size_t resize_width,
                          size_t resize_height) {
  if (!input || !output)
    return cudaErrorInvalidDevicePointer;

  const dim3 blockDim(32, 32, 1);
  const dim3 gridDim((width + blockDim.x - 1) / blockDim.x,
                     (height + blockDim.y - 1) / blockDim.y, 1);
  RGBBilinearResize<<<gridDim, blockDim>>>(input, output, width, height,
                                           resize_width, resize_height);
  return cudaDeviceSynchronize();
}

RGBToFloat

这里的实现要额外记录下,因为涉及到debug中的opencv-dump所以在传入模型前的数据都是BGR格式的,在转浮点这里重新调整成模型需要的RGB格式。

__global__ void RGBToFloat(uint8_t *input, float *output, int width, int height) {
    int x = blockIdx.x * blockDim.x + threadIdx.x;
    int y = blockIdx.y * blockDim.y + threadIdx.y;

    if (x >= width || y >= height) return;

    int idx = y * width + x;
    output[idx * 3 + 0] = input[idx * 3 + 2] / 255.0f; // R
    output[idx * 3 + 1] = input[idx * 3 + 1] / 255.0f; // G
    output[idx * 3 + 2] = input[idx * 3 + 0] / 255.0f; // B
}

int cudaRGBToFloat(uint8_t *input, float *output, int width, int height) {
    dim3 blockDim(16, 16);
    dim3 gridDim((width + blockDim.x - 1) / blockDim.x, (height + blockDim.y - 1) / blockDim.y);

    RGBToFloat<<<gridDim, blockDim>>>(input, output, width, height);

    return cudaDeviceSynchronize();
}

RGBNormalize

__global__ void RGBNormalize(float *image, int width, int height, float mean[], float std[]) {
    int x = blockIdx.x * blockDim.x + threadIdx.x;
    int y = blockIdx.y * blockDim.y + threadIdx.y;

    if (x >= width || y >= height) {
        return;
    }

    int idx = y * width + x;

    if (std[0] < 1e-6 || std[1] < 1e-6 || std[2] < 1e-6) {
        printf("Error: std values are too small for safe division.\n");
        return;
    }

    image[idx * 3 + 0] = (image[idx * 3 + 0] - mean[0]) / std[0]; // B
    image[idx * 3 + 1] = (image[idx * 3 + 1] - mean[1]) / std[1]; // G
    image[idx * 3 + 2] = (image[idx * 3 + 2] - mean[2]) / std[2]; // R
}

int cudaRGBNormalize(float *d_image, int width, int height, float mean[], float std[]) {
    dim3 blockDim(16, 16);
    dim3 gridDim((width + blockDim.x - 1) / blockDim.x, (height + blockDim.y - 1) / blockDim.y);
    
    RGBNormalize<<<gridDim, blockDim>>>(d_image, width, height, mean, std);
    
    cudaError_t cudaStatus = cudaDeviceSynchronize();
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "CUDA error: %s\n", cudaGetErrorString(cudaStatus));
        return -1;
    }
    
    return 0;
}

HWC2CHW

template <typename T>
__global__ void HWC2CHW(const T* input, T* output, int height, int width) {
    int x = blockIdx.x * blockDim.x + threadIdx.x;
    int y = blockIdx.y * blockDim.y + threadIdx.y;

    if (x >= width || y >= height) return;

    int channelSize = width * height;
    int hwcIndex = y * width + x;
    int chwIndex;

    for (int c = 0; c < 3; ++c) {
        chwIndex = c * channelSize + y * width + x;
        output[chwIndex] = input[hwcIndex * 3 + c];
    }
}

template <typename T>
int cudaHWC2CHW(const T* input, T* output, int height, int width) {
    dim3 blockDim(16, 16);
    dim3 gridDim((width + blockDim.x - 1) / blockDim.x, (height + blockDim.y - 1) / blockDim.y);

    HWC2CHW<<<gridDim, blockDim>>>(input, output, height, width);
    return cudaDeviceSynchronize();
}
template int cudaHWC2CHW<float>(const float* input, float* output, int height, int width);

cuda_transformation.h

void convertNV12toYUV444withActions_cuda(uint8_t *src_img, uint8_t *src_imgcuda,
                                         uint8_t *tmpImagecuda,
                                         ImageTransParam &trans_param,
                                         uint8_t *dst_imgcuda, uint8_t *dst_img,
                                         cudaStream_t stream);
void convertNV12toYUV444withActions_cuda1(uint8_t *src_imgcuda,
                                          ImageTransParam &trans_param,
                                          uint8_t *dst_imgcuda);

int cudaNV12toRGB(uint8_t* input, uint8_t* output, size_t width, size_t height);

int cudaRGBBilinearResize(uint8_t *input, uint8_t *output, size_t width,
                          size_t height, size_t resize_width,
                          size_t resize_height);

int cudaRGBToFloat(uint8_t *input, float *output, int width, int height);

int cudaRGBNormalize(float *d_image, int width, int height, float mean[], float std[]);

template <typename T>
int cudaHWC2CHW(const T* input, T* output, int height, int width);

image_transformation.h

这里也是对该变换进行封装,虽然项目是面向对象的抽象出了类似Transformer这个类,但是出于逻辑清晰和方便调试,我这里提供的都是面向过程的代码,另外附上了cpu中算子的实现。实际上一个图像处理算子的实现,一般过程是先生成cpu的,基于NCHW的循环版本,再对其改装成gpu上的算子,毕竟gpu的算子调试相较cpu不是很方便。虽然有cuda-gdb这种东西。可以看到cpu和gpu的版本基本上只在循环方式上有差别,因此核函数也是可以称为 for_each_pixel_func

  void TransformNV12toRGB(uint8_t *input, uint8_t *output,
                         int width, int height) {
    int ret = cudaNV12toRGB(input, output, width, height);
    if (ret != 0){
        HSLOG_E << "cudaNV12toRGB FAILED";
    }
  }

  void CpuTransformNV12toRGB(uint8_t *yuv, uint8_t *rgb,
                             int width, int height) {
    const int nv_start = width * height;
    uint32_t i, j, index = 0, rgb_index = 0;
    uint8_t y, u, v;
    int r, g, b, nv_index = 0;

    for (i = 0; i < height; i++) {
      for (j = 0; j < width; j++) {
        // nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;
        nv_index = i / 2 * width + j - j % 2;

        y = yuv[rgb_index];
        u = yuv[nv_start + nv_index];
        v = yuv[nv_start + nv_index + 1];

        r = y + (140 * (v - 128)) / 100;                         // r
        g = y - (34 * (u - 128)) / 100 - (71 * (v - 128)) / 100; // g
        b = y + (177 * (u - 128)) / 100;                         // b

        if (r > 255)
          r = 255;
        if (g > 255)
          g = 255;
        if (b > 255)
          b = 255;
        if (r < 0)
          r = 0;
        if (g < 0)
          g = 0;
        if (b < 0)
          b = 0;

        // index = rgb_index % width + (height - i - 1) * width;
        index = rgb_index % width + i * width;
        rgb[index * 3 + 0] = b;
        rgb[index * 3 + 1] = g;
        rgb[index * 3 + 2] = r;
        rgb_index++;
      }
    }
  }

  void TransformRGBResize(uint8_t *input, uint8_t *output, size_t width,
                          size_t height, size_t resize_width,
                          size_t resize_height) {
    int ret = cudaRGBBilinearResize(input, output, width, height, resize_width, resize_height);
    if (ret != 0){
        HSLOG_E << "cudaRGBBilinearResize FAILED: " << ret;
    }
  }

  void CPURGBBilinearResize(uint8_t *input, uint8_t *output,
                            int inputWidth, int inputHeight, int outputWidth,
                            int outputHeight) {
    for (int y = 0; y < outputHeight; y++) {
      for (int x = 0; x < outputWidth; x++) {
        // 计算对应的原图中的浮点位置
        float gx = ((float)x) / outputWidth * (inputWidth - 1);
        float gy = ((float)y) / outputHeight * (inputHeight - 1);

        // 对应的整数位置及其偏移量
        int gxi = (int)gx;
        int gyi = (int)gy;
        float dx = gx - gxi;
        float dy = gy - gyi;

        // 读取四个最近的像素值
        uint8_t topLeft[3] = {input[(gyi * inputWidth + gxi) * 3 + 0],
                                    input[(gyi * inputWidth + gxi) * 3 + 1],
                                    input[(gyi * inputWidth + gxi) * 3 + 2]};
        uint8_t topRight[3] = {
            input[(gyi * inputWidth + gxi + 1) * 3 + 0],
            input[(gyi * inputWidth + gxi + 1) * 3 + 1],
            input[(gyi * inputWidth + gxi + 1) * 3 + 2]};
        uint8_t bottomLeft[3] = {
            input[((gyi + 1) * inputWidth + gxi) * 3 + 0],
            input[((gyi + 1) * inputWidth + gxi) * 3 + 1],
            input[((gyi + 1) * inputWidth + gxi) * 3 + 2]};
        uint8_t bottomRight[3] = {
            input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 0],
            input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 1],
            input[((gyi + 1) * inputWidth + gxi + 1) * 3 + 2]};

        // 对每个通道进行双线性插值
        for (int i = 0; i < 3; i++) {
          float top = topLeft[i] * (1 - dx) + topRight[i] * dx;
          float bottom = bottomLeft[i] * (1 - dx) + bottomRight[i] * dx;
          output[(y * outputWidth + x) * 3 + i] =
              static_cast<uint8_t>(top * (1 - dy) + bottom * dy);
        }
      }
    }
  }

  void TransfromConvertRGBToFloat(uint8_t *input, float *output, int width, int height){
    int ret = cudaRGBToFloat(input, output, width, height);
    if (ret != 0){
        HSLOG_E << "cudaRGBToFloat FAILED: " << ret;
    }
  }

  void TransfromRGBNormalize(float *input, int width, int height, float* mean, float* std){
    int ret = cudaRGBNormalize(input, width, height, mean, std);
    if (ret != 0){
        HSLOG_E << "cudaRGBNormalize FAILED: " << ret;
    }
  }

  template <typename T>
  int TransfromHWC2CHW(const T* input, T* output, int height, int width){
    int ret = cudaHWC2CHW<T>(input, output, height, width);
    if (ret != 0){
      HSLOG_E << "cudaHWC2CHW FAILED: " << ret;
    }
  }

pre_process_module.cpp

这里额外加入一些dump的操作,以及debuggpu前N个字节的操作,方便调试

void PreProcessModule::Transform21dImage(hobot::dataflow::spMsgResourceProc proc,
                      const hobot::dataflow::MessageLists &msgs){
  UNUSED(proc);
  auto &input_img_batch_msgs = msgs[0];
  std::shared_ptr<ImageBatchMsg<GPUImageMsg>> batch_image_msg =
      std::static_pointer_cast<ImageBatchMsg<GPUImageMsg>>(
          input_img_batch_msgs->at(0));

  for (int i = 0; i < batch_image_msg->batch_size_; ++i) {
    auto image_msg = batch_image_msg->batch_img_msg_[i];
    int height = image_msg->img_trans_param_.src_height;
    int width = image_msg->img_trans_param_.src_width;

    image_transformation_[i].TransformNV12toRGB(image_msg->cuda_nv12_, image_transformation_[i].cuda_image_out_, width, height);

        static int cnt = 0;
    if (true)
    {
        std::string input_file_path= "/home/yuxuan03.zhang/utils_code/lcc/query/" + std::to_string(cnt) + ".jpg";
        cv::Mat bgrImage = cv::imread(input_file_path);
        if (bgrImage.empty()) {
            std::cerr << "Error: Image cannot be loaded!" << std::endl;
        }
        size_t size = bgrImage.total() * bgrImage.elemSize(); // 计算需要复制的内存大小
        HSLOG_E << "height: " << height << "width: " << width << "size: " << size << "file" << input_file_path;
        // 将数据从 cv::Mat 复制到 GPU 内存
        cudaMemcpy(image_transformation_[i].cuda_image_out_, bgrImage.ptr(), size, cudaMemcpyHostToDevice);
        image_msg->SetDoneTimestamp(cnt);
        cnt++;
    }


    // int size = width * height * 3 / 2;
    // uint8_t* cpu_nv12 = new uint8_t[size];
    // cudaMemcpy(cpu_nv12, image_msg->cuda_nv12_, size, cudaMemcpyDeviceToHost);
    // cv::Mat nv12Img(height + height / 2, width, CV_8UC1, cpu_nv12);
    // cv::Mat bgrImg;
    // cv::cvtColor(nv12Img, bgrImg, cv::COLOR_YUV2BGR_NV12);
    // std::string file = std::to_string(image_msg->GetGenTimestamp()) + "_nv12.png";
    // cv::imwrite(file, bgrImg);
    // delete[] cpu_nv12;

    // int dataSize = width * height * 3;
    // uint8_t* cpu_rgb = new uint8_t[dataSize];
    // cudaMemcpy(cpu_rgb, image_transformation_[i].cuda_image_out_, dataSize, cudaMemcpyDeviceToHost);
    // cv::Mat rgb_img(height, width, CV_8UC3, cpu_rgb);
    // std::string file1 = std::to_string(image_msg->GetGenTimestamp()) + "_rgb.png";
    // cv::imwrite(file1, rgb_img);
    // delete[] cpu_rgb;


    image_transformation_[i].TransformRGBResize(image_transformation_[i].cuda_image_out_, image_transformation_[i].cuda_image_trans_buffer_, width, height, 910, 512);
    HSLOG_E <<"Resize: " << PrintFirstNUint8Bytes((uint8_t*)image_transformation_[i].cuda_image_trans_buffer_);
    // uint8_t* cpu_rgb_resize = new uint8_t[910*512*3];
    // cudaMemcpy(cpu_rgb_resize, image_transformation_[i].cuda_image_trans_buffer_, 910*512*3, cudaMemcpyDeviceToHost);
    // cv::Mat rgb_resize_img(512, 910, CV_8UC3, cpu_rgb_resize);
    // std::string file2 = std::to_string(image_msg->GetGenTimestamp()) + "_rgb_resize.png";
    // cv::imwrite(file2, rgb_resize_img);
    // delete[] cpu_rgb_resize;

    image_transformation_[i].TransfromConvertRGBToFloat(image_transformation_[i].cuda_image_trans_buffer_, (float*)image_transformation_[i].cuda_image_out_, 910, 512);
    HSLOG_E <<"BRGToRGBFloat: " << PrintFirstNFloatBytes((float*)image_transformation_[i].cuda_image_out_);

    std::vector<float> mean = {0.485, 0.456, 0.406};
    std::vector<float> std  = {0.229, 0.224, 0.225};
    float* mean_gpu = (float*)image_transformation_[i].cuda_image_trans_buffer_;
    float* std_gpu = mean_gpu+3;
    cudaMemcpy(mean_gpu, mean.data(), 3 * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(std_gpu, std.data(), 3 * sizeof(float), cudaMemcpyHostToDevice);
    image_transformation_[i].TransfromRGBNormalize((float*)image_transformation_[i].cuda_image_out_, 910, 512, mean_gpu, std_gpu);
    HSLOG_E <<"Norm: " << PrintFirstNFloatBytes((float*)image_transformation_[i].cuda_image_out_);
    image_transformation_[i].TransfromHWC2CHW((float*)image_transformation_[i].cuda_image_out_, (float*)image_msg->cuda_yuv444_, 512, 910);
    HSLOG_E <<"HWC2CHW: " << PrintFirstNFloatBytes((float*)image_msg->cuda_yuv444_);

    if (true) {
        float *cuda_image_out_ = (float*)image_msg->cuda_yuv444_;
        size_t dataSize = 3 * 512 * 910 * sizeof(float);
        float *hostData = new float[dataSize / sizeof(float)];
        cudaMemcpy(hostData, cuda_image_out_, dataSize, cudaMemcpyDeviceToHost);
        std::string input_file_path= "./dump_bin/" + std::to_string(cnt) + ".bin";
        std::ofstream outFile(input_file_path, std::ios::out | std::ios::binary);
        outFile.write(reinterpret_cast<char *>(hostData), dataSize);
        outFile.close();
        delete[] hostData;
    }
  }
  SEND_DATA(SLOT_OUT_BATCH_TRANS_IMAGE, batch_image_msg);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/339192.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python 正则表达式学习(1)

正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串是否与某种模式匹配。 1. 特殊符号 1.1 符号含义 模式描述^匹配字符串的开头$匹配字符串的末尾.匹配任意字符&#xff0c;除了换行符&#xff0c;当re.DOTALL标记被指定时&#xff0c;则可以匹配包…

芯片工程系列(1)封装基础知识、分来、步骤与方法.md

英文缩写 环氧树脂模塑料&#xff08;Epoxy Molding Compound&#xff0c;EMC&#xff09;引线框架封装&#xff08;Leadframe&#xff09;&#xff0c;基板封装&#xff08;Substrate&#xff09;&#xff0c;Substrate 基板晶圆片级芯片规模封装&#xff08;Wafer Level Chi…

ESP32-UDP通信 (Arduino)

ESP32配置UDP通信 介绍 用户数据报协议UDP UDP&#xff08;User Datagram Protocol&#xff09;是一种在计算机网络中常用的传输层协议&#xff0c;它与TCP&#xff08;Transmission Control Protocol&#xff09;一样属于传输层协议的一种。UDP主要用于在网络中传输数据&…

小程序学习-20

建议每次构建npm之前都先删除miniprogram_npm

第15届蓝桥杯嵌入式省赛准备第三天总结笔记(使用STM32cubeMX创建hal库工程+串口接收发送)

因为我是自己搞得板子&#xff0c;原本的下程序和串口1有问题&#xff0c;所以我用的是串口2&#xff0c;用的PA2和PA3 一&#xff0c;使用CubeMX配置串口 选择A开头的这个是异步通信。 配置串口参数&#xff0c;往届的题基本用的9600波特率&#xff0c;所以我这里设置为9600…

【Linux】解决能访问github但克隆不了的问题

文章目录 1.查看你的代理的地址&#xff1a;2.git设置3.尝试clone 1.查看你的代理的地址&#xff1a; 2.git设置 先看看当前的git设置 $ git config --list然后git中要设置好对应的地址 git config --global http.proxy 127.0.0.1:78903.尝试clone $ git clone https://git…

异或运算的骚操作,由浅入深拿捏一类型的题

文章目录 &#x1f680;前言&#x1f680;异或运算的基本用法&#x1f680;一组数中一种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;找出这个数&#x1f680;一组数中有两种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;求这两个数✈️得到一个…

4D毫米波雷达——FFT-RadNet 目标检测与可行驶区域分割 CVPR2022

前言 本文介绍使用4D毫米波雷达&#xff0c;实现目标检测与可行驶区域分割&#xff0c;它是来自CVPR2022的。 会讲解论文整体思路、输入数据分析、模型框架、设计理念、损失函数等&#xff0c;还有结合代码进行分析。 论文地址&#xff1a;Raw High-Definition Radar for Mu…

[pytorch] 2. tensorboard

tensorboard简介 TensorBoard 是一组用于数据可视化的工具。它包含在流行的开源机器学习库 Tensorflow 中.但是也可以独立安装&#xff0c;服务Pytorch等其他的框架 可以常常用来观察训练过程中每一阶段如何输出的 安装pip install tensorboard启动tensorboard --logdir<d…

自定义注解与拦截器实现不规范sql拦截(自定义注解填充插件篇)

在自定义注解与拦截器实现不规范sql拦截&#xff08;拦截器实现篇&#xff09;中提到过&#xff0c;写了一个idea插件来辅助对Mapper接口中的方法添加自定义注解&#xff0c;这边记录一下插件的实现。 需求简介 在上一篇中&#xff0c;定义了一个自定义注解对需要经过where判…

理解PCIE设备透传

PCIE设备透传解决的是使虚拟机直接访问PCIE设备的技术&#xff0c;通常情况下&#xff0c;为了使虚拟机能够访问Hypervisor上的资源&#xff0c;QEMU&#xff0c;KVMTOOL等虚拟机工具提供了"trap and emulate"&#xff0c; Virtio半虚拟化等机制实现。但是这些实现都…

[学习笔记]刘知远团队大模型技术与交叉应用L4-Prompt-learning Delta-learning

Prompt-Learning and Delta-Tunning 背景和概览 但是从T5开始&#xff0c;大模型越来越大了。 微调很难了。 模型的趋势 Model Scaling&#xff1a;模型越来越大 Difficult Tuning&#xff1a;微调越来越难 Prompt-Learning 基本组成与流程介绍 预训练和fine-tuning有一…

数学建模学习笔记||层次分析法

评价类问题 解决评价类问题首先需要想到一下三个问题 我们评价的目标是什么我们为了达到这个目标有哪几种可行方案评价的准则或者说指标是什么 对于以上三个问题&#xff0c;我们可以根据题目中的背景材料&#xff0c;常识以及网上收集到的参考资料进行结合&#xff0c;从而筛…

反欺诈与异常点检测

1. 反欺诈检检测 1.1 反欺诈检测的难点 反诈骗实际是个多分类问题&#xff0c;每种不同的诈骗都当做一种单独的类型。除了欺诈手段多样且持续变化&#xff0c;欺诈检测一般还面临以下问题&#xff1a; 1. 大部分情况下数据是没有标签的&#xff0c;各种成熟的监督学习没有用武…

反序列化字符串逃逸(下篇)

这里承接上篇文章反序列化字符串逃逸&#xff08;上篇&#xff09;-CSDN博客带大家学习反序列化字符串逃逸减少&#xff0c;没有看过的可以先去看看&#xff0c;不会吃亏。 例题&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); function filter($name…

vectorCast基于分类树设计测试用例

根据代码的条件,以图表的形式为大家展示出各个变量组合的等价类划分。性别分为2类,年龄分为3类,工作年数分为3类。 那么它们最全面的组合结果就是2*3*3=18 也就是说它们最多有18种组合情况的测试用例 2.选中该函数,点击右键 3.自动生成一个map的基于分类树的测试用例 4.此…

commit 历史版本记录修正

commit 历史版本记录修正 当 Bug 发生的时候&#xff0c;我们会需要去追踪特定 bug 的历史记录&#xff0c;以查出该 bug 真正发生的原因&#xff0c;这个时候就是版本控制带来最大价值的时候。 因此&#xff0c;要怎样维持一个好的版本记录是非常重要的&#xff0c;下面是一…

机器学习--Matplotlib

机器学习–Matplotlib Matplotlib 是专门用于开发2D图表(包括3D图表)以渐进、交互式方式实现数据可视化 简单的Matplotlib画图 — 以折线图为例 matplotlib.pyplot模块 matplotlib.pytplot包含了一系列类似于matlab的画图函数。 import matplotlib.pyplot as plt图形绘制流…

7.【CPP】String类

一.汉字的编码 我们知道计算机存储英文字母&#xff0c;标点&#xff0c;数字用的是ascall码&#xff0c;128种用一个字节表示绰绰有余。而汉字远远不止128种&#xff0c;因此汉字需要两个字节表示。 1.gbk编码中汉字占两个字节。 2.utf-8中&#xff0c;一个汉字占三个字节。…

Java - 深入四大限流算法:原理、实现与应用

文章目录 Pre概述简单计数器原理实现测试优缺点 滑动窗口算法原理实现测试优缺点 漏桶算法原理实现测试优缺点 令牌桶算法原理实现测试优缺点 小结 Pre 深入理解分布式技术 - 限流 并发编程-25 高并发处理手段之消息队列思路 应用拆分思路 应用限流思路 SpringBoot - 优雅…