当前位置: 首页 > news >正文

深度学习中卷积与互相关

1. 互相关运算 (cross-correlation)

  • 输出位置 (m, n) 的值:
    Y[m,n]=∑i=0Hk−1∑j=0Wk−1X[m+i,n+j]⋅K[i,j]Y[m,n] = \sum_{i=0}^{H_k-1} \sum_{j=0}^{W_k-1} X[m+i, n+j] \cdot K[i,j]Y[m,n]=i=0Hk1j=0Wk1X[m+i,n+j]K[i,j]
  • 输出尺寸公式:
    output_height=Hx−Hk+1\text{output\_height} = H_x - H_k + 1output_height=HxHk+1
    output_width=Wx−Wk+1\text{output\_width} = W_x - W_k + 1output_width=WxWk+1
    (其中 Hx,WxH_x, W_xHx,Wx 是输入尺寸,Hk,WkH_k, W_kHk,Wk 是卷积核尺寸)
  • $ X[m+i, n+j] $ 是输入图像的局部区域。
  • $ K[i,j] $ 是核的对应位置元素。

2. 卷积运算 (convolution)

  • 数学定义要求先翻转卷积核:
    Kflipped[i,j]=K[Hk−1−i,Wk−1−j]K_{\text{flipped}}[i,j] = K[H_k-1-i, W_k-1-j]Kflipped[i,j]=K[Hk1i,Wk1j]
  • 卷积输出:
    Y[m,n]=∑i=0Hk−1∑j=0Wk−1X[m+i,n+j]⋅Kflipped[i,j]Y[m,n] = \sum_{i=0}^{H_k-1} \sum_{j=0}^{W_k-1} X[m+i, n+j] \cdot K_{\text{flipped}}[i,j]Y[m,n]=i=0Hk1j=0Wk1X[m+i,n+j]Kflipped[i,j]
  • 等价形式(直接使用原始核):
    Y[m,n]=∑i=0Hk−1∑j=0Wk−1X[m+i,n+j]⋅K[Hk−1−i,Wk−1−j]Y[m,n] = \sum_{i=0}^{H_k-1} \sum_{j=0}^{W_k-1} X[m+i, n+j] \cdot K[H_k-1-i, W_k-1-j]Y[m,n]=i=0Hk1j=0Wk1X[m+i,n+j]K[Hk1i,Wk1j]
3. 工作流程图示

卷积计算详细过程(结合公式)

输入数据:
输入 X:       卷积核 K:      翻转核 K_flipped:
[1, 2, 3]     [0, 1]        [3, 2]
[4, 5, 6]     [2, 3]        [1, 0]
[7, 8, 9]
卷积公式:

数学定义的卷积运算:
Y[m,n]=∑i=0Hk−1∑j=0Wk−1X[m+i,n+j]⋅Kflipped[i,j]Y[m,n] = \sum_{i=0}^{H_k-1} \sum_{j=0}^{W_k-1} X[m+i, n+j] \cdot K_{\text{flipped}}[i,j]Y[m,n]=i=0Hk1j=0Wk1X[m+i,n+j]Kflipped[i,j]

其中:

  • Hk=2H_k = 2Hk=2(核高度)
  • Wk=2W_k = 2Wk=2(核宽度)
  • 输出尺寸:(3−2+1)×(3−2+1)=2×2(3-2+1) \times (3-2+1) = 2 \times 2(32+1)×(32+1)=2×2
计算步骤:
  1. 位置 (0,0) 的计算

    • 输入窗口:
      [1, 2]
      [4, 5]
      
    • 翻转核:
      [3, 2]
      [1, 0]
      
    • 计算过程:
      1*3 = 3
      2*2 = 4
      4*1 = 4
      5*0 = 0
      ---------
      总和 = 3 + 4 + 4 + 0 = 11
      
    • 公式表示:
      Y[0,0]=∑i=01∑j=01X[i,j]⋅Kflipped[i,j]Y[0,0] = \sum_{i=0}^{1}\sum_{j=0}^{1} X[i,j] \cdot K_{\text{flipped}}[i,j]Y[0,0]=i=01j=01X[i,j]Kflipped[i,j]
  2. 位置 (0,1) 的计算

    • 输入窗口:
      [2, 3]
      [5, 6]
      
    • 翻转核:
      [3, 2]
      [1, 0]
      
    • 计算过程:
      2*3 = 6
      3*2 = 6
      5*1 = 5
      6*0 = 0
      ---------
      总和 = 6 + 6 + 5 + 0 = 17
      
  3. 位置 (1,0) 的计算

    • 输入窗口:
      [4, 5]
      [7, 8]
      
    • 翻转核:
      [3, 2]
      [1, 0]
      
    • 计算过程:
      4*3 = 12
      5*2 = 10
      7*1 = 7
      8*0 = 0
      ---------
      总和 = 12 + 10 + 7 + 0 = 29
      
  4. 位置 (1,1) 的计算

    • 输入窗口:
      [5, 6]
      [8, 9]
      
    • 翻转核:
      [3, 2]
      [1, 0]
      
    • 计算过程:
      5*3 = 15
      6*2 = 12
      8*1 = 8
      9*0 = 0
      ---------
      总和 = 15 + 12 + 8 + 0 = 35
      
最终输出:
Y = [[11, 17],[29, 35]]
图解计算过程:
输入 X 和滑动窗口:
[1, 2, 3]    [1,2] [2,3] 
[4, 5, 6] →  [4,5] [5,6] → 输出 Y[0,0] 和 Y[0,1]
[7, 8, 9]    [4,5] [5,6] [7,8] [8,9] → 输出 Y[1,0] 和 Y[1,1]每个窗口与翻转核进行元素乘加:
[1,2] ⊙ [3,2] = 1*3 + 2*2 + 4*1 + 5*0 = 11
[4,5]   [1,0]

关键点:数学卷积需要先翻转卷积核(180°旋转),然后执行互相关运算(滑动点积)。深度学习框架通常省略翻转步骤,直接进行互相关操作。

code

import torch
import numpy as np# 手动实现的卷积函数
def flip_kernel1(K):"""180° 翻转卷积核"""# 上下翻转K_ud = K[::-1]# 左右翻转K_flipped = [row[::-1] for row in K_ud]return K_flippeddef flip_kernel(K):"""180° 翻转卷积核(完全基础实现)"""# 1. 获取卷积核尺寸height = len(K)       # 总行数width = len(K[0])     # 总列数# 2. 创建空的结果矩阵(尺寸相同)K_flipped = []# 3. 逐行处理(从最后一行到第一行)for row_index in range(height):# 创建新行new_row = []# 4. 逐列处理(从最后一列到第一列)for col_index in range(width):# 计算翻转后的位置flipped_row = height - 1 - row_indexflipped_col = width - 1 - col_index# 5. 获取原始核对应位置的元素original_value = K[flipped_row][flipped_col]# 6. 添加到新行new_row.append(original_value)# 7. 将完整新行添加到结果矩阵K_flipped.append(new_row)return K_flippeddef corr2d(X, K):h = len(K)  # 核的高度 H_kw = len(K[0])  # 核的宽度 W_k# 输出矩阵的尺寸output_height = len(X) - h + 1output_width = len(X[0]) - w + 1Y = [[0 for _ in range(output_width)] for _ in range(output_height)]for m in range(output_height):  # 外部循环:输出位置 mfor n in range(output_width):  # 外部循环:输出位置 ncurrent_sum = 0.0for i in range(h):  # 内部循环:卷积核行索引 ifor j in range(w):  # 内部循环:卷积核列索引 jx_val = X[m + i][n + j]  # 输入矩阵的对应位置 X[m+i, n+j]k_val = K[i][j]  # 卷积核的对应位置 K[i, j]current_sum += x_val * k_val  # 乘积累加Y[m][n] = current_sum  # 存储结果 Y[m,n]return Ydef conv2d(X, K):"""二维卷积运算(先翻转核,再调用互相关)"""K_flipped = flip_kernel(K)return corr2d(X, K_flipped)# 构造输入数据和卷积核
X =[[0, 0, 0, 0, 0],[0, 1, 0, 2, 0],[0, 0, 0, 0, 0],[0, 3, 0, 4, 0],[0, 0, 0, 0, 0]]K = [[8, 7],[6, 5]]
# 手动实现的互相关结果
manual_result = corr2d(X, K)
manual_conv_result = conv2d(X, K)# 转换为 PyTorch 张量
X_tensor = torch.tensor(X, dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # [1, 1, 5, 5]
K_tensor = torch.tensor(K, dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # [1, 1, 3, 3]# 使用 PyTorch 的 Conv2d 进行卷积
conv_layer = torch.nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3, 3), stride=1, padding=0, bias=False)
conv_layer.weight.data = K_tensorwith torch.no_grad():pytorch_result = conv_layer(X_tensor).squeeze().tolist()# 打印结果对比
print("手动实现卷积结果:")
for row in manual_conv_result:print(row)print("手动实现互相关结果:")
for row in manual_result:print(row)print("\nPyTorch 卷积结果:")
for row in pytorch_result:print(row)# 计算误差
manual_flat = [item for row in manual_result for item in row]
pytorch_flat = [item for row in pytorch_result for item in row]error = [abs(m - p) for m, p in zip(manual_flat, pytorch_flat)]
max_error = max(error)
mean_error = sum(error) / len(error)print("\n误差分析:")
print(f"最大误差:{max_error:.6f}")
print(f"平均误差:{mean_error:.6f}")

结果:

手动实现卷积结果:
[8.0, 7.0, 16.0, 14.0]
[6.0, 5.0, 12.0, 10.0]
[24.0, 21.0, 32.0, 28.0]
[18.0, 15.0, 24.0, 20.0]
手动实现互相关结果:
[5.0, 6.0, 10.0, 12.0]
[7.0, 8.0, 14.0, 16.0]
[15.0, 18.0, 20.0, 24.0]
[21.0, 24.0, 28.0, 32.0]PyTorch 卷积结果:
[5.0, 6.0, 10.0, 12.0]
[7.0, 8.0, 14.0, 16.0]
[15.0, 18.0, 20.0, 24.0]
[21.0, 24.0, 28.0, 32.0]误差分析:
最大误差:0.000000
平均误差:0.000000
http://www.lryc.cn/news/609142.html

相关文章:

  • [ java Thread 线程 ] 由“一对一“到“一对多“
  • 【Linux网络编程基础--socket地址API】
  • 使用 Vuepress + GitHub Pages 搭建项目文档
  • GraphRAG:基于知识图谱的检索增强生成技术解析
  • 微分方程模型:用“变化率”的语言,描绘世间万物的动态演化
  • async/await和Promise之间的关系是什么?(补充)
  • 图像识别区分指定物品与其他物体
  • SelectDB数据库,新一代实时数据仓库的全面解析与应用
  • Kubernetes滚动更新、蓝绿部署与金丝雀发布方案对比分析及选型建议
  • 延迟任务方案-DelayQueue
  • noob靶机复现笔记
  • 【stm32】GPIO输入
  • 环绕字符串中的唯一子字符串-动态规划
  • 其它IO函数
  • STM32 串口发送
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘scikit-learn’问题
  • Linux环境下使用Docker搭建多服务环境
  • 学习游戏制作记录(实现克隆攻击的克隆复制和水晶代替克隆)8.3
  • 【gradle】插件那些事
  • 7.28-8.3周报
  • C的数据类型与变量
  • 高质量数据集|从武汉光谷《面向科技情报大模型的高质量数据集建设》招标项目谈起
  • Matlab算法编程示例4:数值解法求解常微分方程的代码实例
  • deep research|从搜索引擎到搜索助手的实践(一)
  • Android 之 MVC架构
  • TVS二极管数据手册解读
  • kraft的设计与实现
  • 【数据结构】队列的顺序存储与链式存储(C语言版)
  • 深度学习中的模型知识蒸馏
  • 【Bluetooth】【Transport层篇】第三章 基础的串口(UART)通信