PyTorch 基础
0. 概述1. 导入 PyTorch2. 张量(Tensor)
2.1 张量初始化 (Tensor Initialization)2.2 张量的属性 (Attributes)2.3 高维张量 3. 张量的基本运算
3.1 Reshape *** 作3.2 元素间 *** 作 (Element-Wise Operations)3.3 访问 *** 作 (Access Operations)3.4 归约 *** 作 (reduction operations) 4. PyTorch Tensor 与 Python List 和 Aumpy Array 的转换5. Tensor 综合练习
PyTorch 基础 0. 概述在开始深度学习项目之前,选择一个合适的框架是非常重要的。常见的深度学习框架包括 TensorFlow, Keras, PyTorch, Caffe, Theano, CNTK, PaddlePaddle 等。本次实验我们将选用 PyTorch,并学习 PyTorch 的背景知识和一些基本使用方法。最后,我们将基于 PyTorch 搭建一个卷积神经网络 (Convolutional Neural Network, CNN),并在数据集上进行测试。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eTXI6ZNb-1642942422380)(C:Users张清望AppDataRoamingTyporatypora-user-imagesimage-20220123192851747.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. 导入 PyTorchimport 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.02. 张量(Tensor)
PyTorch 中的张量 (tensor) 与数组和矩阵类似,是一种特殊的数据结构。在 PyTorch 中,我们使用 tensor 来表示模型的输入、输出以及模型的参数等。PyTorch 中的 tensor 类似于 Numpy 中的数组类型(ndarrays),不同的是 tensor 运算可以在 GPU 或其他硬件加速上高效快速的运行,而 Numpy 数组只能在 CPU 上运行。实际上,tensor 和 Numpy 数组通常可以共享相同的底层内存,从而消除类型转换时复制数据的需求。与此同时,tensor 也支持自动求导功能 (我们将在后面详细介绍)。如果你熟悉 Numpy 数组,那也将会对 tensor API 感到非常熟悉。
下图展示了一维张量到六维张量。其中零维张量也称为标量,一维张量称为向量,二维张量就是我们一般说的矩阵。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rLw2f2U5-1642942422381)(C:Users张清望AppDataRoamingTyporatypora-user-imagesimage-20220123194000385.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: tt", t.shape) print("type(t): tt", 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: tt", t.shape) # 请注意,reshape *** 作并不会更改原本的张量 t 的形状
t.shape: torch.Size([3, 3]) type(t):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: tt", t.shape) print("type(t): tt", 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: tt", t.shape) # 请注意,reshape *** 作并不会更改原本的张量 t 的形状
t.shape: torch.Size([3, 3, 3]) type(t):3. 张量的基本运算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.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): nt", t.reshape(1,12),"n") print("reshape(2,6): nt", t.reshape(2,6),"n") print("reshape(12,1): nt", t.reshape(12,1),"n") print("reshape(2,2,3): nt", 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))
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.03.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
5. Tensor 综合练习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.]])
假设我们有三张图片,每张图片为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.]])
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)