3.线性神经网络

3.1 线性回归

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
%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l

n=10000
a=torch.ones([n])
b=torch.ones([n])

#定义计时器
class Timer: #@save
#记录多次运行时间
def __init__(self):
self.times=[]
self.start()

def start(self):
#启动计时器
self.tik=time.time()

def stop(self):
#停止计时器并将时间记录在列表中
self.times.append(time.time()-self.tik)
return self.times[-1]

def avg(self):
#返回平均时间
return sum(self.times)/len(self.times)

def sum(self):
#返回时间总和
return sum(self.times)

def cumsum(self):
#返回累计时间
return np.array(self.times).cumsum().tolist()

1
2
3
4
5
c=torch.zeros(n)
timer=Timer()
for i in range(n):
c[i]=a[i]+b[i]
f'{timer.stop():.5f}sec'
'0.14660sec'
1
2
3
timer.start()
d=a+b
f'{timer.stop():.5f}sec'
'0.00000sec'
1
2
3
4
5
6
7
8
9
10
def normal(x,mu,sigma):
p=1/math.sqrt(2*math.pi*sigma**2)
return p*np.exp(-0.5/sigma**2*(x-mu)**2)

#再次使用numpy进行可视化
x=np.arange(-7,7,0.01)

#均值和标准差对
params=[(0,1),(0,2),(3,1)]
d2l.plot(x,[normal(x,mu,sigma)for mu,sigma in params],xlabel='x',ylabel='p(x)',figsize=(4.5,2.5),legend=[f'mean{mu},std{sigma}'for mu,sigma in params])


svg

3.2 线性回归的从零开始实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
%matplotlib inline
import random
import torch
from d2l import torch as d2l

#生成数据集
def synthetic_data(w,b,num_examples): #@save
#生成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)

print('features:',features[0],'\nlabel:',labels[0])
features: tensor([ 0.7328, -0.5520]) 
label: tensor([7.5513])
1
2
d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1);


svg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#读取数据集
def data_iter(batch_size,features,labels):
num_examples=len(features)
indices=list(range(num_examples))
#这些样本是随机读取的,没有特定顺序
random.shuffle(indices)
for i in range(0,num_examples,batch_size):
batch_indices=torch.tensor(indices[i:min(i+batch_size,num_examples)])
yield features[batch_indices],labels[batch_indices]

batch_size=10

for X,y in data_iter(batch_size,features,labels):
print(X,'\n',y)
break
tensor([[ 0.9175, -0.1441],
        [-0.3328, -0.4237],
        [-0.1287,  1.6801],
        [ 0.8705, -0.9030],
        [-0.4966,  1.4015],
        [ 1.3378, -1.8026],
        [ 0.5129,  1.2806],
        [ 1.1026,  1.2080],
        [ 0.6151,  0.6337],
        [-0.4683, -0.4388]]) 
 tensor([[ 6.5336],
        [ 4.9801],
        [-1.7645],
        [ 9.0089],
        [-1.5652],
        [12.9979],
        [ 0.8680],
        [ 2.2893],
        [ 3.2902],
        [ 4.7695]])
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
#初始化模型参数
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)

#定义模型
def linreg(X,w,b): #@save
#线性回归模型
return torch.matmul(X,w)+b

#定义损失函数
def squared_loss(y_hat,y): #@save
#均方损失
return(y_hat-y.reshape(y_hat.shape))**2/2

#定义优化算法——小批量随机梯度下降
#lr:学习速率(梯度下降步长);batch_size:批量大小
def sgd(params,lr,batch_size): #@save
#小批量随机梯度下降
with torch.no_grad():
for param in params:
param-=lr*param.grad/batch_size
param.grad.zero_()

#训练
#设置超参数
lr=0.03#学习率
num_epochs=3#迭代周期个数
net=linreg
loss=squared_loss

for epoch in range(num_epochs):
for X,y in data_iter(batch_size,features,labels):
l=loss(net(X,w,b),y)#X和y的小批量损失
#因为l的形状是(batch_size,1),而不是一个标量。l中的所有元素被加到一起,并以此计算关于[w,b]的梯度
l.sum().backward()
sgd([w,b],lr,batch_size)#使用参数的梯度以更新参数
with torch.no_grad():
train_l=loss(net(features,w,b),labels)
print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
epoch1,loss0.036941
epoch2,loss0.000134
epoch3,loss0.000049
1
2
print(f'w的估计误差:{true_w-w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b-b}')
w的估计误差:tensor([ 0.0002, -0.0002], grad_fn=<SubBackward0>)
b的估计误差:tensor([0.0002], grad_fn=<RsubBackward1>)

3.3 线性回归的简洁实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#生成数据集
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=d2l.synthetic_data(true_w,true_b,1000)

#读取数据集
def load_array(data_arrays,batch_size,is_train=True): #@save
#构造一个pytorch数据迭代器
dataset=data.TensorDataset(*data_arrays)
return data.DataLoader(dataset,batch_size,shuffle=is_train)

batch_size=10
data_iter=load_array((features,labels),batch_size)

next(iter(data_iter))
[tensor([[-0.6422, -0.7470],
         [-2.1785,  0.3340],
         [ 1.4011, -1.1104],
         [-0.8083, -0.3035],
         [ 0.1077, -0.1201],
         [-0.4151, -0.1079],
         [ 1.8074,  0.0904],
         [-0.3707,  0.6197],
         [ 0.3739,  0.2972],
         [ 0.2383,  1.1791]]),
 tensor([[ 5.4457],
         [-1.3122],
         [10.7837],
         [ 3.6281],
         [ 4.8105],
         [ 3.7284],
         [ 7.5017],
         [ 1.3465],
         [ 3.9247],
         [ 0.6800]])]
1
2
3
4
5
6
#定义模型
from torch import nn#nn:神经网络
net=nn.Sequential(nn.Linear(2,1))

#初始化模型参数
net[0].weight.data.normal_(0,0.01),net[0].bias.data.fill_(0)
(tensor([[ 0.0106, -0.0055]]), tensor([0.]))
1
2
3
4
#定义损失函数
loss=nn.MSELoss()#均方误差:MSELoss类,平方L2范数
#定义优化算法
trainer=torch.optim.SGD(net.parameters(),lr=0.03)
1
2
3
4
5
6
7
8
9
num_epochs=3#迭代周期个数
for epoch in range(num_epochs):
for X,y in data_iter:
l=loss(net(X),y)#X和y的小批量损失
trainer.zero_grad()
l.backward()
trainer.step()#使用参数的梯度以更新参数
l=loss(net(features),labels)
print(f'epoch{epoch+1},loss{l:f}')
epoch1,loss0.000223
epoch2,loss0.000112
epoch3,loss0.000112
1
2
3
4
w=net[0].weight.data
print('w的估计误差:',true_w-w.reshape(true_w.shape))
b=net[0].bias.data
print('b的估计误差:',true_b-b)
w的估计误差: tensor([ 0.0014, -0.0004])
b的估计误差: tensor([0.0008])
阅读更多

2.预备知识

2.1 数据操作

1
2
3
import torch
x = torch.arange(12)
x
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
1
x.shape
torch.Size([12])
1
x.numel()
12
1
2
X=x.reshape(3,4)
X
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
1
X.shape
torch.Size([3, 4])
1
2
Y=x.reshape(-1,4)
Y
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
1
2
Z=x.reshape(3,-1)
Z
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
1
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.]]])
1
torch.randn(3,4)
tensor([[ 1.6438, -1.2879,  0.2324,  0.2719],
        [-0.6636,  0.9939, -0.8435, -1.0906],
        [-0.5617,  0.2107, -0.9530,  0.7362]])
1
2
3
x=torch.tensor([1.0,2,4,8])
y=torch.tensor([2,2,2,2])
x+y,x-y,x*y,x/y,x**y
(tensor([ 3.,  4.,  6., 10.]),
 tensor([-1.,  0.,  2.,  6.]),
 tensor([ 2.,  4.,  8., 16.]),
 tensor([0.5000, 1.0000, 2.0000, 4.0000]),
 tensor([ 1.,  4., 16., 64.]))
1
torch.exp(x)
tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])
1
2
X=torch.arange(12,dtype=torch.float32).reshape((3,4))
X
tensor([[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.]])
1
2
Y=torch.tensor([[2.0,1,4,3],[1,2,3,4],[4,3,2,1]])
Y
tensor([[2., 1., 4., 3.],
        [1., 2., 3., 4.],
        [4., 3., 2., 1.]])
阅读更多