Pytorch的基本使用

目录

一、张量(Tensor)

基本类型

Numpy转换

初始化

二、神经网络包nn和优化器optm

定义一个网络

损失函数

优化器

三、数据的加载和预处理

Dataset

Dataloader

torchvision 包


一、张量(Tensor)

张量的英文是Tensor,它是PyTorch里面基础的运算单位,与Numpy的ndarray相同都表示的是一个多维的矩阵。 与ndarray的最大区别就是,PyTorch的Tensor可以在 GPU 上运行,而 numpy 的 ndarray 只能在 CPU 上运行,在GPU上运行大大加快了运算速度。

生成一个简单的张量:

x = torch.rand(2,3)
print(x)
# tensor([[0.6904, 0.7419, 0.8010],
#        [0.1722, 0.2442, 0.8181]])

以上生成了一个,2行3列的的矩阵,我们看一下他的大小:

# 可以使用与numpy相同的shape属性查看
print(x.shape)
# torch.Size([2, 3])
# 也可以使用size()函数,返回的结果都是相同的
print(x.size())
# torch.Size([2, 3])

张量(Tensor)是一个定义在一些向量空间和一些对偶空间的笛卡儿积上的多重线性映射,其坐标是|n|维空间内,有|n|个分量的一种量, 其中每个分量都是坐标的函数, 而在坐标变换时,这些分量也依照某些规则作线性变换。r称为该张量的秩或阶(与矩阵的秩和阶均无关系)

可以生成一个多维张量:

y=torch.rand(2,3,4,5)
print(y.size())
# torch.Size([2, 3, 4, 5])
y
tensor([[[[0.9071, 0.0616, 0.0006, 0.6031, 0.0714],
#           [0.6592, 0.9700, 0.0253, 0.0726, 0.5360],
#           [0.5416, 0.1138, 0.9592, 0.6779, 0.6501],
#           [0.0546, 0.8287, 0.7748, 0.4352, 0.9232]],

#          [[0.0730, 0.4228, 0.7407, 0.4099, 0.1482],
#           [0.5408, 0.9156, 0.6554, 0.5787, 0.9775],
#           [0.4262, 0.3644, 0.1993, 0.4143, 0.5757],
#           [0.9307, 0.8839, 0.8462, 0.0933, 0.6688]],

#          [[0.4447, 0.0929, 0.9882, 0.5392, 0.1159],
#           [0.4790, 0.5115, 0.4005, 0.9486, 0.0054],
#           [0.8955, 0.8097, 0.1227, 0.2250, 0.5830],
#           [0.8483, 0.2070, 0.1067, 0.4727, 0.5095]]],


#         [[[0.9438, 0.2601, 0.2885, 0.5457, 0.7528],
#           [0.2971, 0.2171, 0.3910, 0.1924, 0.2570],
#           [0.7491, 0.9749, 0.2703, 0.2198, 0.9472],
#           [0.1216, 0.6647, 0.8809, 0.0125, 0.5513]],

#          [[0.0870, 0.6622, 0.7252, 0.4783, 0.0160],
#           [0.7832, 0.6050, 0.7469, 0.7947, 0.8052],
#           [0.1755, 0.4489, 0.0602, 0.8073, 0.3028],
#           [0.9937, 0.6780, 0.9425, 0.0059, 0.0451]],

#          [[0.3851, 0.8742, 0.5932, 0.4899, 0.8354],
#           [0.8577, 0.3705, 0.0229, 0.7097, 0.7557],
#           [0.1505, 0.3527, 0.0843, 0.0088, 0.8741],
#           [0.6041, 0.8797, 0.6189, 0.9495, 0.1479]]]])

在同构的意义下,第零阶张量 (r = 0) 为标量 (Scalar),第一阶张量 (r = 1) 为向量 (Vector), 第二阶张量 (r = 2) 则成为矩阵 (Matrix),第三阶以上的统称为多维张量。

对于标量:

# 我们直接使用现有数字生成
scalar =torch.tensor(3.1433223)
print(scalar)
# tensor(3.1433)
# 打印标量的大小
scalar.size()
# torch.Size([])

对于标量,我们可以直接使用 .item() 从中取出其对应的python对象的数值;特别地,如果张量中只有一个元素的tensor也可以调用tensor.item方法

scalar.item()
# 3.143322229385376

# 如果张量中只有一个元素的tensor
tensor = torch.tensor([3.1433223]) 
print(tensor)
# tensor([3.1433])
tensor.size()
# torch.Size([1])
tensor.item()
# 3.143322229385376

基本类型

Tensor的基本数据类型有五种:

  • 32位浮点型:torch.FloatTensor。 (默认)
  • 64位整型:torch.LongTensor。
  • 32位整型:torch.IntTensor。
  • 16位整型:torch.ShortTensor。
  • 64位浮点型:torch.DoubleTensor。

除以上数字类型外,还有 byte和chart型

long=tensor.long()
long
# tensor([3])

half=tensor.half()
half
# tensor([3.1426], dtype=torch.float16)

int_t=tensor.int()
int_t
# tensor([3], dtype=torch.int32)

flo = tensor.float()
flo
# tensor([3.1433])

short = tensor.short()
short
# tensor([3], dtype=torch.int16)

ch = tensor.char()
ch
# tensor([3], dtype=torch.int8)

bt = tensor.byte()
bt
# tensor([3], dtype=torch.uint8)

Numpy转换

使用numpy方法将Tensor转为ndarray

a = torch.randn((3, 2))
# tensor转化为numpy
numpy_a = a.numpy()
print(numpy_a)

numpy转化为Tensor

torch_a = torch.from_numpy(numpy_a)

Tensor和numpy对象共享内存,所以他们之间的转换很快,而且几乎不会消耗什么资源。但这也意味着,如果其中一个变了,另外一个也会随之改变。

初始化

Pytorch中有许多默认的初始化方法可以使用

# 使用[0,1]均匀分布随机初始化二维数组
rnd = torch.rand(5, 3)
rnd

# tensor([[0.3804, 0.0297, 0.5241],
#         [0.4111, 0.8887, 0.4642],
#         [0.7302, 0.5913, 0.7182],
#         [0.3048, 0.8055, 0.2176],
#         [0.6195, 0.1620, 0.7726]])

# 初始化,使用1填充
one = torch.ones(2, 2)
one
# tensor([[1., 1.],
#         [1., 1.]])

# 初始化,使用0填充
zero=torch.zeros(2,2)
zero
# tensor([[0., 0.],
#        [0., 0.]])

# 初始化一个单位矩阵,即对角线为1 其他为0
eye=torch.eye(2,2)
eye
# tensor([[1., 0.],
#        [0., 1.]])

二、神经网络包nn和优化器optm

torch.nn是专门为神经网络设计的模块化接口。nn构建于 Autograd之上,可用来定义和运行神经网络。 这里我们主要介绍几个一些常用的类

约定:torch.nn 我们为了方便使用,会为他设置别名为nn,本章除nn以外还有其他的命名约定

除了nn别名以外,我们还引用了nn.functional,这个包中包含了神经网络中使用的一些常用函数,这些函数的特点是,不具有可学习的参数(如ReLU,pool,DropOut等),这些函数可以放在构造函数中,也可以不放,但是这里建议不放。

一般情况下我们会将nn.functional 设置为大写的F,这样缩写方便调用 

import torch.nn.functional as F

定义一个网络

PyTorch中已经为我们准备好了现成的网络模型,只要继承nn.Module,并实现它的forward方法,PyTorch会根据autograd,自动实现backward函数,在forward函数中可使用任何tensor支持的函数,还可以使用if、for循环、print、log等Python语法,写法和标准的Python写法一致。

class Net(nn.Module):
    def __init__(self):
        # nn.Module子类的函数必须在构造函数中执行父类的构造函数
        super(Net, self).__init__()
        
        # 卷积层 '1'表示输入图片为单通道, '6'表示输出通道数,'3'表示卷积核为3*3
        self.conv1 = nn.Conv2d(1, 6, 3) 
        #线性层,输入1350个特征,输出10个特征
        self.fc1   = nn.Linear(1350, 10)  #这里的1350是如何计算的呢?这就要看后面的forward函数
    #正向传播 
    def forward(self, x): 
        print(x.size()) # 结果:[1, 1, 32, 32]
        # 卷积 -> 激活 -> 池化 
        x = self.conv1(x) #根据卷积的尺寸计算公式,计算结果是30,具体计算公式后面第二章第四节 卷积神经网络 有详细介绍。
        x = F.relu(x)
        print(x.size()) # 结果:[1, 6, 30, 30]
        x = F.max_pool2d(x, (2, 2)) #我们使用池化层,计算结果是15
        x = F.relu(x)
        print(x.size()) # 结果:[1, 6, 15, 15]
        # reshape,‘-1’表示自适应
        #这里做的就是压扁的操作 就是把后面的[1, 6, 15, 15]压扁,变为 [1, 1350]
        x = x.view(x.size()[0], -1) 
        print(x.size()) # 这里就是fc1层的的输入1350 
        x = self.fc1(x)        
        return x

net = Net()
print(net)

# Net(
#  (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
#  (fc1): Linear(in_features=1350, out_features=10, bias=True)
# )

网络的可学习参数通过net.parameters()返回

for parameters in net.parameters():
    print(parameters)

net.named_parameters可同时返回可学习的参数及名称。

for name,parameters in net.named_parameters():
    print(name,':',parameters.size())


# conv1.weight : torch.Size([6, 1, 3, 3])
# conv1.bias : torch.Size([6])
# fc1.weight : torch.Size([10, 1350])
# fc1.bias : torch.Size([10])

forward函数的输入和输出都是Tensor

input = torch.randn(1, 1, 32, 32) # 这里的对应前面fforward的输入是32
out = net(input)
out.size()

# torch.Size([1, 1, 32, 32])
# torch.Size([1, 6, 30, 30])
# torch.Size([1, 6, 15, 15])
# torch.Size([1, 1350])
# torch.Size([1, 10])

在反向传播前,先要将所有参数的梯度清零

net.zero_grad() 
out.backward(torch.ones(1,10)) # 反向传播的实现是PyTorch自动实现的,我们只要调用这个函数即可

注意:torch.nn只支持mini-batches,不支持一次只输入一个样本,即一次必须是一个batch。

也就是说,就算我们输入一个样本,也会对样本进行分批,所以,所有的输入都会增加一个维度,我们对比下刚才的input,nn中定义为3维,但是我们人工创建时多增加了一个维度,变为了4维,最前面的1即为batch-size

损失函数

在nn中PyTorch还预制了常用的损失函数,下面我们用MSELoss用来计算均方误差

y = torch.arange(0,10).view(1,10).float()
criterion = nn.MSELoss()
loss = criterion(out, y)
#loss是个scalar,我们可以直接用item获取到他的python类型的数值
print(loss.item())

# 28.92203712463379

优化器

在反向传播计算完所有参数的梯度后,还需要使用优化方法来更新网络的权重和参数,例如随机梯度下降法(SGD)的更新策略如下:

weight = weight - learning_rate * gradient

在torch.optim中实现大多数的优化方法,例如RMSProp、Adam、SGD等,下面我们使用SGD做个简单的样例

import torch.optim
out = net(input) # 这里调用的时候会打印出我们在forword函数中打印的x的大小
criterion = nn.MSELoss()
loss = criterion(out, y)
#新建一个优化器,SGD只需要要调整的参数和学习率
optimizer = torch.optim.SGD(net.parameters(), lr = 0.01)
# 先梯度清零(与net.zero_grad()效果一样)
optimizer.zero_grad() 
loss.backward()

#更新参数
optimizer.step()

这样,神经网络的数据的一个完整的传播就已经通过PyTorch实现了

三、数据的加载和预处理

PyTorch通过torch.utils.data对一般常用的数据加载进行了封装,可以很容易地实现多线程数据预读和批量加载。 并且torchvision已经预先实现了常用图像数据集,包括CIFAR-10,ImageNet、COCO、MNIST、LSUN等数据集,可通过torchvision.datasets方便的调用

Dataset

class torch.utils.data.TensorDataset(data_tensor, target_tensor)

包装数据和目标张量的数据集。

通过沿着第一个维度索引两个张量来恢复每个样本。

参数:

  • data_tensor (Tensor) - 包含样本数据
  • target_tensor (Tensor) - 包含样本目标(标签)

Dataset是一个抽象类,为了能够方便的读取,需要将要使用的数据包装为Dataset类。 自定义的Dataset需要继承它并且实现两个成员方法:

  1. __getitem__() 该方法定义用索引(0 到 len(self))获取一条数据或一个样本
  2. __len__() 该方法返回数据集的总长度

下面我们使用kaggle上的一个竞赛bluebook for bulldozers自定义一个数据集,为了方便介绍,我们使用里面的数据字典来做说明(因为条数少)

#引用
from torch.utils.data import Dataset
import pandas as pd

#定义一个数据集
class BulldozerDataset(Dataset):
    """ 数据集演示 """
    def __init__(self, csv_file):
        """实现初始化方法,在初始化的时候将数据读载入"""
        self.df=pd.read_csv(csv_file)
    def __len__(self):
        '''
        返回df的长度
        '''
        return len(self.df)
    def __getitem__(self, idx):
        '''
        根据 idx 返回一行数据
        '''
        return self.df.iloc[idx].SalePrice

至此,我们的数据集已经定义完成了,我们可以实例话一个对象访问他

ds_demo= BulldozerDataset('median_benchmark.csv')

#实现了 __len__ 方法所以可以直接使用len获取数据总数
len(ds_demo)

#用索引可以直接访问对应的数据,对应 __getitem__ 方法
ds_demo[0]

自定义的数据集已经创建好了,下面我们使用官方提供的数据载入器,读取数据

Dataloader

DataLoader为我们提供了对Dataset的读取操作,常用参数有:batch_size(每个batch的大小)、 shuffle(是否进行shuffle操作)、 num_workers(加载数据的时候使用几个子进程)。下面做一个简单的操作

class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=, pin_memory=False, drop_last=False)

数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。

参数:

  • dataset (Dataset) – 加载数据的数据集。
  • batch_size (int, optional) – 每个batch加载多少个样本(默认: 1)。
  • shuffle (bool, optional) – 设置为True时会在每个epoch重新打乱数据(默认: False).
  • sampler (Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数。
  • num_workers (int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认: 0)
  • collate_fn (callable, optional) –
  • pin_memory (bool, optional) –
  • drop_last (bool, optional) – 如果数据集大小不能被batch size整除,则设置为True后可删除最后一个不完整的batch。如果设为False并且数据集的大小不能被batch size整除,则最后一个batch将更小。(默认: False)

DataLoader返回的是一个可迭代对象,我们可以使用迭代器分次获取数据

idata=iter(dl)
print(next(idata))

# tensor([24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000.,
#        24000.], dtype=torch.float64)

常见的用法是使用for循环对其进行遍历

for i, data in enumerate(dl):
# for i,(batch_x,batch_y) in enumerate(dl):
    print(i,data)
#   print(i,batch_x,batch_y)
    # 为了节约空间,这里只循环一遍
    break

我们已经可以通过dataset定义数据集,并使用Datalorder载入和遍历数据集,除了这些以外,PyTorch还提供能torcvision的计算机视觉扩展包

torchvision 包

torchvision 是PyTorch中专门用来处理图像的库,PyTorch官网的安装教程中最后的pip install torchvision 就是安装这个包。

torchvision.datasets

torchvision.datasets 可以理解为PyTorch团队自定义的dataset,这些dataset帮我们提前处理好了很多的图片数据集,我们拿来就可以直接使用:

  • MNIST
  • COCO
  • Captions
  • Detection
  • LSUN
  • ImageFolder
  • Imagenet-12
  • CIFAR
  • STL10
  • SVHN
  • PhotoTour 我们可以直接使用,示例如下:
import torchvision.datasets as datasets
trainset = datasets.MNIST(root='./data', # 表示 MNIST 数据的加载的目录
                                      train=True,  # 表示是否加载数据库的训练集,false的时候加载测试集
                                      download=True, # 表示是否自动下载 MNIST 数据集
                                      transform=None) # 表示是否需要对数据进行预处理,none为不进行预处理

torchvision.models

torchvision不仅提供了常用图片数据集,还提供了训练好的模型,可以加载之后,直接使用,或者在进行迁移学习 torchvision.models模块的 子模块中包含以下模型结构。

  • AlexNet
  • VGG
  • ResNet
  • SqueezeNet
  • DenseNet
# 我们直接可以使用训练好的模型,当然这个与datasets相同,都是需要从服务器下载的
import torchvision.models as models
resnet18 = models.resnet18(pretrained=True)

torchvision.transforms

transforms 模块提供了一般的图像转换操作类,用作数据处理和数据增强

from torchvision import transforms as transforms
transform = transforms.Compose([
    transforms.RandomCrop(32, padding=4),  #先四周填充0,在把图像随机裁剪成32*32
    transforms.RandomHorizontalFlip(),  #图像一半的概率翻转,一半的概率不翻转
    transforms.RandomRotation((-45,45)), #随机旋转
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.229, 0.224, 0.225)), #R,G,B每层的归一化用到的均值和方差
])

 

你可能感兴趣的:(Pytorch,深度学习,pytorch)