0.前言
中间有很多修改代码的是过程笔记,都是不可用的,仅仅用于记录思路,如果想看最终代码直接翻到最下面。
运行李沫2021深度学习线性回归代码如下
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
报以下错误:
TypeError Traceback (most recent call last) <ipython-input-14-13b36a1f7ef4> in <module> 8 true_w = torch.tensor([2, -3.4]) 9 true_b = 4.2 ---> 10 features, labels = synthetic_data(true_w, true_b, 1000) <ipython-input-14-13b36a1f7ef4> in synthetic_data(w, b, num_examples) 1 def synthetic_data(w, b, num_examples): 2 """生成 y = Xw + b + 噪声。""" ----> 3 X = torch.normal(0, 1, (num_examples, len(w))) 4 y = torch.matmul(X, w) + b 5 y += torch.normal(0, 0.01, y.shape) TypeError: normal() received an invalid combination of arguments - got (int, int, tuple), but expected one of: * (Tensor mean, Tensor std, torch.Generator generator, Tensor out) * wei * (float mean, Tensor std, torch.Generator generator, Tensor out)
为了弄懂错误,就去查阅文档看看,发现网上大部分介绍都是
torch.normal(mean, std, out=None) → Tensor
Tensor mean, Tensor std
torch.normal(mean, std=1.0, out=None) → Tensor
Tensor mean, float std
torch.normal(mean=0.0, std, out=None) → Tensor
float mean, Tensor std
错误里还有torch.Generator generator没有介绍,故专门查阅下包含torch.Generator generator的文档。
注:翻阅pytorch1.0中文文档没有介绍torch.normal(mean, std, *, generator=None, out=None),最终查阅了最新pytorch英文文档得出以下记录。发现多出了两种torch.normal()函数的格式。
1.torch.normal()函数的另外两种格式介绍
torch.normal(mean, std, *, generator=None, out=None) → Tensor
torch.normal(mean, std, *, generator=None, out=None) → Tensor
返回从单独的正态分布中提取的随机数张量,这些正态分布的平均值和标准差是给定的。
mean 是一个张量,具有每个输出元素正态分布的均值
std 是一个张量,每个输出元素的正态分布的标准差
mean 和 std 的形状不需要匹配,但是每个张量中的元素总数需要相同。
当形状不匹配时,平均值的形状被用作返回输出张量的形状
当std是CUDA张量时,这个函数使它的设备与CPU同步。
参数
mean (Tensor) –每个元素平均值的张量
std (Tensor) –每个元素标准偏差的张量
关键字参数
generator (torch.Generator, optional) –用于采样的伪随机数生成器
out (Tensor, optional) –输出张量
torch.normal(mean, std, size, *, out=None) → Tensor
torch.normal(mean, std, size, *, out=None) → Tensor
与上述函数类似,但所有绘制的元素都共享平均值和标准差。由此产生的张量大小由大小给定。
参数
mean (float)-所有分布的平均值
std(float)–所有分布的标准偏差
size (int...)–定义输出张量形状的整数序列。
关键字参数
out(张量,可选)–输出张量。
2.对代码的修改(记录的错误代码及笔记)
由错误看出代码格式为(int, int, tuple)以及课程中老师所说,大胆推测使用的格式为
torch.normal(mean, std, size, *, out=None)
修改代码如下:
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
X = torch.normal(0., 1., (num_examples, len(w)))
#X = torch.normal(mean = 0.,std= 1., size =(num_examples, len(w)))
#尝试上述也不行
y = torch.matmul(X, w) + b
y += torch.normal(0., 0.01, y.shape)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
运还是报错老问题
注:以上代码在pytorch1.0.0版本还是报错
3.结论以及代码其它修改过程记录(也是错误的代码)
经过反复的尝试,最终确认。因为使用的版本为pytorch1.0.0而不是新版本,无法使用老师给的程序。(pytorch1.0.0版本normal函数无size的使用方式)
最终决定按照pytorch1.0.0版本魔改代码如下:
此处采用格式为(Tensor mean, float std, torch.Generator generator, Tensor out)
修改代码如下:
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
X = torch.normal(torch.tensor([0]), 1.)
y = torch.matmul(X, w) + b
y += torch.normal(torch.tensor([0]), 0.01)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
出现新的错误:
RuntimeError: _th_normal is not implemented for type torch.LongTensor
原因类型默认为float64,类型太长,故改成32位
故修改代码如下:
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
a1 = torch.tensor([0],dtype=torch.float32)#直接放函数里会报错,故使用a1先生成好
X = torch.normal(a1, 1.)
y = torch.matmul(X, w) + b
y += torch.normal(a1, 0.01)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
出现新的错误:
RuntimeError Traceback (most recent call last) <ipython-input-48-e254f9fc8d52> in <module> 10 true_w = torch.tensor([2, -3.4],dtype=torch.float32) 11 true_b = 4.2 ---> 12 features, labels = synthetic_data(true_w, true_b, 1000) <ipython-input-48-e254f9fc8d52> in synthetic_data(w, b, num_examples) 4 5 X = torch.normal(a1, 1.) ----> 6 y = torch.matmul(X, w) + b 7 y += torch.normal(a1, 0.01) 8 return X, y.reshape((-1, 1))
RuntimeError: inconsistent tensor size, expected tensor [1] and src [2] to have the same number of elements, but got 1 and 2 elements respectively
原因是计算时维数不一样。
修改代码如下:
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
a1 = torch.tensor([0,0],dtype=torch.float32)#直接放函数里会报错,故使用a1先生成好
X = torch.normal(a1, 1.)
y = torch.matmul(X, w) + b
y += torch.normal(a1,1.)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
出现错误如下:
RuntimeError Traceback (most recent call last) <ipython-input-36-915e79a2fa26> in <module> 10 true_w = torch.tensor([2, -3.4]) 11 true_b = 4.2 ---> 12 features, labels = synthetic_data(true_w, true_b, 1000) <ipython-input-36-915e79a2fa26> in synthetic_data(w, b, num_examples) 5 X = torch.normal(a1, 1.) 6 y = torch.matmul(X, w) + b ----> 7 y += torch.normal(a1,1.) 8 return X, y.reshape((-1, 1)) 9 RuntimeError: output with shape [] doesn't match the broadcast shape [2]
由于广播机制等原因,张量的 y+=a 和 y=a+y 的运算是有区别的,故修改代码如下:
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
a1 = torch.tensor([0,0],dtype=torch.float32)#直接放函数里会报错,故使用a1先生成好
X = torch.normal(a1, 1.)
y = torch.matmul(X, w) + b
y = torch.normal(a1,1.) + y
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
此处代码运行以及不会报错,但是接下来运行下面代码:
print('features:', features[0], '\nlabel:', labels[0])
输出如下:
features: tensor(-0.9737) label: tensor([7.3704])
与课程中输出不一样,:如下
features: tensor([-0.0748, -0.3831]) label: tensor([5.3410])
后来反思之后发现陷入误区,不能根据错误而该程序,应该从课程中要设计个什么函数而写代码,以上代码仅仅是思考的过程笔记,都不是正确的,正确代码从第4节开始。
==============================分界线=================================
==============补充函数torch.matmul()介绍=================
torch.matmul(tensor1, tensor2, out=None) → Tensor
两张量的矩阵积。
行为取决于张量的维数,如下所示:
如果两个张量都是一维的,则返回点积(标量)。
如果两个参数都是二维的,则返回矩阵积。
如果第一个参数是一维的,第二个参数是二维的,那么为了矩阵相乘,在其维数前面加上1。在矩阵相乘之后,前面的维度被移除。
如果第一个参数是二维的,第二个参数是一维的,则返回矩阵向量积。
如果两个参数都至少是一维的,并且至少有一个参数是N维的(其中N>2),则返回一个成批矩阵乘法。如果第一个参数是一维的,则为了成批矩阵相乘的目的,在其维数前面加一个1,然后将其删除。如果第二个参数是一维的,则为了成批矩阵的倍数,在其维数后附加一个1,并在其后删除。非矩阵(即批处理)维度是广播的(因此必须是可广播的)。例如,如果tensor1是torch张量,tensor2是torch张量,out将是torch张量。
注意
此函数的一维点积版本不支持out参数。
参数:
tensor1(张量)–要相乘的第一个张量
tensor2(张量)–要相乘的第二个张量
out(张量,可选)–输出张量
====================================================================
==============================分界线=================================
====================================================================
4.最终程序如下(正确修改后的代码):
于是从最根本的地方出发,想办法找个类似函数替换。课程根据带有噪声的线性模型构造一个人造数据集。 设训练数据集样本数为1000,输入个数(特征数)为2。就有了如下代码:
import numpy as np
def synthetic_data(w, b, num_examples):
"""生成 y = Xw + b + 噪声。"""
#X = torch.normal(0, 1, (num_examples, len(w)))
#原本老师定义size 为(num_examples=1000,len(w)=2)
X = torch.tensor(np.random.normal(0, 1, size=(num_examples, len(w))), dtype=torch.float32)
#或者使用下面代码与上面代码差不多效果
#X = torch.randn(num_examples, len(w), dtype=torch.float32)
#以下代码创建一个形状为 (3, 4) 的张量。其中的每个元素都从均值为0、标准差为1的标准高斯(正态)分布中随机采样。
#参考自https://zh-v2.d2l.ai/chapter_preliminaries/ndarray.html#id2
#的torch.randn(3, 4)函数
# numpy.random.normal(loc=0,scale=1e-2,size=shape)
#参数loc(float):正态分布的均值,对应着这个分布的中心。loc=0说明这一个以Y轴为对称轴的正态分布
#参数scale(float):正态分布的标准差,对应分布的宽度,scale越大,正态分布的曲线越矮胖,scale越小,曲线越高瘦
#参数size(int 或者整数元组):输出的值赋在shape里,默认为None
#补充 (w,b)的初始化 若维数为d
#可以证明,如果X服从正态分布,均值为0,方差为1,且各个维度线性无关,而(w,b)是
#(-1/(d的根号),1/(d的根号))的均匀分布,则 (W^T)X+b 是均值为0,方差为1/3的正态分布
#原因:若(W^T)X+b很大或很小会导致梯度趋近于0,造成梯度消失现象
y = torch.matmul(X, w) + b
#若input维度1D,other维度2D,则先将1D的维度扩充到2D(1D的维数前面+1),
#然后得到结果后再将此维度去掉,得到的与input的维度相同。
#即使作扩充(广播)处理,input的维度也要和other维度做对应关系
#y += torch.normal(0, 0.01, y.shape)
#其中噪声项 ϵ 服从均值为0、标准差为0.01的正态分布。
y += torch.tensor(np.random.normal(0, 0.01, size=y.size()), dtype=torch.float32)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
print('features:', features[0], '\nlabel:', labels[0])
输出
features: tensor([-0.7966, -0.0960]) label: tensor([2.9413])
d2l.set_figsize()
d2l.plt.scatter(features[:, (1)].detach().numpy(),
labels.detach().numpy(), 1);
输出图片
================================补充================================
在后面课程使用
d2l.synthetic_data(true_w, true_b, 1000)
会报错如下:
TypeError Traceback (most recent call last) <ipython-input-2-296d220dc8b5> in <module> 7 true_w = torch.tensor([2, -3.4]) 8 true_b = torch.tensor(4.2) ----> 9 features, labels = d2l.synthetic_data(true_w, true_b, 1000) 10 #D:\Anaconda3\lib\site-packages\d2l\torch.py in synthetic_data(w, b, num_examples) 11 #对代码进行了修改 D:\1learnsoft\2PyTorch\Anaconda3\lib\site-packages\d2l\torch.py in synthetic_data(w, b, num_examples) 130 """Generate y = Xw + b + noise""" 131 --> 132 X = d2l.normal(0, 1, (num_examples, len(w))) 133 134 y = d2l.matmul(X, w) + b TypeError: normal() received an invalid combination of arguments - got (int, int, tuple), but expected one of: * (Tensor mean, Tensor std, torch.Generator generator, Tensor out) * (Tensor mean, float std, torch.Generator generator, Tensor out) * (float mean, Tensor std, torch.Generator generator, Tensor out)
按报错地址找到文件夹中的torch.py的synthetic_data(w, b, num_examples)函数
按照上面使用np.random.normal修改即可,如下:
def synthetic_data(w, b, num_examples):
"""Generate y = Xw + b + noise.由于pytorch版本使用的1.0故进行以下修改"""
X = torch.tensor(np.random.normal(0, 1, size=(num_examples, len(w))), dtype=torch.float32)
#X = d2l.normal(0, 1, (num_examples, len(w)))
y = d2l.matmul(X, w) + b
y += torch.tensor(np.random.normal(0, 0.01, size=y.size()), dtype=torch.float32)
#y += d2l.normal(0, 0.01, y.shape)
return X, d2l.reshape(y, (-1, 1))
补充错误:
TabError: inconsistent use of tabs and spaces in indentation
注:此错误表示你修改代码时缩进不一样,复制其余地方的缩进粘贴即可
================================结束================================