卷积神经网络的原理、实现及变体

卷积神经网络convolutional neural network,CNN 是为处理图像数据而生的网络,主要由卷积层(填充和步幅)、池化层(汇聚层)、全连接层组成。

卷积

虽然卷积层得名于卷积(convolution)运算,但我们通常在卷积层中使用更加直观的互相关(cross-correlation)运算。

真实的卷积运算是f(a,b)g(i-a,j-b),其实有一个取反的过程,但是我们实际代码里使用的是互相关运算。

输入的宽度为n,卷积核宽度为k,则输出宽度为n-k+1。

卷积层的参数包括卷积核和偏置,感受野receptive field指的是在前向传播期间影响x计算的所有元素(来自之前所有层)。

一般填充p行在上下,为了上下保持一致,卷积核一般是奇数的长度。输出变为n+p-k+1

滑动步幅为s时,输出变为(n+p-k+s)/s

多输入通道可以:构造相同通道的卷积核,最后对多通道求和输出

多输出通道可以:为每个输出通道o创建一个i*w*h的卷积核,有o个这样的卷积核。

1x1卷积层的作用:看作在每个像素位置应用的全连接层,把i个输入值转换为o个输出层。看这个博主的动图1x1卷积核,没有太明白。文章2 作用:降维/升维,增加非线性,跨通道信息交互。

LeNet

python 复制代码
import torch
from torch import nn 
from torchvision import transforms
import torchvision
from torch.utils import data
import matplotlib.pyplot as plt
def load_data_fashion_mnist(batch_size, resize=None):
    """下载Fashion-MNIST数据集,然后将其加载到内存中"""
    trans = [transforms.ToTensor()]
    if resize:
        trans.insert(0, transforms.Resize(resize))
    trans = transforms.Compose(trans)
    mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)
    mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)
    #print(len(mnist_train),len(mnist_test))
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
        data.DataLoader(mnist_test, batch_size, shuffle=False)) #windows下不能多进程,linux下可以
batch_size=256
train_iter, test_iter = load_data_fashion_mnist(batch_size)

net=nn.Sequential(
    nn.Conv2d(1,6,kernel_size=5,padding=2),
    nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2,stride=2),
    nn.Conv2d(6,16,kernel_size=5),
    nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2,stride=2),
    nn.Flatten(),
    nn.Linear(16*5*5,120),
    nn.Sigmoid(),
    nn.Linear(120,84),
    nn.Sigmoid(),
    nn.Linear(84,10)
)

def accuracy(y_hat, y): 
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = y_hat.argmax(axis=1)
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())
class Accumulator: 
    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n
    def add(self, *args):
        self.data = [a + float(b) for a, b in zip(self.data, args)]
    def reset(self):
        self.data = [0.0] * len(self.data)
    def __getitem__(self, idx):
        return self.data[idx]
def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    """使⽤GPU计算模型在数据集上的精度"""
    if isinstance(net, nn.Module):
        net.eval() # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device
    # 正确预测的数量,总预测的数量
    metric = Accumulator(2)
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(X, list):
                # BERT微调所需的(之后将介绍)
                X = [x.to(device) for x in X]
            else:
                X = X.to(device)
            y = y.to(device)
            metric.add(accuracy(net(X), y), y.numel())
            return metric[0] / metric[1]

def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()
class Animator: 
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
    ylim=None, xscale='linear', yscale='linear',
    fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
    figsize=(3.5, 2.5)):
        # 增量地绘制多条线
        if legend is None:
            legend = []
        self.fig, self.axes = plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使⽤lambda函数捕获参数
        self.config_axes = lambda: set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts
    def add(self, x, y):
        # 向图表中添加多个数据点
        if not hasattr(y, "__len__"):
            y = [y]
        n = len(y)
        if not hasattr(x, "__len__"):
            x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a, b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
        self.axes[0].cla()
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt)
        self.config_axes()
        #display.display(self.fig)
        # 通过以下两行代码实现了在PyCharm中显示动图
        plt.draw()

def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """⽤GPU训练模型(在第六章定义)"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train acc', 'test acc'])
    num_batches = len(train_iter)
    for epoch in range(num_epochs):
        # 训练损失之和,训练准确率之和,样本数
        metric = Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()
            with torch.no_grad():
                metric.add(l * X.shape[0], accuracy(y_hat, y), X.shape[0])
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,(train_l, train_acc, None))
        test_acc = evaluate_accuracy_gpu(net, test_iter)
        animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, 'f'test acc {test_acc:.3f}')

lr, num_epochs = 0.9, 10
def try_gpu(i=0): #@save
    """如果存在,则返回gpu(i),否则返回cpu()"""
    if torch.cuda.device_count() >= i + 1:
        return torch.device(f'cuda:{i}')
    return torch.device('cpu')
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu())

现代卷积神经网络

AlexNet 第一个击败传统模型的大型神经网络

VGG 使用重复的神经网络块

NiN 重复使用1x1卷积层构造深层网络

GoogLeNet 并行连结的网络

ResNet 残差网络 是计算机视觉最流行的体系架构 特点是跨层数据通路前向传播

DenseNet 是resnet的逻辑扩展(泰勒展开),使用的是cancat而不是相加,主要由稠密层和过渡层(1x1卷积核,降低通道数)构成

相关推荐
易连EDI—EasyLink几秒前
电动汽车供应链协同新范式:蔚来(NIO)企业级EDI平台建设实践
网络·人工智能·edi·nio·as2
AI星桥小王子2 分钟前
分清原生音画同步!主流 AI 视频生成平台横向对比
人工智能
xqqxqxxq6 分钟前
技术笔记:上下文工程(Context Engineering)心得总结(李博杰《深入理解 AI Agent》2.1,2.2观后总结)
人工智能·笔记
成都被卷死的程序员6 分钟前
生活与工作AI高效使用指南
人工智能·生活
万岳科技系统开发10 分钟前
智慧医院小程序开发推动医疗服务流程全面线上化
大数据·开发语言·人工智能
用户81818706274614 分钟前
第5章 核心对象与配置系统
人工智能
Litluecat18 分钟前
2026年7月24日科技热点新闻
人工智能·科技·新闻·每日·速览
用户81818706274622 分钟前
第6章 thinkingLevel 思维层级体系
人工智能
熙丫 1338148238631 分钟前
人工智能训练工程师考试报名2026:报考条件、报名入口及注意事项
人工智能
凡情36 分钟前
dify 图片提取文字
人工智能