1 导入库& 数据说明
import numpy as np
import torch
import matplotlib.pyplot as plt
from tensorboardX import SummaryWriter
x=np.array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 7, 10],
[ 13, 18],
[ 23, 30],
[ 37, 50],
[ 63, 86],
[109, 146],
[183, 246]])
xx=torch.tensor(x,dtype=torch.float32,requires_grad=True)
xx
我们有这样一组数据x,每一行代表一个时刻的二维数据,我们希望的是
2 模型
pytorch笔记 pytorch模型中的parameter与buffer_UQI-LIUWJ的博客-CSDN博客
import torch
class Net(torch.nn.Module):
def __init__(self,lag_list):
super(Net,self).__init__()
self.lag_list=lag_list
#时滞集
self.l=len(self.lag_list)
#时滞集大小
self.param=torch.nn.Parameter(torch.zeros(self.l,2))
#自回归系数,一个time lag 一行自回归系数
#自回归系数放入Parameter里面,那么也会随着神经网路梯度下降更新
#定义前向传播方式
def forward(self,x):
max_len=max(self.lag_list)
#时滞集的最大元素,从这个元素之后的一个元素开始,考虑自回归预测和本身的差距
l=x.shape[0]
if(type(l)==type(1)):
pass
else:
l=int(l)
#这里为什么要这么分类一下呢?其实这也是我的一个疑问。
'''
直接用pytorch的话,l是一个int类型的数字
但是如果使用了tensorboardX之后,l是一个Tensor,那么就得用类型转换回int
'''
tensor_len=l-max_len
#表示需要进行(自回归预测-数据本身)比较的长度
#也就是max_len后一位开始到最后的这一部分的长度
lst_lag=[]
#不同时滞集对应的输入数据的部分
for i in self.lag_list:
lst_lag.append(x[max_len-i:max_len-i+tensor_len].clone())
#这里为什么要通过这种clone+放入列表的方式呢?
#因为如果你直接在原始数据上进行切片操作【比如x[i]=x[i-1]+x[i-2]】这种
#它会因为切片和inplace的问题,而无法传递梯度,最终会报错
ret_tmp_origin=x[max_len:max_len+tensor_len].clone()
#原始数据需要比较的一部分
ret_var=self.param[0]*lst_lag[0]
for i in range(1,self.l):
ret_var=ret_var+self.param[i]*lst_lag[i]
#自回归预测的部分
return(ret_var-ret_tmp_origin)
#自回归预测的部分和原始部分的差距
3 模型训练& tensorboardX可视化
net=Net([3,1])
from tensorboardX import SummaryWriter
writer = SummaryWriter('runs/AR_pytorch')
#提供一个路径,将使用该路径来保存日志
writer.add_graph(net,xx)
#添加net的计算图
#使用Adams进行梯度下降,设置学习率为0.02
optimizer=torch.optim.Adam(net.parameters(),lr=0.02)
#开始训练
for epoch in range(1000):
prediction=net(xx)
loss=torch.linalg.norm(prediction)
#每次损失函数都是自回归预测和原始数据之间的L2范数
writer.add_scalar('loss_',loss,epoch)
#添加loss的summary信息
optimizer.zero_grad()
#清空上一步残余的参数更新值
loss.backward()
#误差反向传播,计算参数更新值
optimizer.step()
#将参数更新值施加到net的parameters上
for i in net.parameters():
writer.add_scalar('param-0_time_lag-3',i[0][0].item(),epoch)
writer.add_scalar('param-1_time_lag-3',i[0][1].item(),epoch)
writer.add_scalar('param-0_time_lag-1',i[1][0].item(),epoch)
writer.add_scalar('param-1_time_lag-1',i[1][1].item(),epoch)
在tensorboardX上,有:
3.1 损失函数图像
3.2 自回归系数图像
可以看到,最后和我们目标的[2,1]很接近了
3.3 TensorboardX 计算图
整体如下,左边是自回归的计算路径,右边是原始数据(截取max_len之后的部分)的计算路径
3.3.1 右侧计算路径
ret_tmp_origin=x[max_len:max_len+tensor_len].clone()
#原始数据需要比较的一部分
3.3.2 左侧计算路径
左右路(下) x[2:9] (X[t-1])
左左路(下) x[0:7] (X[t-3])
左中路
就是不同时滞对应的切片*对应的param值
最后这是一个减法,自回归得到的和原始数据相减
4 使用Linear 进行自回归
1~3小节说的模型,可以想成是
其中Cl是向量
现在我们按照机器学习笔记:向量自回归模型VAR 中所说的那样,认为自回归的内容是矩阵(即Cl是矩阵)
4.1 重新构造数据集
首先我们重新构造数据集
import numpy as np
import torch
import matplotlib.pyplot as plt
from tensorboardX import SummaryWriter
x=np.array([[ 1, 2],
[ 3, 4],
[ 5, 6]])
for i in range(7):
tmp=np.array([[1,0],[2,1]])@x[2+i].T+np.array([[2,1],[3,1]])@x[0+i].T
tmp=tmp.reshape(1,-1)
x=np.append(x,tmp,axis=0)
x
'''
array([[ 1, 2],
[ 3, 4],
[ 5, 6],
[ 9, 21],
[ 19, 52],
[ 35, 111],
[ 74, 229],
[ 164, 486],
[ 345, 1030],
[ 722, 2171]])
'''
xx=torch.tensor(x,dtype=torch.float32,requires_grad=True)
可以想象成,此时
4.2 模型稍作修改
把param的部分换成了 modlst,其他的基本上都不变
import torch
class Net(torch.nn.Module):
def __init__(self,lag_list):
super(Net,self).__init__()
self.lag_list=lag_list
#时滞集
self.l=len(self.lag_list)
#时滞集大小
self.modlst=torch.nn.ModuleList([])
for i in range(self.l):
self.modlst.append(torch.nn.Linear(2,2,bias=False))
#自回归矩阵,一个time lag 一个自回归矩阵
#自回归矩阵放入Parameter里面,那么也会随着神经网路梯度下降更新
#定义前向传播方式
def forward(self,x):
max_len=max(self.lag_list)
#时滞集的最大元素,从这个元素之后的一个元素开始,考虑自回归预测和本身的差距
l=x.shape[0]
if(type(l)==type(1)):
pass
else:
l=int(l)
#这里为什么要这么分类一下呢?其实这也是我的一个疑问。
'''
直接用pytorch的话,l是一个int类型的数字
但是如果使用了tensorboardX之后,l是一个Tensor,那么就得用类型转换回int
'''
tensor_len=l-max_len
#表示需要进行(自回归预测-数据本身)比较的长度
#也就是max_len后一位开始到最后的这一部分的长度
lst_lag=[]
#不同时滞集对应的输入数据的部分
for i in self.lag_list:
lst_lag.append(x[max_len-i:max_len-i+tensor_len].clone())
#这里为什么要通过这种clone+放入列表的方式呢?
#因为如果你直接在原始数据上进行切片操作【比如x[i]=x[i-1]+x[i-2]】这种
#它会因为切片和inplace的问题,而无法传递梯度,最终会报错
ret_tmp_origin=x[max_len:max_len+tensor_len].clone()
#原始数据需要比较的一部分
ret_var=self.modlst[0](lst_lag[0])
for i in range(1,self.l):
ret_var=ret_var+self.modlst[i](lst_lag[i])
#自回归预测的部分
return(ret_var-ret_tmp_origin)
#自回归预测的部分和原始部分的差距
4.3 训练模型
训练的时候也和之前的类似
net=Net([3,1])
from tensorboardX import SummaryWriter
writer = SummaryWriter('runs/AR_fc_1_pytorch')
#提供一个路径,将使用该路径来保存日志
writer.add_graph(net,xx)
#添加net的计算图
#使用Adams进行梯度下降,设置学习率为0.02
optimizer=torch.optim.Adam(net.parameters(),lr=0.02)
#开始训练
for epoch in range(10000):
prediction=net(xx)
loss=torch.linalg.norm(prediction)
#每次损失函数都是自回归预测和原始数据之间的L2范数
if(epoch>=200):
writer.add_scalar('loss_',loss,epoch)
#添加loss的summary信息
optimizer.zero_grad()
#清空上一步残余的参数更新值
loss.backward()
#误差反向传播,计算参数更新值
optimizer.step()
#将参数更新值施加到net的parameters上
'''
for i in net.parameters():
writer.add_scalar('param-0_time_lag-3',i[0][0].item(),epoch)
writer.add_scalar('param-1_time_lag-3',i[0][1].item(),epoch)
writer.add_scalar('param-0_time_lag-1',i[1][0].item(),epoch)
writer.add_scalar('param-1_time_lag-1',i[1][1].item(),epoch)
'''
if(epoch % 100==0):
for i in net.parameters():
print(i)
'''
最后一次输出的参数为:
Parameter containing:
tensor([[1.9996, 0.9999],
[3.0016, 1.0017]], requires_grad=True)
Parameter containing:
tensor([[9.9960e-01, 2.0738e-04],
[2.0016e+00, 1.0019e+00]], requires_grad=True)
已经很接近我们设置数据集时候的自回归矩阵了
'''