动手学深度学习(Pytorch版)代码实践 -计算机视觉-48全连接卷积神经网络(FCN)

48全连接卷积神经网络(FCN

在这里插入图片描述

1.构造函数
import torch
import torchvision
from torch import nn
from torch.nn import functional as F
import matplotlib.pyplot as plt
import liliPytorch as lp
from d2l import torch as d2l

# 构造模型
pretrained_net = torchvision.models.resnet18(pretrained=True)
# print(list(pretrained_net.children())[-3:]) # ResNet-18模型的最后几层
"""
[Sequential(
  (0): BasicBlock(
    (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (downsample): Sequential(
      (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
      (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    )
  )
  (1): BasicBlock(
    (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
), AdaptiveAvgPool2d(output_size=(1, 1)), Linear(in_features=512, out_features=1000, bias=True)]  
"""

# 创建一个全卷积网络net。 它复制了ResNet-18中大部分的预训练层,
# 除了最后的全局平均汇聚层和最接近输出的全连接层。
net = nn.Sequential(*list(pretrained_net.children())[:-2])

# ResNet-18中
"""
X = torch.rand(size=(1, 1, 96, 96))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:\t', X.shape)
# Sequential output shape:         torch.Size([1, 64, 24, 24])
# Sequential output shape:         torch.Size([1, 64, 24, 24])
# Sequential output shape:         torch.Size([1, 128, 12, 12])
# Sequential output shape:         torch.Size([1, 256, 6, 6])
# Sequential output shape:         torch.Size([1, 512, 3, 3])
前向传播将输入的高和宽减小至原来的 1/32
"""
# 使用1 X 1 卷积层将输出通道数转换为Pascal VOC2012数据集的类数(21类)。 
# 最后需要将特征图的高度和宽度增加32倍,从而将其变回输入图像的高和宽。
num_classes = 21
net.add_module('final_conv', nn.Conv2d(512, num_classes, kernel_size=1))
net.add_module('transpose_conv', 
               nn.ConvTranspose2d(num_classes, 
                                  num_classes,
                                  kernel_size=64, 
                                  padding=16, 
                                  stride=32))
# print(list(net.children())[-2:]) 
"""
[Conv2d(512, 21, kernel_size=(1, 1), stride=(1, 1)), 
ConvTranspose2d(21, 21, kernel_size=(64, 64), stride=(32, 32), padding=(16, 16))]
"""
2.双线性插值
# 初始化转置卷积层
# 在图像处理中,我们有时需要将图像放大,即上采样(upsampling)
# 双线性插值(bilinear interpolation) 是常用的上采样方法之一,
# 它也经常用于初始化转置卷积层
# 双线性插值的上采样可以通过转置卷积层实现,内核由以下bilinear_kernel函数构造。
def bilinear_kernel(in_channels, out_channels, kernel_size):
    factor = (kernel_size + 1) // 2  # 计算中心因子,用于确定卷积核的中心位置
    if kernel_size % 2 == 1: # 确定卷积核的中心位置
        # 如果卷积核大小是奇数
        center = factor - 1
    else:
        # 如果卷积核大小是偶数
        center = factor - 0.5
    # 生成坐标网格,用于计算每个位置的双线性内核值
    og = (torch.arange(kernel_size).reshape(-1, 1),  # 列向量
          torch.arange(kernel_size).reshape(1, -1))  # 行向量
    # 计算双线性内核值,基于当前位置与中心位置的距离并归一化
    filt = (1 - torch.abs(og[0] - center) / factor) * \
           (1 - torch.abs(og[1] - center) / factor)
    # 初始化权重张量
    weight = torch.zeros((in_channels, out_channels, kernel_size, kernel_size))
    # 填充权重张量,将计算好的双线性内核值赋值给权重张量
    weight[range(in_channels), range(out_channels), :, :] = filt
    # 返回生成的双线性卷积核权重张量
    return weight

# 定义转置卷积层 (n + 4 - 2 - 2 ) * 2
conv_trans = nn.ConvTranspose2d(3, 3, kernel_size=4, padding=1, stride=2,
                                bias=False)
# 将双线性卷积核权重复制到转置卷积层的权重
conv_trans.weight.data.copy_(bilinear_kernel(3, 3, 4))

img = torchvision.transforms.ToTensor()(d2l.Image.open('../limuPytorch/images/catdog.jpg'))
"""
d2l.Image.open('../limuPytorch/images/catdog.jpg') 首先被执行,返回一个 PIL.Image 对象。
然后,torchvision.transforms.ToTensor() 创建一个 ToTensor 对象。
最后,ToTensor 对象被调用(通过 () 运算符),将 PIL.Image 对象作为参数传递给 ToTensor 的 __call__ 方法,
转换为 PyTorch 张量。
"""
X = img.unsqueeze(0) # 添加一个新的维度,形成形状为 (1, C, H, W) 的张量 X,
Y = conv_trans(X)
out_img = Y[0].permute(1, 2, 0).detach()

print('input image shape:', img.permute(1, 2, 0).shape)
# input image shape: torch.Size([561, 728, 3])
plt.imshow(img.permute(1, 2, 0))
plt.show()
print('output image shape:', out_img.shape)
# output image shape: torch.Size([1122, 1456, 3])
# 图片放大了两倍
plt.imshow(out_img)
plt.show()
3.模型训练
# 37微调章节的代码
def train_batch_ch13(net, X, y, loss, trainer, devices):
    """使用多GPU训练一个小批量数据。
    参数:
    net: 神经网络模型。
    X: 输入数据,张量或张量列表。
    y: 标签数据。
    loss: 损失函数。
    trainer: 优化器。
    devices: GPU设备列表。
    返回:
    train_loss_sum: 当前批次的训练损失和。
    train_acc_sum: 当前批次的训练准确度和。
    """
    # 如果输入数据X是列表类型
    if isinstance(X, list):
        # 将列表中的每个张量移动到第一个GPU设备
        X = [x.to(devices[0]) for x in X]
    else:
        X = X.to(devices[0])# 如果X不是列表,直接将X移动到第一个GPU设备
    y = y.to(devices[0])# 将标签数据y移动到第一个GPU设备
    net.train() # 设置网络为训练模式
    trainer.zero_grad()# 梯度清零
    pred = net(X) # 前向传播,计算预测值
    l = loss(pred, y) # 计算损失
    l.sum().backward()# 反向传播,计算梯度
    trainer.step() # 更新模型参数
    train_loss_sum = l.sum()# 计算当前批次的总损失
    train_acc_sum = d2l.accuracy(pred, y)# 计算当前批次的总准确度
    return train_loss_sum, train_acc_sum# 返回训练损失和与准确度和


def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
               devices=d2l.try_all_gpus()):
    """训练模型在多GPU
    参数:
    net: 神经网络模型。
    train_iter: 训练数据集的迭代器。
    test_iter: 测试数据集的迭代器。
    loss: 损失函数。
    trainer: 优化器。
    num_epochs: 训练的轮数。
    devices: GPU设备列表,默认使用所有可用的GPU。
    """
    # 初始化计时器和训练批次数
    timer, num_batches = d2l.Timer(), len(train_iter)
    # 初始化动画器,用于实时绘制训练和测试指标
    animator = lp.Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0, 1],
                           legend=['train loss', 'train acc', 'test acc'])
    # 将模型封装成 DataParallel 模式以支持多GPU训练,并将其移动到第一个GPU设备
    net = nn.DataParallel(net, device_ids=devices).to(devices[0])
    # 训练循环,遍历每个epoch
    for epoch in range(num_epochs):
        # 初始化指标累加器,metric[0]表示总损失,metric[1]表示总准确度,
        # metric[2]表示样本数量,metric[3]表示标签数量
        metric = lp.Accumulator(4)
        # 遍历训练数据集
        for i, (features, labels) in enumerate(train_iter):
            timer.start()  # 开始计时
            # 训练一个小批量数据,并获取损失和准确度
            l, acc = train_batch_ch13(net, features, labels, loss, trainer, devices)
            metric.add(l, acc, labels.shape[0], labels.numel())   # 更新指标累加器
            timer.stop()  # 停止计时
            # 每训练完五分之一的批次或者是最后一个批次时,更新动画器
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                             (metric[0] / metric[2], metric[1] / metric[3], None))
        test_acc = d2l.evaluate_accuracy_gpu(net, test_iter) # 在测试数据集上评估模型准确度
        animator.add(epoch + 1, (None, None, test_acc))# 更新动画器
    # 打印最终的训练损失、训练准确度和测试准确度
    print(f'loss {metric[0] / metric[2]:.3f}, train acc '
          f'{metric[1] / metric[3]:.3f}, test acc {test_acc:.3f}')
    # 打印每秒处理的样本数和使用的GPU设备信息
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec on '
          f'{str(devices)}')


# 全卷积网络用双线性插值的上采样初始化转置卷积层
W = bilinear_kernel(num_classes, num_classes, 64)
net.transpose_conv.weight.data.copy_(W)
# 读取数据集
batch_size, crop_size = 32, (320, 480)
train_iter, test_iter = lp.load_data_voc(batch_size, crop_size) # 46语义分割和数据集代码
# 损失函数
def loss(inputs, targets):
    return F.cross_entropy(inputs, targets, reduction='none').mean(1).mean(1)

num_epochs, lr, wd, devices = 5, 0.001, 1e-3, d2l.try_all_gpus()
trainer = torch.optim.SGD(net.parameters(), lr=lr, weight_decay=wd)
train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, devices)
# loss 0.443, train acc 0.863, test acc 0.848
# 254.0 examples/sec on [device(type='cuda', index=0), device(type='cuda', index=1)]
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/759549.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Class Constructors and Destructors (类的构造函数和析构函数)

Class Constructors and Destructors [类的构造函数和析构函数] 1. Declaring and Defining Constructors (声明和定义构造函数)2. Using Constructors (使用构造函数)3. Default Constructors (默认构造函数)4. Destructors (析构函数)5. Improving the Stock Class (改进 Sto…

香港回归庆典开序幕,蝴蝶效应集团齐献礼

6月29日,香港各界庆典委员会庆祝香港回归祖国27周年活动启动礼在维多利亚公园举行。香港特区行政长官李家超、中央政府驻港联络办主任郑雁雄、香港各界庆典委员会主席谭锦球和筹委会主席陈鸿道等出席并致辞。 作为香港物流行业推广的领军企业,香港蝴蝶效应集团也以优秀企业代表…

Go 语言切片遍历地址会发生改变吗?

引言:今天面试的时候,面试官问了一道学 Go 语言的同学都会的简单代码,是关于 Go 语言 for 循环问题的,他询问了一个点,循环中共享变量的地址会发生改变吗? 相信听到这个问题的你,第一反应肯定是…

分享屏幕坐标和窗口通信

简介 实现功能&#xff0c;通过url传参选择扑克牌&#xff0c;桌面同时打开两个以上该窗口&#xff0c;扑克牌可以在窗口之间移动。 在线演示 屏幕坐标和窗口通信 实现代码 <!DOCTYPE html><html><head> <meta http-equiv"Content-Type" co…

Linux_动、静态库

目录 一、静态库 1、静态库的概念 2、制作静态库的指令 3、制作静态库 4、链接静态库 二、动态库 1、动态库的概念 2、制作动态库的指令 3、制作动态库 4、链接动态库 5、动态库的加载 三、静态库与动态库的区别 结语 前言&#xff1a; 在Linux下大部分程序进…

学习笔记——动态路由——OSPF(报头信息、报文信息、三张表)

六、OSPF协议的报头信息、报文信息、三张表 OSPF的协议报文在一个广播域内进行传递&#xff0c;是直接封装在IP报文中的&#xff0c;协议号为89。 OSPF本身5种类型&#xff1a;分别是Hello报文、DD报文、LSR报文、LSU报文、LSAck报文&#xff0c;各种不同类型的LSA其实只是包含…

Jedis、Lettuce、RedisTemplate连接中间件

jedis就像jdbc一样&#xff0c;用于两个端直接的连接。 1.创建Spring项目 这里不过多赘述... 2.导入连接工具jedis 在pom文件中导入jedis的依赖。 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version&…

第一周:李宏毅机器学习笔记

第一周学习周报 摘要一、机器学习基础理论1. 什么是机器学习&#xff1f;2. 机器学习“寻找”的函数有哪些类型&#xff1f;3. 机器学习中机器如何“寻找”函数&#xff1f;三步走3.1 第一步&#xff1a;设定函数的未知量&#xff08;Function with Unknown Parameters&#xf…

昇思25天学习打卡营第12天|ShuffleNet图像分类

1. 学习内容复盘 ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到最好的模型精度。ShuffleNetV1的设计核心是引入了两种操作&a…

C++ 数据库MySQL 学习笔记(3) - 数据库操作

C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表&#xff0c;是一种虚拟存在的表。视图就像一个窗口&#xff0c;通过这个窗口可以看到系统专门提供的数据&#xff0c;这样用户可以不看整个数据库表中的数据&#xff0c;而只关心对自己有…

Chrome备份数据

Chrome备份数据 1、 导出谷歌浏览器里的历史记录 参考&#xff1a;https://blog.csdn.net/qq_32824605/article/details/127504219 在资源管理器中找到History文件&#xff0c;文件路径&#xff1a; C:\Users\你的电脑用户名\AppData\Local\Google\Chrome\User Data\Default …

【Linux】Linux系统配置,linux的交互方式

1.Linux系统环境安装 有三种方式 裸机安装或者双系统 -- 不推荐虚拟机安装 --- 不推荐云服务器/安装简单&#xff0c; 维护成本低——推荐&#xff0c; 未来学习效果好 我们借助云服务器 云服务器&#xff08;Elastic Compute Service&#xff0c;ECS&#xff09;的标准定义…

昇思25天学习打卡营第7天|网络构建

昇思25天学习打卡营第7天|网络构建 前言函数式自动微分函数与计算图微分函数与梯度计算Stop GradientAuxiliary data神经网络梯度计算 个人任务打卡&#xff08;读者请忽略&#xff09;个人理解与总结 前言 非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型&#xff01;从今…

基于SpringBoot的超市进销存系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 工具&#xff1a;MyEclipse、Tomcat 系统展示 首页 首页界面图 个人中心 个人中心…

使用LabVIEW和示波器测试IGBT参数

使用LabVIEW和示波器测试绝缘栅双极型晶体管&#xff08;IGBT&#xff09;参数的综合解决方案。过程包括硬件设置、示波器和其他必要设备的配置&#xff0c;以及开发LabVIEW程序以自动化数据采集、过滤、关键参数计算和结果显示。该方法确保了IGBT测试的准确性、可靠性和高效性…

Python自动化运维 系统基础信息模块

1.系统信息的收集 系统信息的收集&#xff0c;对于服务质量的把控&#xff0c;服务的监控等来说是非常重要的组成部分&#xff0c;甚至是核心的基础支撑部分。我们可以通过大量的核心指标数据&#xff0c;结合对应的检测体系&#xff0c;快速的发现异常现象的苗头&#xff0c;进…

5.How Fast Should You Be When Learning?(你应该用多快的速度学习? (二))

Are you failing to reach an ideal or you dont know what the ideal is? 你是否没有达到理想状态&#xff0c;或者不知道理想状态是什么? A lot of learing involves having a mental representation of what the ideal performance ought to be, a method or approach t…

【JavaEE】多线程代码案例(1)

&#x1f38f;&#x1f38f;&#x1f38f;个人主页&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;JavaEE专栏&#x1f38f;&#x1f38f;&#x1f38f; &#x1f38f;&#x1f38f;&#x1f38f;上一篇文章&#xff1a;多线程&#xff08;2…

维卡币(OneCoin)是投资骗局!中国成维卡币传销重灾区,信徒们醒醒吧!创始人被通缉,生死不明!

维卡币(英文名&#xff1a;OneCoin)是一个隐藏在加密货币外表下的庞氏骗局&#xff0c;因传销诈骗和违法吸金被起诉&#xff0c;受害者遍布全球。它的创始人Ruja Ignatova因欺骗和洗钱被列为通缉嫌疑人&#xff0c;成为全球最大金融诈骗案件之一的逃犯&#xff0c;目前美国政府…

ELK企业级实战

一、Elstic stack在企业的常⻅架构 https://www.bilibili.com/video/BV1x94y1674x/?buvidXY705117E90F73A790429C9CFBD5F70F22168&vd_source939ea718db29535a3847d861e5fe37ef ELK 解决取得问题 痛点1: ⽣产出现故障后&#xff0c;运维需要不停的查看各种不同的⽇志进⾏…