深度学习第一节

pytorch是广泛应用于机器学习领域的强大开源框架,因其易用性和高效性备受青睐。其中 pytorch的核心数据类型是张量对象。 pytorch提供了许多帮助构建神经网络的高级方法及组件,并提供了利用GPU更快的训练神经网络的张量对象。

张量类似于Numpy中的多为矩阵ndarrays,标量可以表示为零维张量,向量可以表示为一维张量,二维矩阵可以表示为二维矩阵,多维矩阵可以表示为多维张量。

PyTorch 中的张量(Tensor)和 NumPy 中的 ndarray相比,pytorch张量对象经过优化配合gpu使用。

数据基本操作

1.导入pytorch并通过在列表上调用torch.tensor来初始化张量

import torch
x = torch.tensor([[1,2]])
y = torch.tensor([[1],[2]])

2.内置函数快速生成张量

x = torch.arange(12)
#tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
​
x = torch.zeros((2,3,4))
#tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],
​
        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])
         
x = torch.ones((2,3,4))
#tensor([[[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]],
​
        [[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]]])
         
#随机填充
c = torch.randint(low=0,high=10,size=(3,4))
#每个元素为0到10之间的随机整数值
#tensor([[4, 5, 5, 4],
         [1, 5, 3, 2],
         [3, 5, 7, 6]])
​
d = torch.rand(3,4)
#每个元素为0到1之间的随机浮点值
#tensor([[0.0413, 0.9341, 0.4687, 0.3344],
         [0.1153, 0.6723, 0.3727, 0.3245],
         [0.6182, 0.1326, 0.9461, 0.5833]])
​
e = torch.randn((3,4))
# 每个元素服从正态分布
#tensor([[ 0.1260,  1.5217, -0.0127,  2.3229],
         [ 0.5907,  0.1080, -0.5392,  0.9487],
         [ 1.0874, -0.0342,  0.9897, -1.0400]])

3.获取张量对象的形状和数据类型

x.shape
x.dtype

注意:同一张量的所有元素的数据类型相同,这意味着如果张量包含不同数据类型的数据(例如布尔、整数和浮点数),则整个张量被强制转换为最通用的数据类型:

x = torch.tensor([False,1,2.0])
print(x)
#tensor([0.,1.,2.])

4.numpy中 ndarray可以转换为tensor

A = X.numpy()
B = torch.tensor(A)
#type(A),type(B)
#(numpy.ndarray, torch.Tensor)
​
注意:只有一个元素可以转换为标量
a = torch.tensor([3.5])
#a,a.item,float(a),int(a)
#tensor([3.5000]), <function Tensor.item>, 3.5, 3

5.原地操作内存地址不变

Y = torch.arange(12)
before = id(Y)
Y = x+y
#id(Y) == before
#False
#内存地址变化
​
Y = torch.arange(12).reshape((2,6))
before = id(Y)
X = x.reshape((2,6))
Y[:] = X+Y
#id(Y) == before
#True
#原地操作内存地址不变化

6.张量运算

神经网络中常见运算包括输入与权重的矩阵相乘,添加偏置项,以及需要时整形(reshape)输入或权重值。

每个元素×10,每个元素+10
A = torch.tensor([[1,2,3,4],[3,4,5,6]])
#A*10,A+10,A.add(10)
#tensor([[10, 20, 30, 40],
         [30, 40, 50, 60]]),
 tensor([[11, 12, 13, 14],
         [13, 14, 15, 16]]),
 tensor([[11, 12, 13, 14],
         [13, 14, 15, 16]])
#矩阵乘法
torch.matmul(x,y)
x@y
x==y
#tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])

7.改变张量形状

在 PyTorch 中,reshape、view和 squeeze都是用于改变张量形状(shape)的操作

torch.reshape()
#reshape 函数会返回一个具有指定形状的新张量。它既可以操作连续的张量,也可以操作不
连续的张量。
#可能复制数据,如果张量不连续则会复制数据
​
troch.view()
#只能操作连续的张量
#不复制数据,返回一个共享底层数据的视图
​
torch.squeeze()
#移除张量中所有或指定维度中大小为 1 的维度
#如果不指定维度,squeeze() 会移除所有大小为 1 的维度。
#如果指定维度 dim,squeeze(dim) 只会移除该维度,前提是该维度的大小为 1。如果指定维度的大小不为 1,则该操作不会改变张量的形状。
#squeeze 操作通常返回一个共享底层数据的新视图,不进行数据复制。
x = torch.randn(10,1,10)
z1 = torch.squeeze(x,1)
z2 = x.squeeze(1)
assert torch.all(z1==z2)
#x.shape,z1.shape
#torch.Size([10, 1, 10]), torch.Size([10, 10])
与squeeze相反的操作是unsqueeze,向矩阵添加一个新维度
x = torch.randn(10,10)
z1 = x.unsqueeze(0)
z2,z3,z4 = x[None],x[:,None],x[:,:,None]#也可以使用None进行创建新通道/维度
#x.shape,z1.shape,z2.shape,z3.shape
#torch.Size([10, 10]),
 torch.Size([1, 10, 10]),
 torch.Size([1, 10, 10]),
 torch.Size([10, 1, 10])

8.张量连接运算

x = torch.arange(12,dtype = torch.float32).reshape((3,4))
y = torch.tensor([[2.0,1,4,3],[1,2,3,4],[4,3,2,1]])
#torch.cat((x,y),dim=0),torch.cat((x,y),dim=1)
#tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [ 2.,  1.,  4.,  3.],
         [ 1.,  2.,  3.,  4.],
         [ 4.,  3.,  2.,  1.]]),
 tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
         [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
         [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]])

9.提取张量中最大值

#提取张量中的最大值
x = torch.arange(25).reshape(5,5)
#x.max()
#tensor(24)
#提取最大值以及存在最大值的行索引
#x.max(dim=0)
#torch.return_types.max(
values=tensor([20, 21, 22, 23, 24]),
indices=tensor([4, 4, 4, 4, 4]))
#m,argm = x.max(dim=1)
#tensor([ 4,  9, 14, 19, 24]), tensor([4, 4, 4, 4, 4])

10.张量对象的自动梯度计算

微分和计算梯度在更新神经网络的权重中至关重要,pytorch中的张量对象内置梯度计算函数。

#定义一个张量对象,同时指定它需要计算梯度,requires_grad = True指定腰围张#量对象计算梯度
x = torch.tensor([[2.,-1.],[1.,1.]],requires_grad = True)
#tensor([[ 2., -1.],
        [ 1.,  1.]], requires_grad=True)

11.计算所有输入的平方和

out = x.pow(2).sum()
#x,out
#tensor([[ 2., -1.],
         [ 1.,  1.]], requires_grad=True),
 tensor(7., grad_fn=<SumBackward0>)

12.计算梯度

x.grad
#tensor([[ 4., -2.],
        [ 2.,  2.]])

13.比较numpy数组和tensor张量执行矩阵所花费的时间

#生成不同的torch对象
import torch
import time
x = torch.rand(1,6400)
y = torch.rand(6400,5000)
#定义用于存储张量对象的设备
device = 'cuda' if torch.cuda.is_available() else 'cpu'
assert device == 'cuda',"this exercise is on a GPU machine"
#将创建的张量对象注册到设备中,注册张量对象意味着将信息存储到指定设备中
x,y = x.to(device),y.to(device)
#执行torch对象的矩阵乘法,并对其计时,并比较在numpy数组中执行矩阵乘法的速度。
start = time.time()
for i in range(10):
    z = x@y
end = time.time()
print(end - start)
#在cpu上执行相同的矩阵乘法
x,y = x.cpu(),y.cpu()
start = time.time()
for i in range(10):
    z = x@y
end = time.time()
print(end - start)
#在numpy数组上执行相同的矩阵乘法
import numpy as np
x = np.random.random((1,6400))
y = np.random.random((6400,5000))
start = time.time()
for i in range(10):
    z = np.matmul(x,y)
end = time.time()
print(end - start)

在gpu上对torch对象执行的矩阵乘法比在cpu上的torch对象快约18倍,比在numpy数组上执行矩阵乘法快约40倍,一般来说,在cpu中使用torch张量的矩阵乘法同样比numpy更快。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐