详细请看:<Python深度学习基于Pytorch>
Pytorch是Facebook团队于2017年1月发布的深度学习框架,是Torch框架在Python上的衍生。采用Python语言来实现编程,非常容易上手。
Pytorch主要特点
(1)继承了Torch灵活、动态的编程环境和用户友好的界面。
(2)支持以快速和灵活的方式构建动态神经网络。
(3)支持在训练过程中快速更改代码而不妨碍其性能。
(4)支持动态图形等尖端AI模型的能力,是快速实验的理想选择。
Pytorch四个主要的包
(1)torch:类似于Numpy的通用数据库,包括多维张量Tensor的数据结构以及多种数学操作。
(2)torch.autograd:用于构建计算图形并自动获取梯度的包。
(3)torch.optim:具有通用优化算法(如SGD、Adam等)优化包。
(4)torch.nn:具有共享层和损失函数的神经网络库。
Numpy与Tensor的区别
(1)Numpy产生的ndarray只支持在CPU中进行加速运算;
(2)Torch产生的Tensor可以支持在GPU中进行加速运算(假设当前环境有GPU)
要检查当前环境是否有GPU,如果没有,则安装CPU版;如果有,则安装GPU版本。(推荐离线安装)
Pytorch安装如下:
- (1)【CPU版本】Python -> Pytorch(CPU)
- (2)【GPU版本】NVIDIA驱动 -> CUDA -> cuDNN -> Python -> Pytorch(GPU)
备注1:CUDA是英伟达公司推出的通用计算架构,它能利用英伟达GPU的并行计算引擎,比CPU更高效的解决复杂计算任务。
备注2:NVIDIA cuDNN是用于深度神经网络的GPU加速库。
离线安装Pytorch 最简单高效的方法
torchvision官方链接(离线安装)
基于Pytorch中安装torchvision简单详细完整版
python | pytorch | torchvision | cuda |
---|---|---|---|
3.7-3.9 | 1.12.0 | 0.12 | 10.2(不支持windows),11.3,11.6 |
>=3.6 | 1.11.0 | 0.12.0 | 11.3,10.2 |
>=3.6 | 1.10.0/1 | 0.11.0/2 | 10.2,11.3 |
>=3.6 | 1.9.0 | 0.10.0 | 10.2,11.3 |
>=3.6 | 1.8.0 | 0.9.0 | 10.2,11.1 |
>=3.6 | 1.7.1 | 0.8.2 | 9.2, 10.1,10.2,11.0 |
>=3.6 | 1.7.0 | 0.8.0 | 9.2, 10.1,10.2,11.0 |
>=3.6 | 1.6.0 | 0.7.0 | 9.2, 10.1,10.2 |
>=3.6 | 1.5.1 | 0.6.1 | 9.2, 10.1,10.2 |
>=3.6 | 1.5.0 | 0.6.0 | 9.2, 10.1,10.2 |
PyToch和Torchvision对应版本(更多版本对应)
数据处理:决定了数据质量和模型性能,是项目中耗时又重要的任务。包括:数据装载、数据预处理、数据增强等。常用工具箱如下:
备注1:data.Dataset 一般只处理同一个目录下的数据。
若数据在不同目录下,则很不方便(不同目录往往代表不同类别。如:1和0文件夹下分别存放了对应的数据集。)
备注2:torchvision 可以处理多个目录下的数据。
且可以自动获取标签,提供数据预处理、数据增强等转换函数。
Dataset 和 DataLoader 的搭配调用过程如下。
(1)原始数据转变成 torch.utils.data.Dataset 类;
(2)将torch.utils.data.Dataset 类当作一个参数传递给 torch.utils.data.DataLoader 类,得到一个数据加载器。这个数据加载器每次可以返回一个 Batch 的数据供模型训练使用。
(3)在输出时对数据进行相应的预处理或数据增广操作。
PyTorch中torch.utils.data.Dataset 类和 torch.utils.data.DataLoader 类的介绍与实战
❤️ torch.utils.data.Dataset ❤️ 是一个抽象类。
且只能实现单样本数据读取。
若自定义读取数据的方法,则必须要继承这个类。 其包含两个函数:
- (__ getitem__):通过给定索引获取数据和标签;
- (__ len__):提供数据的大小size。
import torch
from torch.utils import data
import numpy as np
class TestDataset(data.Dataset): # 继承Dataset
"""自定义Dataset"""
def __init__(self):
# 由二维向量表示的数据集
self.Data = np.asarray([[1, 2], [3, 4], [1, 2], [3, 4], [4, 5], [1, 2], [3, 4], [1, 2], [7, 2], [7, 9]])
# 数据集对应的标签
self.Label = np.asarray([0, 1, 0, 1, 2, 0, 1, 0, 3, 5])
def __getitem__(self, item):
txt = torch.from_numpy(self.Data[item]) # 将numpy转换为Tensor
label = torch.tensor(self.Label[item])
return txt, label
def __len__(self):
return len(self.Data)
Test = TestDataset() # 类的实例化
test_loader = data.DataLoader(Test, batch_size=4, shuffle=False, drop_last=False)
# 打印
for i, train_data in enumerate(test_loader):
Data, Label = train_data
print('迭代获取批数据:i=', i)
print('Data={}, Label={}' .format(Data, Label))
❤️ torch.utils.data.DataLoader ❤️ 定义一个新的迭代器。
主要实现批量数据读取(batch)、数据打乱(shuffle)、提供并行加速等功能。
# DataLoader在训练集与测试集上的调用。而测试集不需要更新梯度,故train=False。
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=16, shuffle=True, num_workers=2)
testloader = torch.utils.data.DataLoader(testset, batch_size=16, shuffle=False, num_workers=2)
##############################################################################
# data.DataLoader(dataset=Test, batch_size=2, shuffle=False, sampler=None, batch_sampler=None,
# num_workers=0, collate_fn=None, pin_memory=False, drop_lost=False)
# 主要参数说明:
# (1)dataset:加载的数据集
# (2)batch_size:批大小
# (3)shuffle:是否将数据打乱
# (4)sampler:样本抽样
# (5)num_workers:使用多进程加载的进程数,0代表不适用多进程
# (6)collate_fn:如何将多个样本数据拼接成一个batch,一般取默认值。
# (7)pin_memory:是否将数据保存在pin_memory区,pin_memory中的数据转到GPU会快一些。
# (8)drop_last:若drop_last=True将丢弃最后不足一个batch的数据。
##############################################################################
❤️ torchvision.datasets ❤️ 中包含了以下数据集:MNIST(手写数字识别)、COCO(用于图像标注和目标检测、LSUN Classification、ImageFolder、Imagenet-12、CIFAR10 and CIFAR100、STL10、SVHN、PhotoTour。Pytorch:torchvision.datasets
所有数据集都是torch.utils.data.Dataset的子类, 即它们具有getitem和len实现方法。 因此,它们都可以传递给torch.utils.data.DataLoader 可以使用torch.multiprocessing工作人员并行加载多个样本的数据。
所有的数据集都有几乎相似的API。 他们都有两个共同的参数: transform和 target_transform分别转换输入和目标。
# CIFAR10数据集使用的例子
# 要注意测试集数据不更新梯度,故train=False。
import torchvision.datasets
import torchvision.transforms as transforms
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=16, shuffle=True, num_workers=2)
testloader = torch.utils.data.DataLoader(testset, batch_size=16, shuffle=False, num_workers=2)
❤️ torchvision.models ❤️ 主要提供深度学习中多种经典的网络结构以及训练好的模型(若选择,则pretrained=True)。
包括:AlexNet、VGG系列、ResNet系列、SqueezeNet系列、Densenet系列、Inception v3
等。Pytorch:torchvision.models
- VGG系列:vgg11、vgg13、vgg16、vgg19
- ResNet系列:resnet18、resnet34、resnet50、resnet101、resnet151
- SqueezeNet系列:SqueezeNet 1.0、SqueezeNet 1.1
- DenseNet系列:Densenet-121、Densenet-169、Densenet-201、Densenet-161
import torchvision.models as models
# 随机初始化模型
alexnet = models.alexnet()
vgg16 = models.vgg16()
resnet18 = models.resnet18()
inception =models.inception_v3()
squeezenet = models.squeezenet1_0()
desnet = models.densenet161()
# 使用预训练好的参数
resnet18 = models.resnet18(pretrained=True)
alexnet = models.alexnet(pretrained=True)
squeezenet = models.squeezenet1_0(pretrained=True)
vgg16 = models.vgg16(pretrained=True)
densenet = models.densenet161(pretrained=True)
inception = models.inception_v3(pretrained=True)
❤️ torchvision.utils ❤️ 中包含两个函数:
- (1)make_grid:制作图像网格。若有多张图片,将连接在一个网络中(同一画布上);
torchvision.utils.make_grid(tensor, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)
- (2)save_img:将给定的Tensor张量保存到图像文件中。
torchvision.utils.save_image(tensor, filename, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)
# 输入参数
(1)tensor (Tensor or list) – 4D小批量形状Tensor张量(B x C x H x W)或所有大小相同的图像列表。
(2)nrows (int, optional) – 网格中的行数。最终的网格大小(B / nrow,nrow)。默认值是8。
(3)normalize (bool, optional) – 如果TRUE,将图像移到范围(0, 1)中,减去最小值并除以最大像素值。
(4)range (tuple, optional) – 元组(min,max),其中min和max是数字,然后使用这些数字对图像进行标准化。默认情况下,min和max是从张量计算的。
(5)scale_each (bool, optional) – 如果TRUE,则在批处理图像中分别缩放每个图像,而不是在所有图像上(最小、最大)缩放图像。
(6)pad_value (float, optional) – 填充像素的值。
imshow(torchvision.utils.make_grid(images[0:16]))
其中,imshow()为自定义的显示图像函数。
❤️ torchvision.transforms ❤️ 是一个图像变换工具包。在深度学习中,图像变换(Image Transform)通常是必不可少的一环,其可以用来对Tensor、PIL Image对象进行图像预处理,数据增强等。
以下是torchvision.transforms 提供的一些图像预处理功能。
玩转pytorch中的torchvision.transforms(请点击:图解)
调用transforms的两种方法
(1)单操作。即直接调用 torchvision.transforms()方法进行图像处理,但每次只能选择一个 (transform变换)。
# (1) Transforms on PIL Image ———— 对图像处理库(Pillow, PIL)中Image的处理。
torchvision.transforms.CenterCrop # CenterCrop的作用是从图像的中心位置裁剪指定大小的图像
torchvision.transforms.ColorJitter # ColorJitter的作用是随机修改图片的亮度、对比度和饱和度,常用来进行数据增强
torchvision.transforms.FiveCrop # FiveCrop的作用是分别从图像的四个角以及中心进行五次裁剪
torchvision.transforms.Grayscale # Grayscale的作用是将图像转换为灰度图像,默认通道数为1,通道数为3时,RGB三个通道的值相等。
torchvision.transforms.Pad # Pad的作用是对图像进行填充,可以设置要填充的值及填充的大小,默认是图像四边都填充。
torchvision.transforms.RandomAffine # RandomAffine的作用是保持图像中心不变的情况下对图像进行随机的仿射变换。
torchvision.transforms.RandomApply # RandomApply的作用是以一定的概率执行提供的transforms操作,即可能执行,也可能不执行。
torchvision.transforms.RandomChoice # RandomChoice的作用是从提供的transforms操作中随机选择一个执行。
torchvision.transforms.RandomCrop # RandomCrop的作用是在一个随机位置上对图像进行裁剪。
torchvision.transforms.RandomGrayscale # RandomGrayscale的作用是以一定的概率将图像变为灰度图像。
torchvision.transforms.RandomHorizontalFlip # RandomHorizontalFlip的作用是以一定的概率对图像进行水平翻转。
torchvision.transforms.RandomOrder # RandomOrder的作用是以随机顺序执行提供的transforms操作。
torchvision.transforms.RandomPerspective # RandomPerspective的作用是以一定的概率对图像进行随机的透视变换。
torchvision.transforms.RandomResizedCrop # RandomResizedCrop的作用是以随机大小和随机长宽比裁剪图像并缩放到指定的大小。
torchvision.transforms.RandomRotation # RandomRotation的作用是对图像进行随机旋转。
torchvision.transforms.RandomVerticalFlip # RandomVerticalFlip的作用是以一定的概率对图像进行垂直翻转。
torchvision.transforms.Resize # Resize的作用是对图像进行缩放。
# (2) Transforms on torch.*Tensor(对Tensor的变换)
torchvision.transforms.GaussianBlur # GaussianBlur的作用是随机高斯模糊,模糊程度随机
torchvision.transforms.LinearTransformation # LinearTransformation的作用是使用变换矩阵和离线计算的均值向量对图像张量进行变换,可以用在白化变换中,白化变换用来去除输入数据的冗余信息。常用在数据预处理中。
torchvision.transforms.Normalize # Normalize的作用是用均值和标准差对Tensor进行归一化处理。
torchvision.transforms.RandomErasing # RandomErasing的作用是随机选择图像中的一块区域,擦除其像素,主要用来进行数据增强。
# (3) Conversion Transforms(格式转换)
torchvision.transforms.ToPILImage # ToPILImage的作用是将pytorch的Tensor或numpy.ndarray转为PIL的Image。
torchvision.transforms.ToTensor # ToTensor的作用是将PIL Image或numpy.ndarray转为pytorch的Tensor,并会将像素值由[0, 255]变为[0, 1]之间。通常是在神经网络训练中读取输入图像之后使用。
(2)组合操作。torchvision.transforms.Compose()方法将多个图像变换操作组合在一起。Compose()会自动遍历【transforms列表】中的所有 (transform变换) 。
torchvision.transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])
一个通用的数据加载器。当数据在不同文件下时,可以利用torchvision.datasets.ImageFolder来直接构造出dataset。
dataset = torchvision.datasets.ImageFolder(path)
loader = torch.utils.data.DataLoader(dataset)
torchvision.datasets.ImageFolder前的数据整理及使用方法
# 主要流程:
# (1)通过ImageFolder读取不同目录下的图像数据。
# (2)利用transforms.compose进行多个图像预处理操作,然后使用DataLoader加载。
# (3)对预处理后的数据用torchvision.utils中的save_image保存为文件,然后用Image.open打开。
import torch
import torchvision
from torchvision import transforms, utils
from torchvision import datasets
from torch.utils import data
import matplotlib.pyplot as plt
my_trans = transforms.Compose([transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor()])
train_data = torchvision.datasets.ImageFolder(R'data/torchvision_data', transform=my_trans)
train_loader = torch.utils.data.DataLoader(train_data, batch_size=8, shuffle=True)
for i_batch, img in enumerate(train_loader):
if i_batch == 0:
print(img[1])
fig = plt.figure()
grid = torchvision.utils.make_grid(img[0])
plt.imshow(grid.numpy().transpose((1, 2, 0)))
plt.show()
utils.save_image(grid, 'test01.png')
break
TensorBoard是Google TensorFlow的可视化工具。可以记录:训练数据、评估数据、网络结构、图像等。并可以在web上展示。
Pytorch使用tensorboardX可视化(超详细)
Welcome to tensorboardX’s documentation!
在神经网络中,最重要的内容就是参数学习,而参数学习离不开求导。torch.autograd提供了自动求导功能,其有两个核心类:torch.Tensor和torch.function。
Pytorch采用计算图的形式进行模型构建,且在每次前向传播时,都将重新构建。该计算图为动态图,且为有向无环图(DAG)。而其他深度学习框架,如:TensorFlow、Keras为静态图。
自动求导要点:
(1)创建叶子节点(leaf node)的Tensor。其参数requires_grad=True表示自动求导。缺省值为False。
(2)可利用 requires_grad_ 方法修改Tensor的 requires_grad 属性。
(3)对非叶子节点的Tensor计算,会自动记录在grad_fn属性中。该属性表示梯度函数,而叶子节点的grad_fn为None。
(4)对Tensor执行backward()函数。
- 00、backward(gradient=None, retain_graph=None, create_graph=False)
- 11、对当前目标函数进行反向传播,自动计算所有(叶子节点)变量的梯度,其结果保存在 .grad 属性中。
- 22、接收参数的维度要与Tensor相同。若求导的Tensor为标量(即数字),则参数可省略。如:torch.Tensor([2])
- 33、反向传播调用后,(非叶子节点)缓存的梯度值会自动清空。
- 44、若进行梯度值累加,需要多次调用反向传播,且指定其参数 retain_graph=True。**
(5)调用 .detach() 或 with torch.no_grad(): 表示不再计算张量的梯度,不再跟踪张量的历史记录。
备注1:梯度(gradient) ———— 即某一函数在该点处的方向导数,其沿着该方向取得最大值。
备注2:缺省值 ———— 即默认选项(计算机术语)
什么是叶子节点、非叶子节点、算子节点?
如:z=wx+b,该公式可以拆分为:y=wx;z=y+b;其中:x、w、b为输入变量(即叶子节点);y、z为计算得到的变量(即非叶子节点),z又叫做根节点;mul()和add()操作符(即算子节点)。
###############################################
# 假设z=wx+b; 其中,x、w、b都是标量。 ———— 对标量z调用backward(),无需传入参数。
###############################################
# (1)定义叶子节点
import torch
x = torch.Tensor([2])
w = torch.randn(1, requires_grad=True) # 初始化权重参数 w
b = torch.randn(1, requires_grad=True) # 初始化权重参数 b
# (2)前向传播:定义算子节点
y = torch.mul(w, x) # 乘法计算
z = torch.add(y, b) # 加法计算
# (3)调用backward(), 实现目标函数的梯度自动计算
z.backward()
##########################
# 查看各节点是否为叶子节点(.is_leaf)
print('x、w、b、y、z是否为叶子节点:{},{},{},{},{}' .format(x.is_leaf, w.is_leaf, b.is_leaf, y.is_leaf, z.is_leaf))
# 查看叶子节点的requires_grad属性(缺省值为False)
print('x、w、b的requires_grad属性分别为:{},{},{}' .format(x.requires_grad, w.requires_grad, b.requires_grad))
# 查看非叶子节点的requires_grad属性 ———— 因为y、z与w、b有依赖关系
print('y、z的requires_grad属性分别为:{},{}' .format(y.requires_grad, z.requires_grad))
# 查看叶子节点的grad_fn属性
print('x、w、b的grad_fn属性分别为:{},{},{}' .format(x.grad_fn, w.grad_fn, b.grad_fn))
# 查看非叶子节点的grad_fn属性
print('y、z的grad_fn属性分别为:{},{}' .format(y.grad_fn, z.grad_fn))
# 查看叶子节点的梯度 ———— x是叶子节点但无须求导,故其梯度为None
print('x、w、b的梯度分别为:{},{},{}' .format(x.grad, w.grad, b.grad))
# 查看非叶子节点的梯度(非叶子节点不支持调用梯度属性,系统警告提示)
print('y、z的梯度分别为:{},{}' .format(y.grad, z.grad))
##########################################
# 题目:(1)随机给定向量 x。目标函数:y=3x^2+2+随即噪音。
# (2)构建机器学习模型
# 11、通过给定数据,基于y=wx^2+b,【手动计算梯度】w、b;
# 22、采用梯度下降法学习参数,并多次迭代,得到最接近目标函数的w、b值(w=3、b=2)。
##########################################
import numpy as np
from matplotlib import pyplot as plt
# (1)生成输入向量(x)及目标数据(y)
np.random.seed(100) # 如果设置相同的seed值,则每次运行程序都将生成相同的随机数
x = np.linspace(-1, 1, 100).reshape(100, 1) # 生成线性等份向量,并改变形状
y = 3*np.power(x, 2) + 2 + 0.2*np.random.rand(x.size).reshape(100, 1)
# plt.scatter(x, y)
# plt.show()
# (2)随机初始化权重参数
w1 = np.random.rand(1, 1)
b1 = np.random.rand(1, 1)
# (3)训练模型
lr = 0.001 # 学习率初始化
global y_predict
for ii in range(800+1): # 右值取不到
y_predict = np.power(x, 2)*w1 + b1 # 前向传播
loss = 0.5*(y_predict - y) ** 2 # 定义损失函数
loss = loss.sum()
# 对损失函数(手动)求导,计算梯度
grad_w = np.sum((y_predict - y) * np.power(x, 2))
grad_b = np.sum((y_predict - y))
# 使用梯度下降法学习参数,使loss最小
w1 -= lr * grad_w
b1 -= lr * grad_b
if ii % 100 == 0: # 每隔100次打印一次训练结果
print('迭代次数{} ———— 损失值={:.4},权重={},偏置={}' .format(ii, loss, w1, b1))
# (4)可视化结果
plt.plot(x, y_predict, 'r-', label='predict') # 预测值
plt.scatter(x, y, color='blue', marker='o', label='true') # 真实值
plt.xlim(-1, 1), plt.ylim(2, 6), plt.legend(loc=1)
plt.show()
###########################################
# 获取axes并作图:plt.plot()
# 图例位置调整:legend(loc=num) 其中,num=1~10, 不同数值对应不同位置。默认loc=1
# 设置x轴的数值显示范围:plt.xlim(x_min, x_max)
# 设置y轴的数值显示范围:plt.ylim(y_min, y_max)
###########################################
##########################################
# 题目:(1)随机给定向量 x。目标函数:y=3x^2+2+随即噪音。
# (2)构建机器学习模型
# 11、通过给定数据,基于y=wx^2+b,【自动计算梯度】w、b;
# 22、采用梯度下降法学习参数,并多次迭代,得到最接近目标函数的w、b值(w=3、b=2)。
##########################################
import torch
from matplotlib import pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' # "OMP: Error #15: Initializing libiomp5md.dll"
# (1)生成输入向量(x)及目标数据(y)
torch.manual_seed(100) # 如果设置相同的seed值,则每次运行程序都将生成相同的随机数
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # 添加一个维度(dim=0按行索引,dim=1按列索引)
y = 3*torch.pow(x, 2) + 2 + 0.2*torch.rand(x.size())
# plt.scatter(x.numpy(), y.numpy())
# plt.show()
# (2)随机初始化权重参数
w1 = torch.randn(1, 1, requires_grad=True) # requires_grad=True表示参数w、b需要学习
b1 = torch.randn(1, 1, requires_grad=True)
# (3)训练模型
lr = 0.001 # 学习率初始化
global y_predict
for ii in range(800+1): # 右值取不到
y_predict = torch.pow(x, 2).mm(w1) + b1 # 前向传播 # torch.mm(input1, input2) # 对2D矩阵进行点积运算
loss = 0.5*(y_predict - y) ** 2 # 定义损失函数
loss = loss.sum()
# 自动计算梯度,梯度存放在属性grad中
loss.backward() # 反向传播
with torch.no_grad():
w1 -= lr * w1.grad
b1 -= lr * b1.grad
w1.grad.zero_() # 梯度清零
b1.grad.zero_()
if ii % 100 == 0: # 每隔100次打印一次训练结果
print('迭代次数{} ———— 损失值={:.4},权重={},偏置={}' .format(ii, loss, w1, b1))
# (4)可视化结果
plt.plot(x.numpy(), y_predict.detach().numpy(), 'r-', label='predict') # 预测值
# 调用 .detach() 或 with torch.no_grad(): 表示不再计算张量的梯度,不再跟踪张量的历史记录。
plt.scatter(x.numpy(), y.numpy(), color='blue', marker='o', label='true') # 真实值
plt.xlim(-1, 1), plt.ylim(2, 6), plt.legend(loc=1)
plt.show()
###########################################
# 获取axes并作图:plt.plot()
# 图例位置调整:legend(loc=num) 其中,num=1~10, 不同数值对应不同位置。默认loc=1
# 设置x轴的数值显示范围:plt.xlim(x_min, x_max)
# 设置y轴的数值显示范围:plt.ylim(y_min, y_max)
###########################################
常用的优化方法都封装在torch.optim中,且都继承了基类torch.optim.optimizer。其设计灵活,可以扩展为自定义的优化方法。
# 优化器的执行步骤:
(1)优化器实例化:optimizer = torch.optim.SGD(model.parameters(), lr, momentum)
(2)前向传播:out = model(img) # model是模型实例化对象。输入img,执行forward(),得到输出值。
(2)损失函数:loss = loss_func(out, label)
(3)梯度清零:optimizer.zero_grad()
(4)反向传播:loss.backward()
(5)参数更新:optimizer.step()
import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' # "OMP: Error #15: Initializing libiomp5md.dll"
####################################
# (1)定义超参数
LR = 0.01
BATCH_SIZE = 32
EPOCH = 12
####################################
# (2)生成数据
# torch.manual_seed(100) # 如果设置相同的seed值,则每次运行程序都将生成相同的随机数
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1) # torch只能处理二维数据
y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size())) # 目标函数+随即噪音
torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True)
####################################
# (3)构建神经网络
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.hidden = torch.nn.Linear(1, 20) # 隐藏层
self.predict = torch.nn.Linear(20, 1) # 输出层
# 前向传递
def forward(self, x):
x = F.relu(self.hidden(x)) # 激活函数
x = self.predict(x)
return x
####################################
if __name__ == '__main__':
# (4)定义多个神经网络
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]
# (5)调用多个优化器
opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.9)
opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSprop, opt_Adam]
# (6)定义损失函数
loss_func = torch.nn.MSELoss()
losses = [[], [], [], []] # 记录损失值
# (7)训练函数
for epoch in range(EPOCH):
for step, (batch_x, batch_y) in enumerate(loader):
for net, opt, loes in zip(nets, optimizers, losses):
output = net(batch_x) # 获取每层网络的输出
loss = loss_func(output, batch_y) # 比较每层网络的损失
opt.zero_grad() # 梯度清零
loss.backward() # 自动计算梯度
opt.step() # 梯度更新
loes.append(loss.data.numpy()) # 保存每次训练的结果(损失值)。画图数据需numpy格式
# (8)可视化结果
labels = ['SGD', 'Momentun', 'RMSprop', 'Adam']
colors = ['b', 'k', 'y', 'r'] # plot中画线的颜色通常是八种:r红、g绿、b蓝、c蓝绿、m紫红、y黄、k黑、w白
for ii, loes in enumerate(losses):
plt.plot(loes, label=labels[ii], color=colors[ii]) # 获取axes并作图:plt.plot()
plt.legend(loc='best') # 图例位置调整:legend(loc=num) 其中,num=1~10, 不同数值对应不同位置。默认loc=1
plt.xlabel('Steps') # 设置x轴标签
plt.ylabel('Loss') # 设置y轴标签
plt.ylim((0, 0.2)) # 设置y轴的数值显示范围:plt.ylim(y_min, y_max)
plt.show()
构建神经网络的两个主要工具:torch.nn、torch.nn.functional。 —— 两者功能相同,且性能没有很大区别。
【官方推荐】具有学习参数的网络层,使用torch.nn.Module。如:卷积层、全连接层、Dropout层
【官网推荐】没有学习参数的网络层,使用torch.nn.functional。如:激活函数、池化层
两者主要区别:
(1)nn.Module中的网络层将继承Module类,会自动提取可学习参数(表现形式:nn.Xxx)
- 11、nn.Xxx能够与nn.Sequential结合使用。 —— 而nn.functional.xxx不能。
- 22、nn.Xxx不需要自定义和管理weight、bias参数,可自动计算。 —— 而nn.functional.xxx需要自定义且需要手动传入。
- 33、nn.Xxx定义Dropout,在调用module.eval()之后,可自动实现状态转换。 —— 而nn.functional.xxx不能。
(2)nn.functional更像是纯函数。(表现形式:nn.xxx)
实现神经网络的关键步骤:
(1)构建网络层:torch.nn.Sequential() 。 —— 将网络的层组合到一起。
(2)前向传播:forward()。 —— 将输入层、网络层、输出层连接起来
(3)后向传播:loss.backward()。 —— 选择损失函数和优化器
- 方法一:基于torch.autograd。 Tensor需设置requires_grad=True,然后调用backward(),最后再从grad属性中提取梯度。
- 方法二:基于torch.nn。 优化器实例化 -> 损失函数 -> optimizer.zero_grad() -> loss.backward() -> optimizer.step()
(4)训练与测试
- 训练模式:调用model.train()将所有的module设置为训练模式。
- 测试模式:调用model.eval()将所有的training属性设置为False
备注1:如果希望用GPU训练,调用.to(device)。 —— 将模型、训练数据、测试数据发送到GPU上。
备注2:如果希望用多GPU训练,可使模型或相关数据引用nn.DataParallel。
############################################
# 主要步骤:
# (1)利用Pytorch内置函数mnist下载数据。
# (2)利用torchvision对数据进行预处理,调用torch.utils建立一个数据迭代器。
# (3)可视化源数据
# (4)利用nn工具箱构建神经网络模型
# (5)实例化模型,并定义损失函数及优化器。
# (6)训练模型
# (7)可视化结果
############################################
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F
import torch.optim as optim
import torch.nn as nn
from torchvision.datasets import mnist # 导入内置的mnist数据
import torchvision.transforms as transforms # 导入图像预处理模块
from torch.utils.data import DataLoader
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' # "OMP: Error #15: Initializing libiomp5md.dll"
############################################
# (1)定义超参数
train_batch_size = 64
test_batch_size = 128
learning_rate = 0.01
num_epoches = 20
lr = 0.01
momentum = 0.5
############################################
# (2)下载数据,并进行数据预处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])
# 11、transforms.Compose()方法是将多种变换组合在一起。Compose()会将transforms列表里面的transform操作进行遍历。
# 22、torchvision.transforms.Normalize(mean, std):用给定的均值和标准差分别对每个通道的数据进行正则化。
# 单通道=[0.5], [0.5] ———— 三通道=[m1,m2,m3], [n1,n2,n3]
train_dataset = mnist.MNIST('./pytorch_knowledge', train=True, transform=transform, download=True)
test_dataset = mnist.MNIST('./pytorch_knowledge', train=False, transform=transform)
# download参数控制是否需要下载。如果目录下已有MNIST,可选择False。
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
############################################
# (3)可视化源数据
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
fig = plt.figure()
for i in range(6):
plt.subplot(2, 3, i+1)
plt.tight_layout()
plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
plt.title('Ground Truth:{}' .format((example_targets[i])))
plt.xticks(([]))
plt.yticks(([]))
plt.show()
############################################
# (4)构建网络模型
class Net(nn.Module):
# 使用Sequential构建网络,将网络的层组合到一起
def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
super(Net, self).__init__()
self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1), nn.BatchNorm1d(n_hidden_1))
self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2), nn.BatchNorm1d(n_hidden_2))
self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))
def forward(self, x):
x = F.relu(self.layer1(x))
x = F.relu(self.layer2(x))
x = self.layer3(x)
return x
if __name__ == '__main__':
############################################
# (5)检测是否有可用的GPU,有则使用,否则使用GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 实例化网络
model = Net(28*28, 300, 100, 10)
model.to(device)
# 定义损失函数和优化器
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
criterion = nn.CrossEntropyLoss()
############################################
# (6)训练模型
losses = []
acces = []
eval_losses = []
eval_acces = []
for epoch in range(num_epoches):
# 动态修改参数学习率
if epoch % 5 == 0:
optimizer.param_groups[0]['lr'] *= 0.1
# 训练集 #######################################
train_loss = 0
train_acc = 0
# 将模型切换为训练模式
model.train()
for img, label in train_loader:
img = img.to(device)
label = label.to(device)
img = img.view(img.size(0), -1)
out = model(img) # 前向传播
loss = criterion(out, label) # 损失函数
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 参数更新
# 记录误差
train_loss += loss.item()
# 记录分类的准确率
_, pred = out.max(1) # 提取分类精度最高的结果
num_correct = (pred == label).sum().item() # 汇总准确度
acc = num_correct / img.shape[0]
train_acc += acc
train_loss_temp = train_loss / len(train_loader) # 记录单次训练损失
train_acc_temp = train_acc / len(train_loader) # 记录单次训练准确度
losses.append(train_loss / len(train_loader))
acces.append(train_acc / len(train_loader))
# 测试集 #######################################
eval_loss = 0
eval_acc = 0
# 将模型切换为测试模式
model.eval()
for img, label in test_loader:
img = img.to(device)
label = label.to(device)
img = img.view(img.size(0), -1)
out = model(img) # 前向传播
loss = criterion(out, label) # 损失函数
# 记录误差
eval_loss += loss.item()
# 记录分类的准确率
_, pred = out.max(1) # 提取分类精度最高的结果
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
eval_acc += acc
eval_loss_temp = train_loss / len(train_loader) # 记录单次测试损失
eval_acc_temp = train_acc / len(train_loader) # 记录单次测试准确度
eval_losses.append(eval_loss / len(test_loader))
eval_acces.append(eval_acc / len(test_loader))
print('epoch:{}, Train_loss:{:.4f}, Train_Acc:{:.4f}, Test_loss:{:.4f}, Test_Acc:{:4f}'
.format(epoch, train_loss_temp, train_acc_temp, eval_loss_temp, eval_acc_temp))
# (7)可视化结果
plt.title('Train Loss')
plt.plot(np.arange(len(losses)), losses)
plt.legend(['train loss'], loc='upper right')
plt.xlabel('Steps') # 设置x轴标签
plt.ylabel('Loss') # 设置y轴标签
plt.ylim((0, 1.2)) # 设置y轴的数值显示范围:plt.ylim(y_min, y_max)
plt.show()
# 备注1:model.eval()的作用是不启用 Batch Normalization 和 Dropout。
# 备注2:model.train()的作用是启用 Batch Normalization 和 Dropout。
model.eval()和model.train()
Tensor自称是神经网络界的Numpy,它与Numpy相似,两者可以共享内存,且之间的转换非常方便和高效。
对Tensor的操作,按接口分为两类:(1)torch.function(2)tensor.function。两类操作对大部分Tensor都是等价的,依据个人爱好选择。
torch.device()
表示将torch.Tensor分配到指定设备上。torch.device()
包含两种设备类型:cpu与cuda。
# 方式一
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 检测是否有可用的GPU,有则使用,否则使用CPU。
# 方式二
if torch.cuda.is_available():
device = torch.device("cuda") # 表示分配到GPU设备上
else:
device = torch.device("cpu") # 表示分配到CPU设备上
data = data.to(device) # 表示将张量(data)分配到指定设备上
model = Model.to(device) # 表示将模型(Model)分配到指定设备上
torch.device()
包含可选的设备序号(多个GPU)。
torch_GPU_count = torch.cuda.device_count() # 获取GPU数量
# 以下两种方式等价。表示分配到序号0的GPU设备上
torch.device('cuda', 0)
torch.device('cuda:0')
如果没有显式指定设备序号(如:torch.device('cuda')
),则默认获取当前设备序号(torch.cuda.current_device()
),两个方式效果等同,但type()有所区别。
(1)CPU tensor转GPU tensor。cpu_tensor.cuda()
(2)GPU tensor 转CPU tensor。gpu_tensor.cpu()
(3)numpy转为CPU tensor。torch.from_numpy(numpy_test )
(4)CPU tensor转为numpy数据。cpu_tensor.numpy()
import torch
import numpy as np
####################################
# 生成 0~1 之间的随机数
np_ndarray = np.random.random([4, 4])
####################################
# (1)numpy转为 CPU tensor。
torch_tensor = torch.Tensor(np_ndarray)
torch_from = torch.from_numpy(np_ndarray)
# (2)CPU tensor转为numpy数据
torch_numpy = torch_tensor.numpy()
# 备注:'Tensor' object has no attribute 'copy'
torch_Tensor = torch.Tensor([3, 4]) # torch.Tensor(size) # 创建Tensor(支持List、tuple),只有一个元素且为列表
torch_eye = torch.eye(5) # torch.eye(size) # 创建指定大小的单位矩阵
torch_rand = torch.rand([3, 4]) # torch.rand(size) # 生成[0, 1]均匀分布数据
torch_randn = torch.randn([3, 4]) # torch.randn(size) # 生成[0, 1]标准正态分布数据 ———— 标准正态分布:服从均值为0,方差为1的分布。
torch_randint = torch.randint(10, [3, 4]) # torch.randint(high, size) # 创建size大小数组,元素值在0~high之间随机生成(torch.int64)
torch_ones = torch.ones([3, 4]) # torch.ones(size) # 创建size大小数组,元素全为1。
torch_zeros = torch.zeros([3, 4]) # torch.zeros(size) # 创建size大小数组,元素全为0。
torch_ones_like = torch.ones_like(torch_ones) # torch.ones_like(input) # 创建与input相同维度,元素全为1的数组。
torch_zeros_like = torch.zeros_like(torch_zeros) # torch.zeros_like(input) # 创建与input相同维度,元素全为0的数组。
torch_arange = torch.arange(0, 10, 3) # torch.arange(start, stop, step) # 在区间[start, end]上以步长step生成一个序列张量。
torch_linspace = torch.linspace(0, 10, 3) # torch.linspace(start, stop, num) # 生成线性等份向量:从start到stop
torch_logspace = torch.logspace(0, 10, 3) # torch.logspace(start, stop, num) # 生成log等份向量:从10^start到10^stop
torch_rand = torch.rand([3, 4]) # torch.rand(size) # 生成[0, 1]均匀分布数据
temp_numel = torch_rand.numel() # Tensor.numel # 计算Tensor元素个数
temp_dtype = torch_rand.dtype # Tensor.dtype # 查看Tensor数据类型
temp_ndim = torch_rand.ndim # Tensor.ndim # 查看数组维度数
temp_shape = torch_rand.shape # Tensor.shape # 查看Tensor形状
temp_size = torch_rand.size() # Tensor.size() # 查看Tensor形状
torch_rand = torch.rand([3, 4]) # torch.rand(size) # 生成[0, 1]均匀分布数据
torch_arange = torch.arange(0, 10, 3) # torch.arange(start, stop, step) # 在区间[start, end]上以步长step生成一个序列张量。
temp_reshape = torch_rand.reshape(1, 12) # Tensor.reshape() # 改变数组形状(不改变原数组,返回值为reshape后数组)
# temp_resize = torch_rand.resize(3, 4) # Tensor.resize() # 改变数组形状(不改变原数组,返回值为resize后数组)
# Tensor.resize()可以通过系统运行,但是有警告提示:non-inplace resize is deprecated(不推荐/已放弃使用resize())
temp_view = torch_rand.view(2, 6) # Tensor.view() # 改变数组形状(不改变原数组,返回值为view后数组)
temp_unsqueeze = torch.unsqueeze(torch_arange, 0) # torch.unsqueeze(Tensor, dim) # 添加一个维度(dim=0按行索引,dim=1按列索引)
temp_squeeze = torch.squeeze(torch_arange, 0) # torch.squeeze(Tensor, dim) # 压缩一个维度(dim=0按行索引,dim=1按列索引)
# (1)类型不同:torch.Tensor使用全局默认dtype(FloatTensor)。
# ———— 而torch.tensor是从数据中推断数据类型
# (2)定义不同:torch.Tensor(1)返回shape=1的张量,该值是随机初始化。
# ———— 而torch.tensor(1)返回整数为1的张量。
print('torch.Tensor.type(): ', torch.Tensor(1).type())
print('torch.tensor.type(): ', torch.tensor(1).type())
print('torch.Tensor.dtype(): ', torch.Tensor(1).dtype)
print('torch.tensor.dtype(): ', torch.tensor(1).dtype)
index3 = torch.Tensor([[0, 1, 1]]) # torch.Tensor(列表) # 生成32位浮点型Tensor
index2 = torch.FloatTensor([[0, 1, 1]]) # torch.FloatTensor(列表) # 生成32位浮点型Tensor(与torch.Tensor等价)
index1 = torch.IntTensor([[0, 1, 1]]) # torch.IntTensor(列表) # 生成32位整型Tensor(很少用)
index0 = torch.LongTensor([[0, 1, 1]]) # torch.LongTensor(列表) # 生成64位整型Tensor
print('torch.Tensor.dtype(): ', torch.FloatTensor([[0, 1, 1]]).dtype)
print('torch.tensor.dtype(): ', torch.LongTensor([[0, 1, 1]]).dtype)
torch_rand = torch.rand([3, 4]) # torch.rand(size) # 生成[0, 1]均匀分布数据
# (2.6.1)通过【索引】,获取第一行所有数据
torch_ind = torch_rand[0, :]
# (2.6.2)获取非0元素的下标:torch.nonzero(input)
torch_nonzero = torch.nonzero(torch_rand)
# (2.6.3)使用二元值获取数据:torch.masked_select(input, mask)
torch_masked_select = torch.masked_select(torch_rand, torch_rand > 0.1) # 获取大于0的值
# (2.6.4)在指定维度上,获取行/列数据:torch.index_select(input, dim, index)
# 输入参数:(1)input 索引对象(Tensor类型)
# (2)dim 0表示行索引,1表示列索引
# (3)index 数据的索引号(必须是LongTensor)
torch_index_select = torch.index_select(torch_rand, 1, torch.tensor([1, 3])) # 获取第1列和第3列的数据。
# (2.6.5)在指定维度上,获取与index形状一致的数据:torch.gather(Tensor, dim, index)
torch_gather = torch.gather(torch_rand, 1, torch.tensor([[1, 3]])) # 获取 1*3 大小的数据。
# (2.6.6)根据指定索引补充数据(gather的反操作):torch.scatter(dim, index, src)
torch_scatter = torch_rand.scatter(1, torch.tensor([[1, 3]]), torch_gather)
AA = np.arange(4).reshape(4, 1)
BB = np.arange(0, 3)
A1 = torch.from_numpy(AA) # torch.from_numpy(ndarray) # numpy的ndarray转换为torch的Tensor
B1 = torch.from_numpy(BB)
C1 = A1 + B1 # Tensor自动实现广播
# 均会创建新的Tensor,若需要就地操作,可使用下划线版本:abs_()
torch_add = torch.add(torch.Tensor([3.1, -4.92]), torch.Tensor([3, 4])) # torch.add(input1, input2) # 加法计算
torch_abs = torch.abs(torch.Tensor([3.1, -4.92])) # torch.abs(input) # 取绝对值
torch_sqrt = torch.sqrt(torch.Tensor([3.1, -4.92])) # torch.sqrt(input) # 开根号
torch_exp = torch.exp(torch.Tensor([3.1, -4.92])) # torch.exp(input) # 指数函数
torch_log = torch.log(torch.Tensor([3.1, -4.92])) # torch.log(input) # 以自然数e为底的对数函数
torch_pow = torch.pow(torch.Tensor([3.1, -4.92]), 2) # torch.pow(input, exponent) # 以exponent为底的幂函数
torch_sign = torch.sign(torch.Tensor([3.1, -4.92])) # torch.sign(input) # 取符号(1表示正,-1表示负)
torch_ceil = torch.ceil(torch.Tensor([3.1, -4.92])) # torch.ceil(input) # 向上取整
torch_floor = torch.floor(torch.Tensor([3.1, -4.92])) # torch.floor(input) # 向下取整
torch_sigmoid = torch.sigmoid(torch.Tensor([3.1, -4.92])) # torch.sigmoid(input) # 激活函数
torch_tanh = torch.tanh(torch.Tensor([3.1, -4.92])) # torch.tanh(input) # 激活函数
torch_softmax = torch.softmax(torch.Tensor([3.1, -4.92]), 0, torch.float32) # torch.softmax(input, dim, dtype) # 激活函数
# 可以对整个Tensor,也可以沿着指定维度操作
torch_lin = torch.linspace(1, 10, 6).view(2, 3) # 初始化线性等份向量Tensor并改变数组形状
torch_sum = torch.sum(torch_lin, 0) # torch.sum(input, dim) # 求和
torch_prod = torch.prod(torch_lin, 0) # torch.prod(input, dim) # 积运算
torch_cumsum = torch.cumsum(torch_lin, 0) # torch.cumsum(input, dim) # 对指定维度数据进行【累加】
torch_cumprod = torch.cumprod(torch_lin, 0) # torch.cumprod(input, dim) # 对指定维度数据进行【累积】
# 累加或累积的计算方式:dim=0表示第一列不变,后面的列依次在上一列基础上加/乘上自身的数。
torch_mean = torch.mean(torch_lin, 0) # torch.mean(input, dim) # 计算均值
torch_median = torch.median(torch_lin, 0) # torch.median(input, dim) # 计算中位数
torch_std = torch.std(torch_lin, 0) # torch.std(input, dim) # 计算标准差
torch_var = torch.var(torch_lin, 0) # torch.var(input, dim) # 计算方差
torch_norm = torch.norm(torch_lin, 1) # torch.norm(input, p) # 返回 p 阶范数(默认值p=2)
torch_dist = torch.dist(torch_lin, torch_lin-1, 2) # torch.dist(input1, input2, p) # 返回a,b之间的 p 阶范数(默认值p=2)
# 范数是一个函数,表示方式为:||X||
# 范数定义了向量空间里的距离,它的出现使得向量之间的比较成为了可能。
# 简单理解:范数可以把一组实数列表,映射成一个实数。
# L1范数:表示向量x中非零元素的绝对值之和。
# L2范数:表示向量元素的平方和再开平方。
# 一般是逐元素比较,也可以沿着指定维度操作
torch_lin1 = torch.linspace(1, 10, 6).view(2, 3) # 初始化线性等份向量Tensor并改变数组形状
torch_max = torch.max(torch_lin1, 0) # torch.max(input, dim) # 返回最大值
torch_min = torch.min(torch_lin1, 0) # torch.min(input, dim) # 返回最小值
torch_eq = torch.eq(torch_lin1, 2.8) # torch.eq(input, digit) # 相等比较:比较Tensor中的每个元素是否与digit相等
torch_ge = torch.ge(torch_lin1, 2.8) # torch.ge(input, digit) # 大于比较:比较Tensor中的每个元素是否大于digit
torch_le = torch.le(torch_lin1, 2.8) # torch.le(input, digit) # 小于比较:比较Tensor中的每个元素是否小于digit
torch_gt = torch.gt(torch_lin1, 2.8) # torch.gt(input, digit) # 大于等于比较:比较Tensor中的每个元素是否大于等于digit
torch_lt = torch.lt(torch_lin1, 2.8) # torch.lt(input, digit) # 小于等于比较:比较Tensor中的每个元素是否小于等于digit
torch_topk = torch.topk(torch_lin1, 1, 0) # torch.topk(input, k, dim) # 在指定维度上,分别取前K个最大值
torch_equal = torch.equal(torch_lin1, torch_lin1) # torch.equal(input1, input2) # 比较两个Tensor是否有相同的shape与值。
# 一种是逐元素乘法,另外一种是点积乘法
temp_a = torch.tensor([2, 3])
temp_b = torch.tensor([3, 4])
torch_dot = torch.dot(temp_a, temp_b) # torch.dot(input1, input2) # 对1D矩阵进行点积运算
temp_a1 = torch.randint(10, [2, 3])
temp_b1 = torch.randint(6, [3, 4])
torch_mm = torch.mm(temp_a1, temp_b1) # torch.mm(input1, input2) # 对2D矩阵进行点积运算(2*3)*(3*4)=(2*4)
temp_a2 = torch.randint(10, [2, 2, 3])
temp_b2 = torch.randint(6, [2, 3, 4])
torch_bmm = torch.bmm(temp_a2, temp_b2) # torch.bmm(input1, input2) # 对3D矩阵进行点积运算(2*2*3)*(2*3*4)=(2*2*4)
temp_mv = torch.mv(temp_a1, torch.arange(3)) # torch.mv(input1, input2) # 计算矩阵与向量乘法(2*3)*(3*1)=(2*1)
temp_t = torch.t(temp_a1) # torch.t(input) # 矩阵转置(只适用于<=2维数组)
torch_svd = torch.svd(torch.linspace(0, 6, 6).view(3, 2)) # torch.svd(input) # 计算SVD分解(至少是二维数组;torch.float32)
NumPy是使用Python进行科学计算的基础包。
- Numpy是Python的外部库,不在标准库中。因此调用前需先导入:
import numpy as np
- Numpy提供了两种基本的对象:ndarray(N-dimensional Array Object,多维数组对象)和ufunc(Universal Function Object)。
- Numpy官网(PDF免费下载):
http://www.Numpy.org/
import numpy as np
##########################
# 列表转换为数组
# np_list1 = np.array([3.14, 1], dtype=float) # 列表转换为ndarray(元组等同)
# np_list2 = np.array( [[3.14, 1], [1, 2]] ) # 嵌套列表转换为多维ndarray(元组等同)
##########################
# 创建特定形状的多维数组(可以指定数据类型)
np_eye = np.eye(5) # np.eye(5) # 创建5*5的单位矩阵。对角线为1,其余为0。
np_eye = np.diag([1, 2, 3]) # np.diag([1,2,3]) # 创建三阶对角矩阵。对角线分别为1,2,3,其余为0。
np_zeros = np.zeros((3, 4)) # np.zeros((3, 4)) # 创建3*4的元素全为0的数组。输入可为列表或元组。
np_ones = np.ones((3, 4)) # np.ones((3, 4)) # 创建3*4的元素全为1的数组。
np_empty = np.empty((3, 4)) # np.empty((3, 4)) # 创建3*4的空数组。空数组中的值不为0,而是未初始化的垃圾值。
np_full = np.full((3, 5), 666) # np.full((3, 5), 666) # 创建3*5的元素全为666的数组,666为指定值。
np_zeros_like = np.zeros_like(np_zeros) # np.zeros_like(arr) # 以arr相同维度创建元素全为0的数组。
np_ones_like = np.ones_like(np_zeros) # np.ones_like(arr) # 以arr相同维度创建元素全为1的数组。
np_empty_like = np.empty_like(np_zeros) # np.empty_like(arr) # 以arr相同维度创建空数组(未初始化的垃圾值)。
np_full_like = np.full_like(np_full , 666) # np.full_like(np_full , 666) # 以arr相同维度创建全为666的数组,666为指定值。
##########################
# 生成线性等份向量:np.linspace(start, stop, num, endpoint=True, retstep=False, dtype=None)
# 其中:endpoint默认为True;等份数量num默认为50;若retstep为True,则返回一个带步长的数组。
np_linspace = np.linspace(1, 1, 10)
##########################
# 生成指定范围向量
arr = np.arange(25)
# 提取数据(向量):1、获取指定位置的数据:arr[3] 2、截取片段数据:arr[3, 6]
# 3、截取固定间隔数据:arr[1:6:2] 4、倒序取数:arr[::-2]
# 提取数据(数组):5、截取多维数组的区域数据:arr[1:3, 1:2]
# 6、截取多维数组的条件数据:arr[(arr>3) & (arr<10)]
##########################
# np.random模块常用函数
np_uniform = np.random.uniform([1, 2]) # np.random.uniform() # 生成在[0,1)上均匀分布的随机数
np_rand = np.random.rand(5) # np.random.rand() # 生成在[0,1)上均匀分布的随机数
np_randn = np.random.randn(5) # np.random.rand() # 生成标准正态分布的随机数 ———— 标准正态分布:服从均值为0,方差为1的分布。
np_randint = np.random.randint([1, 2]) # np.random.randint() # 生成随机的整数 ———— (等同)用import random模块的randint()函数:生成随机的整数
np_normal = np.random.normal([1, 2]) # np.random.normal() # 生成正态分布
np_sample = np.random.sample([1, 2]) # np.random.sample() # 生成随机的浮点数
##########################
# 随机抽取数据(从指定数组中):np.random.choice(arr, size=(a, b), replace=True)
# 1、replace=True(默认),即可重复抽取数组中的值。 replace=False,不可重复抽取数组中的值。每个元素抽取概率相同。
# 2、arr必须是一维数组(可配合展平函数一起使用)
np_choice1 = np.random.choice(arr, size=(3, 4))
np_choice1 = np.random.choice(arr, size=(3, 4), p=arr/np.sum(arr)) # 参数p指定每个元素对应的抽取改概率
##########################
# 设置随机数种子:np.random.seed() ———— 将影响np.random模块的所有函数
# (1)每次运行程序,如果设置相同的seed()值,则每次生成的随机数都相同;若不设置则不相同。
# (2)若需要生成两个及以上相同的随机数:其一需要每次均调用seed()函数;其二需要seed()值均相同。
np.random.seed(123)
np_random1 = np.random.random([4, 4]) # np.random.random() # 生成0~1之间的随机数
np.random.seed(123) # 若删除该语句,则每次调用程序,两个数组分别生成的随机数恒定相同,但两个数组不等同。
np_random2 = np.random.random([4, 4])
print('np.random.random:', np_random1)
np.random.shuffle(np_random1) # np.random.shuffle() # 打乱生成的随机数
print('np.random.shuffle:', np_random1)
##########################
arr= np.random.random([4, 4]) # np.random.random() # 生成0~1之间的随机数
# arr.shape # 查看数组形状
# arr.size # 查看数组元素个数
# arr.ndim # 查看数组维度数
# arr.dtype # 查看数组数据类型
# arr.itemsize # 查看数组元素的字节大小
##########################
# 保存数据为txt文本:savetxt(arr, file_name) ———— 将覆盖原文本数据,若有
np.savetxt(X=np.eye(5), fname='1.txt')
A_arr = np.array([[3, 9], [3, 5.1]]) # 嵌套列表转换为多维ndarray
B_arr = np.array([[3, 9], [3, 5.1]]) # 嵌套列表转换为多维ndarray
##########################
# 1.3.1、逐元乘法(对应位置的元素相乘)
C1 = A_arr * B_arr # 数组(乘)数组 # 方法一:*
C2 = np.multiply(A_arr, B_arr) # 方法二:np.multipy()
C3 = A_arr * 2 # 数组(乘或除)数值
##########################
# 1.3.2、点积或内积元素:np.dot(A, B)
# 计算如下: A的第一行 * B的第一列 = C对应(1,1)的值。
# A(2*3) * B(3*2) = C(2*2)
np_dot = np.dot(A_arr, B_arr)
arr = np.arange(6).reshape(6, 1) # 向量/数组
arr_reshape = arr.copy().reshape(3, -1) # arr.reshape() # 改变数组维度(不改变原数组,返回值为reshape后数组)。'-1'表示系统自动计算改位置对应的值
arr_resize = arr.copy().resize(2, 3) # arr.resize() # 改变数组维度(改变原数组,返回值为None)
arr_T = arr.copy().T # arr.T # 数组转置
arr_reval = arr.copy().ravel('F') # arr.ravel() # 数组展平 ———— (默认)杭展平:arr.ravel(); 列展平:arr.ravel('F')
arr_flatten = arr.copy().flatten() # arr.flatten() # 数组转换为向量(行展平) ———— 应用于卷积网络与全连接层之间
arr_squeeze = arr.copy().squeeze().shape # arr.squeeze() # 对维数为1的数组降维,去掉1. ———— 对多维数组无效但不报错。
arr_trans = np.arange(75).reshape([5, 5, 3])
arr_transpose = arr_trans.transpose(1, 0, 2) # arr.transpose(1,0,2) # 对高维矩阵进行轴对换(012分别对应原数组的维度)———— 深度学习:RGB改为BGR
# np.append(A, B, axis=0) # 将数组B合并到A(占用内存大)
# np.concatenate(A, B, axis=0) # 沿指定轴连接数组或矩阵(没有内存问题)
#
# np.stack(A, B, axis=0) # 沿指定轴合并数组或矩阵 # 堆叠:stack
# np.vstack(A, B, C) # x轴合并(axis=0):多张图垂直的上下拼接 # 垂直:vertical
# np.hstack(A, B, C) # y轴合并(axis=1):多张图水平的左右拼接 # 水平:horizontal
# np.dstack(A, B, C) # z轴合并(axis=2):多张图摞在一起(举例:叠乌龟) # 深度:deep
#
# 注意1:np.append、np.concatenate 以及 np.stack ———— 都有axis参数,用于控制数组的合并方式。(默认)行:axis=0 ———— 列:axis=1
# 注意2:np.append 和 np.concatenate ———— 要求待合并的数组必须具有相同的行数或列数(满足其一即可)
# 注意3:np.vstack、np.hstack 以及 np.dstack ———— 要求待合并的数组必须具有相同的形状(shape)
# 可以对数据的每个元素进行操作
# (1)许多 ufunc 函数都是用 C 语言实现的,故计算速度非常快。
# (2)比 math 模块中的函数更灵活。 ———— math 模块的输入一般是标量,但 Numpy 中的函数可以使向量或矩阵,进而可以避免使用循环语句。
# 常用通用函数:
arr_ufunc = 0.5 + np.random.random(10) # 生成0~1之间的随机数
# 下述方法即可输入数值也可输入向量
np_sqrt = np.sqrt(arr_ufunc ) # np.sqrt() # 计算平方根
np_log = np.log(arr_ufunc ) # np.log/log10/log2() # 对数函数
np_exp = np.exp(arr_ufunc) # np.exp(arr) # 指数函数
np_sin = np.sin(arr_ufunc) # np.sin/cos(arr) # 三角函数
np_abs = np.abs(arr_ufunc) # np.abs(arr) # 计算平方根
np_power = np.power(arr_ufunc, 2) # np.power(arr, x) # 计算arr的x次方
# 下述方法只可输入向量
np_sum = np.sum(arr_ufunc) # np.sum(arr) # 求和
np_mean = np.mean(arr_ufunc) # np.mean(arr) # 计算均值
np_median = np.median(arr_ufunc) # np.median(arr) # 计算中位数
np_std = np.std(arr_ufunc) # np.std(arr) # 计算标准差
np_var = np.var(arr_ufunc) # np.var(arr) # 计算方差
np_corr = np.corrcoef(arr_ufunc, arr_ufunc-0.2) # np.corrcoef(arr1, arr2) # 计算相关系数
# 适用范围:当数组的shape不相等时
# 需满足下述四个必要条件:
# 条件1:所有输入数组都向最大维度的数组看齐,维度不足的数组则在最前面加1进行补齐。
# 条件2:输出数组的shape:取输入数组各个维度上的最大值。
# 条件3:当输入数组的某个轴的长度为1时,沿着此轴运算时都用(或复制)此轴上的第一组值。
# 条件4:【注意】如果输入数组的某个轴和输出数组的对应轴的长度相同或某个轴的长度为1时,则该数组能被用于计算,否则出错。
#
# (例如)目的:C=A+B 其中A为(4, 1)二维矩阵, B为一维数值(3,)
# 条件一:B向A看齐,把B变为(1, 3)
# 条件二:输出结果C=(4, 3)
# 条件三:将A的列数组复制两份拼成4*3;将B的行数据复制三份拼成4*3;然后A(4*3) + B(4*3)得到C(4*3)
A_mac = np.arange(4).reshape(4, 1)
B_mac = np.arange(0, 3)
C_mac = A_mac + B_mac
print('【广播机制】A_shape:{}, B_shape:{}, C_shape:{}' .format(A_mac.shape, B_mac.shape, C_mac.shape))
# 获取数据集 -> 随机打乱数据 -> 定义批数据大小(Batch) -> 批量处理(Mini-Batch)
data_train = np.random.randn(1000, 2, 3) # 三维矩阵,第一维为样本数,后两个为数据形状
np.random.shuffle(data_train)
batch_size = 100
for ii in range(0, len(data_train), batch_size):
batch_sum = np.sum(data_train[ii:ii+batch_size])
print('第{}批次,该批次的数据之和:{}' .format(int(ii/batch_size), batch_sum))