卷积神经网络之手撕代码

1、计算卷积神经网络的输出尺寸

n=WF+2PS+1

其中:N 代表输出尺寸,W 代表输入尺寸,F 代表卷积核大小,P 代表填充尺寸,S 代表步长

2、网络参数量的计算

对于CNN而言,每个卷积层的参数量如下:

params=Co×(Ci×kw×kh+1)

其中, Ci 代表输入特征的通道数,也即是每个卷积核的通道数,kw,kh 分别代表卷积核的宽和高,Co 代表输出特征的通道数,也即是卷积核的个数。+1 代表偏置项。

对于全连接层而言,每个全连接层的参数量如下:

parames=I×O+O

其中,I 代表输入神经元的个数,O 代表输出神经元的个数,+O 代表偏置项

3、网络运算量(Flops)

FLOPs 是英文 floating point operations 的缩写,表示浮点运算量,中括号内的值表示卷积操作计算出 feature map 中一个点所需要的运算量(乘法和加法)。

对于CNN而言,每个卷积层的运算量如下:

FLOPs=[(Ci×kw×kh)+(Ci×kw×kh1)+1]×Co×W×H

其中,Ci 表示输入特征图的通道,kw,kh 分别代表卷积核的宽和高,Co 代表输出特征的通道数,H,W 分别代表输出特征向量的宽和高。由于输出特征的每个像素都是由卷积核元素与输入特征向量对应位置一一相乘然后再相加得到的,因此乘法计算量为:(Ci×kw×kh)×Co×W×H,加法计算量为:(Ci×kw×kh1)×Co×W×H,因为如果乘了9次,只做了8次加法运算,偏置的计算量为:Co×W×H,所以总的 FLOPs 如上所示。

对于全连接网络而言,每个全连接层的FLOPs如下:

FLOPs=[I+(I1)+1]×O

其中,I 代表每个输出神经元的乘法运算量,I1 代表每个输出神经元的加法运算量,+1 代表偏置。

4、CNN中感受野的计算

在卷积神经网络中, 感受野(Receptive Field)是指特征图上的某个点能看到的输入图像的区域,即特征图上的点是由输入图像中感受野大小区域的计算得到的,计算如下:

RFi+1=RFi+(k1)×Si

其中,RFi+1RFi 分别表示第 i+1 和第 i 层的感受野大小,k 表示卷积核的大小,Si 表示之前所有层的步长的乘积(不包括本层)。

5、CNN中上采样的方法

双三次插值:其根据离待插值最近的4*4=16个已知值来计算待插值,每个已知值的权重由距离待插值距离决定,距离越近权重越大。


k = nn.Upsample(scale_factor=2, mode='bicubic', align_corners=True)	# 创建双三次插值实例
Output = k(Input)

反卷积:该方式将引入许多‘0’的行和‘0’的列,导致实现上非常的低效。并且,反卷积只能恢复尺寸,并不能恢复数值,因此经常用在神经网络中作为提供恢复的尺寸,具体的数值往往通过训练得到。

Input = torch.arange(1,10,dtype=torch.float32).view(1,1,3,3)
Transposed = nn.ConvTranspose2d(1,1,3,stride=2, padding = 1)
Output = Transposed(Input)

亚像素上采样:假设原始输入为 [C,H,W],需要变成 [C,sH,sW] 的大小,那么亚像素上采样分两步走:

  1. [C,H,W] ==> [s2C,H,W],通过卷积实现通道的扩充
  2. [s2C,H,W]==>[C,sH,sW],通过 PixelShuffle 的方式实现长宽的增加
class Net(nn.Module):
    def __init__(self, upscale_factor):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
        self.conv2 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
        self.conv3 = nn.Conv2d(32, 1 * (upscale_factor ** 2), (3, 3), (1, 1), (1, 1))	# 最终将输入转换成 [32, 9, H, W]
        self.pixel_shuffle = nn.PixelShuffle(upscale_factor)	# 通过 Pixel Shuffle 来将 [32, 9, H, W] 重组为 [32, 1, 3H, 3W]
    def forward(self, x):
        x = torch.tanh(self.conv1(x))
        x = torch.tanh(self.conv2(x))
        x = torch.sigmoid(self.pixel_shuffle(self.conv3(x)))
        return x

6、Softmax函数

Softmax 函数:将激活值与所有神经元的输出值联系在一起,所有神经元的激活值加起来为1。第L层(最后一层)的第j个神经元的激活输出为:

ajL=eZjLkeZtL

def softmax(x):
    shift_x = x - np.max(x)#防止输入增大时输出为nan
    exp_x = np.exp(shift_x)
    return exp_x / np.sum(exp_x)

7、手写一个卷积神经网络的训练模板

import torch
import torch.nn as nn
class Network(nn.Module):
    def __init__(self):
        super().__init__()     
        self.head = nn.Senquential(
		nn.Conv2d(1,20,5),
		nn.ReLU(),
		nn.Conv2d(20,64,5),
		nn.ReLU())
        self.tail = nn.Senquential(
		nn.Conv2d(64,20,5),
		nn.ReLU(),
		nn.Conv2d(20,3,5),
		nn.ReLU())   
    def forward(self, x):
        x = self.head(x)
        x = self.tail(x)
        return x

import torch.optimal
optimal = torch.optimal.Adam()
MSE = nn.MSELoss()

model = Network()
Input = torch.floatTensor(1,3,32,32)
for i in range(epochs):
    out = model(Input)
    loss = MSE(out, label)
    loss.backward()
    loss.step()
posted @   ZhiboZhao  阅读(1002)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示