标准卷积的初始化和详细计算步骤,在代码中哪一步开始更新卷积核(权重)

embedded/2024/10/20 10:45:32/

标准卷积的初始化和详细计算步骤,在代码中哪一步开始更新卷积核(权重)

flyfish

卷积 - 感受野(Receptive Field)
卷积神经网络(CNN)中为什么可以使用多个较小的卷积核替代一个较大的卷积核,以达到相同的感受野

卷积操作转换为矩阵乘法
动画展示卷积的计算过程
卷积层的输出

卷积的计算 - numpy的实现 1
卷积的计算 - numpy的实现 2

卷积的计算 - im2col 1
卷积的计算 - im2col 2
卷积的计算 - im2col 3

卷积核的初始化

实践经验,卷积核(权重)常用的初始化方法包括:

  1. 随机初始化
    使用标准正态分布(均值为0,标准差为1)的随机数初始化权重。
    例如:nn.init.normal_(tensor, mean=0, std=1)

  2. 均匀分布初始化
    使用均匀分布的随机数初始化权重。
    例如:nn.init.uniform_(tensor, a=0, b=1)

  3. Xavier初始化(Glorot初始化)
    适用于Sigmoid和Tanh激活函数。
    公式:U[-sqrt(6 / (fan_in + fan_out)), sqrt(6 / (fan_in + fan_out))]
    例如:nn.init.xavier_uniform_(tensor)

  4. He初始化(Kaiming初始化)
    适用于ReLU激活函数。
    公式:N(0, sqrt(2 / fan_in))
    例如:nn.init.kaiming_normal_(tensor, mode='fan_in', nonlinearity='relu')

  5. 常数初始化
    使用常数值初始化权重。
    例如:nn.init.constant_(tensor, val=0)

卷积核初始化代码示例

一个简单的卷积神经网络中初始化卷积核。这里使用了Xavier初始化方法来初始化权重,并将偏置初始化为零。

import torch
import torch.nn as nn
import torch.nn.init as initclass ConvNet(nn.Module):def __init__(self):super(ConvNet, self).__init__()self.conv1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)# Initialize weights using Xavier initializationinit.xavier_uniform_(self.conv1.weight)init.xavier_uniform_(self.conv2.weight)# Initialize biases (if using) to zeroif self.conv1.bias is not None:init.constant_(self.conv1.bias, 0)if self.conv2.bias is not None:init.constant_(self.conv2.bias, 0)def forward(self, x):x = self.conv1(x)x = self.conv2(x)return x# Instantiate the network
net = ConvNet()# Print initialized weights
print("Conv1 weights:", net.conv1.weight)
print("Conv2 weights:", net.conv2.weight)

一个完整的训练示例

import torch
import torch.nn as nn
import torch.optim as optim# 定义一个简单的卷积神经网络
import torch
import torch.nn as nn
import torch.optim as optim# 定义一个简单的卷积神经网络
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.conv1 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0)def forward(self, x):x = self.conv1(x)x = self.conv2(x)return x# 初始化网络、损失函数和优化器
net = SimpleCNN()
criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)# 示例输入和目标
input_tensor = torch.randn(1, 1, 5, 5)
target_tensor = torch.randn(1, 1, 1, 1)# 示例训练步骤
num_epochs = 3
for epoch in range(num_epochs):print(f'Epoch {epoch+1}/{num_epochs}',":start")optimizer.zero_grad()   # 清空梯度outputs = net(input_tensor)  # 前向传播loss = criterion(outputs, target_tensor)  # 计算损失loss.backward()  # 反向传播,计算梯度print(f'Updated before optimizer.step() conv1 weights: {net.conv1.weight}')optimizer.step()  # 使用优化器更新参数# 打印损失print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item()}')# 打印卷积核的梯度print(f'Gradient of conv1 weights after backward: {net.conv1.weight.grad}')# 打印更新后的卷积核权重print(f'Updated after optimizer.step()conv1 weights: {net.conv1.weight}')

代码解释

对每个 epoch:
1. optimizer.zero_grad():清空之前计算的梯度。
2. outputs = net(input_tensor):前向传播,计算模型输出。
3. loss = criterion(outputs, target_tensor):计算损失。
4. loss.backward():反向传播,计算梯度,并将其存储在参数的 .grad 属性中。
5. optimizer.step():优化器根据存储的梯度和学习率更新模型的参数。

打印输出

Epoch 1/3 :start
Updated before optimizer.step() conv1 weights: Parameter containing:
tensor([[[[-0.0435, -0.0704,  0.0776],[-0.2496, -0.2133,  0.1125],[-0.0481, -0.2408,  0.1175]]]], requires_grad=True)
Epoch 1/3, Loss: 0.12892843782901764
Gradient of conv1 weights after backward: tensor([[[[ 0.0707, -0.2553, -0.1103],[ 0.3029,  0.4249,  0.3205],[-0.2261, -0.0902,  0.1702]]]])
Updated after optimizer.step()conv1 weights: Parameter containing:
tensor([[[[-0.0442, -0.0679,  0.0787],[-0.2527, -0.2175,  0.1093],[-0.0459, -0.2399,  0.1158]]]], requires_grad=True)
Epoch 2/3 :start
Updated before optimizer.step() conv1 weights: Parameter containing:
tensor([[[[-0.0442, -0.0679,  0.0787],[-0.2527, -0.2175,  0.1093],[-0.0459, -0.2399,  0.1158]]]], requires_grad=True)
Epoch 2/3, Loss: 0.11386992782354355
Gradient of conv1 weights after backward: tensor([[[[ 0.0681, -0.2368, -0.1066],[ 0.2894,  0.4049,  0.2971],[-0.2128, -0.0811,  0.1610]]]])
Updated after optimizer.step()conv1 weights: Parameter containing:
tensor([[[[-0.0449, -0.0655,  0.0797],[-0.2556, -0.2216,  0.1063],[-0.0437, -0.2391,  0.1142]]]], requires_grad=True)
Epoch 3/3 :start
Updated before optimizer.step() conv1 weights: Parameter containing:
tensor([[[[-0.0449, -0.0655,  0.0797],[-0.2556, -0.2216,  0.1063],[-0.0437, -0.2391,  0.1142]]]], requires_grad=True)
Epoch 3/3, Loss: 0.10046691447496414
Gradient of conv1 weights after backward: tensor([[[[ 0.0655, -0.2198, -0.1027],[ 0.2760,  0.3853,  0.2757],[-0.2002, -0.0729,  0.1523]]]])
Updated after optimizer.step()conv1 weights: Parameter containing:
tensor([[[[-0.0455, -0.0633,  0.0808],[-0.2583, -0.2254,  0.1036],[-0.0417, -0.2383,  0.1127]]]], requires_grad=True)

根据输出结果

Updated after optimizer.step()conv1 weights: Parameter containing:
tensor([[[[-0.0442, -0.0679,  0.0787],[-0.2527, -0.2175,  0.1093],[-0.0459, -0.2399,  0.1158]]]], requires_grad=True)
Epoch 2/3 :start
Updated before optimizer.step() conv1 weights: Parameter containing:
tensor([[[[-0.0442, -0.0679,  0.0787],[-0.2527, -0.2175,  0.1093],[-0.0459, -0.2399,  0.1158]]]], requires_grad=True)

net.conv1.weight.grad 存储了 conv1 层的权重梯度,
optimizer.step() 则真正的更新模型的参数。

更新模型参数

卷积神经网络中,每一层都有若干卷积核。这些卷积核的权重和偏置是在训练过程中更新的。
通过反向传播算法(backpropagation),计算每个参数的梯度,并使用优化算法(如SGD、Adam等)更新这些权重和偏置,以最小化损失函数。其中特征图是通过卷积运算得到的输出,不是模型的参数。使用优化器更新参数 optimizer.step()这步更新的就是卷积 (权重)和偏置 (如果有的话)

标准卷积操作详细计算

参数
  • 输入特征图:5x5,内容为 1 到 25

  • 卷积核:3x3,内容为 1 到 9

  • 步幅:1

  • 填充:0

输入特征图和卷积

输入特征图

1   2   3   4   5
6   7   8   9   10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25

卷积

1  2  3
4  5  6
7  8  9

使用 PyTorch 计算结果

import torch
import torch.nn as nn# 定义输入特征图和卷积
input_tensor = torch.tensor([[1, 2, 3, 4, 5],[6, 7, 8, 9, 10],[11, 12, 13, 14, 15],[16, 17, 18, 19, 20],[21, 22, 23, 24, 25]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # 添加批次维度和通道维度# 定义卷积
kernel = torch.tensor([[1, 2, 3],[4, 5, 6],[7, 8, 9]
], dtype=torch.float32)# 转换卷积核为与Conv2d兼容的形状
weight = kernel.view(1, 1, 3, 3)  # 1个输出通道,1个输入通道,3x3卷积# 定义卷积
conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=0, bias=False)# 设置卷积层的权重为我们定义的卷积
conv.weight = nn.Parameter(weight)# 执行卷积操作
output_tensor = conv(input_tensor)# 打印输出特征图
print(output_tensor)

运行结果应该如下:

tensor([[[[411., 456., 501.],[636., 681., 726.],[861., 906., 951.]]]], grad_fn=<ConvolutionBackward0>)

计算输出特征图尺寸

根据公式:
H out = ⌊ H in + 2 P − K S ⌋ + 1 H_{\text{out}} = \left\lfloor \frac{H_{\text{in}} + 2P - K}{S} \right\rfloor + 1 Hout=SHin+2PK+1
W out = ⌊ W in + 2 P − K S ⌋ + 1 W_{\text{out}} = \left\lfloor \frac{W_{\text{in}} + 2P - K}{S} \right\rfloor + 1 Wout=SWin+2PK+1由于步幅 S = 1 S=1 S=1,填充 P = 0 P=0 P=0卷积核大小 K = 3 K=3 K=3,输入特征图大小 5 × 5 5 \times 5 5×5
H out = ⌊ 5 + 0 − 3 1 ⌋ + 1 = 3 H_{\text{out}} = \left\lfloor \frac{5 + 0 - 3}{1} \right\rfloor + 1 = 3 Hout=15+03+1=3
W out = ⌊ 5 + 0 − 3 1 ⌋ + 1 = 3 W_{\text{out}} = \left\lfloor \frac{5 + 0 - 3}{1} \right\rfloor + 1 = 3 Wout=15+03+1=3
所以输出特征图的尺寸是 3x3。

详细逐位置计算输出特征图

第一位置(左上角,起始点 (0,0))
输入区域:
1   2   3
6   7   8
11  12  13卷积计算:
1*1 + 2*2 + 3*3 + 6*4 + 7*5 + 8*6 + 11*7 + 12*8 + 13*9
= 1 + 4 + 9 + 24 + 35 + 48 + 77 + 96 + 117 = 411
第二位置(水平移动一格,起始点 (0,1))
输入区域:
2   3   4
7   8   9
12  13  14卷积计算:
2*1 + 3*2 + 4*3 + 7*4 + 8*5 + 9*6 + 12*7 + 13*8 + 14*9
= 2 + 6 + 12 + 28 + 40 + 54 + 84 + 104 + 126 = 456
第三位置(水平移动一格,起始点 (0,2))
输入区域:
3   4   5
8   9   10
13  14  15卷积计算:
3*1 + 4*2 + 5*3 + 8*4 + 9*5 + 10*6 + 13*7 + 14*8 + 15*9
= 3 + 8 + 15 + 32 + 45 + 60 + 91 + 112 + 135 = 501
第四位置(垂直移动一格,起始点 (1,0))
输入区域:
6   7   8
11  12  13
16  17  18卷积计算:
6*1 + 7*2 + 8*3 + 11*4 + 12*5 + 13*6 + 16*7 + 17*8 + 18*9
= 6 + 14 + 24 + 44 + 60 + 78 + 112 + 136 + 162 = 636
第五位置(水平移动一格,起始点 (1,1))
输入区域:
7   8   9
12  13  14
17  18  19卷积计算:
7*1 + 8*2 + 9*3 + 12*4 + 13*5 + 14*6 + 17*7 + 18*8 + 19*9
= 7 + 16 + 27 + 48 + 65 + 84 + 119 + 144 + 171 = 681
第六位置(水平移动一格,起始点 (1,2))
输入区域:
8   9   10
13  14  15
18  19  20卷积计算:
8*1 + 9*2 + 10*3 + 13*4 + 14*5 + 15*6 + 18*7 + 19*8 + 20*9
= 8 + 18 + 30 + 52 + 70 + 90 + 126 + 152 + 180 = 726
第七位置(垂直移动一格,起始点 (2,0))
输入区域:
11  12  13
16  17  18
21  22  23卷积计算:
11*1 + 12*2 + 13*3 + 16*4 + 17*5 + 18*6 + 21*7 + 22*8 + 23*9
= 11 + 24 + 39 + 64 + 85 + 108 + 147 + 176 + 207 = 861
第八位置(水平移动一格,起始点 (2,1))
输入区域:
12  13  14
17  18  19
22  23  24卷积计算:
12*1 + 13*2 + 14*3 + 17*4 + 18*5 + 19*6 + 22*7 + 23*8 + 24*9
= 12 + 26 + 42 + 68 + 90 + 114 + 154 + 184 + 216 = 906
第九位置(水平移动一格,起始点 (2,2))
输入区域:
13  14  15
18  19  20
23  24  25卷积计算:
13*1 + 14*2 + 15*3 + 18*4 + 19*5 + 20*6 + 23*7 + 24*8 + 25*9
= 13 + 28 + 45 + 72 + 95 + 120 + 161 + 192 + 225 = 951

最终输出特征图

通过上述计算步骤,我们得到输出特征图为:

411  456  501
636  681  726
861  906  951

http://www.ppmy.cn/embedded/56078.html

相关文章

汽车电子行业知识:什么是车载智能座舱

1.什么是车载智能座舱 车载智能座舱是指搭载在汽车内部的一种智能系统&#xff0c;它集成了各种功能和技术&#xff0c;旨在提升驾驶体验、增加安全性和提供更多的便利。这种系统可以包括诸如智能驾驶辅助、信息娱乐、智能语音控制、车内环境控制、车辆健康监测等功能。通过车…

Study--Oracle-05-Oracler体系结构

一、oracle 体系概览 Oracle数据库的体系结构通常包括以下主要组件&#xff1a; 1、实例&#xff08;Instance&#xff09;&#xff1a;运行数据库的软件环境&#xff0c;包括内存结构&#xff08;SGA&#xff09;和进程结构&#xff08;Background Processes and User Proces…

CF - 1676 - G White-Black Balanced Subtrees

White-Black Balanced Subtrees - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include <bits/stdc.h> using namespace std; int t; int n; vector<int> gv[4005]; string s; int tot; int dp(int x){int val;if(s[x]B){val1;}else if(s[x]W){val-1;}if(gv[x]…

【乐吾乐2D可视化组态编辑器】文件

1 文件 文件&#xff1a;文件的新建、打开、导入、保存、另存为、下载JOSN文件、下载ZIP打包文件、导出为HTML、导出为Vue2组件、导出为Vue3组件、导出为React组件&#xff08;老版将不再维护&#xff09;、下载为PNG、下载为SVG 乐吾乐2D可视化组态编辑器demo&#xff1a;ht…

在linux 下交叉编译gdb 8.1.1 ,生成 windows下的exe程序

在Linux环境下进行交叉编译,生成适用于Windows的可执行程序(.exe),需要使用交叉编译工具链。对于特定的GDB版本(如8.1.1),你需要确保有适用于目标平台(Windows)的交叉编译工具链。以下是一些基本步骤和考虑因素: 获取GDB源码:首先,需要下载GDB 8.1.1的源码包。你可…

day62--若依框架(基础应用篇)

若依搭建 若依版本 官方 若依官方针对不同开发需求提供了多个版本的框架&#xff0c;每个版本都有其独特的特点和适用场景&#xff1a; 前后端混合版本&#xff1a;RuoYi结合了SpringBoot和Bootstrap的前端开发框架&#xff0c;适合快速构建传统的Web应用程序&#xff0c;其…

golang string、byte[]以及rune的基本概念,用法以及区别

在 Go 语言中&#xff0c;string、byte[] 和 rune 是处理文本和字符的三种不同数据类型。它们有各自的用途和特点&#xff0c;下面将详细介绍它们的基本概念、用法以及区别。 1. string 基本概念 字符串类型&#xff1a;string 是 Go 语言中的一种基本类型&#xff0c;用于表…

动态规划精品课 2024.6.26-24.7.3

一、斐波那契数列模型 0、第N个泰波那契数 class Solution {public int tribonacci(int n) {// 1. 创建 dp 表// 2. 初始化// 3. 填表// 4. 返回结果// 处理边界情况if (n 0)return 0;if (n 1 || n 2)return 1;int[] dp new int[n 1];dp[0] 0;dp[1] dp[2] 1;for (int i…