pytorch

1.安装anaconda

1.1.anaconda介绍

anaconda是一个开源的python发行版本,包含了conda,python等100多个科学包及其依赖项。简而言之就是一个包管理软件,和maven与springboot的作用类似,以前安装一个包不仅散且版本管理困难,现在通过anaconda就可以有效地管理这些包。

1.2.anaconda安装

官网安装即可
https://www.anaconda.com/products/distribution#Downloads

1.3.anaconda环境配置

同一个电脑不能同时安装不同版本的pytorch,但是不同的工程需要不同版本的pytorch,这时候就需要隔离不同的区域,为不同的工程提供不同的选择。
这点类似docker。anaconda简单地使用环境这一概念来定义不同的区域。不同环境可以安装不同版本,不同种类的包,互不影响,再一次体现了去耦合这一编程思想。

开始栏找到anaconda prompt,右键管理员身份运行
在这里插入图片描述
可以看到,已经有一个默认的base环境。

创建环境learn,-n指名字
在这里插入图片描述

使用conda activate learn激活环境
在这里插入图片描述
pip list查看环境中有哪些工具包
在这里插入图片描述
可以看到没有安装pytorch
安装pytorch
https://pytorch.org/
在这里插入图片描述
显卡需要是英伟达显卡,查看自己显卡支持的cudanvidia-smi
在这里插入图片描述
再次pip list可以看到已经安装好了包括pytorch在内的工具包
验证pytorch是否可以导入,验证是否可以使用cuda(gpu)

然后需要安装jupyter notebook
base环境默认是安装jupyter notebook的,我们需要在learn环境中安装jupyter notebook,需要使用以下命令:conda install nb_conda,如果报错或者卡住,更改命令:conda install ipykernel,参考这篇文章:
https://blog.csdn.net/qq_45138078/article/details/129274834

安装jupyter的时候如果遇到报错ImportError: cannot import name ‘secure_write‘参考这篇博客
https://blog.csdn.net/weixin_44086998/article/details/127188511
https://blog.csdn.net/qq_40296501/article/details/127776366

jupyter的快捷键
在这里插入图片描述

2.上手工程

工程目录结构:
在这里插入图片描述

# read_data.py
from torch.utils.data import Dataset
from PIL import Image
import os


class MyData(Dataset):

    def __init__(self, root_dir, label_dir):
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.path = os.path.join(root_dir, label_dir)
        # 根据路径获取全部的图片名列表
        self.img_path = os.listdir(self.path)

    def __getitem__(self, item):
        # 获取文件名
        img_name = self.img_path[item]
        # 获取文件路径
        img_item_path = os.path.join(self.path,img_name)
        # 根据文件路径获取图片
        img = Image.open(img_item_path)
        # 返回图片和标签
        return img, self.label_dir

root_dir = "dataset/train"
label_dir1 = "ants"
label_dir2 = "bees"
# 根据根目录和标签目录获得两个数据集
ants_dataset = MyData(root_dir,label_dir1)
bees_dataset = MyData(root_dir,label_dir2)
# 根据重写的魔法方法就可以将数据集像列表一样得到想到的图片和标签
img,label = ants_dataset[0]
img.show()

注意导入的模块是Dateset而不是dataset

3.TensorBoard和Transforms

遇到一个严重的问题,pip安装后的包在pycharm解释器里找不到:
参考这篇博客:
https://blog.csdn.net/weixin_43920383/article/details/125204970

下面利用SummaryWriter和tensorboard来显示图片
在这里插入图片描述

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

# 创建writer
writer = SummaryWriter("logs")
# 获取图片
img_path = "dataset/train/ants/7759525_1363d24e88.jpg"
imgPIL = Image.open(img_path)
# 图片转array
img_array = np.array(imgPIL)
# 写图片
writer.add_image("ants",img_array,1,dataformats='HWC')
# 关闭writer
writer.close()

使用tensorboard --logdir=dirname即可使用tb可视化writer写的东西
在这里插入图片描述
进入本地的6006端口即可看到,注意要想保留步骤需要依次增加step
在这里插入图片描述
下面介绍transform的使用

  • transform可以将图片转化为tensor
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

writer = SummaryWriter("logs")

# transforms.ToTensor()
# 获取图片路径
img_path = "dataset/train/ants/116570827_e9c126745d.jpg"
# 获取图片
img = Image.open(img_path)
# 1. ToTensor()
# 创建ToTensor()对象
trans_to = transforms.ToTensor()
# 将图片转化为tensor
img_tensor = trans_to(img)

# 通过writer写
writer.add_image("ToTensor",img_tensor)
# 关闭writer
writer.close()

  • transform可以将图片进行归一化处理
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

writer = SummaryWriter("logs")

# transforms.ToTensor()
# 获取图片路径
img_path = "dataset/train/ants/116570827_e9c126745d.jpg"
# 获取图片
img = Image.open(img_path)
# 1. ToTensor()
# 创建ToTensor()对象
trans_to = transforms.ToTensor()
# # 将图片转化为tensor
img_tensor = trans_to(img)

# 2. Normalize()
# 创建Normalize()对象
trans_normal = transforms.Normalize([1,1,1],[2,2,2])
img_normal = trans_normal(img_tensor)

# 通过writer写
writer.add_image("Totensor",img_tensor)
writer.add_image("Normalize",img_normal)
# 关闭writer
writer.close()
  • transform可以将图片进行Resize处理
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

writer = SummaryWriter("logs")

# transforms.ToTensor()
# 获取图片路径
img_path = "dataset/train/ants/116570827_e9c126745d.jpg"
# 获取图片
img = Image.open(img_path)
# 1. ToTensor()
# 创建ToTensor()对象
trans_to = transforms.ToTensor()
# # 将图片转化为tensor
img_tensor = trans_to(img)

# 2. Normalize()
# 创建Normalize()对象
trans_normal = transforms.Normalize([1,1,1],[2,2,2])
img_normal = trans_normal(img_tensor)

# 3. Resize()
# 创建Resize()对象
trans_resize = transforms.Resize(512)
# 组合两个操作,PIL -> PIL -> Tensor
trans_compose = transforms.Compose([trans_resize,trans_to])
# 转化为尺寸变化的tensor,resize的输入和输入都是PIL图片格式
img_resize = trans_compose(img)

# 通过writer写
writer.add_image("Totensor",img_tensor)
writer.add_image("Normalize",img_normal)
writer.add_image("Resize",img_resize)
# 关闭writer
writer.close()
  • datasets数据集与transform一起进行batch processing
from torchvision import datasets
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

# 构造compose器
trans_compose = transforms.Compose([
    transforms.ToTensor()
])

# 获取writer
writer = SummaryWriter("logs")

# 获取数据集
train_set = datasets.CIFAR10(root="dataset02", train=True, transform=trans_compose, download=True)
test_set = datasets.CIFAR10(root="dataset02", train=False, transform=trans_compose, download=True)

print(train_set[0])

# 写入图片列表
for i in range(10):
    img, target = train_set[i]
    writer.add_image("train_set", img, i)

# writer关闭
writer.close()

4.dataloader

dataloader就是一个分批次读取数据的工具,下面是一个一次提取16张图片的例子

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

# 1.datasets获取数据集
train_set = datasets.CIFAR10("./dataset03", train=True, transform=torchvision.transforms.ToTensor(), download=True)
# 2.dataloader分批处理数据
train_loader = DataLoader(train_set, 16, shuffle=True, drop_last=False)
# 3.创建writer
writer = SummaryWriter("dataloader")
# 4.分批写
step = 0
for item in train_loader:
    # 注意已经是一次取样了,直接赋值
    imgs, label = item
    writer.add_images("train_images", imgs, step)
    step = step + 1
# 5.关闭writer
writer.close()

5.nn.Module

torch.nn是一个构建神经网络骨架的包,其中有很多模块,最常用的是module模块,通过继承module模块,重写其方法,可以非常简单的实现神经网络的基本功能,下面是一个实现tensor值加1的神经网络的例子

import torch
import torch.nn as nn
import torch.nn.functional as F


class MyNetwork(nn.Module):

    def __init__(self) -> None:
    # 调用父类的初始方法
        super().__init__()
	
	# 重写向前传播方法
    def forward(self, input):
        output = input + 1
        return output

# 创建神经网络对象
myNetwork = MyNetwork()
# 输入tensor
x = torch.Tensor([1.0])
# 输出结果tensor
print(myNetwork(x))

通过Conv2d创建简单卷积示例(因为没有激活层,所以连单层卷积都算不上)

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

# 引入数据集
dataset = torchvision.datasets.CIFAR10("./dataset04", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
# 分批加载数据
dataloader = DataLoader(dataset, batch_size=64)

# 创建神经网络类
class MyNet(torch.nn.Module):
    def __init__(self):
        # 继承父类的初始方法
        super(MyNet, self).__init__()
        # 利用Conv2d写自己的卷积
        self.conv1 = Conv2d(3, 6, 3, 1)

    def forward(self, x):
        # 前向传播
        return self.conv1(x)


# 创建神经网络
myNet = MyNet()

#  分批处理数据集
step = 0
for data in dataloader:
    img, label = data
    output = myNet(img)
    print(img.shape)
    # (n,c,h,w)
    # --n 每批图片的数量
    # --c 每张图片的通道数
    # --h 图片的像素高
    # --w 图片的像素宽
    # n不变,输出通道是6,宽高根据公式计算
    print(output.shape)

输出是

torch.Size([64, 3, 32, 32])
torch.Size([64, 6, 30, 30])
。。。

MaxPool2d,池化层,一般都是2d

import torch
from torch.nn import MaxPool2d

input_tensor = torch.tensor([[1, 2, 3, 4, 5],
                             [2, 3, 4, 5, 6],
                             [2, 4, 4, 6, 7],
                             [3, 5, 6, 7, -2],
                             [6, 8, 2, 4, 1]], dtype=torch.float32)
# 注意MaxPool2d的输入shape为(n,c,h,w)
input_tensor = torch.reshape(input_tensor, [-1, 1, 5, 5])

class MyNet(torch.nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        # 根据MaxPool2d写自己的最大池化层
        self.maxpool1 = MaxPool2d(kernel_size=3, stride=2,
                                  ceil_mode=False)

    def forward(self, x):
        return self.maxpool1(x)


myNet = MyNet()
print(myNet(input_tensor))


# 输出如下
# tensor([[[[4., 7.],[8., 7.]]]])

非线性激活
下面是一个relu激活的例子

import torch
import torch.nn as nn
from torch.nn import ReLU

# 创建tensor
input = torch.tensor([[-1, -2], [3, 5]])


# 创建神经网络类
class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        # 根据Relu模块定义自己的激活层
        self.relu = ReLU()

    def forward(self, x):
        return self.relu(x)


# 创建神经网络对象
myNet = MyNet()
# 查看输出
print(myNet(input))

# 输出如下
# tensor([[0, 0],
#       [3, 5]])

6.综合例子

下面是一个完整的综合例子

import torch
import torchvision.datasets

# 引入数据集
from torch.nn import Module, Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

train_set = torchvision.datasets.CIFAR10("./dataset06/train_set", train=True,
                                         transform=torchvision.transforms.ToTensor(), download=True)
test_set = torchvision.datasets.CIFAR10("./dataset06/test_set", train=False,
                                        transform=torchvision.transforms.ToTensor(), download=True)
# 查看数据集属性
print("训练集的大小是:{}".format(len(train_set)))
print("测试集的大小是:{}".format(len(test_set)))
# 加载数据
train_loader = DataLoader(train_set, 64)
test_loader = DataLoader(test_set, 64)


# 创建神经网络类
class MyNet(Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, 1, 2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, 1, 2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, 1, 2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        return self.model1(x)


# 创建神经网络对象
myNet = MyNet()

# 创建损失函数
loss_fn = torch.nn.CrossEntropyLoss()
# 设置训练速度
learning_rate = 1e-2
# 创建优化器
opt = torch.optim.SGD(myNet.parameters(), lr=learning_rate)

# 设置参数
epoch = 10
# 训练步数
train_step = 0

# 创建writer
writer = SummaryWriter("full_train_02")
for i in range(epoch):
    print("------------- 第 {} 轮测试开始 -------------".format(i + 1))
    # 开始训练
    myNet.train()
    for data in train_loader:
        # 每加载一组数据算一次
        train_step = train_step + 1
        # 赋值图片,目标值
        imgs, targets = data
        # 计算输出
        output = myNet(imgs)
        # 计算损失
        loss = loss_fn(output, targets)
        # 梯度清零
        opt.zero_grad()
        # 计算梯度
        loss.backward()
        # 反向传播
        opt.step()
        # 输出损失(每一百步)
        if train_step % 100 == 0:
            # 打印损失
            print("------------- 第 {} 次的训练损失是:{} -------------".format(train_step, loss.item()))
            # 写board上
            writer.add_scalar("training", loss.item(), train_step)

    # 开始测试
    myNet.eval()
    # 精确度
    total_accuracy = 0
    # 训练损失
    test_loss = 0
    # 训练不需要梯度,这步是优化
    accuracy = 0
    with torch.no_grad():
        for data in test_loader:
            # 赋值图片,目标值
            imgs, targets = data
            # 计算输出
            output = myNet(imgs)
            # 计算损失
            loss = loss_fn(output, targets)
            # 累计损失
            test_loss = test_loss + loss
            # 累计正确数
            accuracy = accuracy + (output.argmax(1) == targets).sum().item()
            # 计算精确度

    total_accuracy = accuracy / len(test_set)
    # 输出该轮的测试数据
    print("------------- 第 {} 轮测试的损失是:{} -------------".format(i + 1, test_loss))
    print("------------- 第 {} 轮测试的精确度是:{} -------------".format(i + 1, total_accuracy))
    # 写board上
    writer.add_scalar("testing_loss", test_loss, i + 1)
    writer.add_scalar("testing_accuracy", total_accuracy, i + 1)

    # 保留模型
	torch.save(myNet, "./models/myNet_{}.pth".format(i + 1))
    print("第 {} 轮模型已经保存".format(i + 1))
    
# 关闭writer
writer.close()

验证模型

import torch
import torchvision.transforms
from PIL import Image
from torch.nn import Conv2d, MaxPool2d, Module, Linear, Flatten, Sequential

imag_path = "./dd.jpg"
image = Image.open(imag_path)

transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)), torchvision.transforms.ToTensor()])


class MyNet(Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, 1, 2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, 1, 2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, 1, 2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        return self.model1(x)


image = transform(image)
model = torch.load("./myNet_20")
image = torch.reshape(image, (1, 3, 32, 32))
image = image.cuda()
print(image.shape)
model.eval()
with torch.no_grad():
    output = model(image)
print(output.argmax(1))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值