- Published on
《动手学深度学习》学习笔记(二)
- Authors

- Name
- 祝你好运
注:说实话如果单纯看书,我觉得难度很大,但现在有了ChatGPT,不懂的直接甩过去,给我讲的明明白白,顺带一连串的彩虹屁,让我觉得我马上就能训练出ChatGPT 6!
第二章:预备知识
数据操作
首先我后面的学习都只用PyTorch,别的几种都不用了。然后PyTorch在导入的时候其实是torch,这个习惯了就好了。
初始化
然后我们数据操作先讲的就是数据初始化,比如生成12个浮点数(注意这里是0到11而不是1到12):
x = torch.arange(12, dtype=torch.float32)
x
tensor([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])
其实我认为刚开始学习的时候,应该教下面的,少一些参数,会更容易学习:
x = torch.arange(12)
x
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
很多时候我们想要一份全0数据,注意这里是一份3维数据,第一维有2个元素,第三维有4个。
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.]]])
有些时候我们又想要全1的数据:
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.]]])
当然随机数也非常重要,尤其是我们训练开始的时候,直接用随机数初始化,然后开始训练。注意下面的是randn而不是rand,rand是随机出0到1的数,而randn是随机出0附近的正态分布的数,这个如果不了解可以去问大模型,我已经问明白了(当然也是之前学过,大概是高中):
torch.randn(3, 4)
tensor([[-0.7823, -2.0361, 0.6767, 1.6542],
[ 0.4277, -1.8274, 0.0578, -0.3718],
[-0.0502, -0.9920, 0.7946, 0.4622]])
调整大小
注意我们这里用的x就是上面的哈
X = x.reshape(3, 4)
X
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
X.shape
torch.Size([3, 4])
索引与切片
这里的索引与切片就类似Python里面的数组的索引和切片,那边懂了这里就没问题。比如下面的X[-1],这里意思就是X的第一维数据的最后一个元素。X[1:3]这个就是X的第一维数据做切片,从第1到第2个,一共两个。
X[-1], X[1:3]
(tensor([ 8., 9., 10., 11.]),
tensor([[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]]))
而且修改值的时候,可以用单个值覆盖多维数据: 比如
x = torch.randn(3, 4, 5)
x[1:2] = 6
tensor([[[-1.8204, -1.2844, 0.4844, 0.4788, -0.0531],
[-0.1200, -0.7851, -0.3964, 0.6313, 0.7284],
[-1.0022, 0.5124, 1.1530, 0.4703, -0.0768],
[ 0.4584, 0.6001, -0.6398, -0.3655, 0.4246]],
[[ 6.0000, 6.0000, 6.0000, 6.0000, 6.0000],
[ 6.0000, 6.0000, 6.0000, 6.0000, 6.0000],
[ 6.0000, 6.0000, 6.0000, 6.0000, 6.0000],
[ 6.0000, 6.0000, 6.0000, 6.0000, 6.0000]],
[[-0.2148, -0.5980, -0.0466, -0.3548, 1.2645],
[ 0.6480, 0.2927, 0.3504, -1.9341, -0.9903],
[ 0.0111, -1.1888, -1.4203, 0.8937, 0.3412],
[ 0.4003, 0.5873, -0.4195, -0.9600, 0.8594]]])
操作符
这里介绍了一些常见的操作符,比如加减乘除次方,拼接,求自然指数,求和。注意,有些操作符是要求两个运算数的维度要一样,比如下面的求和就会报错:
>>> x = torch.tensor([1, 2, 4])
>>> y = torch.tensor([3, 6, 9, 12])
>>> x + y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: The size of tensor a (3) must match the size of tensor b (4) at non-singleton dimension 0
而有些运算符就不要求,比如求和,求自然指数
torch.exp(x)
X.sum()
对于维度不一样,又想做计算,可能会用到Broadcasting这种技术,他会把两个参与计算的tensor的维度搞成一样,这样就可以计算了。不是说维度不一样的数据就可以用broadcasting,而是数据复制的时候没有歧义(也就是要被复制的那一行或者列只有1个元素),比如下面的x和y
>>> x = torch.tensor([[1, 2, 3]])
>>> y = torch.tensor([[1], [2], [3]])
>>> x + y
tensor([[2, 3, 4],
[3, 4, 5],
[4, 5, 6]])
节省内存
当数据量很大的时候,复制数据会变得很慢,所以原地操作就是分必要了,而Python这种语言,他有的是原地修改,有些是复制的,除了基础类型(整数,浮点数,布尔),别的基本都是原地修改(字符串和元组例外)。树上举的例子也很好:
before = id(X)
X += Y
id(X) == before
True