Pytorch深度学习快速入门笔记【小土堆】

news2024/9/20 18:54:44

目录

1 Python学习中两大重要函数

2 Python代码编辑的三种方式

3 Pytorch学习

3.1 Dataset和DataLoader

3.1.1 Dataset

3.1.2 DataLoader

3.2 TensorBoard

3.2.1 add_scalar

3.2.2 add_image

3.3 Transforms

3.3.1 ToTensor

3.3.2 Normalize

3.3.3 Resize

3.3.4 Compose

3.3.5 RandomCrop

3.4 torchvision中的数据集使用

4 神经网络

4.1 nn.Module

4.2 卷积层

4.2.1 torch.nn.functional.conv2d

4.2.2 nn.Conv2d

4.3 池化层 nn.MaxPool2d

4.4 非线性激活

4.5 线性层

4.6 自定义网络

4.7 损失函数和反向传播

4.7.1 nn.L1Loss

4.7.2 nn.MSELoss

4.7.3 nn.CrossEntropyLoss

4.7.4 反向传播

4.8 优化器 torch.optim

4.9 现有模型的操作

4.9.1 使用及修改

4.9.2 保存及加载

4.10 完整的模型训练套路

4.11 利用GPU进行训练

4.11.1 xx = xx.cuda()

4.11.2 xx = xx.to(device)

4.12 完整的模型验证套路

4.13 看看开源项目


1 Python学习中两大重要函数

1、dir()函数:能让我们知道工具箱及工具箱中的分隔区有什么工具。

2、help()函数:能让我们知道工具如何使用。

查看torch工具箱下有哪些分隔区:

我们发现torch工具箱有很多分隔区,包括cuda。

查看cuda分隔区有哪些工具:

我们发现cuda分隔区有很多工具,包括is_available。

查看is_available工具的作用:

我们发现is_available工具的作用是返回CUDA是否可用的bool值。

2 Python代码编辑的三种方式

1、Python文件

运行Python文件,即运行文件中所有行的代码。

优点:通用,适用于大型项目。

缺点:如果某行出错,修改改行后,需要从头运行整个Python文件。

2、Python控制台

通常情况下,每次运行一行。

优点:可以显示每个变量属性,可以用于程序调试。

缺点:不利于代码阅读及修改。

3、Jupyter

每个单元格(块)内可以编写一行或者多行代码,每次运行一个单元格。

优点:利于代码阅读及修改。

缺点:环境需要配置。

3 Pytorch学习

3.1 Dataset和DataLoader

3.1.1 Dataset

from torch.utils.data import Dataset
help(Dataset)
Dataset??

Dataset和DataLoader是Pytorch读取数据的两个类。

Dataset将数据和label进行组织编号0,1,2,3...,使得Pytorch可以根据编号读取数据。若需要获取样本数量、每个数据及其label,则需要实现len()方法和getitem()方法。len()方法是用来返回数据集的样本数量,getitem()方法是用来根据给定的索引编号返回对应的数据样本。

from torch.utils.data import Dataset
import os
from PIL import Image


# 若需要自定义数据集,则需要创建一个继承自Dataset的子类,并实现__len__()方法和__getitem__()方法
class MyDataset(Dataset):
    # 初始化拼接路径
    def __init__(self,root_path,label_path):
        self.root_path = root_path
        self.label_path = label_path
        # 拼接路径
        self.path = os.path.join(root_path,label_path)
        # 以列表的形式返回路径下的图片名
        self.imgArr = os.listdir(self.path)


    # 根据索引返回某个图片的open状态
    def __getitem__(self, index):
        # 根据索引获取某个图片名
        img = self.imgArr[index]
        img_path = os.path.join(self.path, img)
        img_open = Image.open(img_path)
        return img_open

    # 返回列表长度
    def __len__(self):
        return len(self.imgArr)


# 创建ants_dataset对象,初始化root_path和label_path
ants_dataset = MyDataset("dataset/train", "ants")
# dataset/train\ants
print(ants_dataset.path)
# ['0013035.jpg', '1030023514_aad5c608f9.jpg', '1095476100_3906d8afde.jpg', '1099452230_d1949d3250.jpg', '116570827_e9c126745d.jpg', '1225872729_6f0856588f.jpg', '1262877379_64fcada201.jpg', '1269756697_0bce92cdab.jpg', '1286984635_5119e80de1.jpg', '132478121_2a430adea2.jpg', '1360291657_dc248c5eea.jpg', '1368913450_e146e2fb6d.jpg', '1473187633_63ccaacea6.jpg', '148715752_302c84f5a4.jpg', '1489674356_09d48dde0a.jpg', '149244013_c529578289.jpg', '150801003_3390b73135.jpg', '150801171_cd86f17ed8.jpg', '154124431_65460430f2.jpg', '162603798_40b51f1654.jpg', '1660097129_384bf54490.jpg', '167890289_dd5ba923f3.jpg', '1693954099_46d4c20605.jpg', '175998972.jpg', '178538489_bec7649292.jpg', '1804095607_0341701e1c.jpg', '1808777855_2a895621d7.jpg', '188552436_605cc9b36b.jpg', '1917341202_d00a7f9af5.jpg', '1924473702_daa9aacdbe.jpg', '196057951_63bf063b92.jpg', '196757565_326437f5fe.jpg', '201558278_fe4caecc76.jpg', '201790779_527f4c0168.jpg', '2019439677_2db655d361.jpg', '207947948_3ab29d7207.jpg', '20935278_9190345f6b.jpg', '224655713_3956f7d39a.jpg', '2265824718_2c96f485da.jpg', '2265825502_fff99cfd2d.jpg', '226951206_d6bf946504.jpg', '2278278459_6b99605e50.jpg', '2288450226_a6e96e8fdf.jpg', '2288481644_83ff7e4572.jpg', '2292213964_ca51ce4bef.jpg', '24335309_c5ea483bb8.jpg', '245647475_9523dfd13e.jpg', '255434217_1b2b3fe0a4.jpg', '258217966_d9d90d18d3.jpg', '275429470_b2d7d9290b.jpg', '28847243_e79fe052cd.jpg', '318052216_84dff3f98a.jpg', '334167043_cbd1adaeb9.jpg', '339670531_94b75ae47a.jpg', '342438950_a3da61deab.jpg', '36439863_0bec9f554f.jpg', '374435068_7eee412ec4.jpg', '382971067_0bfd33afe0.jpg', '384191229_5779cf591b.jpg', '386190770_672743c9a7.jpg', '392382602_1b7bed32fa.jpg', '403746349_71384f5b58.jpg', '408393566_b5b694119b.jpg', '424119020_6d57481dab.jpg', '424873399_47658a91fb.jpg', '450057712_771b3bfc91.jpg', '45472593_bfd624f8dc.jpg', '459694881_ac657d3187.jpg', '460372577_f2f6a8c9fc.jpg', '460874319_0a45ab4d05.jpg', '466430434_4000737de9.jpg', '470127037_513711fd21.jpg', '474806473_ca6caab245.jpg', '475961153_b8c13fd405.jpg', '484293231_e53cfc0c89.jpg', '49375974_e28ba6f17e.jpg', '506249802_207cd979b4.jpg', '506249836_717b73f540.jpg', '512164029_c0a66b8498.jpg', '512863248_43c8ce579b.jpg', '518773929_734dbc5ff4.jpg', '522163566_fec115ca66.jpg', '522415432_2218f34bf8.jpg', '531979952_bde12b3bc0.jpg', '533848102_70a85ad6dd.jpg', '535522953_308353a07c.jpg', '540889389_48bb588b21.jpg', '541630764_dbd285d63c.jpg', '543417860_b14237f569.jpg', '560966032_988f4d7bc4.jpg', '5650366_e22b7e1065.jpg', '6240329_72c01e663e.jpg', '6240338_93729615ec.jpg', '649026570_e58656104b.jpg', '662541407_ff8db781e7.jpg', '67270775_e9fdf77e9d.jpg', '6743948_2b8c096dda.jpg', '684133190_35b62c0c1d.jpg', '69639610_95e0de17aa.jpg', '707895295_009cf23188.jpg', '7759525_1363d24e88.jpg', '795000156_a9900a4a71.jpg', '822537660_caf4ba5514.jpg', '82852639_52b7f7f5e3.jpg', '841049277_b28e58ad05.jpg', '886401651_f878e888cd.jpg', '892108839_f1aad4ca46.jpg', '938946700_ca1c669085.jpg', '957233405_25c1d1187b.jpg', '9715481_b3cb4114ff.jpg', '998118368_6ac1d91f81.jpg', 'ant photos.jpg', 'Ant_1.jpg', 'army-ants-red-picture.jpg', 'formica.jpeg', 'hormiga_co_por.jpg', 'imageNotFound.gif', 'kurokusa.jpg', 'MehdiabadiAnt2_600.jpg', 'Nepenthes_rafflesiana_ant.jpg', 'swiss-army-ant.jpg', 'termite-vs-ant.jpg', 'trap-jaw-ant-insect-bg.jpg', 'VietnameseAntMimicSpider.jpg']
print(ants_dataset.imgArr)

# 获取索引为0的图片的open状态
ants_0= ants_dataset[0] # ants_0 = ants_dataset.__getitem__(0)
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=768x512 at 0x19611329BE0>
print(ants_0)
# 展示图片
ants_0.show()

# 124
print(len(ants_dataset)) # print(ants_dataset.__len__())

3.1.2 DataLoader

DataLoader对数据进行打包,将数据集划分为小批量,按batchsize送入网络模型。可以接收一个Dataset对象作为输入,并根据指定的批量大小、是否打乱数据、是否使用多线程等参数,来构建一个用于数据加载的迭代器。

dataset=test_set: 指定要加载的数据集,这里是test_set。

batch_size=64: 设置每个批次的大小为64。这意味着每次从数据集中取出64个样本进行处理。

shuffle=True: 设置为True就是表示每个epoch开始时,对数据进行打乱,为False表示不打乱。

num_workers=0: 设置工作进程的数量。这里设置为0意味着数据加载将在主进程中进行,不会使用额外的子进程来加速数据加载。

drop_last=True: 如果数据集的大小不能被批次大小整除,设置为True会丢弃最后一个不完整的批次。这可以确保所有批次都有相同的大小,避免因批次大小不一致而导致的问题。

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
test_loader = DataLoader(dataset=test_set, batch_size=64, shuffle=True, num_workers=0, drop_last=True)

img,target = test_set[0]
# torch.Size([3, 32, 32])  (C,H,W)
print(img.shape)
# 3
print(target)

# 迭代器取出test_loader的第一个被打包的imgs和tags
iterator_loader = iter(test_loader)
imgs,targets = next(iterator_loader)
# torch.Size([64, 3, 32, 32]) (N,C,H,W)
print(imgs.shape)
# tensor([7, 2, 3, 1, 4, 1, 9, 8, 8, 5, 6, 9, 4, 5, 8, 7, 6, 3, 8, 3, 4, 5, 2, 6,
#         7, 1, 4, 1, 1, 1, 0, 5, 5, 5, 5, 0, 0, 8, 8, 3, 6, 2, 2, 5, 8, 0, 4, 4,
#         5, 9, 2, 8, 3, 9, 3, 4, 5, 0, 9, 2, 1, 6, 8, 6])
# 这个包64个数据所对应的类别
print(targets)

writer = SummaryWriter("log")

# Tensorboard中生成两个标签页Epoch0和Epoch1
for epoch in range(2):
    # 在每个标签页中每一步step都会呈现64张图片
    step = 0
    for data in test_loader:
        imgs,targets = data
        writer.add_images("Epoch:{}".format(epoch),imgs,step)
        step += 1

writer.close()

注意:add_image与add_images的区别

3.2 TensorBoard

TensorBoard的作用是提供一套用于数据可视化的工具,帮助开发者理解和分析机器学习模型的训练过程。

3.2.1 add_scalar

add_scalar用于在TensorBoard中添加标量数据。该方法可以用来添加训练过程中的损失值、准确率等指标,以便于在TensorBoard中进行可视化和比较。

tag(字符串):数据标识,用作图表的标题。

scalar_value(数值):要记录的标量数据的值,例如损失值、准确率等。

global_step(整数):迭代次数。例如,在训练神经网络时,可以将当前的迭代次数传递给global_step,以便在TensorBoard中可视化某些指标随着训练步数变化而变化的曲线。

walltime(时间戳):记录的时间。如果不指定,则默认使用当前时间。

案例:使用TensorBoard绘制y=x的函数图像

from torch.utils.tensorboard import SummaryWriter

# 日志文件存储位置
writer = SummaryWriter("log")
for i in range(100):
    # 参数:标题,纵坐标,横坐标
    writer.add_scalar("y=2x",2*i,i)
writer.close()

运行上述代码,产生log文件夹,里面存放了一个文件。

在terminal中运行如下代码,再点击网址跳转。

出现了y=2x图像

补充:可通过tensorboard --logdir=log --port=XXXX 指定端口号

当未改变图像标题,重复修改y值,如writer.add_scalar(“y = x”, i, i),writer.add_scalar(“y = x”, 2i, i),writer.add_scalar(“y = x”, 3i, i),会导致新绘制会包含之前绘制的图像。

解决方法:删除所有log文件,重新执行程序,再在tensorboard中查看

3.2.2 add_image

tag(字符串):数据标识,用作图表的标题。

img_tensor(torch.tensor、numpy.ndarray或string/blobname):图像数据,注意类型的要求。

global_step(整数):迭代次数。可以通过滑块来查看不同图片。

walltime(时间戳):记录的时间。如果不指定,则默认使用当前时间。

dataformats(字符串):表单的图像数据格式规范CHW、HWC、HW、WH等。

案例:将图像数据添加到TensorBoard的img标签页上

from torch.utils.tensorboard import SummaryWriter
from PIL import Image
import numpy as np

img_path = "dataset/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)
# 将图片PIL类型转换为numpy类型
img_array = np.array(img_PIL)

# (512, 768, 3) (高度、宽度、通道数)
print(img_array.shape)

writer = SummaryWriter("log")
# 标题,图片数据,迭代次数,数据形式(高度H、宽度W、通道数C)
writer.add_image("img",img_array,1,dataformats='HWC')
writer.close()

问题:PIL报错`AttributeError: module ‘PIL.Image‘ has no attribute ‘ANTIALIAS

原因及解决方法:因为10.0.0以后版本的Pillow已经舍弃了ANTIALIAS,我们可以先卸载掉现有的Pillow,再安装9.5.0版本的Pillow。

#卸载当前的pillow(我的版本是10.4.0)
pip uninstall pillow


#安装9.5.0版本的pillow(镜像源是清华的)
pip install pillow==9.5.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

3.3 Transforms

Transforms用于对图像进行预处理和数据增强操作,如调整图像大小、中心裁剪、随机裁剪、随机水平翻转、归一化、将 PIL 图像转换为 Tensor 等等。

3.3.1 ToTensor

ToTensor可以将图像PIL或者numpy的数据类型转换为tensor的数据类型。

from torchvision import transforms
from PIL import Image


# img_path = "F:\\研0学习\\DeepLearning\\Project\\Pytorch\\dataset\\train\\ants\\0013035.jpg"(绝对路径)
img_path = "dataset/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)
print(img_PIL)

# 实例化一个tensor_trans对象
tensor_trans = transforms.ToTensor()
# 将图像PIL的数据类型转换为tensor的数据类型,默认调用ToTensor类的call方法
img_tensor = tensor_trans(img_PIL)
print(img_tensor)

 ToTensor类的call方法(参数:图像PIL或者numpy的数据类型,返回:图像tensor的数据类型)

运行结果: 

可以看到,张量数据是一个三维数组,由3个通道(3个二维数组)构成。

补充:Pycharm中查看包的结构Structure(快捷键Alt+7)

查看需要传入的参数(快捷键Ctrl+P)

案例:将图像数据添加到TensorBoard的Img标签页上

注意:本案例在add_image函数中传入的参数是图像tensor的数据类型,而在3.2.2 add_image,传入的参数是图像numpy的数据类型。

from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

img_path = "dataset/train/bees/16838648_415acd9e3f.jpg"
img_PIL = Image.open(img_path)

# 实例化一个tensor_trans对象
tensor_trans = transforms.ToTensor()
# 将图像PIL的数据类型转换为tensor的数据类型
img_tensor = tensor_trans(img_PIL)

writer = SummaryWriter("log")
# 传入的参数是图像tensor的数据类型
writer.add_image("Img",img_tensor)
writer.close()

3.3.2 Normalize

我们采用标准化对图片张量进行处理:

列表中0.5的作用是设置标准化的均值和标准差。在这个例子中,每个通道的像素值将被减去0.5(均值),然后除以0.5(标准差),从而实现标准化。这样做的目的是使得图片的像素值分布在-1到1之间,有助于神经网络的训练。

from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

img_path = "dataset/train/ants/5650366_e22b7e1065.jpg"
img_PIL = Image.open(img_path)

# 实例化一个tensor_trans对象
tensor_trans = transforms.ToTensor()
# 将图像PIL的数据类型转换为tensor的数据类型
img_tensor = tensor_trans(img_PIL)

# 打印图片张量的第一个通道的第一个通道值
# tensor(0.3804)
print(img_tensor[0][0][0])

writer = SummaryWriter("log")
# 将图片张量添加到Tensorboard中
writer.add_image("img_ant",img_tensor,1)

# 使用Normalize对图片张量进行标准化处理
# 前面的参数[0.5,0.5,0.5]表示每个通道的均值,后面的参数[0.5,0.5,0.5]表示每个通道的标准差
norm_trans = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
img_norm_tensor = norm_trans(img_tensor)

# 打印归一化后的图片张量的第一个通道的第一个通道值
# tensor(-0.2392)
print(img_norm_tensor[0][0][0])

# 将归一化后的图片张量添加到Tensorboard中
writer.add_image("img_ant",img_norm_tensor,2)
writer.close()

图片张量添加到Tensorboard中 

将标准化后的图片添加到Tensorboard中

归一化和标准化都是对数据做变换的方式,将原始的一列数据转换到某个范围,或者某种形态。

归一化:通过对原始数据进行变换把数据映射到(默认为[0,1])之间。如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变,所以这种方法健壮性较差,只适合传统精确小数据场景。

公式:

标准化:通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内。如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小,所以在已有样本足够多的情况下比较稳定适合现代嘈杂大数据场景

公式:

3.3.3 Resize

Resize函数在transforms库中用于改变图像的尺寸。它接受两个参数,第一个是图像的新高度,第二个是新宽度。如果只提供一个参数,另一个参数默认为None,此时图像会被按比例缩放。

from torchvision import transforms
from PIL import Image


img_path = "dataset/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=768x512 at 0x23DEDD6B0D0>
print(img_PIL)

# 实例化一个resize_trans对象
resize_trans = transforms.Resize((512, 512))
# 传入的参数可以是图片PIL或者tensor
img_resize_PIL = resize_trans(img_PIL)
# <PIL.Image.Image image mode=RGB size=512x512 at 0x23DEC241DC0>
print(img_resize_PIL)

# 实例化一个resize_trans2对象
resize_trans2 = transforms.Resize(300)
# 传入的参数可以是图片PIL或者tensor
img_resize2_PIL = resize_trans2(img_PIL)
# <PIL.Image.Image image mode=RGB size=450x300 at 0x23DEC1370A0>
print(img_resize2_PIL)

3.3.4 Compose

Compose用于将多个数据变换操作组合成一个变换序列,以便能够按顺序执行多个操作。通过使用transforms.Compose(),可以方便地串联起多个单独的变换操作,例如裁剪、缩放、旋转等,并将它们应用到数据集中的每张图像上。

from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from PIL import Image

img_path = "dataset/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)

# 实例化一个resize_trans的对象
resize_trans = transforms.Resize(300)

# 实例化一个tensor_trans对象
tensor_trans = transforms.ToTensor()

# 实例化一个compose_trans对象,将上面创建好的两个对象依次传入
compose_trans = transforms.Compose([resize_trans, tensor_trans])
# img_PIL -> img_resize_PIL -> img_resize_tensor
img_resize_tensor = compose_trans(img_PIL)

writer = SummaryWriter("log")
# 将img_resize_tensor写入Tensorboard的img_compose标签页中
writer.add_image("img_compose",img_resize_tensor)
writer.close()

3.3.5 RandomCrop

RandomCrop 是 PyTorch 中用于图像数据增强(data augmentation)的函数之一,它可以在图像或张量的随机位置裁剪出指定大小的区域。

from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from PIL import Image

writer = SummaryWriter("log")
img_path = "dataset/train/ants/0013035.jpg"
img_PIL = Image.open(img_path)

# 实例化一个crop_trans对象
crop_trans = transforms.RandomCrop(30)
# 实例化一个tensor_trans对象
tensor_trans = transforms.ToTensor()
# 实例化一个compose_trans对象
compose_trans = transforms.Compose([crop_trans, tensor_trans])

# 循环将img_crop_tensor写入Tensorboard的RandomCrop标签页中
for i in range(10):
    img_crop_tensor = compose_trans(img_PIL)
    writer.add_image("RandomCrop",img_crop_tensor,i)
writer.close()

3.4 torchvision中的数据集使用

数据集链接:https://pytorch.org/pytorch-domains

以CIFAR10数据集为例,其他的数据集相似:CIFAR-10是一个常用的计算机视觉数据集,包含了60,000张32x32像素的彩色图像,分为10个类别,每个类别有6,000张图像。这些图像涵盖了飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车等常见物体。

torchvision.datasets.CIFAR10: 这是PyTorch库中的一个类,用于加载CIFAR-10数据集。
root="./dataset": 指定了数据集下载和存储的位置。
train=True: 表示想要加载的是训练集,为False,则会加载测试集。
download=True: 这是一个布尔值参数,为True,则表示如果数据集尚未下载,就会自动下载。如果设置为False,则不会下载数据集。

import torchvision
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter("log")
compose_tensor = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

train_set = torchvision.datasets.CIFAR10("./dataset", train=True, transform=compose_tensor, download=True)
test_set = torchvision.datasets.CIFAR10("./dataset",train=False,transform=compose_tensor,download=True)

# (tensor(...),3)
print(test_set[0])

# img对应img的tensor数据形式,target对应分类的编号
img,target = test_set[0]
# tensor(...)
print(img)
# 3
print(target)

# ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] 一共有10个类别
print(test_set.classes)

# cat
print(test_set.classes[target])

# 所以test_set[0]表示的是cat数据

# 循环将test_set前10个数据写入Tensorboard中的dataset_transform的标签页中
for i in range(10):
    img,target = test_set[i]
    writer.add_image("dataset_transform",img,i)

writer.close()

4 神经网络

4.1 nn.Module

文档连接:https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module

nn.Module是PyTorch中的一个类,用于表示神经网络的层。使用步骤如下:

  • 定义网络结构:通过继承nn.Module类并实现__init__()和forward()方法来定义自己的网络结构。
  • 添加层:在__init__()方法中,使用super().__init__()调用父类的初始化方法,然后添加所需的层,如卷积层、全连接层等。
  • 前向传播:在forward()方法中,定义输入数据在网络中的传播过程。
  • 实例化网络:创建自定义网络类的实例,并传入所需的参数。
  • 训练和评估:将实例化的网络用于训练和评估。
import torch
from torch import nn

class MyModule(nn.Module):
    def __init__(self):
        # 使用super调用父类的构造方法
        super().__init__()

    # 重写forward构造方法
    def forward(self,input):
        output = input + 1
        return output

# 实例化一个module对象
module = MyModule()
# 创建一个张量作为输入
input = torch.tensor(1.0)
# 将输入传入到模型中,调用模型的forward方法,得到输出
output = module(input)
# tensor(2.)
print(output)

4.2 卷积层

4.2.1 torch.nn.functional.conv2d

torch.nn.functional(通常简称为F)是PyTorch库中的一个模块,它提供了大量的功能函数,这些函数可以对张量tensor进行操作。

import torch
import torch.nn.functional as F

# 输入图像(5×5)
input = torch.tensor([[1,2,0,3,1],
                      [0,1,2,3,1],
                      [1,2,1,0,0],
                      [5,2,3,1,1],
                      [2,1,0,1,1]])

# 卷积核(3×3)
kernal = torch.tensor([[1,2,1],
                       [0,1,0],
                       [2,1,0]])

# torch.Size([5, 5])
print(input.shape)
# torch.Size([3, 3])
print(kernal.shape)

# 修改张量的shape  (H,W)->(minibatch,channel,H,W)
input = input.reshape(1,1,5,5)
kernal = kernal.reshape(1,1,3,3)

# torch.Size([1, 1, 5, 5])
print(input.shape)
# torch.Size([1, 1, 3, 3])
print(kernal.shape)

print("卷积运算:-----------------------")
# 每次移动1位
output = F.conv2d(input,kernal,stride=1)
print(output)

# 每次移动2位
output2 = F.conv2d(input,kernal,stride=2)
print(output2)

# 在input的上下左右补上0(默认为0),且每次移动1位
output3 = F.conv2d(input,kernal,stride=1,padding=1)
print(output3)

torch.Size([1, 1, 5, 5])的参数解析:

第一个维度的大小为1,表示我们有一个批次的数据,但只有一个样本。

第二个维度的大小也为1,表示每个样本只有一个通道。在图像处理中,通道通常表示颜色通道(例如,RGB图像有3个通道,灰度图像通道数是1。)

第三个维度的大小为5,表示每个通道的高度为5。

第四个维度的大小为5,表示每个通道的宽度为5。

output = F.conv2d(input,kernal,stride=1)图解如下:

output3 = F.conv2d(input,kernal,stride=1,padding=1)图解如下:

4.2.2 nn.Conv2d

torch.nn.Conv2d()是一个类,需要在实例化时指定卷积层的参数,如输入通道数、输出通道数、卷积核大小等。实例化后,可以通过调用其 forward() 方法进行卷积操作。简单说:就是定义一个卷积层。

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter


class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)

    def forward(self,input):
        output = self.conv(input)
        return output


test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)

dataloader = DataLoader(test_set,batch_size=64)

module = MyModule()
# MyModule(
#   (conv): Conv2d(3, 6, kernel_size=(3, 3), stride=(1, 1))
# )
print(module)

writer = SummaryWriter("./log")
step = 0

for data in dataloader:
    imgs,target = data
    output = module(imgs)
    # # torch.Size([64, 3, 32, 32])
    # print(imgs.shape)
    # # torch.Size([64, 6, 30, 30])
    # print(output.shape)

    # 分别将imgs和output_imgs输入到Tensorboard中,进行对比
    writer.add_images("imgs",imgs,step)
    # ouput是6通道的,而add_images只能接受3通道的,所以需要reshape
    # (64,6,30,30) -> (-1,3,30,30) "-1"表示该维度的大小根据其他维度的大小自动计算
    output_imgs = torch.reshape(output,(-1,3,30,30))
    writer.add_images("output_imgs",output_imgs,step)
    step = step + 1

writer.close()

 

self.conv = nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)

解释如下:

in_channels=3: 输入图像的通道数。在这个例子中,输入图像有3个通道,通常对应于RGB颜色空间中的红、绿、蓝三个通道。

out_channels=6: 输出特征图的通道数。在这个例子中,卷积层将产生6个不同的特征图,每个特征图对应一个特定的过滤器。

kernel_size=3: 卷积核的大小。这里使用的是3x3的卷积核,意味着在计算特征时,会考虑输入图像中每个3x3的区域。

stride=1: 卷积核在输入图像上移动的步长。这里步长为1,表示每次移动一个像素。较大的步长可以减少输出特征图的空间尺寸,但可能会丢失一些细节信息。

padding=0: 在输入图像周围添加的零填充的数量。"0"表示无填充。

即:创建了一个二维卷积层conv,用于处理具有3个通道的输入图像,并生成具有6个不同特征的输出特征图。6个卷积核大小都为3x3,步长为1,且不使用填充。

如下图:in_channel=1,卷积核2个,out_channel=2。2个卷积核分别会与输入图像进行一轮计算,得到两个输出。(1×2=2)

有几个卷积核,就会有多少个输出通道:一个卷积核作用完输入图像的所有通道后,会把得到的所有矩阵的对应值相加,最终产生一个通道。

4.3 池化层 nn.MaxPool2d

nn.MaxPool2d是PyTorch中的一个类,用于实现二维的最大池化层。最大池化是一种取局部区域最大值的操作,它可以将输入的特征图尺寸减小,同时保留最重要的特征信息,以减少后续的计算量。降维是通过选择窗口大小(kernel_size)和滑动步长(stride)来实现的。例如,如果我们有一个8×8的特征图,使用3×3的窗口和2的步长进行最大池化,那么输出的特征图尺寸就会变成3×3。

注意,降维和下采样的区别:

  • 降维:降维的主要目的是减少数据的维度,同时尽可能保留原始数据中的重要信息。
  • 下采样:下采样的主要目的是减少数据样本的数量。

import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter


class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        # 定义一个最大池化层
        # kernel_size=3,池化核3×3,默认情况下stride也为3
        # ceil_mode:决定输出大小计算时采用向上取整还是向下取整。为True,向上取值,为False,向下取整
        self.max_pool = nn.MaxPool2d(kernel_size=3,ceil_mode=False)

    def forward(self,input):
        output = self.max_pool(input)
        return output


test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
dataloader = DataLoader(test_set, batch_size=64)

module = MyModule()
# MyModule(
#   (max_pool): MaxPool2d(kernel_size=3, stride=3, padding=0, dilation=1, ceil_mode=False)
# )
print(module)

writer = SummaryWriter("./log")

step = 0
for data in dataloader:
    imgs,targets = data
    output_imgs = module(imgs)
    writer.add_images("imgs_maxpool",imgs,step)
    writer.add_images("output_imgs_maxpool",output_imgs,step)
    step = step + 1
writer.close()

4.4 非线性激活

非线性激活函数是在神经网络中用于引入非线性特性的一种函数。线性激活函数只能处理线性关系,而非线性激活函数可以处理更复杂的非线性关系。常见的非线性激活函数有ReLU、Sigmoid、Tanh等。

ReLU(Rectified Linear Unit):ReLU函数是一种简单的非线性激活函数,它将所有负数映射为0,保留所有正数不变。

  • inplace参数的含义:为True时,对原输入进行激活函数的计算,计算结果赋给原输入;为False时,对原输入进行激活函数的计算,生成计算结果,原输入不变。

Sigmoid函数:Sigmoid函数是一个常用的非线性激活函数,它将输入值映射到0和1之间。

Tanh函数:Tanh函数是双曲正切函数,它将输入值映射到-1到1之间。

import torch
from torch import nn

input = torch.tensor([[1,-0.5],
                      [-1,3]])

# 增加一个参数batchsize
input = torch.reshape(input, (-1, 1, 2, 2))
# torch.Size([1, 1, 2, 2])
print(input.shape)

class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.relu = nn.ReLU()

    def forward(self,input):
        output = self.relu(input)
        return output


module = MyModule()
output = module(input)
# tensor([[[[1., 0.],
#           [0., 3.]]]])
print(output)
class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.sigmoid = nn.Sigmoid()

    def forward(self,input):
        output = self.sigmoid(input)
        return output


test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
dataloader = DataLoader(test_set, batch_size=64)

writer = SummaryWriter("./log")
module = MyModule()

step = 0
for data in dataloader:
    imgs,target = data
    output_imgs = module(imgs)
    writer.add_images("imgs_sigmoid",imgs,step)
    writer.add_images("output_imgs_sigmoid",output_imgs,step)
    step = step + 1
writer.close()

4.5 线性层

线性层是神经网络中的一种基本层,也被称为全连接层(全连接意味着每个神经元都与前一层的所有神经元相连)。线性层对输入数据进行线性变换,通过权重矩阵和偏置向量将输入数据映射到输出数据。线性层能够连接不同的神经元,实现信息的传递和转换。

nn.Linear是PyTorch中的一个线性层,用于实现全连接神经网络。它的作用是将输入数据进行线性变换,然后输出到下一层。具体来说,它将输入数据矩阵乘以权重矩阵,然后加上偏置向量(如果启用了偏置)。

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader

class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        # 定义线性层
        # in_features:输入数据的维度,即输入特征的数量。196608是根据后续reshape或者flatten得到的。
        # out_features:输出数据的维度,即输出特征的数量。
        # bias:布尔值,表示是否使用偏置项。默认为True,表示使用偏置项。
        self.linear = nn.Linear(196608,10)

    def forward(self,input):
        return self.linear(input)

test_set = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)

dataloader = DataLoader(test_set, batch_size=64,drop_last=True)

module = MyModule()

for data in dataloader:
    imgs,targets = data
    # torch.Size([64, 3, 32, 32])
    # print(imgs.shape)

    # 法一:通过reshape改变形状
    input = torch.reshape(imgs, (1, 1, 1, -1))
    # torch.Size([1, 1, 1, 196608])
    print(input.shape)
    output = module(input)
    # torch.Size([1, 1, 1, 10])
    print(output.shape)

    # 法二:将数据展平开,它将输入张量沿着指定的维度范围进行扁平化处理,并返回一个一维张量作为结果
    input2 = torch.flatten(imgs)
    # torch.Size([196608])
    print(input2.shape)
    output2 = module(input2)
    # torch.Size([10])
    print(output2.shape)

4.6 自定义网络

nn.Sequential是PyTorch中一个非常重要的类,用于构建简单的顺序连接模型。可以将其看做一个容器,它允许用户通过顺序堆叠多个层来创建神经网络模型。这个类的主要作用是简化模型的构建过程,使得用户可以通过简单、直观的方式定义复杂的网络结构。

CIFAR 10 model结构图如下:

 最后两步的线性层略有省略,在此补充:

搭建上图的网络,各层的padding和stride需要手动计算一下:

import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter


class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024,64),
            nn.Linear(64,10)
        )

    def forward(self,input):
        output = self.model(input)
        return output


module = MyModule()
# 64个数据,每个数据3个通道,每个通道32×32(每个值都是1.0)
input = torch.ones((64, 3, 32, 32))
output = module(input)
# torch.Size([64, 10])
print(output.shape)

writer = SummaryWriter("./log")
# (模型,模型的输入数据),
# add_graph是将PyTorch的计算图进行可视化,方便查看模型的层次结构和数据流动
writer.add_graph(module,input)
writer.close()

4.7 损失函数和反向传播

损失函数(Loss Function)用于衡量模型的预测输出与实际标签之间的差异或者误差。损失越小越好,根据loss调整参数(反向传播),更新输出,减少损失。

4.7.1 nn.L1Loss

4.7.2 nn.MSELoss

4.7.3 nn.CrossEntropyLoss

交叉熵损失函数(Cross-Entropy Loss Function)是在分类问题中经常使用的一种损失函数,特别是在多分类问题中。它衡量了模型输出的概率分布与真实标签之间的差异,通过最小化交叉熵损失来调整模型参数,使得模型更好地适应分类任务。

import torch
from torch import nn

inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)

loss = nn.L1Loss()
result = loss(inputs, targets)
# tensor(0.6667)    (|1-1|+|2-2|+|3-5|)/3
print(result)

loss2 = nn.L1Loss(reduction="sum")
result2 = loss2(inputs, targets)
# tensor(2.)    |1-1|+|2-2|+|3-5|
print(result2)

mse_loss = nn.MSELoss()
mse_result = mse_loss(inputs, targets)
# tensor(1.3333)    ((1-1)^2+(2-2)^2+(3-5)^2)/3=4/3
print(mse_result)

x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
x = torch.reshape(x,(1,3))
# tensor([[0.1000, 0.2000, 0.3000]])
print(x)
cross_loss = nn.CrossEntropyLoss()
cross_result = cross_loss(x,y)
# tensor(1.1019)    -0.2+ln(exp(0.1)+exp(0.2)+exp(0.3))
print(cross_result)

loss function的使用应根据需求,选定好损失函数后,按损失函数要求的维度(形状)输入 。

使用前面搭建的网络结合CrossEntropyLoss计算损失:

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
dataloader = DataLoader(dataset, batch_size=1, drop_last=True)


class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024,64),
            nn.Linear(64,10)
        )

    def forward(self,input):
        output = self.model(input)
        return output


cross_loss = nn.CrossEntropyLoss()
module = MyModule()
for data in dataloader:
    imgs,targets = data
    outputs = module(imgs)
    # print(outputs)
    # print(targets)
    result_loss = cross_loss(outputs, targets)
    result_loss.backward()
    print(result_loss)

4.7.4 反向传播

反向传播(Backpropagation)是一种在神经网络中用于训练模型的核心算法,主要通过计算损失函数对每个参数的梯度,并利用优化器,根据这些梯度更新网络中的权重和偏置,以最小化损失函数。在pycharm中对该行打断点,可以看到具体的梯度值。

4.8 优化器 torch.optim

torch.optim是PyTorch中用于优化神经网络模型参数的模块,它提供了多种优化算法,通过调整学习率等参数来最小化损失函数。

torch.optim中的一些常用优化器包括SGD、Adam、RMSprop和Adagrad等。这些优化器有不同的参数,如学习率(lr)、动量(momentum)和权重衰减(weight_decay)等,可以根据具体需求进行选择和调整。

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
dataloader = DataLoader(dataset, batch_size=1, drop_last=True)


# 自定义网络,训练分类【CIFAR10】
class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024,64),
            nn.Linear(64,10)
        )

    def forward(self,input):
        output = self.model(input)
        return output


# 实例化自定义网络
module = MyModule()
# 定义交叉熵损失函数
cross_loss = nn.CrossEntropyLoss()
# 定义优化器(SGD 随机梯度下降)
# lr 学习率
optim_sgd = torch.optim.SGD(module.parameters(), lr=0.01)

# 进行20轮数据的训练,每轮遍历整个数据集一次
for epoch in range(20):
    running_loss = 0
    for data in dataloader:
        imgs,targets = data
        outputs = module(imgs)
        result_loss = cross_loss(outputs, targets)
        # 清除每个参数的梯度
        optim_sgd.zero_grad()
        # 利用反向传播计算每个参数的梯度
        result_loss.backward()
        # 利用优化器,根据每个参数的梯度,更新模型参数,优化模型
        optim_sgd.step()
        running_loss = running_loss + result_loss
    # 打印每轮遍历总的损失
    print(running_loss)

4.9 现有模型的操作

4.9.1 使用及修改

使用PyTorch提供的现有模型vgg16

import torchvision
from torch import nn

# weights=None 加载模型结构,不加载模型参数
vgg16_false = torchvision.models.vgg16(weights=None)

# weights="DEFAULT" 加载模型结构和模型参数
# vgg16_true = torchvision.models.vgg16(weights="DEFAULT")

test_set = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)
# 在vgg16网络最后添加一个线性层,在CIFR10上对10个类别进行分类
# vgg16_false.add_module("add_linear",nn.Linear(1000,10))
# print(vgg16_false)

# 将添加的线性层加在classifier中
# vgg16_false.classifier.add_module("add_linear",nn.Linear(1000,10))
# print(vgg16_false)

# 不添加层,仅修改vgg16中的classifier的最后一个线性层
vgg16_false.classifier[6] = nn.Linear(4096,10)
print(vgg16_false)

 ​​​​​​​​​​​​​​​​​​​​​在vgg16网络最后添加一个线性层,在CIFR10上对10个类别进行分类

将添加的线性层加在classifier中

 不添加层,仅修改vgg16中的classifier的最后一个线性层

​​​​​​​

4.9.2 保存及加载

model_save.py

import torch
import torchvision

vgg16 = torchvision.models.vgg16(weights=None)
# 保存方式1:保存模型结构+模型参数
torch.save(vgg16,"vgg16_method1.pth")

# 保存方式2:保存模型参数(官方推荐)
torch.save(vgg16.state_dict(),"vgg16_method2.pth")

model_load.py

import torch
import torchvision

# 加载方式1:加载模型结构和模型参数
model = torch.load("vgg16_method1.pth")
print(model)

# 加载方式2:先加载模型结构,后加载模型参数
# 先加载模型结构
vgg16 = torchvision.models.vgg16(weights=None)
# 后加载模型参数
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16)

4.10 完整的模型训练套路

model.py

import torch
from torch import nn

class MyModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3,32,5,1,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,1,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,1,padding=2),
            nn.MaxPool2d(2),
            # 展平后的序列长度为64*4*4=1024
            nn.Flatten(),
            nn.Linear(64*4*4,64),
            nn.Linear(64,10)
        )

    def forward(self,x):
        x = self.model(x)
        return x

# 测试神经网络是否正常运行,调用model.py就不会进行如下测试
if __name__ == '__main__':
    module = MyModule()
    input = torch.ones((64, 3, 32, 32))
    # print(input)
    output = module(input)
    # print(output)
    # torch.Size([64, 10])
    print(output.shape)

train.py

# _*_ coding : utf-8 _*_
# @Time : 2024/9/8 18:51
# @Author : 春风吹又生
# @File : train
# @Project : DeepLearning

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10("../dataset", train=True, transform=torchvision.transforms.ToTensor(),
                                      download=True)
test_data = torchvision.datasets.CIFAR10("../dataset", train=False, transform=torchvision.transforms.ToTensor(),
                                      download=True)

# len()获取数据集长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练集数据集的长度为:{}".format(train_data_size))
print("测试集数据集的长度为:{}".format(test_data_size))

# 利用DataLoader加载数据集
train_dataloader = DataLoader(train_data, batch_size=64, drop_last=True)
test_dataloader = DataLoader(test_data, batch_size=64, drop_last=True)

# 网络模型
module = MyModule()

# 损失函数
loss_func = nn.CrossEntropyLoss()

# 优化器
learning_rate = 1e-2
optimizer = torch.optim.SGD(module.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加Tensorboard
writer = SummaryWriter("../log")

# 10轮训练
for i in range(epoch):
    print("----------第{}轮训练开始----------".format(i+1))
    # 训练步骤开始
    module.train()
    for data in train_dataloader:
        imgs,targets = data
        outputs = module(imgs)
        loss = loss_func(outputs,targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step = total_train_step + 1
        # 如果训练次数能被100整除,就打印loss并且绘制x-y图像
        if total_train_step % 100 == 0:
            # item()函数用于从只包含单个元素的张量中提取Python数值,将张量转换为标量值
            print("训练次数:{},Loss:{}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss.item(),total_train_step)

    # 测试步骤开始
    module.eval()
    total_test_loss = 0
    total_accuracy = 0
    # 评估模型时,不需要进行反向传播
    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets = data
            outputs = module(imgs)
            loss = loss_func(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print("整体测试集上的Loss:{}".format(total_test_loss))
    print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss",total_test_loss,total_test_step)
    writer.add_scalar("test_accuracy",total_accuracy/test_data_size,total_test_step)
    total_test_step = total_test_step + 1

    torch.save(module,"torch_{}.pth".format(i))
    print("模型已保存")
writer.close()

4.11 利用GPU进行训练

4.11.1 xx = xx.cuda()

if torch.cuda.is_available():
    # 网络模型使用GPU
    module = module.cuda()


if torch.cuda.is_available():
    # 损失函数使用GPU
    loss_func = loss_func.cuda()


# 训练数据使用GPU
    if torch.cuda.is_available():
        imgs = imgs.cuda()
        targets = targets.cuda()


# 测试数据使用GPU
   if torch.cuda.is_available():
       imgs = imgs.cuda()
       targets = targets.cuda()

4.11.2 xx = xx.to(device)

# 定义训练的设备
# device = torch.device("cuda:0")
# device = torch.device("cuda:1")
device = torch.device("cuda")

# 网络模型使用GPU
module = module.to(device)

# 损失函数使用GPU
loss_func = loss_func.to(device)

# 训练数据使用GPU
imgs = imgs.to(device)
targets = targets.to(device)

# 测试数据使用GPU
imgs = imgs.to(device)
targets = targets.to(device)

4.12 完整的模型验证套路

import torchvision
from PIL import Image
import torch

img_path = "./dog.jpg"
img = Image.open(img_path)
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1082x810 at 0x26AC11FA850>
print(img)
# 将img转换为RGB的形式
img = img.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                            torchvision.transforms.ToTensor()])
img = transform(img)
# torch.Size([3, 32, 32])
print(img.shape)

# 加载模型结构和参数
model = torch.load("./torch_0.pth")
# 增加一个batchsize的维度
img = torch.reshape(img, (1, 3, 32, 32))
# 验证开始
model.eval()
# 不进行反向传播,计算梯度
with torch.no_grad():
    # img使用GPU
    img = img.to("cuda")
    output = model(img)
# tensor([[-1.7493,  0.0590,  0.3859,  0.9509,  0.7353,  0.9401,  1.3249,  0.9609,
#          -2.0142, -0.2805]], device='cuda:0')
print(output)
# tensor([6], device='cuda:0')
print(output.argmax(1))
# 使用gpu训练保存的模型在cpu上使用
model = torch.load("XXXX.pth",map_location= torch.device("cpu"))

4.13 看看开源项目

python XXX.py --参数名 值

https://github.com/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据场景练习

1 行列转换 (1) 列拆分为多行 把指定字段按指定分隔符进行拆分为多行,然后其它字段直接复制. select字段列,hobby2 from tbl -- lateral view udtf(expression) tablealias as columnalias (‘,’ columnalias) lateral view explode(split(hobby,;)) temp as hobby2 (2) 行扁…

uniapp小程序,使用腾讯地图获取定位

本篇文章分享一下在实际开发小程序时遇到的需要获取用户当前位置的问题&#xff0c;在小程序开发过程中经常使用到获取定位功能。uniapp官方也提供了相应的API供我们使用。 官网地址&#xff1a;uni.getLocation(OBJECT)) 官网获取位置的详细介绍这里就不再讲述了&#xff0c;大…

区块链的可伸缩性以及面临的挑战

1. 可伸缩性 在过去的几年中&#xff0c;可伸缩性&#xff08;Scalability,也称为可扩展性) 问题一直是激烈辩论、严格研究和媒体关注的焦点。 这是一个至关重要的问题&#xff0c;因为它可能意味着区块链不适于广泛应用&#xff0c;而仅限于联盟许可的私有网络。在经过对该领域…

C++设计模式——Mediator中介者模式

一&#xff0c;中介者模式的定义 中介者模式是一种行为型设计模式。它通过一个中介者对象将多个对象之间的交互关系进行封装&#xff0c;使得对象之间的交互需要通过中介者对象来完成。该设计模式的结构很容易理解&#xff0c;以中介者为中心。 中介者模式的设计思想侧重于在…

遗传算法与深度学习实战(12)——粒子群优化详解与实现

遗传算法与深度学习实战&#xff08;12&#xff09;——粒子群优化详解与实现 0. 前言1. 粒子群优化1.1 粒子群优化原理1.2 算法流程 2. 实现 PSO 解决方程2.1 问题描述2.2 代码实现 小结系列链接 0. 前言 粒子群优化 (Particle Swarm Optimization, PSO) 是一种借鉴适者生存和…

医疗行业怎么节约和管理能源

医院建筑能耗平台 医院智能照明平台 医院能源综合管理平台 目前&#xff0c;能源短缺已成为一个全球性问题。在建筑业的发展中&#xff0c;建筑电气照明系统的节能水平与中国的能源利用率有关。照明系统中的低功率因数和高电压波动将导致较大的功率损失。因此&#xff0c;要认…

计算机网络——ARP篇(二)

上一次学习了ARP的基本概念&#xff0c;ARP缓存&#xff0c;ARP类型&#xff0c;以及ARP协议在网络中是如何工作的。这一次&#xff0c;我又深入的了解了ARP协议的工作原理&#xff0c;下面是我的学习笔记&#xff1a; 在学习之前&#xff0c;首先提出三个问题&#xff1a;ARP协…

BizDevOps落地实践

我理解BizDevOps就是端到端&#xff0c;从战略业务机会到开发上线 参考资料 十六年所思所感&#xff0c;聊聊这些年我所经历的 DevOps 系统 必致&#xff08;BizDevOps&#xff09;白皮书2022免费下载_在线阅读_藏经阁-阿里云开发者社区 具体落地实践 战略规划 战略&…

C#使用TCP-S7协议读写西门子PLC(一)

之前本人发布西门子S7协议的报文 西门子PLC的S7协议报文解析说明_西门子报文详解-CSDN博客 西门子PLC的S7协议是西门子公司在ModbusTcp协议的基础上自定义的一种协议,仅支持西门子PLC,S7协议本质仍然属于TCP协议的一种自定义具体实现 第一步,准备工作。VS2022中新建窗体应…

动态规划及其MATLAB实现

目录 引言 动态规划的基本原理 动态规划的常见应用 动态规划的求解步骤 动态规划的复杂度分析 表格总结&#xff1a;动态规划常见问题及其复杂度 结论 引言 动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种求解最优化问题的有效方法&#xff0c;特别适合…

华为 HCIP-Datacom H12-821 题库 (16)

1.需要题库的小伙伴至博客最下方添加微信公众号关注后回复题库 2.有兴趣交流IT问题的小伙伴微信公众号回复交流群&#xff0c;加入微信IT交流群 1. OSPF 邻居关系建立出现故障&#xff0c;通过 display ospf error 命令来检查&#xff0c;输出结果如图所示&#xff0c;根据图中…

从零开始配置 TypeScript 项目

ESLint 配置 从背景的介绍中可以理解&#xff0c;对于全新的 TypeScript 项目&#xff08;直接抛弃 TSLint&#xff09;需要包含解析 AST 的解析器 typescript-eslint/parser 和使用校验规则的插件 typescript-eslint/eslint-plugin&#xff0c;这里需要在项目中进行安装&…

CentOS 安装Squid代理

环境&#xff1a; 华为云服务器一台&#xff1a;123.60.53.69&#xff0c;放行3128端口 Windows 11 电脑&#xff1a;动态IP 需求&#xff1a; 客户端电脑通过华为云服务器实现代理上网 一、服务器设置 1、安装 yum install squid httpd-tools -y 2、创建用户&#x…

word文档转换为PPT文档最佳方案

目前&#xff0c;笔者发现word文档转换为ppt最好的解决方案。 注&#xff1a;目前AI生成PPT&#xff0c;一般是给定一个标题&#xff0c;直接生成PPT文档内容&#xff0c;属于AI原创&#xff1b;另外&#xff0c;还有一些在线编辑、生成PPT工具&#xff0c;需要付费&#xff0c…

MySQL数据库SQL语句和常用函数大全

前言 MySQL 8数据库提供了丰富的SQL语句操作功能以及一系列高级特性&#xff0c;这些功能使得数据库的管理、查询、更新和维护变得更加高效和灵活。以下是对MySQL 8数据库SQL语句操作大全及高级特性的详细概述&#xff1a; 一、SQL语句操作大全 1. 数据定义语言&#xff08…

【雅特力AT32】 MCU CAN入门指南(超详细)

通信协议与接口知识参考文章&#xff1a; 【通信理论知识】数据传送的方式&#xff1a;串/并行&#xff1b;传输方向&#xff1a;单工、半/全双工&#xff1b;传输方式&#xff1a;同步/异步 【串口通信详解】USART/UART、RS232、RS485标准接口与协议特点解析 【同步串行通信接…

重拾精髓:go doc -http让离线包文档浏览更便捷

Go语言团队近期接受了Go团队成员、Go圣经《The Go Programming Language[1]》合著者Alan Donovan[2]的新提案[3]&#xff0c;旨在进一步提升开发者体验。这个提案为go doc命令[4]的离线文档展示形式&#xff0c;同时增强了查看本地文档的交叉引用功能。看到这个提案功能&#x…

重装电脑系统时硬盘被重新分区:数据恢复实战指南与深度解析

在数字化时代的浪潮中&#xff0c;电脑作为我们日常生活和工作的核心工具&#xff0c;其系统的稳定性与数据的完整性至关重要。然而&#xff0c;在追求系统性能优化或解决系统故障的过程中&#xff0c;重装电脑系统成为了一个常见的操作。不幸的是&#xff0c;这一过程中若不慎…

PB9一个运行时错误:Non-array expected in ANY Variable

反编译修改一个项目。遇到这个问题。 仿佛一看&#xff0c;这是一个莫名其妙的问题&#xff0c;在百度也只搜到一个类似问题。 但是定睛一看&#xff0c;是一个很奇怪的错误&#xff0c;就是说代码自己写错了 for i 1 to uo_1.is_arr ls_arrstr uo_1.is_arr[i] ... next …

掌握 JavaScript ES6+:现代编程技巧与模块化实践

掌握 JavaScript ES6&#xff1a;现代编程技巧与模块化实践 一 . 变量声明 let二 . 声明常量 const三 . 模板字符串四 . 函数的参数默认值五 . 箭头函数六 . 对象初始化七 . 解构7.1 接收 JSON 对象7.2 接收数组 八 . 延展操作符九 . 导入和导出9.1 方式一9.2 方式二 这篇文章我…