赞
踩
PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】
视频作者:我是土堆
进入命令行
win+r
,在弹出的窗口中输入cmd
,即可进入命令行
在命令行下为anaconda创建新环境
conda create -n 环境名 python=版本号 # 如果没有创建成功,有可能是网络的问题,关了VPN再试试
例:conda create -n pytorch python=3.6
,即在anaconda中创建了python为3.6的pytorch环境。
在命令行下查看anaconda有哪些环境
conda info --envs
在命令行下进入anaconda的某个环境
conda activate 环境名 # 如果提示“IMPORTANT: You may need to close and restart your shell after running 'conda init'”,就在命令行中执行conda init,重开命令行再执行conda activate 环境名,即可进入anaconda的某个环境。
例:conda avtivate pytroch
,即在命令行中切换到pytorch的环境。
在命令行下查看环境中有哪些包
pip list
pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple # pip install 包名 -i 国内pip源 #常见国内pip源有: #清华:https://pypi.tuna.tsinghua.edu.cn/simple #阿里云:http://mirrors.aliyun.com/pypi/simple/ #中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ #华中理工大学:http://pypi.hustunique.com/ #山东理工大学:http://pypi.sdutlinux.org/ #豆瓣:http://pypi.douban.com/simple/
进入pycharm,在file-settings-project:项目名-Python Interpreter中添加pytorch环境
进入pycharm的Python Console中,输入import torch
,验证pytorch是否安装成功。
Python Console中可以单命令行执行,
jupyter notebook可以实时交互
要改变jupyter的启动位置有两种方式,一种是进入命令行,在命令行中切换到启动位置路径,再输入
jupyter notebook
,即可启动;另一种是修改jupyter notebook配置文件中的默认启动地址,推荐前一种,用起来比较方便,不用频繁修改配置文件。
可以在 jupyter notebook 或者 pycharm的 python console中运行下面的命令,查看安装包的具体情况。
dir():打开,看见包的情况
如果dir打开的是某个函数,不能加()。
比如:这个是对的:dir(torch.cuda.is_available),但是dir(torch.cuda.is_avaliable())是错误的。
help():查看某个函数的说明
如果help打开的是某个函数,不能加()。
比如:这个是对的:dir(torch.cuda.is_available),但是dir(torch.cuda.is_avaliable())是错误的。
Python文件:代码是以所有行为一个块运行 优点:适合大型项目,缺点:需要从头运行。
Python console:代码是以每一行为块运行 优点:显示每个变量的属性,缺点:不利于代码阅读和修改。
Jupyter notebook:代码是以任意行为块运行 有点:有利于代码的阅读和修改,缺点:环境需要配置。
读取单张图片操作
# 1.获取img的地址
img_path = "../数据集/练手数据集/train/ants_image/0013035.jpg"
# 2.读取Image
img = Image.open(img_path)
读取一个文件夹的所有图片
# 1.获取文件夹路径
dir_path = "../数据集/练手数据集/train/ants_image"
# 2.获取文件夹下所有图片的名称,os.listdir()返回一个列表,该列表由文件夹下所有图片的名称组成
img_path_list = os.listdir(dir_path)
print(type(img_path_list))
# 3.获取每一张图片的相对路径
img_path_list2 = []
for img_path in img_path_list:
img_path_list2.append(os.path.join(dir_path, img_path))
for img_path in img_path_list2:
img = Image.open(img_path)
print(img.show())
使用Dataset读取数据集中的数据
class MyData(Dataset): def __init__(self, root_dir, label_dir): # 主要为后面的方法提供一些类变量,供该类的所有函数使用 self.root_dir = root_dir # 获取当前神经网络训练集的根目录 self.label_dir = label_dir # 我理解为训练集中的数据根据它的label分类保存到各自子文件夹中 self.path = os.path.join(self.root_dir, self.label_dir) # 将上述的路径进行拼接 self.img_path = os.listdir(self.path) # 获得当前神经网络所有图片的名称,返回由这些名称组成的列表 def __getitem__(self, idx): # 读取其中的图片 img_name = self.img_path[idx] # 获取列表中第idx张图片的名称 img_item_path = os.path.join(self.path, img_name) # 将名称和其上级目录进行一个拼接 img = Image.open(img_item_path) # 读取图像 label = self.label_dir return img, label def __len__(self): return len(self.img_path) root_path = "../数据集/练手数据集/train" ants_dir_path = "ants_image" bees_dir_path = "bees_image" ants_dataset = MyData(root_path, ants_dir_path) # 调用了MyData类的init函数,返回了ants_dataset对象 bees_dataset = MyData(root_path, bees_dir_path) # 调用了MyData类的init函数,返回了ants_dataset对象 train_dataset = ants_dataset + bees_dataset # 将两个MyData类对象相加,train_dataset对象包含了两个对象的所有数据 img, label = ants_dataset[0] # 调用了MyData类的getitem函数,返回了img及其label img.show()
用anaconda或者pycharm的 terminal 命令行,在其中输入 tensorboard --logdir='目录位置'
例:tensorboard --logdir=logs
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("logs") # 将事件文件存储在logs当中
# writer.add_image() # 添加图片
for i in range(100):
# 添加数至tensorboard中,参数如下所示:tag表明图表的名称,scale_value对应图的y轴,global step对应图的x轴
writer.add_scalar("y=x", i, i) # y轴是i,x轴也是i,对应y=x这条曲线
writer.close()
from torch.utils.tensorboard import SummaryWriter # 第一步:加载图片 from PIL import Image image_path = "../数据集/练手数据集/train/ants_image/0013035.jpg" img_PIL = Image.open(image_path) # img的类型是PIL.JpegImagePlugin.JpegImageFile import numpy as np img_array = np.array(img_PIL) # 将PIL类型的图片转换为numpy.ndarray类型 print(type(img_array)) writer = SummaryWriter("logs") # 添加数至tensorboard中,参数如下所示: # tag表明图表集的名称, # img_tensor可以是torch.Tensor,numpy.array,或者string/blobname类型, # global step对应图表集中具体哪一张图片 # 注:并不是任何numpy类型的数据都可以输入,默认是[3,H,W],可以通过修改dataformats参数接收``CHW``, ``HWC``, ``HW``.这几个类型 writer.add_image(tag="test", img_tensor=img_array, global_step=1, dataformats='HWC') # 创建test图表集,并将img_array放在图表集下标为1的位置 writer.close() # 一定要写着一句,不然tensorboard中即使刷新网页也不会加载图片
alt + enter
:快捷查看当前划红线部分的补救办法
ctrl + p
:快捷查看当前函数所需参数及其类型
取消大小写匹配:settings - keymap - 搜索框输入case
- Code Completion - 取消Match case前面的框框
from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transforms # python的用法 -》 tensor的数据类型 # 通过transform.ToTensor去解决两个问题 # 1. transform该如何使用(python) # 2. 为什么我们需要Tensor数据类型 img_path = "../数据集/练手数据集/train/ants_image/0013035.jpg" img = Image.open(img_path) # img是PIL数据类型 writer = SummaryWriter("logs") # 1.transforms该如何使用(python):将IMG类型转换为Tensor类型 # 第一步:创建ToTensor对象 tensor_trans = transforms.ToTensor() # tensor是返回的ToTensor对象,调用了ToTensor()的init方法,用于后续将PIL类型的图像转化为totensor类的图像 # 第二步:将图片传入ToTensor对象中,返回了Tensor数据类型的图片 tensor_img = tensor_trans(img) # img由PIL类型转换为totensor类型,调用了ToTensor()的call方法 print(tensor_img) # 2. 为什么我们需要Tensor数据类型:因为Tensorboard记录图片时要求这个类型 writer.add_image(tag="tensor_img", img_tensor=tensor_img) writer.close()
from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transforms writer = SummaryWriter("logs") img = Image.open("../数据集/练手数据集/train/ants_image/0013035.jpg") # 读取图片,img是PIL格式 print(img) # totensor的使用 trans_totensor = transforms.ToTensor() # 创建一个ToTensor类型对象 img_tensor = trans_totensor(img) # 将图片转换为torch.Tensor格式 writer.add_image(tag="ToTensor", img_tensor=img_tensor) # 将图片写到tensorboard中 # Normalize的使用 trans_norm = transforms.Normalize([1, 3, 5], [3, 2, 1]) # 创建一个Normalize类型对象,根据图片的channel输入相应长度的均值和方差列表 img_norm = trans_norm(img_tensor) # 输入的图片必须已经转换为tensor类型,将图片归一化 writer.add_image("Normalize", img_norm, 1) # Resize的使用 print(img.size) trans_resize = transforms.Resize((512, 512)) # 创建一个Resize类型的对象,图片裁剪为(512,512) img_resize = trans_resize(img) # 输入的图片必须是PIL类型,得到的img_resize仍然是PIL类型 img_resize = trans_totensor(img_resize) # 再将数据转换成torch.Tensor类型 writer.add_image("Resize", img_resize, 0) print(img_resize) # Compose的使用(将transforms的多个操作合并在一起写) trains_resize_2 = transforms.Resize(512) # 创建一个Resize类型的对象,图片缩放至(512),长宽比不变 # PIL -> PIL -> torch.tensor trans_compose = transforms.Compose([trains_resize_2, trans_totensor]) # 创建一个Compose类型,提供transforms对象数组作为参数,注意它是按照数组中元素的顺序依次对图片执行操作,所以后一个数组元素所需要的输入和前一个数组元素的输出要匹配 img_resize_2 = trans_compose(img) writer.add_image("Resize", img_resize_2, 1) # RandomCrop trans_random = transforms.RandomCrop((500, 700)) # 创建一个RandomCrop类型对象,随机裁剪出(500,700)的图像,裁剪后返回的图片仍然是PIL类型 trans_compose_2 = transforms.Compose([trans_random, trans_totensor]) for i in range(10): img_crop = trans_compose_2(img) writer.add_image("RandomCrop", img_crop, i) writer.close()
torchvision中的数据集查找路径 python.org - Docs - torchvision - datasets
Torchvision中的Datasets (pytorch.org):包含大量数据集
常用数据集
COCO数据集:用于目标检测 、语义分割
MNIST数据集:手写文字数据集
CIFAR 10 数据集:物体识别
https://pytorch.org/vision/stable/models.html:包含预训练好的model
通过打断点的方式可以获取test_set的属性和方法
# 标准数据集 import torchvision from torch.utils.data import DataLoader dataset_transform = torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), ]) # 四个参数,root指定根目录,train指定是否为训练集,download设为true时会查看本地有无数据,无就从网上下载数据,有就什么事情都不做 train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True) test_set = torchvision.datasets.CIFAR10(root="./dataset", train=False, transform=dataset_transform, download=True) print(train_set[0]) # (<PIL.Image.Image image mode=RGB size=32x32 at 0x23172B19D00>, 6) # 可以看到train_set与之前我们自定义的Dataset类很像,通过下标获取元素跟我们调用getitem方法类似 img, target = test_set[0] print(img) print(img.show()) # 展示图片 print(target) print(test_set.classes[target]) # 通过classes属性获取具体的类别名称 print(test_set[0])
import torchvision # 准备的测试数据集 from torch.utils.data import DataLoader # 从数据集中加载数据 from torch.utils.tensorboard import SummaryWriter test_data = torchvision.datasets.CIFAR10(root='./dataset', train=False,transform=torchvision.transforms.ToTensor()) # DataLoader是PyTorch版本的dataset类,用于分批次从数据集中取数据 # 将数据加载到DataLoader中,dataset指定数据集,batch_size指定每次从数据集抽取的数据量,shuffle指定多个epoch中是否打乱数据读取顺序,num_workers指定加载数据的进程数,drop_last指定剩余的数据小于batch_size时是否还用于训练 test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=False, num_workers=0, drop_last=False) # 测试数据集中第一张图片及target img, target = test_data[0] print(img.shape) print(target) writer = SummaryWriter("dataloader") step = 0 for epoch in range(2): # 将shuffle设置成false,两轮循环的数据都是相同的,反之,如果设置为true,两轮循环的数据就是相同的 for data in test_loader: imgs, targets = data # print(imgs.shape) # print(targets) writer.add_images("Epoch: {}".format(epoch), imgs, step) step = step + 1 writer.close()
torch.nn官方文档:torch.nn
import torch import torch.nn as nn class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() def forward(self, input): output = input + 1 return output myModule = MyModule() # 调用了MyModule类的init方法,返回一个MyModule对象 x = torch.tensor(1.0) output = myModule(x) # 调用了MyModule类的forward方法,返回output print(output)
先看一下torch.nn.Conv2d()与torch.nn.functional.conv2d()的区别
torch.nn.Conv2d()的参数
#torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
#in_channels:输入图片的通道数
#out_channels:由卷积核数量决定
#kernel_size:卷积核函数的大小
#stride:步长。默认为1
#padding:填充。默认为0
#dilation:核函数元素之间的间隔。默认为1
#groups:对输入的通道进行分组卷积核操作
#bias:偏置,如果为True,向output中添加一个可学习的偏置参数。默认为True
torch.nn.functional.conv2d()的参数
#torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
#input:输入tensor的大小(mini_batch,in_channels,iH,iW)
#weight:权重大小(out_channels,in_channels/groups,kH,kW)
#bias:偏置,tensor数据类型 shape为(out_channels),默认为None
#stride:步长,
#padding:填充
不同点:
相同点:
conv2d的示例:
import torch import torch.nn as nn import torch.nn.functional as F 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]]) # 仿照图片格式创建一个二维矩阵 kernel = torch.tensor([[1, 2, 1], [0, 1, 0], [2, 1, 0] ]) # 创建卷积核函数 # torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) # input:输入tensor的大小(mini_batch,in_channels,iH,iW) # weight:权重大小(out_channels,in_channels/groups,kH,kW) # bias:偏置,tensor数据类型 shape为(out_channels),默认为None # stride:步长, # padding:填充 # input/kernel size = (batch_size,channel,height,width),一因为conv2d函数对参数有形状要求,所以要reshape input = torch.reshape(input, [1, 1, 5, 5]) kernel = torch.reshape(kernel, [1, 1, 3, 3]) print(input.shape) print(kernel.shape) output = F.conv2d(input, kernel, stride=1) # 对input按照卷积核kernel进行s=1,p=0的卷积操作 print(output) output2 = F.conv2d(input, kernel, stride=2) print(output2) output3 = F.conv2d(input, kernel, stride=2, padding=1) print(output3)
nn.MaxPool2d()的参数
#Parameters
# kernel_size:池化核函数的大小
# stride:步长,默认等于kernel_size
# dilation:控制核函数单元的间隔
# return_indices - if True , will return the max indices along with the outputs
# ceil_mode:True时采用cell型,即如果步长不一致,导致核函数与对应的原图部分大小不一致,仍然保留这一组的池化值,False时采用floor型,就不保留这一组池化值
注意:nn.MaxPool2d()的输入输出要求如下
m = nn.MaxPool2d(3,stride=2)
input = torch,randn(20,16,50,32)
output = m(input)
池化的作用:有点类似于马赛克,池化之后的图片会更加模糊,但是减少了数据量,降低了计算量。
nn.ReLU()的参数
# 参数:inplace。如果inplace是True,则为引用传递,会改变实参,若为False,则为值传递,不改实参。
# Input:任意维度
# Output:与Input相同的维度
nn.ReLU()示例:
m = nn.ReLU()
input = torch.randn(2)
output = m(input)
import torch import torchvision.datasets from torch import nn from torch.nn import ReLU, Sigmoid from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter input = torch.tensor([[1, -0.5], [-1, 3]]) input = torch.reshape(input, (-1, 1, 2, 2)) # -1表示batch_size自己算 print(input.shape) dataset = torchvision.datasets.CIFAR10('./dataset', train=False, download=True, transform=torchvision.transforms.ToTensor()) dataloader = DataLoader(dataset, batch_size=64) class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.relu1 = ReLU() # inplace可以理解为引用,如果是False,则是值传递,否则,是引用传递,会修改传入的变量 self.sigmoid1 = Sigmoid() def forward(self, input): output = self.sigmoid1(input) return output myModule = MyModule() # 调用MyModule类的init方法,创建MyModule对象 writer = SummaryWriter("logs_relu") step = 0 for data in dataloader: imgs, targets = data # 一次读取64张图片,imgs.shape = (64,3,32,32) writer.add_images("input", imgs, global_step=step) output = myModule(imgs) # output.shape = (64,3,32,32) ,对每一个数据做sigmoid操作,不改变input的维度 writer.add_images("output", output, step) step = step + 1 writer.close()
nn.Linear的参数
# in_features:输入的size
# out_features:输出的size
# bias:偏置,默认为True
# Input:(*,iH)
# Output:(*,oH)
# 仅对输入tensor的最后一层进行全连接计算,如下所示:
m = nn.Linear(20, 30)
input = torch.randn(128, 20)
output = m(input)
print(output.size()) # torch.Size([128, 30])
以CIFAR-10网络架构作为示例
检测网络模型是否正确:创建一个tensor对象,输入到模型中,看看能不能正常运行输出结果。(代码见下方代码块中)
如果经过卷积和池化之后不记得当前size,Linear层第一个参数如何填入:注释掉Linear层后面的参数,创建一个tensor对象,输入到模型中,查看输出结果的尺寸,即可求得当前size。
from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential import torch from torch.utils.tensorboard import SummaryWriter class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.model1 = Sequential( Conv2d(3, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 64, 5, padding=2), MaxPool2d(2), Flatten(), Linear(1024, 64), Linear(64, 10) ) def forward(self, x): x = self.model1(x) return x # 检验模型是否出错,创建一个MyModule对象,传入模型中,看看运行结果是否正确 myModule = MyModule() input = torch.ones((64, 3, 32, 32)) output = myModule(input) print(output.shape) # 使用tensorboard可视化神经网络架构 # writer.add_graph(myModule,input) 第一个参数是模型对象,第二个参数是模型的输入 writer = SummaryWriter("logs_seq") writer.add_graph(myModule, input) writer.close()
如图所示,以下是tensorboard中保存的myModule结构:
Pytorch官网lossfunction:torch.nn loss functions
nn.L1Loss:绝对值损失函数
参数
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
size_average:
reduce:
reduction:
输入与输出
Input: 任意维度
Target: 与Input相同维度
nn.MSELoss:平方差损失函数
参数
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
输入与输出
Input: 任意维度
Target: 与Input相同维度
nn.CrossEntropyLoss:交叉熵损失函数
参数:
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean', label_smoothing=0.0)
weight
size_average
ignore_index
reduce
reduction
label_smoothing
输入与输出
Input:(N,C) or (C) or (N,C,d1,2)
Output:(N) or () or (N,d1,d2,d3,...dk)
在nn中使用loss示例:
import torchvision from torch import nn from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear 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) class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.model1 = Sequential( Conv2d(3, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 64, 5, padding=2), MaxPool2d(2), Flatten(), Linear(1024, 64), Linear(64, 10) ) def forward(self, x): x = self.model1(x) return x loss = nn.CrossEntropyLoss() myModule = MyModule() for data in dataloader: imgs, targets = data # img.shape = (64,3,32,32), targets.shape = (1) outputs = myModule(imgs) # outputs.shape = (1,10) result_loss = loss(outputs, targets) result_loss.backward() # print(outputs) # print(targets) # print(result_loss)
优化器示例:
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.9)
for input, target in dataset:
optimizer.zero_grad() # 每一个batch梯度都要重置为0
output = model(input) # 前向传播,计算输出值
loss = loss_fn(output, target) # 损失函数计算
loss.backward() # 反向传播,计算梯度
optimizer.step(closure) # 模型参数优化
# 调用step()方法,会利用之前反向传播得到的梯度更新
完整示例:
import torch import torchvision from torch import nn from torch.nn import L1Loss, MSELoss, Sequential, Conv2d, MaxPool2d, Flatten, Linear from torch.utils.data import DataLoader dataset = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True) dataloader = DataLoader(dataset, batch_size=64) class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.model1 = Sequential( Conv2d(3, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 64, 5, padding=2), MaxPool2d(2), Flatten(), Linear(1024, 64), Linear(64, 10) ) def forward(self, x): x = self.model1(x) return x loss = nn.CrossEntropyLoss() myModule = MyModule() # 创建MyModule类对象 optim = torch.optim.SGD(myModule.parameters(), lr=0.01) # 创建随机梯度下降法优化器 for epoch in range(20): running_loss = 0.0 # 统计每一个epoch的损失情况 for data in dataloader: imgs, targets = data # imgs.shape = (64,3,32,32) targets.shape = (1,10) outputs = myModule(imgs) # 前向传播 outputs.shape = (1),符合loss的参数要求 result_loss = loss(outputs, targets) # 计算损失 reslut_loss.shape = () 它就是一个数 optim.zero_grad() # 将grads设为0,上一批数据的梯度对这一批数据没有影响 result_loss.backward() # 反向传播 optim.step() # 参数优化 running_loss = running_loss + result_loss print(running_loss)
常见神经网络模型Pytorch网址:Models and pre-trained weights
参数:
torchvision.models.vgg16(pretrained: bool = False, progress: bool = True, **kwargs: Any)
# pretrained:如果为True,则返回框架+模型参数,如果为False,仅返回框架
# progress:如果为True,显示下载进度条;否则不显示
import torchvision # root指定根目录,split指定数据集还是训练集,download指定是否下载该数据集,transform指定数据是否要修改数据类型 # train_data = torchvision.datasets.ImageNet(root="./data_image_net", split="train", download=True, # transform=torchvision.transforms.ToTensor()) # pretrained为false,没有得到预训练好的模型参数;progress为true,显示进度条, # 当pretrained为false的时候,它只是加载网络模型(相当于把写好了模型的代码),不会下载对应的数据集, # 当pretrained为true的时候,它需要下载预训练好的模型参数 from torch import nn vgg16_false = torchvision.models.vgg16(pretrained=False) vgg16_true = torchvision.models.vgg16(pretrained=True) print("ok") # print(vgg16_true) # 如何利用现有的网络进行迁移学习 train_data = torchvision.datasets.CIFAR10("./dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True) # 操作:vgg16在classifier后添加线性层 vgg16_true.add_module("add_linear", nn.Linear(1000, 10)) print(vgg16_true) # 操作:vgg在classiffier中添加线性层 vgg16_true.classifier.add_module("add_linear", nn.Linear(1000, 10)) print(vgg16_true) # 操作:修改vgg中classifier某一神经网络层的结构 vgg16_false.classifier[6] = nn.Linear(4096, 10) print(vgg16_false)
import torch import torchvision from torch import nn vgg16 = torchvision.models.vgg16(pretrained=False) # 保存方式1 # 保存了模型的结构 + 参数 torch.save(vgg16, "vgg16_method1.pth") # 保存方式2(官方推荐) # 将vgg16的状态保存成一种字典形式,保存了模型的参数 torch.save(vgg16.state_dict(), "vgg16_method2.pth") # 使用方式一保存和加载模型的陷阱 # class MyModel(nn.Module): # def __init__(self): # super(MyModel, self).__init__() # self.conv1 = nn.Conv2d(3, 64, kernel_size=3) # def forward(self, x): # x = self.conv1(x) # return x # myModule = MyModule() # torch.save(myModule, 'mymodel_method1.pth')
import torch import torchvision from torch import nn # 加载方式1 model = torch.load("vgg16_method1.pth") # print(model) # 加载方式2(因为只保存了模型的参数,所以要恢复模型的结构) vgg16 = torchvision.models.vgg16(pretrained=False) # 获取了网络模型的结构 vgg16.load_state_dict(torch.load("vgg16_method2.pth")) # 通过字典形式加载本地存储的网络模型的参数 # model = torch.load("vgg16_method2.pth") # print(model) # print(vgg16) model = torch.load('mymodel_method1.pth') print(model)
第一步:准备数据集
train_data = torchvision.datasets.CIFAR10(root='./dataset', train=True, transform=torchvision.transforms.ToTensor(),download=True) # root指定根目录,train指定数据是训练集还是数据集,transform是对原始数据进行一些形状调整,方便神经网络读入,download指定是否下载数据集
Pytorch已经内置了常用的数据集和神经网络模型,可以在官网上上找到。附上链接Datasets — Torchvision 0.12 documentation (pytorch.org)
第二步:使用DataLoader加载数据集
train_dataloader = DataLoader(train_data,batch_size=64,shuffle=True) # 将数据集装入DataLoader中,batch_size设置部分数据用于梯度下降,shuffle指定是否打乱数据集
第三步:搭建/加载神经网络
# 搭建神经网络(仿写搭建CIFAR-10网络结构) class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.model = nn.Sequential( #nn.Sequential()简化神经网络编写的过程 nn.Conv2d(3, 32, 5, 1, 2), # nn.Conv2d前五个参数(in_channel,out_channel,卷积核函数,stride,padding) nn.MaxPool2d(2), # 池化核函数2×2 nn.Conv2d(32, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, 1, 2), nn.MaxPool2d(2), nn.Flatten(), # 把神经网络拉直 nn.Linear(64 * 4 * 4, 64), nn.Linear(64, 10) ) def forward(self, x): x = self.model(x) return x # 加载模型 from 神经网络类所在文件名 import * # 加载模型
一般情况下,神经网络类中编写init和forward函数。
第四步:创建网络模型对象
myModule = MyModule()
第五步:创建损失函数
loss_fn = nn.CrossEntroyLoss()
第六步:创建优化器
config = {
"learning_rate": 1e-2,
"momentum": 0.9
}
optimizer = torch.optim.SGD(myModule.parameters(), lr=config["learning_rate"], momentum=config["momentum"])
第七步:设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加tensorboard
writer = SummaryWriter("logs_train") # tensorboard用于可视化神经网络结构和训练过程,这里的参数指定了tensorboard记录的目录,查看文本的方式是在pycharm的terminal中切换到当前.py文件的目录中,输入命令 tensorboard --logdir=logs_train 会弹出网址,网址中可以实现查看网络结构等操作。
第八步:开始训练
for i in range(epoch): print("------------------------第{}轮训练开始-----------------------".format(i + 1)) # 训练步骤开始 myModule.train() # 不设置也可以训练 for data in train_dataloader: # 读取train_dataloader中的data imgs, targets = data # 1.读取data中的imgs,targets outputs = myModule(imgs) # 2.前向传播 loss = loss_fn(outputs, targets) # 3. 损失函数计算 # 优化器优化模型 optimizer.zero_grad() # 4.重置梯度值 loss.backward() # 5.反向传播 optimizer.step() # 6.模型优化 total_train_step = total_train_step + 1 if total_train_step % 100 == 0: print("训练次数:{},Loss:{}".format(total_train_step, loss.item())) # 不加item是tensor类型,加了item是数据 writer.add_scalar("train_loss", loss.item(), total_train_step) # 这里用上了add_scalar(),第一个参数train_loss是可视化的图表的名称,第二个参数loss.item()指定了y轴,第三个参数指定了x轴。 # 测试步骤开始(使用tensorboard可以实时查看损失函数走势,使用argmax可以求出outputs中各行的最大值,再与targets比较,进而得出正确率) myModule.eval() # 不设置也可以测试 total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: # 读取test_dataloader中的data imgs, targets = data # 1.读取data中的imgs,targets outputs = myModule(imgs) # 2.前向传播 loss = loss_fn(outputs, targets) # 3,损失函数计算 total_test_loss = total_test_loss + loss # 统计损失值 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) # 这里用上了add_scalar(),第一个参数test_loss是可视化的图表的名称,第二个参数total_test_loss指定了y轴,第三个参数指定了x轴。 writer.add_scalar("test_accuracy", total_accuracy / test_data_size, total_test_step) # 这里用上了add_scalar(),第一个参数test_accuracy是可视化的图表的名称,第二个参数total_accuracy / test_data_size 指定了y轴,第三个参数指定了x轴。 total_test_step = total_test_step + 1 # 模型保存的方式一 torch.save(myModule, "mymodule_{}.pth".format(i)) # 模型保存的方式二 torch.save(myModule.state_dict(), "mymodule_{}.pth".format(i)) print("模型已经保存") writer.close()
tensorboard训练结果展示
myModule.train()和myModule.eval()对特定的层(dropout,batchNorm)有作用,如果自己的网络结构中没有这些层,加不加这两句关系不大。
# 第一种gpu训练的方式 # 第一步:找到网络模型 + 数据(输入,标注) + 损失函数 # 第二步:.cuda() # 第二种gpu训练的方式 # .to(device) # Device = torch.device("cpu") # Torch.device("cuda") # Torch.device("cuda:0") # 指定训练的显卡 # Torch.device("cuda:1") import time import torch.optim.optimizer import torchvision.datasets from torch import nn # 第一步:准备数据集 from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter train_data = torchvision.datasets.CIFAR10(root='./dataset', train=True, transform=torchvision.transforms.ToTensor(), download=True) test_data = torchvision.datasets.CIFAR10(root="./dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True) train_data_size = len(train_data) test_data_size = len(test_data) print("训练数据集的长度为:{}".format(train_data_size)) # 字符串格式化:把train_data_size带入{}中 print("训练数据集的长度为:{}".format(test_data_size)) # 字符串格式化:把test_data_size带入{}中 # 第二步:利用dataloader加载数据集 train_dataloader = DataLoader(train_data, batch_size=64) test_dataloader = DataLoader(test_data, batch_size=64) # 第三步:搭建/加载神经网络 # 第一种方式:搭建网络 # class MyModule(nn.Module): # def __init__(self): # super(MyModule, self).__init__() # self.model = nn.Sequential( # nn.Conv2d(3, 32, 5, 1, 2), # nn.MaxPool2d(2), # nn.Conv2d(32, 32, 5, 1, 2), # nn.MaxPool2d(2), # nn.Conv2d(32, 64, 5, 1, 2), # nn.MaxPool2d(2), # nn.Flatten(), # nn.Linear(64 * 4 * 4, 64), # nn.Linear(64, 10) # ) # # def forward(self, x): # x = self.model(x) # return x from P25_model import * # 第二种方式:加载网络 # 第四步:创建网络模型对象 myModule = MyModule() if torch.cuda.is_available(): myModule = myModule.cuda() # 找到了网络模型,使用gpu计算时用.cuda # 第五步:创建损失函数 loss_fn = nn.CrossEntropyLoss() if torch.cuda.is_available(): loss_fn = loss_fn.cuda() # 找到了损失函数,使用gpu计算时用.cuda # 第六步:创建优化器 config = { "learning_rate": 1e-2, "momentum": 0.9 } optimizer = torch.optim.SGD(myModule.parameters(), lr=config["learning_rate"], momentum=config["momentum"]) # 第七步:设置训练网络的一些参数 # 记录训练的次数 total_train_step = 0 # 记录测试的次数 total_test_step = 0 # 训练的轮数 epoch = 10 # 添加tensorboard writer = SummaryWriter("logs_train") start_time = time.time() # 第八步 for i in range(epoch): print("------------------------第{}轮训练开始-----------------------".format(i + 1)) # 训练步骤开始 myModule.train() # 不设置也可以训练 for data in train_dataloader: imgs, targets = data if torch.cuda.is_available(): imgs = imgs.cuda() # 找到了数据,使用gpu计算时用.cuda targets = targets.cuda() # 找到了标注,使用gpu计算时用.cuda outputs = myModule(imgs) loss = loss_fn(outputs, targets) # 优化器优化模型 optimizer.zero_grad() # 重置梯度值 loss.backward() # 反向传播 optimizer.step() # 模型优化 total_train_step = total_train_step + 1 if total_train_step % 100 == 0: end_time = time.time() print(end_time - start_time) print("训练次数:{},Loss:{}".format(total_train_step, loss.item())) # 不加item是tensor类型,加了item是数据 writer.add_scalar("train_loss", loss.item(), total_train_step) # 测试步骤开始(使用tensorboard可以实时查看损失函数走势,使用argmax可以求出输出outputs中各行的最大值,再与targets比较,进而得出正确率) myModule.eval() # 不设置也可以测试 total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: imgs, targets = data if torch.cuda.is_available(): imgs = imgs.cuda() # 找到了数据,使用gpu计算时用.cuda targets = targets.cuda() # 找到了标注,使用gpu计算时用.cuda outputs = myModule(imgs) loss = loss_fn(outputs, targets) total_test_loss = total_test_loss + loss 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(myModule, "mymodule_{}.pth".format(i)) # 模型保存的方式二 torch.save(myModule.state_dict(), "mymodule_0.pth".format(i)) print("模型已经保存") writer.close()
# 第二种gpu训练的方式 对
# .to(device)
# device = torch.device("cuda" if torch.cuda.is_available() else 'cpu')
# myModule.to(device)
# loss.to(device)
# imgs.to(device)
# labels.to(device)
示例:
# .to(device) # device = torch.device("cuda" if torch.cuda.is_available() else 'cpu') # myModule.to(device) # loss.to(device) # imgs.to(device) # labels.to(device) import time import torch.optim.optimizer import torchvision.datasets from torch import nn # 第零步:定义训练的设备 device = torch.device("cuda" if torch.cuda.is_available() else 'cpu') # 第一步:准备数据集 from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter train_data = torchvision.datasets.CIFAR10(root='./dataset', train=True, transform=torchvision.transforms.ToTensor(), download=True) test_data = torchvision.datasets.CIFAR10(root="./dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True) train_data_size = len(train_data) test_data_size = len(test_data) print("训练数据集的长度为:{}".format(train_data_size)) # 字符串格式化:把train_data_size带入{}中 print("训练数据集的长度为:{}".format(test_data_size)) # 字符串格式化:把test_data_size带入{}中 # 第二步:利用dataloader加载数据集 train_dataloader = DataLoader(train_data, batch_size=64) test_dataloader = DataLoader(test_data, batch_size=64) # 第三步:搭建/加载神经网络 # class MyModule(nn.Module): # def __init__(self): # super(MyModule, self).__init__() # self.model = nn.Sequential( # nn.Conv2d(3, 32, 5, 1, 2), # nn.MaxPool2d(2), # nn.Conv2d(32, 32, 5, 1, 2), # nn.MaxPool2d(2), # nn.Conv2d(32, 64, 5, 1, 2), # nn.MaxPool2d(2), # nn.Flatten(), # nn.Linear(64 * 4 * 4, 64), # nn.Linear(64, 10) # ) # # def forward(self, x): # x = self.model(x) # return x from P25_model import * # 加载模型 # 第四步:创建网络模型对象 myModule = MyModule() myModule = myModule.to(device) # 找到了网络模型,使用gpu计算时用.cuda # 第五步:创建损失函数 loss_fn = nn.CrossEntropyLoss() loss_fn = loss_fn.to(device) # 第六步:创建优化器 config = { "learning_rate": 1e-2, "momentum": 0.9 } optimizer = torch.optim.SGD(myModule.parameters(), lr=config["learning_rate"], momentum=config["momentum"]) # 第七步:设置训练网络的一些参数 # 记录训练的次数 total_train_step = 0 # 记录测试的次数 total_test_step = 0 # 训练的轮数 epoch = 10 # 添加tensorboard writer = SummaryWriter("logs_train") start_time = time.time() for i in range(epoch): print("------------------------第{}轮训练开始-----------------------".format(i + 1)) # 训练步骤开始 myModule.train() # 不设置也可以训练 for data in train_dataloader: imgs, targets = data imgs = imgs.to(device) # 找到了数据,使用gpu计算时用.cuda targets = targets.to(device) # 找到了标注,使用gpu计算时用.cuda outputs = myModule(imgs) loss = loss_fn(outputs, targets) # 优化器优化模型 optimizer.zero_grad() # 重置梯度值 loss.backward() # 反向传播 optimizer.step() # 模型优化 total_train_step = total_train_step + 1 if total_train_step % 100 == 0: end_time = time.time() print(end_time - start_time) print("训练次数:{},Loss:{}".format(total_train_step, loss.item())) # 不加item是tensor类型,加了item是数据 writer.add_scalar("train_loss", loss.item(), total_train_step) # 测试步骤开始(使用tensorboard可以实时查看损失函数走势,使用argmax可以求出输出outputs中各行的最大值,再与targets比较,进而得出正确率) myModule.eval() # 不设置也可以测试 total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: imgs, targets = data imgs = imgs.to(device) # 找到了数据,使用gpu计算时用.cuda targets = targets.to(device) # 找到了标注,使用gpu计算时用.cuda outputs = myModule(imgs) loss = loss_fn(outputs, targets) total_test_loss = total_test_loss + loss 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(myModule, "mymodule_{}.pth".format(i)) # 模型保存的方式二 torch.save(myModule.state_dict(), "mymodule_0.pth".format(i)) print("模型已经保存") writer.close()
第一步:准备数据集
train_data = torchvision.datasets.CIFAR10(root='./dataset', train=True, transform=torchvision.transforms.ToTensor(),download=True) # root指定根目录,train指定数据是训练集还是数据集,transform是对原始数据进行一些形状调整,方便神经网络读入,download指定是否下载数据集
Pytorch已经内置了常用的数据集和神经网络模型,可以在官网上上找到。附上链接Datasets — Torchvision 0.12 documentation (pytorch.org)
第二步:使用DataLoader加载数据集
train_dataloader = DataLoader(train_data,batch_size=64,shuffle=True) # 将数据集装入DataLoader中,batch_size设置部分数据用于梯度下降,shuffle指定是否打乱数据集
第三步:搭建/加载神经网络
# 搭建神经网络(仿写搭建CIFAR-10网络结构) class MyModule(nn.Module): def __init__(self): super(MyModule, self).__init__() self.model = nn.Sequential( #nn.Sequential()简化神经网络编写的过程 nn.Conv2d(3, 32, 5, 1, 2), # nn.Conv2d前五个参数(in_channel,out_channel,卷积核函数,stride,padding) nn.MaxPool2d(2), # 池化核函数2×2 nn.Conv2d(32, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, 1, 2), nn.MaxPool2d(2), nn.Flatten(), # 把神经网络拉直 nn.Linear(64 * 4 * 4, 64), nn.Linear(64, 10) ) def forward(self, x): x = self.model(x) return x # 加载模型 from 神经网络类所在文件名 import * # 加载模型
一般情况下,神经网络类中编写init和forward函数。
第四步:创建网络模型对象
myModule = MyModule()
第五步:创建损失函数
loss_fn = nn.CrossEntroyLoss()
第六步:创建优化器
config = {
"learning_rate": 1e-2,
"momentum": 0.9
}
optimizer = torch.optim.SGD(myModule.parameters(), lr=config["learning_rate"], momentum=config["momentum"])
第七步:设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加tensorboard
writer = SummaryWriter("logs_train") # tensorboard用于可视化神经网络结构和训练过程,这里的参数指定了tensorboard记录的目录,查看文本的方式是在pycharm的terminal中切换到当前.py文件的目录中,输入命令 tensorboard --logdir=logs_train 会弹出网址,网址中可以实现查看网络结构等操作。
第八步:开始训练
for i in range(epoch): print("------------------------第{}轮训练开始-----------------------".format(i + 1)) # 训练步骤开始 myModule.train() # 不设置也可以训练 for data in train_dataloader: # 读取train_dataloader中的data imgs, targets = data # 1.读取data中的imgs,targets outputs = myModule(imgs) # 2.前向传播 loss = loss_fn(outputs, targets) # 3. 损失函数计算 # 优化器优化模型 optimizer.zero_grad() # 4.重置梯度值 loss.backward() # 5.反向传播 optimizer.step() # 6.模型优化 total_train_step = total_train_step + 1 if total_train_step % 100 == 0: print("训练次数:{},Loss:{}".format(total_train_step, loss.item())) # 不加item是tensor类型,加了item是数据 writer.add_scalar("train_loss", loss.item(), total_train_step) # 这里用上了tensorboard,第一个参数train_loss是可视化的图表的名称,第二个参数loss.item()指定了自变量,第三个参数指定了图表中的某个图。 # 测试步骤开始(使用tensorboard可以实时查看损失函数走势,使用argmax可以求出outputs中各行的最大值,再与targets比较,进而得出正确率) myModule.eval() # 不设置也可以测试 total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: # 读取test_dataloader中的data imgs, targets = data # 1.读取data中的imgs,targets outputs = myModule(imgs) # 2.前向传播 loss = loss_fn(outputs, targets) # 3,损失函数计算 total_test_loss = total_test_loss + loss # 统计损失值 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) # 这里用上了tensorboard,第一个参数test_loss是可视化的图表的名称,第二个参数total_test_loss指定了自变量,第三个参数指定了图表中的某个图。 writer.add_scalar("test_accuracy", total_accuracy / test_data_size, total_test_step) # 这里用上了tensorboard,第一个参数test_accuracy是可视化的图表的名称,第二个参数total_accuracy / test_data_size 指定了自变量,第三个参数指定了图表中的某个图。 total_test_step = total_test_step + 1 # 模型保存的方式一 torch.save(myModule, "mymodule_{}.pth".format(i)) # 模型保存的方式二 torch.save(myModule.state_dict(), "mymodule_{}.pth".format(i)) print("模型已经保存") writer.close()
tensorboard训练结果展示
参考视频:PyTorch深度学习快速入门教程 哔哩哔哩_bilibili
typora + picgo + 阿里云 制作远程图片服务器(后续有需要可以出一期搭建教程)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。