深度学习第一节

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

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

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

数据基本操作

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

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

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

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
28
29
30
31
32
33
34
35
36
37
38
39
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.获取张量对象的形状和数据类型

1
2
x.shape
x.dtype

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

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

4.numpy中 ndarray可以转换为tensor

1
2
3
4
5
6
7
8
9
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.原地操作内存地址不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)输入或权重值。

1
2
3
4
5
6
7
8
9
每个元素×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]])
1
2
3
#矩阵乘法
torch.matmul(x,y)
x@y
1
2
3
4
x==y
#tensor([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])

7.改变张量形状

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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])
1
2
3
4
5
6
7
8
9
与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.张量连接运算

1
2
3
4
5
6
7
8
9
10
11
12
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.提取张量中最大值

1
2
3
4
5
6
7
8
9
10
11
#提取张量中的最大值
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中的张量对象内置梯度计算函数。

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

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

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

12.计算梯度

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

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

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