单通道单核 --多通道多核--矩阵乘法

本文详细介绍了SRCNN超分辨率重建算法中的卷积操作实现过程,包括直接卷积、转换为矩阵乘法、多核多通道矩阵乘法及使用vl_nnconv.dll等方法,并对比了不同方法的运行效率。

前文说过,要找一个放大卷积,而 LapSRN 是通过 matconvnet 的中的一个转置矩阵乘法来实现的,所以

我们先来实现矩阵乘法。

卷积        :是通过 核区对应项相乘,再求和

矩阵乘法:是通过 行列对应项相乘,再求和

由于SRCNN简单一点,先用Matlab来测试

1。先来看原卷积实现(外框架在《超分辨率重建SRCNN--Matlab 7.0中运行》一文中):

function im_h = SRCNN(model, im_b)

%% 加载 CNN 模型参数
load(model);
[conv1_patchsize2,conv1_filters] = size(weights_conv1);
conv1_patchsize = sqrt(conv1_patchsize2);
[conv2_filters,conv3_patchsize2] = size(weights_conv3);
conv3_patchsize = sqrt(conv3_patchsize2);
[hei, wid] = size(im_b);

%   第一层卷积:
%       输入LR图像块,卷积核为:cxf1xf1xn1。 1x9x9x64
%       c为输入图像通道数,Y的话,c为1。
%       f1为卷积核size,可以设置为9
%       n1为当前卷积层输出深度,可以设置为:64

% 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;

%% conv1   %reshape 把指定的矩阵改变形状,但是元素个数不变,
weights_conv1 = reshape(weights_conv1, conv1_patchsize, conv1_patchsize, conv1_filters);
conv1_data = zeros(hei, wid, conv1_filters);
for i = 1 : conv1_filters %=64
    conv1_data(:,:,i) = imfilter(im_b, weights_conv1(:,:,i), 'same', 'replicate');
    conv1_data(:,:,i) = max(conv1_data(:,:,i) + biases_conv1(i), 0);

    %保存64张特征图
%     im_tt=uint8(conv1_data(:,:,i) * 255);
%     imwrite(im_tt, ['conv1_data_0' num2str(i-1) '.jpg']);
end


%% conv2
% 第二层卷积:卷积核尺寸1×1(f2×f2),卷积核数目32(n2),输出32张特征图;
conv2_data = zeros(hei, wid, conv2_filters);
for i = 1 : conv2_filters %=32
    for j = 1 : conv1_filters
        conv2_data(:,:,i) = conv2_data(:,:,i) + weights_conv2(j,:,i) * conv1_data(:,:,j);
    end
    conv2_data(:,:,i) = max(conv2_data(:,:,i) + biases_conv2(i), 0);
    %保存32张特征图
%     im_tt=uint8(conv2_data(:,:,i) * 255);
%     imwrite(im_tt, ['conv2_data_0' num2str(i-1) '.jpg']);
end

%% conv3
% 第三层卷积:卷积核尺寸5×5(f3×f3),卷积核数目1(n3),输出1张特征图即为最终重建高分辨率图像。
conv3_data = zeros(hei, wid);
for i = 1 : conv2_filters %=32
    conv3_subfilter = reshape(weights_conv3(i,:), conv3_patchsize, conv3_patchsize);
    conv3_data(:,:) = conv3_data(:,:) + imfilter(conv2_data(:,:,i), conv3_subfilter, 'same', 'replicate');
    %保存32张特征图
%     im_tt=uint8(conv3_data(:,:) * 255);
%     imwrite(im_tt, ['conv3_data_0' num2str(i-1) '.jpg']);
end

%% SRCNN 重建
im_h = conv3_data(:,:) + biases_conv3;

2。卷积转化为矩阵乘法实现:

%卷积 通过矩阵相乘 实现
function im_h = col_SRCNN(model, im_b)

%% 加载 CNN 模型参数
load(model);
[conv1_patchsize2,conv1_filters] = size(weights_conv1);
conv1_patchsize = sqrt(conv1_patchsize2);
[conv2_filters,conv3_patchsize2] = size(weights_conv3);
conv3_patchsize = sqrt(conv3_patchsize2);
[hei, wid] = size(im_b);

%   第一层卷积:
%       输入LR图像块,卷积核为:cxf1xf1xn1。 1x9x9x64
%       c为输入图像通道数,Y的话,c为1。
%       f1为卷积核size,可以设置为9
%       n1为当前卷积层输出深度,可以设置为:64

% 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;

%% conv1   %reshape 把指定的矩阵改变形状,但是元素个数不变,
weights_conv1 = weights_conv1';
conv1_data = zeros(hei, wid, conv1_filters);

tmp1_data = padarray(im_b,[4 4],'replicate'); % 扩充原始数据 (核宽-1 分两边) 先加
col_data = im2col(tmp1_data,[9 9],'sliding');%图像数据重排 每个核相应区排成列
clear tmp1_data;

for i = 1 : conv1_filters %=64

    col_out=weights_conv1(i,:)*col_data;% 矩阵相乘

    conv1_data(:,:,i) = reshape(col_out, [hei, wid]);%图像数据重排 成原始大小 高-(核宽-1),宽-(核宽-1) 后减(正好大小)
    conv1_data(:,:,i) = max(conv1_data(:,:,i) + biases_conv1(i), 0);
end


%% conv2
% 第二层卷积:卷积核尺寸1×1(f2×f2),卷积核数目32(n2),输出32张特征图;
conv2_data = zeros(hei, wid, conv2_filters);
for i = 1 : conv2_filters %=32
    for j = 1 : conv1_filters
        conv2_data(:,:,i) = conv2_data(:,:,i) + weights_conv2(j,:,i) * conv1_data(:,:,j);
    end
    conv2_data(:,:,i) = max(conv2_data(:,:,i) + biases_conv2(i), 0);
end

%% conv3
% 第三层卷积:卷积核尺寸5×5(f3×f3),卷积核数目1(n3),输出1张特征图即为最终重建高分辨率图像。
conv3_data = zeros(hei, wid);
for i=1:conv2_filters %=32(和第二层同大)
    tmp3_data = padarray(conv2_data(:,:,i),[2 2],'replicate'); % 扩充原始数据 (核宽-1) 先加

    col_data = im2col(tmp3_data,[5 5],'sliding');%图像数据重排 每个核相应区排成列
    col_out=weights_conv3(i,:)*col_data;% 矩阵相乘

    col_out2=reshape(col_out, [hei, wid]);%图像数据重排 成原始大小 高-(核宽-1),宽-(核宽-1) 后减(正好大小)
    conv3_data=conv3_data+col_out2;%32图相加
end

%% SRCNN 重建
im_h = conv3_data + biases_conv3;


3。再把多核,多通道 放在一起乘,也就是一层所有卷积 只用一次乘法:

%多通道 多核矩阵相乘
function im_h = col_m_SRCNN(model, im_b)

%% 加载 CNN 模型参数
load(model);
[conv1_patchsize2,conv1_filters] = size(weights_conv1);
conv1_patchsize = sqrt(conv1_patchsize2);
[conv2_filters,conv3_patchsize2] = size(weights_conv3);
conv3_patchsize = sqrt(conv3_patchsize2);
[hei, wid] = size(im_b);

%   第一层卷积:
%       输入LR图像块,卷积核为:cxf1xf1xn1。 1x9x9x64
%       c为输入图像通道数,Y的话,c为1。
%       f1为卷积核size,可以设置为9
%       n1为当前卷积层输出深度,可以设置为:64

% 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;

%% conv1   %reshape 把指定的矩阵改变形状,但是元素个数不变,
weights_conv1 = weights_conv1';
conv1_data = zeros(hei, wid, conv1_filters);

tmp1_data = padarray(im_b,[4 4],'replicate'); % 扩充原始数据 (核宽-1 分两边) 先加
col_data = im2col(tmp1_data,[9 9],'sliding');%图像数据重排 每个核相应区排成列
clear tmp1_data;

col_out=weights_conv1*col_data;% 矩阵相乘 64核 1通道 

for i = 1 : conv1_filters %=64

    col_tmp=col_out(i,:);% 取一通道

    conv1_data(:,:,i) = reshape(col_tmp, [hei, wid]);%图像数据重排 成原始大小 高-(核宽-1),宽-(核宽-1) 后减(正好大小)
    conv1_data(:,:,i) = max(conv1_data(:,:,i) + biases_conv1(i), 0);
end
clear col_tmp;


%% conv2
% 第二层卷积:卷积核尺寸1×1(f2×f2),卷积核数目32(n2),输出32张特征图;
conv2_data = zeros(hei, wid, conv2_filters);
for i = 1 : conv2_filters %=32
    for j = 1 : conv1_filters
        conv2_data(:,:,i) = conv2_data(:,:,i) + weights_conv2(j,:,i) * conv1_data(:,:,j);
    end
    conv2_data(:,:,i) = max(conv2_data(:,:,i) + biases_conv2(i), 0);
end

%% conv3
% 第三层卷积:卷积核尺寸5×5(f3×f3),卷积核数目1(n3),输出1张特征图即为最终重建高分辨率图像。
conv3_data = zeros(hei, wid);
for i=1:32

    %重排核
    weights0=zeros(32,25);
    for j=1:32
        if j==i
            weights0(i,:)=weights_conv3(i,:);%只有这里有数据
        %else
            %其它位置都是 0
        end
    end
    
     tmp3_data = padarray(conv2_data(:,:,i),[2 2],'replicate'); % 扩充原始数据(核宽-1)
   if i>1
        col_data=[col_data;im2col(tmp3_data,[5 5],'sliding')];%图像数据重排 后面的放到前面的后一个位置(层叠)
        
        weights=[weights,weights0];%排在一线
   else %i==1
        col_data = im2col(tmp3_data,[5 5],'sliding');%图像数据重排 第一图像重排
        weights=weights0;%第一个
    end
end
clear tmp3_data;
    
% 矩阵相乘(多通道32 多核32)  
conv3_data=weights*col_data;

%32通道相加
conv3_data=sum(conv3_data);
conv3_data=reshape(conv3_data, [hei, wid]);%图像数据重排 成原始大小 高-(核宽-1),宽-(核宽-1) 后减(正好大小)


%% SRCNN 重建
im_h = conv3_data + biases_conv3;


4。再把vl_nnconv.dll, vl_nnrelu.m 和 vl_argparse.m 也拿过来:

%使用 vl_nnconv.dll 或 vl_nnconv.m 实现 SRCNN
function im_h = vl_SRCNN(model, im_b)

im_b=single(im_b);

%% 加载 CNN 模型参数
load(model);
[conv1_patchsize2,conv1_filters] = size(weights_conv1);
conv1_patchsize = sqrt(conv1_patchsize2);
[conv2_filters,conv3_patchsize2] = size(weights_conv3);
conv3_patchsize = sqrt(conv3_patchsize2);
[hei, wid] = size(im_b);

%   第一层卷积:
%       输入LR图像块,卷积核为:cxf1xf1xn1。 1x9x9x64
%       c为输入图像通道数,Y的话,c为1。
%       f1为卷积核size,可以设置为9
%       n1为当前卷积层输出深度,可以设置为:64

% 第一层卷积:卷积核尺寸9×9(f1×f1),卷积核数目64(n1),输出64张特征图;

%% conv1   %reshape 把指定的矩阵改变形状,但是元素个数不变,
weights_conv1 = reshape(weights_conv1, conv1_patchsize, conv1_patchsize,1, conv1_filters);
weights_conv1=single(weights_conv1);
biases_conv1=single(biases_conv1);
%这个使用vl_函数实现第一层
    conv1_data = vl_nnconv(im_b,weights_conv1,biases_conv1,'Pad',4);
    conv1_data =  vl_nnrelu(conv1_data);

%% conv2
% 第二层卷积:卷积核尺寸1×1(f2×f2),卷积核数目32(n2),输出32张特征图;

conv2_data = zeros(hei, wid, conv2_filters);
for i = 1 : conv2_filters
    for j = 1 : conv1_filters
        conv2_data(:,:,i) = conv2_data(:,:,i) + weights_conv2(j,:,i) * conv1_data(:,:,j);
    end
end

%这个使用vl_函数实现第二层
    conv2_data =  vl_nnrelu(conv2_data);

%% conv3
% 第三层卷积:卷积核尺寸5×5(f3×f3),卷积核数目1(n3),输出1张特征图即为最终重建高分辨率图像。

%这个使用vl_函数实现第三层
conv3_subfilter=zeros(conv3_patchsize, conv3_patchsize,conv2_filters);
for i = 1 : conv2_filters
    conv3_subfilter(:,:,i) =reshape(weights_conv3(i,:), conv3_patchsize, conv3_patchsize);
end

conv2_data=single(conv2_data);
conv3_subfilter=single(conv3_subfilter);
biases_conv3=single(biases_conv3);

conv3_data = vl_nnconv(conv2_data,conv3_subfilter,biases_conv3,'Pad',2);
    
%% SRCNN 重建
im_h = conv3_data;

最后比较一下四种重建时间(3倍):

原图:

1。3.40秒

2。4.35秒

3。7.65秒

4。3.43秒,这个边界是0填充 有个框

小图是不是不能体现矩阵乘法的优势,还是别的原因呢?

先这样吧。

 

<think>我们已知用户希望了解在瑞萨平台上使用IARJ-Link通过SWD进行多核调试的配置方法。结合用户提供的引用[1]引用[2](虽然引用[2]是关于瑞萨RA系列使用RTT的示例,但其中涉及了J-Link SWD连接调试的基本操作),我们可以整合出配置步骤。 注意:瑞萨多核处理器(如R-Car系列)ARM Cortex-M多核(如Cortex-M33双核)配置有所不同,但核心原理相似。这里以常见的瑞萨双核ARM Cortex-M处理器(例如RA8系列或类似)为例。 ### 瑞萨平台IAR + J-Link SWD多核调试配置方法 #### 1. **硬件准备** - **调试器**:确保使用支持SWD多核调试的J-Link(例如J-Link Ultra或J-Link PRO)。 - **目标板**:瑞萨多核评估板(如RA8D1双核Cortex-M85)。 - **连接**: - 将J-Link的SWD接口(SWDIO, SWCLK, GND)连接到目标板的调试端口。 - 连接复位线(RESET)以确保调试器能复位整个系统。 - 参考引用[2]中的连接方式:使用SWD接口连接目标板,并通过J-Link RTT Viewer查看日志(可选)。 #### 2. **IAR工程配置** - **步骤1:创建多核工程** - 在IAR中为每个核心创建独立的工程(例如`core0_project``core1_project`),或者使用一个工程包含多个核心的配置(需IAR支持多核项目结构)。 - 确保每个核心的代码独立编译,生成对应的ELF文件(如`core0.elf`, `core1.elf`)。 - **步骤2:设置调试器** - 打开任意一个核心的工程,进入`Project > Options > Debugger`: - **Driver**:选择`J-Link/J-Trace`。 - **Interface**:选择`SWD`。 - **Speed**:设置SWD时钟频率(建议初始值1MHz,稳定后可提高)。 - **多核配置**: - 在`Debugger > Extra Options`中添加命令行参数(根据J-Link文档): ``` -select core=all -device Cortex-M85:0,Cortex-M85:1 ``` 这里假设两个核心都是Cortex-M85,核心索引为01。实际设备名需参考瑞萨手册(如R7FA8D1BH)。 - **步骤3:配置多核启动脚本** - 在`Debugger > Setup > Initialization macros`中创建或加载调试脚本(例如`multicore_init.mac`): ```c // 多核初始化脚本 __message "Starting Core 0"; __setCore(0); // 切换到核心0 __driver download "core0.elf"; // 下载核心0固件 __setCore(1); // 切换到核心1 __driver download "core1.elf"; // 下载核心1固件 __message "All cores loaded"; // 可选:设置同步断点 __hwReset(); // 硬件复位 __syncBreakpoint(); // 同步断点(所有核心暂停) ``` > **注意**:脚本路径需为绝对路径或相对于工程根目录的相对路径。 - **步骤4:目标设备选择** - 在`Project > Options > General Options > Target`中: - **Device**:选择实际的多核设备(如瑞萨`R7FA8D1BH`)。 - **Core**:选择`Multi-core`模式(如果IAR版本支持)。 #### 3. **调试流程** 1. **编译**:分别编译两个核心的工程(确保无错误)。 2. **启动调试**:点击IAR的`Download and Debug`按钮。 - 调试器将执行初始化脚本:依次下载两个核心的固件并复位。 3. **多核控制**: - 在IAR的`View > Core Selection`窗口中切换核心。 - 为每个核心单独设置断点或单步执行。 - 使用`Sync Breakpoints`功能(在断点属性中勾选)使所有核心同时暂停。 #### 4. **常见问题解决(瑞萨平台特殊注意事项)** - **问题:核心1无法连接** - **原因**:瑞萨多核启动顺序要求(主核Core0必须先启动)。 - **解决**:在调试脚本中确保先操作Core0,再操作Core1。添加延迟: ```c __setCore(0); __driver download "core0.elf"; __delay(500); // 延迟500ms等待Core0初始化 __setCore(1); __driver download "core1.elf"; ``` - **问题:RTT打印不显示(参考引用[2])** - **原因**:RTT缓冲区地址未正确配置。 - **解决**: 1. 在代码中初始化SEGGER RTT(确保两个核心的RTT缓冲区不冲突)。 2. 调试启动后,打开J-Link RTT Viewer: - 选择设备内核(如Cortex-M85)。 - 根据MAP文件查找`_SEGGER_RTT`地址(需分别获取两个核心的地址)。 - 在RTT Viewer中为每个核心单独添加RTT通道(地址填入对应值)。 - **问题:多核内存冲突** - **原因**:两个核心访问了共享资源(如外设寄存器)未加锁。 - **解决**: - 在代码中使用硬件信号量(如瑞萨的IPC模块)。 - 在调试时使用IAR的`Data Watchpoint`监控冲突地址。 #### 5. **性能优化** - **提高SWD速度**:在J-Link配置中逐步提高SWD时钟(最高可到10MHz+),若不稳定则降低。 - **启用实时模式**:在`Debugger > J-Link > Real-time mode`中勾选,减少调试干扰。 - **使用RTT替代串口**:参考引用[2],通过J-Link RTT Viewer查看多核日志,避免占用SWD带宽。 > **关键提示**:瑞萨多核设备的具体配置可能因型号而异,请参考瑞萨官方文档(如《RA8D1用户手册》)IAR的`C-SPY`调试指南。 §§相关问题§§ 1. 如何在瑞萨多核平台上实现核心间通信(IPC)? 2. IAR调试瑞萨多核时如何配置非对称核心(如Cortex-M85 + Cortex-M33)? 3. 如何通过J-Link脚本实现瑞萨多核的自动测试? 4. 瑞萨RA系列多核启动流程是怎样的?</think>### 瑞萨平台 IAR + J-Link SWD 多核调试配置指南 #### 一、硬件准备与连接 1. **调试器要求**: - 使用支持多核调试的J-Link型号(如J-Link PRO/UItra) - 确保固件版本≥V4.56(支持多核同步调试)[^1] - 连接线缆:SWD四线制(SWDIO/SWCLK/GND/RESET) 2. **目标板配置**: ```mermaid graph LR A[J-Link] -->|SWDIO| B(瑞萨多核处理器) A -->|SWCLK| B A -->|GND| B A -->|RESET| B B --> C[核心0 Cortex-M85] B --> D[核心1 Cortex-M85] ``` #### 二、IAR工程配置步骤 1. **多核工程创建**: - 创建主工程(如`core0_project`)从核工程(如`core1_project`) - 每个工程包含独立代码链接脚本 - 参考瑞萨配置工具生成基础框架(`Tools > RA Smart Configurator`)[^2] 2. **调试器设置**: ```c // Project > Options > Debugger Driver: J-Link/J-Trace Interface: SWD Speed: 4MHz (初始值) Extra Options: -select core=all -device R7FA8D1BH ``` 3. **多核初始化脚本**: 在`Debugger > Setup > Initialization macros`添加: ```c // multicore_init.mac __message "Starting multi-core setup"; __hwReset(); // 硬件复位 // 核心0配置 __setCore(0); __driver download "core0.elf"; __writeMemory32(0x20000000, 0xE000ED08); // 设置VTOR // 核心1配置 __setCore(1); __driver download "core1.elf"; __writeMemory32(0x20010000, 0xE000ED08); __syncBreakpoint(); // 同步断点 __message "Multi-core ready"; ``` #### 三、调试流程操作 1. **启动调试**: - 点击`Download and Debug` - 在IAR的`Core Selection`窗口查看双核状态 - 使用同步控制按钮暂停/运行所有核心 2. **RTT日志配置**(参考引用[2]): - 在代码中初始化`SEGGER_RTT` - 调试时打开J-Link RTT Viewer - 获取各核心`_SEGGER_RTT`地址(查看map文件) - 为每个核心创建独立RTT通道: ``` Core0: Address = 0x20000000 Core1: Address = 0x20010000 ``` 3. **断点同步技巧**: - 在断点属性中勾选`Sync all cores` - 使用条件断点避免资源冲突: ```c if (__getCoreID() == 0) { /* 核心0条件 */ } ``` #### 四、瑞萨平台特殊配置 1. **时钟同步**: - 在初始化脚本中添加时钟锁定: ```c __writeMemory32(0x1, 0x40011000); // 锁定PLL __delay(100); // 等待稳定 ``` 2. **共享资源处理**: - 在链接脚本中划分内存区域: ``` // core0.icf define symbol __ICFEDIT_region_ROM_start__ = 0x01000000; define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; // core1.icf define symbol __ICFEDIT_region_ROM_start__ = 0x02000000; define symbol __ICFEDIT_region_RAM_start__ = 0x20010000; ``` #### 五、常见问题解决 1. **核心无法同步启动**: - 解决方案: - 添加硬件复位延迟:`__hwReset(); __delay(500);` - 检查启动模式引脚配置(BOOT0/BOOT1) 2. **RTT日志混合**: - 解决方法: ```c // 各核心使用独立上行通道 SEGGER_RTT_ConfigUpBuffer(1, "Core0", NULL, 0, RTT_MODE_NO_BLOCK_SKIP); SEGGER_RTT_ConfigUpBuffer(2, "Core1", NULL, 0, RTT_MODE_NO_BLOCK_SKIP); ``` 3. **SWD信号干扰**: - 优化措施: - 缩短线缆长度(<15cm) - 添加22Ω串行电阻 - 降低SWD时钟至1MHz > **调试提示**:瑞萨多核设备首次调试时,建议先单核调试验证基础功能,再启用多核同步[^1]。
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值