【Pytorch(三)】PyTorch 基础

简介: 【Pytorch(三)】PyTorch 基础

PyTorch 基础

0. 概述

在开始深度学习项目之前,选择一个合适的框架是非常重要的。常见的深度学习框架包括 TensorFlow, Keras, PyTorch, Caffe, Theano, CNTK, PaddlePaddle 等。本次实验我们将选用 PyTorch,并学习 PyTorch 的背景知识和一些基本使用方法。最后,我们将基于 PyTorch 搭建一个卷积神经网络 (Convolutional Neural Network, CNN),并在数据集上进行测试。

image.png

在介绍 PyTorch 之前,不得不先介绍 Torch。Torch 是一个有大量机器学习算法支撑的科学计算框架,是一个与 Numpy 类似的张量(Tensor) 操作库,其诞生已经有十年之久,但是真正起势得益于 Facebook 开源了大量 Torch 的深度学习模块和扩展。Torch 的特点在于特别灵活。但因其采用了小众的编程语言 Lua,在目前深度学习大部分都采用以 Python 为编程语言的大环境下,流行度不高,这也就有了 PyTorch 的出现。PyTorch 使用 Python 作为开发语言,其前身就是 Torch,底层和 Torch 框架一样,但是使用 Python 重写了很多内容。


PyTorch 是一个基于 Torch 的 Python 开源机器学习库,可用于计算机视觉、自然语言处理等任务。它主要由 Facebook 的人工智能小组开发,不仅能够实现强大的 GPU 加速,同时还支持动态神经网络,这一点是现在很多主流框架如 TensorFlow 都不支持的。同学们如果有兴趣也可以在课后了解一下 Google 公司开发的 TensorFlow,并和 PyTorch 对比,在未来进行相关研究或应用时,可以选择自己喜欢的深度学习框架。


与上次实验课利用 Numpy 手动搭建神经网络相比,PyTorch 为我们提供了如下几个高级功能:


它具有强大的 GPU 支持的张量计算功能,能够高效实现神经网络中的各种张量运算;

它能够自动实现反向传播过程中的求导运算,大大降低用户的工作量;

我们常用的神经网络组成模块如卷积层 (convolutional layer)、池化层 (pooling layer)、全连接层 (fully-connected layer)、各种激活函数 (activation functions) 等 PyTorch 都支持,对用户来讲使用非常方便。

目前除了 Facebook 之外,Twitter 和 GMU 等许多机构都采用了 PyTorch。


下面,我们就来学习 PyTorch 的基本用法。


PyTorch官方教程 https://pytorch.org/tutorials/beginner/basics/intro.html


http://deeplizard.com/learn/playlist/PLZbbT5o_s2xrfNyHZsM6ufI0iZENK9xgG


1. 导入 PyTorch

import torch
import torchvision
import numpy as np

查看 PyTorch 版本,是否可以使用GPU,以及 CUDA 的版本。


print(torch.__version__)
print(torch.cuda.is_available())
print(torch.version.cuda)
1.7.1+cu110
True
11.0

2. 张量(Tensor)

PyTorch 中的张量 (tensor) 与数组和矩阵类似,是一种特殊的数据结构。在 PyTorch 中,我们使用 tensor 来表示模型的输入、输出以及模型的参数等。PyTorch 中的 tensor 类似于 Numpy 中的数组类型(ndarrays),不同的是 tensor 运算可以在 GPU 或其他硬件加速器上高效快速的运行,而 Numpy 数组只能在 CPU 上运行。实际上,tensor 和 Numpy 数组通常可以共享相同的底层内存,从而消除类型转换时复制数据的需求。与此同时,tensor 也支持自动求导功能 (我们将在后面详细介绍)。如果你熟悉 Numpy 数组,那也将会对 tensor API 感到非常熟悉。


下图展示了一维张量到六维张量。其中零维张量也称为标量,一维张量称为向量,二维张量就是我们一般说的矩阵。


image.png


2.1 张量初始化 (Tensor Initialization)

初始化一个空张量

# create an empty tensor by calling the constructor of torch.Tensor class
t = torch.Tensor()
print(t)
tensor([])

由数据直接创建

# tensors can be created directly from data. The data type is automatically inferred.
data = [1, 2, 3, 4]
t1 = torch.Tensor(data)  # constuctor create the object with the default data type (float32)
print(t1)
print(t1.dtype)  # print the data type
tensor([1., 2., 3., 4.])
torch.float32
t2 = torch.tensor(data)  # the datatype will be int64
print(t2)
print(t2.dtype)
tensor([1, 2, 3, 4])
torch.int64
由 Numpy 数组创建 (反之亦可)
# tensors can be created from Numpy arrays (and vice versa)
np_arr = np.array([1,2,3,4])
t = torch.from_numpy(np_arr)  # they share the same memory
print(t)
print(t.dtype)
tensor([1, 2, 3, 4], dtype=torch.int32)
torch.int32

由 Numpy 数组创建的 tensor 与原数组共享存储空间,因此原数组一经变化,tensor 也会发生相应的改变。


np_arr[0] = 999
print(t)
tensor([999,   2,   3,   4], dtype=torch.int32)
由另一个 Pytorch tensor 创建
# the new tensor retains the properties (shape, datatype) of the argument tensor, unless explicitly overridden
t_ones = torch.ones_like(t2) # retains the properties of t_data
print(f"Ones Tensor: \n {t_ones} \n")
t_rand = torch.rand_like(t2, dtype=torch.float) # overrides the datatype of t_data
print(f"Random Tensor: \n {t_rand} \n"
Ones Tensor: 
 tensor([1, 1, 1, 1]) 
Random Tensor: 
 tensor([0.9006, 0.3040, 0.1702, 0.0847])
其他方式创建
# create tensors with random or constant values
shape = (2,3,)
rand_tensor = torch.rand(shape)  # 构建一个随机初始化的张量
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")
Random Tensor: 
 tensor([[0.6786, 0.6451, 0.3554],
        [0.7361, 0.1580, 0.8583]]) 
Ones Tensor: 
 tensor([[1., 1., 1.],
        [1., 1., 1.]]) 
Zeros Tensor: 
 tensor([[0., 0., 0.],
        [0., 0., 0.]])

2.2 张量的属性 (Attributes)

张量的属性描述了他们的形状 (shape)、数据类型 (datatype)、和存储设备。


print(f"Shape of rand_tensor: {rand_tensor.shape}")
print(f"Datatype of rand_tensor: {rand_tensor.dtype}")  # float32
print(f"Device tensor is stored on: {rand_tensor.device}")  # cpu
Shape of rand_tensor: torch.Size([2, 3])
Datatype of rand_tensor: torch.float32
Device tensor is stored on: cpu
print(f"Shape of t_ones: {t_ones.shape}")
print(f"Datatype of t_ones: {t_ones.dtype}")  # int64
print(f"Device tensor is stored on: {t_ones.device}")  # cpu
Shape of t_ones: torch.Size([4])
Datatype of t_ones: torch.int64
Device tensor is stored on: cpu

存储设备默认是 CPU,假如存在 GPU,可以使用如下命令将数据转移至 GPU


t_ones_gpu = t_ones.cuda()  # move the tensor to gpu
print(t_ones_gpu)  # you will see: tensor([1, 1, 1, 1], device='cuda:0')
tensor([1, 1, 1, 1], device='cuda:0')

请注意,tensor 之间的运算要求参与运算的 tensor 在相同的 “device”上


例如:


print("rand_tensor: \n", rand_tensor)
print("ones_tensor: \n", ones_tensor)
print("rand_tensor + ones_tensor: \n", rand_tensor+ones_tensor
rand_tensor: 
 tensor([[0.9118, 0.0866, 0.5149],
        [0.3336, 0.4063, 0.0159]])
ones_tensor: 
 tensor([[1., 1., 1.],
        [1., 1., 1.]])
rand_tensor + ones_tensor: 
 tensor([[1.9118, 1.0866, 1.5149],
        [1.3336, 1.4063, 1.0159]])

而以下代码运行时会报错,因为参与运算的 tensor 在不同的 “device” 上


print("t_ones: \n", t_ones_gpu)
print("t_rand: \n", t_rand)
print("t_ones + t_rand: \n", t_ones_gpu+t_rand)
t_ones: 
 tensor([1, 1, 1, 1], device='cuda:0')
t_rand: 
 tensor([0.7465, 0.8281, 0.3466, 0.7537])
 RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

2.3 高维张量

刚刚我们主要学习了一维张量,下面我们来看看高维张量。


dd = [[1,2,3], 
      [4,5,6], 
      [7,8,9]] # 2D python list
t = torch.tensor(dd)  # create a rank-2 tensor (dd and t have different memory allocation)
print("t.shape: \t\t", t.shape)
print("type(t): \t\t", type(t))
print("t.reshape(1, 9): \t", t.reshape(1, 9))  # reshape 操作可以变换张量的形状,我们会在下一节详细介绍
print("t.reshape(1, 9).shape: \t", t.reshape(1, 9).shape)
print("t.shape: \t\t", t.shape)  # 请注意,reshape 操作并不会更改原本的张量 t 的形状
t.shape:    torch.Size([3, 3])
type(t):    <class 'torch.Tensor'>
t.reshape(1, 9):   tensor([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
t.reshape(1, 9).shape:   torch.Size([1, 9])
t.shape:    torch.Size([3, 3])
dd = [[[1,2,3],[4,5,6],[7,8,9]],
      [[10,11,12],[13,14,15],[16,17,18]],
      [[19,20,21],[22,23,24],[25,26,27]]]  # 3D python list
t = torch.tensor(dd)  # create a rank-3 tensor
print("t.shape: \t\t", t.shape)
print("type(t): \t\t", type(t))
print("t.reshape(1, 9): \n", t.reshape(3, 9, 1))  # reshape 操作可以变换张量的形状,我们会在下一节详细介绍
print("t.reshape(1, 9).shape: \t", t.reshape(3, 9, 1).shape)
print("t.shape: \t\t", t.shape)  # 请注意,reshape 操作并不会更改原本的张量 t 的形状
t.shape:    torch.Size([3, 3, 3])
type(t):    <class 'torch.Tensor'>
t.reshape(1, 9): 
 tensor([[[ 1],
         [ 2],
         [ 3],
         [ 4],
         [ 5],
         [ 6],
         [ 7],
         [ 8],
         [ 9]],
        [[10],
         [11],
         [12],
         [13],
         [14],
         [15],
         [16],
         [17],
         [18]],
        [[19],
         [20],
         [21],
         [22],
         [23],
         [24],
         [25],
         [26],
         [27]]])
t.reshape(1, 9).shape:   torch.Size([3, 9, 1])
t.shape:    torch.Size([3, 3, 3])

3. 张量的基本运算

本节中,我们将学习如下几种张量基本运算:


3.1  reshape 操作


3.2  元素间操作 (element-wise operations)


3.3  访问操作 (access operations)


3.4  归约操作 (reduction operations)


3.1 Reshape 操作

Reshape 操作是 PyTorch 中最重要的张量操作之一,它可以用来变换张量的形状。我们会在之后构建神经网络、编写前向传播代码(forward() 函数)时用到它。


t = torch.tensor([
    [1,1,1,1], 
    [2,2,2,2], 
    [3,3,3,3]
], dtype=torch.float32)
print("t.size(): ", t.size()) # same as t.shape
print("t.shape: ", t.shape)
print("rank of tensor: ", len(t.shape)) # rank of the tensor (维度)
print("number of elements: ", t.numel()) # get the total # of elements in the tensor
t.size():  torch.Size([3, 4])
t.shape:  torch.Size([3, 4])
rank of tensor:  2
number of elements:  12
print("reshape(1,12): \n\t", t.reshape(1,12),"\n")
print("reshape(2,6): \n\t", t.reshape(2,6),"\n")
print("reshape(12,1): \n\t", t.reshape(12,1),"\n")
print("reshape(2,2,3): \n\t", t.reshape(2,2,3),"\n")  # we can change the rank from 2 to 3 using reshape
print("t.shape (should not change): ", t.shape)  # note that the shape of t is not changed!
reshape(1,12): 
  tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]]) 
reshape(2,6): 
  tensor([[1., 1., 1., 1., 2., 2.],
        [2., 2., 3., 3., 3., 3.]]) 
reshape(12,1): 
  tensor([[1.],
        [1.],
        [1.],
        [1.],
        [2.],
        [2.],
        [2.],
        [2.],
        [3.],
        [3.],
        [3.],
        [3.]]) 
reshape(2,2,3): 
  tensor([[[1., 1., 1.],
         [1., 2., 2.]],
        [[2., 2., 3.],
         [3., 3., 3.]]]) 
t.shape (should not change):  torch.Size([3, 4])

与 reshape 相关的一些其他操作:


squeeze 与 unsqueeze

squeeze: 消除张量中长度为 1 的维度


unsqueeze: 在张量中插入一个长度为 1 的维度


# squeeze:  remove the axes which has a length of 1
print(t.reshape(12,1).squeeze())
print(t.reshape(12,1).squeeze().shape)
print(t.reshape(1,12).squeeze())
print(t.reshape(1,12).squeeze().shape)
print(t)  # 注意原本的张量 t 不会被更改
tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.])
torch.Size([12])
tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.])
torch.Size([12])
tensor([[1., 1., 1., 1.],
        [2., 2., 2., 2.],
        [3., 3., 3., 3.]])
# unsqueeze: add a dimension with the length of 1
print(t.reshape(12).unsqueeze(dim=0)) 
print(t.reshape(12).unsqueeze(dim=0).shape)
print("")
print(t.reshape(12).unsqueeze(dim=1))
print(t.reshape(12).unsqueeze(dim=1).shape)
print("")
print(t)  # 注意原本的张量 t 不会被更改
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])
torch.Size([1, 12])
tensor([[1.],
        [1.],
        [1.],
        [1.],
        [2.],
        [2.],
        [2.],
        [2.],
        [3.],
        [3.],
        [3.],
        [3.]])
torch.Size([12, 1])
tensor([[1., 1., 1., 1.],
        [2., 2., 2., 2.],
        [3., 3., 3., 3.]])
concatenation (并置)
将两个 tensor 沿某个维度拼接起来
t1 = torch.tensor([[1,2,3],
                   [4,5,6,],
                   [7,8,9]], dtype=torch.int32)
t2 = torch.tensor([[0,0,0],
                   [0,0,0],
                   [0,0,0]], dtype=torch.int32)
print(torch.cat((t1,t2), dim=0))
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]], dtype=torch.int32)
print(torch.cat((t1,t2), dim=1))
1
tensor([[1, 2, 3, 0, 0, 0],
        [4, 5, 6, 0, 0, 0],
        [7, 8, 9, 0, 0, 0]], dtype=torch.int32)
t3 = torch.tensor([[0,0],
                   [0,0],
                   [0,0]], dtype=torch.int32)
torch.cat((t1,t3), dim=1)
tensor([[1, 2, 3, 0, 0],
        [4, 5, 6, 0, 0],
        [7, 8, 9, 0, 0]], dtype=torch.int32)
# 注意拼接时,tensor 的维度要对应的上。由于 t1 与 t3 在 dim1 上的长度不同,因此以下代码运行时会报错:
print(t1.shape[1])
print(t3.shape[1])
print(torch.cat((t1,t3), dim=0))
3
2
RuntimeError: Sizes of tensors must match except in dimension 0. Got 3 and 2 in dimension 1 (The offending index is 1)

3.2 元素间操作 (Element-Wise Operations)

与标量的加减乘除操作

t1 = torch.tensor([[1,2],
                   [3,4]], dtype=torch.float32)
print("t1 + 2: \n", t1 + 2)
print("t1.add(2): \n", t1.add(2), "\n")
print("t1 - 2: \n", t1 - 2)
print("t1.sub(2): \n", t1.sub(2), "\n")
print("t1 * 2: \n", t1 * 2)
print("t1.mul(2): \n", t1.mul(2), "\n")
print("t1 / 2: \n", t1 / 2)
print("t1.div(2): \n", t1.div(2), "\n")
t1 + 2: 
 tensor([[3., 4.],
        [5., 6.]])
t1.add(2): 
 tensor([[3., 4.],
        [5., 6.]]) 
t1 - 2: 
 tensor([[-1.,  0.],
        [ 1.,  2.]])
t1.sub(2): 
 tensor([[-1.,  0.],
        [ 1.,  2.]]) 
t1 * 2: 
 tensor([[2., 4.],
        [6., 8.]])
t1.mul(2): 
 tensor([[2., 4.],
        [6., 8.]]) 
t1 / 2: 
 tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])
t1.div(2): 
 tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])

tensor 间的加减乘除操作 (当两个 tensor 具有相同的形状)

t1 = torch.tensor([[1,2],
                   [3,4]], dtype=torch.float32)
t2 = torch.tensor([[1,3],
                   [-9,8]], dtype=torch.float32)
# element-wise computation between tensors:方式一
print("t1 + t2: \n", t1 + t2)
print("t1 - t2: \n", t1 - t2)
print("t1 * t2: \n", t1 * t2)
print("t1 / t2: \n", t1 / t2)
t1 + t2: 
 tensor([[ 2.,  5.],
        [-6., 12.]])
t1 - t2: 
 tensor([[ 0., -1.],
        [12., -4.]])
t1 * t2: 
 tensor([[  1.,   6.],
        [-27.,  32.]])
t1 / t2: 
 tensor([[ 1.0000,  0.6667],
        [-0.3333,  0.5000]])
# 方式二
print("t1.add(t2): \n", t1.add(t2))
print("t1.sub(t2): \n", t1.sub(t2))
print("t1.mul(t2): \n", t1.mul(t2))
print("t1.div(t2): \n", t1.div(t2))
t1.add(t2): 
 tensor([[ 2.,  5.],
        [-6., 12.]])
t1.sub(t2): 
 tensor([[ 0., -1.],
        [12., -4.]])
t1.mul(t2): 
 tensor([[  1.,   6.],
        [-27.,  32.]])
t1.div(t2): 
 tensor([[ 1.0000,  0.6667],
        [-0.3333,  0.5000]])
比较操作
# 方式1
print("t1 == t2: \n", t1 == t2, "\n")
print("t1 >= t2: \n", t1 >= t2, "\n")
print("t1 <= t2: \n", t1 <= t2, "\n")
print("t1 > t2: \n", t1 > t2, "\n")
print("t1 < t2: \n", t1 < t2, "\n")
t1 == t2: 
 tensor([[ True, False],
        [False, False]]) 
t1 >= t2: 
 tensor([[ True, False],
        [ True, False]]) 
t1 <= t2: 
 tensor([[ True,  True],
        [False,  True]]) 
t1 > t2: 
 tensor([[False, False],
        [ True, False]]) 
t1 < t2: 
 tensor([[False,  True],
        [False,  True]])
# 方式二
print("t1.eq(t2): \n", t1.eq(t2), "\n")
print("t1.ge(t2): \n", t1.ge(t2), "\n")
print("t1.le(t2): \n", t1.le(t2), "\n")
print("t1.gt(t2): \n", t1.gt(t2), "\n")
print("t1.lt(t2: \n", t1.lt(t2), "\n")
t1.eq(t2): 
 tensor([[ True, False],
        [False, False]]) 
t1.ge(t2): 
 tensor([[ True, False],
        [ True, False]]) 
t1.le(t2): 
 tensor([[ True,  True],
        [False,  True]]) 
t1.gt(t2): 
 tensor([[False, False],
        [ True, False]]) 
t1.lt(t2): 
 tensor([[False,  True],
        [False,  True]])

关于广播 (broadcast)

哪些情况下可以广播?


从 dim0 开始评估,如果该维度上两个 tensor 的长度是一样的,或其中一个 tensor 在该维度上长度为 1,则我们认为这两个 tensor 在该维度上是兼容的,可以通过广播进行元素间运算。若有任何一个维度上两个 tensor 不兼容,则不能进行元素间运算。


t3 = torch.tensor([[1,2,3]])
t4 = torch.tensor([[4],[5],[6]])
print('t3 shape: ', t3.shape)
print('t4 shape: ', t4.shape)
print(t3 + t4)
t3 shape:  torch.Size([1, 3])
t4 shape:  torch.Size([3, 1])
tensor([[5, 6, 7],
        [6, 7, 8],
        [7, 8, 9]])
# 思考:上面的单元发生了什么?
t3_broadcast = torch.cat((t3,t3,t3),dim=0)
print("t3_broadcast: \n", t3_broadcast)
t4_broadcast = torch.cat((t4,t4,t4),dim=1)
print("t4_broadcast: \n", t4_broadcast)
print(t3_broadcast+t4_broadcast)
t3_broadcast: 
 tensor([[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]])
t4_broadcast: 
 tensor([[4, 4, 4],
        [5, 5, 5],
        [6, 6, 6]])
tensor([[5, 6, 7],
        [6, 7, 8],
        [7, 8, 9]])
其他 element-wise 操作
print(t1.abs())
print(t1.sqrt()) # square root
print(t1.neg())
print(t1.neg().abs())
tensor([[1., 2.],
        [3., 4.]])
tensor([[1.0000, 1.4142],
        [1.7321, 2.0000]])
tensor([[-1., -2.],
        [-3., -4.]])
tensor([[1., 2.],
        [3., 4.]])

3.3 访问操作 (Access Operations)

# 方式一
t = torch.tensor([
    [0,1,0],
    [2,0,2],
    [0,3,0]
], dtype=torch.float32)
for item in t:  # tensor is iterable
    print(item)  # rank-1 tensor
for item in t[0]:
    print(item)  # rank-0 tensor

tensor([0., 1., 0.])
tensor([2., 0., 2.])
tensor([0., 3., 0.])
tensor(0.)
tensor(1.)
tensor(0.)

# 方式二
print(t[0])
print(t[1])
print(t[2])
print(t[0][0] + t[1][0] + t[2][0])  # data type: tensor!
tensor([0., 1., 0.])
tensor([2., 0., 2.])
tensor([0., 3., 0.])
tensor(2.)
print((t[0][0] + t[1][0] + t[2][0]).item())  # item(): 将元素提取出来(这是一个归约操作,我们会在下一小节细讲归约操作)

2.0

3.4 归约操作 (reduction operations)

print("t.sum(): \t", t.sum())  # 对全部元素求和,并返回一个零维 tensor
print("t.prod(): \t", t.prod())  # 对全部元素求积,并返回一个零维 tensor
print("t.mean(): \t", t.mean())  # 对全部元素求均值,并返回一个零维 tensor
print("t.std(): \t", t.std())  # 对全部元素求标准方差,并返回一个零维 tensor
t.sum():   tensor(8.)
t.prod():   tensor(0.)
t.mean():   tensor(0.8889)
t.std():   tensor(1.1667)
print(t.sum().item())  # 将元素从零维 tensor 中提取出来
8.0
print(t.numel())  # 计数元素个数,并返回一个标量
print(t.sum().numel())
9
1

归约操作可单独对某个维度进行


t = torch.tensor([
    [1,1,1,1], 
    [2,2,2,2], 
    [3,3,3,3]
], dtype=torch.float32)
print("t.sum(dim=0): \t", t.sum(dim=0))
print("t.sum(dim=1): \t", t.sum(dim=1), "\n") 
print("t.prod(dim=0): \t", t.prod(dim=0))
print("t.prod(dim=1): \t", t.prod(dim=1), "\n")
print("t.mean(dim=0): \t", t.mean(dim=0))
print("t.mean(dim=1): \t", t.mean(dim=1), "\n")
t.sum(dim=0):   tensor([6., 6., 6., 6.])
t.sum(dim=1):   tensor([ 4.,  8., 12.]) 
t.prod(dim=0):   tensor([6., 6., 6., 6.])
t.prod(dim=1):   tensor([ 1., 16., 81.]) 
t.mean(dim=0):   tensor([2., 2., 2., 2.])
t.mean(dim=1):   tensor([1., 2., 3.])

等一下我们在用 PyTorch 搭建神经网络时,需要用到两个特殊的规约操作:max 和 argmax。


其中 max 会返回给我们 tensor 中的最大值,而 argmax 则会返回最大值对应的索引。


# argmax method: tell us the index of the max value within a tensor
t = torch.tensor([[1,0,0,2],
                  [2,4,1,0],
                  [5,2,7,9]], dtype=torch.float32)
print(t.max())
print(t.argmax())
print(t.reshape(t.numel())[t.argmax()])
tensor(9.)
tensor(11)
tensor(9.)

max 和 argmax 也可以沿某个维度操作


# dim0
print(t.max(dim=0))
print(t.argmax(dim=0))
torch.return_types.max(
values=tensor([5., 4., 7., 9.]),
indices=tensor([2, 1, 2, 2]))
tensor([2, 1, 2, 2])
# dim1
print(t.max(dim=1))
print(t.argmax(dim=1))
torch.return_types.max(
values=tensor([2., 4., 9.]),
indices=tensor([3, 1, 3]))
tensor([3, 1, 3])

我们还可以直接使用 torch.max 函数,它会返回两个值,分别对应 dimX 上的最大值及其索引。


max_val, index = torch.max(t, dim=1) # return the max value in dim=1 and the corresponding index
print(max_val)
print(index)
tensor([2., 4., 9.])
tensor([3, 1, 3])

4. PyTorch Tensor 与 Python List 和 Aumpy Array 的转换

t1 = torch.tensor([
    [1,1,1,1], 
    [2,2,2,2], 
    [3,3,3,3]
], dtype=torch.float32)  # PyTorch tensor
print(type(t1.tolist()))  # transform the tensor to a python list
print(type(t1.numpy()))  # transform the tensor to a numpy array
print("")
t2 = torch.from_numpy(t1.numpy())  # transform a numpy array to a tensor (t2 is a tensor)
print(t2)
print("")
t1[0][0] =  999
print(t2) # t1 and t2 share the memory


tensor([[1., 1., 1., 1.],
        [2., 2., 2., 2.],
        [3., 3., 3., 3.]])
tensor([[999.,   1.,   1.,   1.],
        [  2.,   2.,   2.,   2.],
        [  3.,   3.,   3.,   3.]])

5. Tensor 综合练习

假设我们有三张图片,每张图片为RGB格式(三个通道),每个通道有3*3个像素点,具体信息如下:


图片1: R通道:像素点均取1.0  G通道:像素点均取2.0  B通道:像素点均取3.0


图片2: R通道:像素点均取1.02 B通道:像素点均取2.02 B通道:像素点均取3.0*2


图片3: R通道:像素点均取1.03 G通道:像素点均取2.03 B通道:像素点均取3.0*3


现在我们即将使用这三张图片训练一个全连接层:


1) 图片在 PyTorch 中通常用一个四维张量来表示,我们首先来构建这个四维张量。


下面,请分别写出图片1至3对应的 tensor t1,t2,t3(每张图片的维度为3,其中 dim0 对应通道,dim1 对应行,dim2 对应列)。然后,请通过两种不同方式,将三张图片组织在一起,形成一个四维张量 t_batch(其中,dim0 对应图片;dim1 对应通道;dim2 和 dim3 分别对应行和列)。[提示:例如,第一种方式可以采用 torch.unsqueeze + torch.cat 实现,第二种方式可以采用 torch.cat + reshape 实现。]


2) 请将该四维张量变换形状(reshape),并与如下权重矩阵进行运算(该层为全连接层,因此权重为二维张量)。这里我们将要用到 PyTorch 中的矩阵乘法运算 torch.mm(a, b)。


w = torch.tensor([[1,0,1,0,1,0,1,1,0,0,0,1,0,1,0,1,1,1,0,0,1,0,1,0,0,0,1],


[0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0],


[1,1,0,0,0,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,1]


], dtype=torch.float32)


3) 请问运算结果是什么形状的张量?每一个维度分别对应什么?请在实验报告中回答这些问题,并展示本段代码和运行结果,进行说明。


##################  Please finish the code ###################
# 列出 t1, t2, t3
# t1 = XXX
# t2 = t1*2
# t3 = t1*3
shape=(3,3,3)
t1=torch.ones(shape)
t1[1]*=2
t1[2]*=3
t2=t1*2
t3=t1*3
print(t1)
print(t2)
print(t3)
# 将 t1,t2,t3 组织起来 - 第一种方式:
# ...
# t_batch_1 = XXX
t_batch_1=torch.cat(((t1.unsqueeze(dim=0)),(t2.unsqueeze(dim=0)),(t3.unsqueeze(dim=0))),dim=0)
print(t_batch_1)
# 将 t1,t2,t3 组织起来 - 第二种方式:
# ...
# t_batch_2 = XXX
t_batch_2=torch.cat((t1,t2,t3),dim=0)
t_batch_2=t_batch_2.reshape(3,3,3,3)
# print(t_batch_2)
# 检查以上二者结果是否相同:
# t_batch = (t_batch_1 == t_batch_2)*t_batch_1
# print(t_batch)
t_batch = (t_batch_1 == t_batch_2)*t_batch_1
print(t_batch)
# 将 t_batch 变换形状,并与 w 运算,得到 t_out
# w = torch.tensor([[1,0,1,0,1,0,1,1,0,0,0,1,0,1,0,1,1,1,0,0,1,0,1,0,0,0,1],
#             [0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0],
#             [1,1,0,0,0,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,1],
#             [0,0,0,1,1,0,0,1,0,1,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,1,1]
# ], dtype=torch.float32)
# t_batch = t_batch.reshape(XXX,XXX)
# t_out = torch.mm(XXX,XXX)
# print(t_out)
w = torch.tensor([[1,0,1,0,1,0,1,1,0,0,0,1,0,1,0,1,1,1,0,0,1,0,1,0,0,0,1],
            [0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0],
            [1,1,0,0,0,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,1],
            [0,0,0,1,1,0,0,1,0,1,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,1,1]
], dtype=torch.float32)
t_batch = t_batch_1.reshape(3,27)
t_out = torch.mm(t_batch,w.T)
print(t_out)
########################### end ##############################
tensor([[[1., 1., 1.],
         [1., 1., 1.],
         [1., 1., 1.]],
        [[2., 2., 2.],
         [2., 2., 2.],
         [2., 2., 2.]],
        [[3., 3., 3.],
         [3., 3., 3.],
         [3., 3., 3.]]])
tensor([[[2., 2., 2.],
         [2., 2., 2.],
         [2., 2., 2.]],
        [[4., 4., 4.],
         [4., 4., 4.],
         [4., 4., 4.]],
        [[6., 6., 6.],
         [6., 6., 6.],
         [6., 6., 6.]]])
tensor([[[3., 3., 3.],
         [3., 3., 3.],
         [3., 3., 3.]],
        [[6., 6., 6.],
         [6., 6., 6.],
         [6., 6., 6.]],
        [[9., 9., 9.],
         [9., 9., 9.],
         [9., 9., 9.]]])
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],
         [[2., 2., 2.],
          [2., 2., 2.],
          [2., 2., 2.]],
         [[3., 3., 3.],
          [3., 3., 3.],
          [3., 3., 3.]]],
        [[[2., 2., 2.],
          [2., 2., 2.],
          [2., 2., 2.]],
         [[4., 4., 4.],
          [4., 4., 4.],
          [4., 4., 4.]],
         [[6., 6., 6.],
          [6., 6., 6.],
          [6., 6., 6.]]],
        [[[3., 3., 3.],
          [3., 3., 3.],
          [3., 3., 3.]],
         [[6., 6., 6.],
          [6., 6., 6.],
          [6., 6., 6.]],
         [[9., 9., 9.],
          [9., 9., 9.],
          [9., 9., 9.]]]])
tensor([[[[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]],
         [[2., 2., 2.],
          [2., 2., 2.],
          [2., 2., 2.]],
         [[3., 3., 3.],
          [3., 3., 3.],
          [3., 3., 3.]]],
        [[[2., 2., 2.],
          [2., 2., 2.],
          [2., 2., 2.]],
         [[4., 4., 4.],
          [4., 4., 4.],
          [4., 4., 4.]],
         [[6., 6., 6.],
          [6., 6., 6.],
          [6., 6., 6.]]],
        [[[3., 3., 3.],
          [3., 3., 3.],
          [3., 3., 3.]],
         [[6., 6., 6.],
          [6., 6., 6.],
          [6., 6., 6.]],
         [[9., 9., 9.],
          [9., 9., 9.],
          [9., 9., 9.]]]])
tensor([[24., 29., 29., 23.],
        [48., 58., 58., 46.],
        [72., 87., 87., 69.]])


相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
相关文章
|
6天前
|
TensorFlow 算法框架/工具
第2章 TensorFlow 基础
第2章 TensorFlow 基础
29 0
|
6天前
|
机器学习/深度学习 PyTorch TensorFlow
Pytorch 与 Tensorflow:深度学习的主要区别(1)
Pytorch 与 Tensorflow:深度学习的主要区别(1)
19 2
|
6天前
|
存储 机器学习/深度学习 PyTorch
|
6天前
|
TensorFlow 算法框架/工具
TensorFlow基础
TensorFlow基础
27 0
|
7月前
|
数据采集 PyTorch 算法框架/工具
PyTorch应用实战四:基于PyTorch构建复杂应用
PyTorch应用实战四:基于PyTorch构建复杂应用
61 0
|
8月前
|
机器学习/深度学习 人工智能 PyTorch
什么是Pytorch?
什么是Pytorch?
90 0
|
11月前
|
机器学习/深度学习 人工智能 并行计算
【PyTorch】Pytorch基础第0章
【PyTorch】Pytorch基础第0章
62 0
|
存储 PyTorch 算法框架/工具
pytorch汇总(一)
pytorch汇总(一)
248 0
pytorch汇总(一)
|
机器学习/深度学习 并行计算 算法
pytorch汇总(三)
pytorch汇总(三)
99 0
pytorch汇总(三)
|
机器学习/深度学习 PyTorch 算法框架/工具
pytorch汇总(二)
pytorch汇总(二)
139 0
pytorch汇总(二)