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环境。
- 添加镜像,参考以下两篇文章即可
https://blog.csdn.net/Calistar/article/details/127866608
https://www.jianshu.com/p/e39cb192bde0 - 如果遇到如下报错
CondaSSLError: OpenSSL appears to be unavailable on this machine. OpenSSL is required to downl
,参考这篇文章
https://blog.csdn.net/m0_64007201/article/details/127394125 - anaconda常用操作
https://blog.csdn.net/weixin_44527630/article/details/127023892 - 各种问题总结
https://www.jianshu.com/p/4c7b9127cf83 - 遇到
Solving environment: failed with initial frozen solve. Retrying with flexible solve
之类的问题一般是python版本和pytorch版本过高导致的,降版本就行
https://blog.csdn.net/m0_57143158/article/details/128905007
官网的各种版本
https://pytorch.org/get-started/previous-versions/
中科大镜像永远的的神好吧
https://www.bilibili.com/read/cv18262500/
创建环境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))