尝试使用 Pytorch 实现多项式回归时出错 - 梯度在 loss.backward() 之后为 None
An error while trying to implement a polynomial regression with Pytorch - Gradients are None after loss.backward()
我正在尝试使用 PyTorch 实现自定义多项式回归,但在训练过程中我的实现无法计算梯度;即即使在 loss.backward()
命令之后,权重也总是 None
。下面我给出了所有必要的细节。
步骤 1 我使用以下命令生成一些数据点:
import numpy as np
import torch
import matplotlib.pyplot as plt
from torch.autograd import Function
import torch.nn as nn
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
seed_value = 42
np.random.seed(seed_value)
x = np.sort(np.random.rand(1000))
y = np.cos(1.2 * x * np.pi) + (0.1 * np.random.randn(1000))
然后我使用 sklearn 中的 train-test split 将我的数据分成训练集和测试集。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(x,y,train_size = 0.7,
random_state = seed_value)
步骤 2 我创建名为 poly
的自定义函数,其中 returns 多项式 p(x)=w0+w1x+... w5x^5,对于给定的权重 w.
在 x 处计算
def poly(x,w,batch_size = 10,degree = 5):
x = x.repeat(1,degree+1)
w = w.repeat(batch_size,1)
exp = torch.arange(0.,degree+1).repeat(batch_size,1)
return torch.sum(w*torch.pow(x,exp),dim=1)
第 3 步 我构建了 class custom_dataset
继承自 PyTorch 的数据集来处理我的批处理训练。
class custom_dataset(Dataset):
def __init__(self,X,y):
self.x = torch.from_numpy(X).type(torch.float32).reshape(len(X),1)
self.y = torch.from_numpy(y).type(torch.float32)
def __len__(self):
return len(self.x)
def __getitem__(self,idx):
return self.x[idx], self.y[idx]
第 4 步 我构建处理训练过程的循环。
training_data = custom_dataset(X_train,y_train)
test_data = custom_dataset(X_test,y_test)
def training_loop(train_loader, w, epochs, lr, batch_size,
loss_fn = nn.MSELoss(), degree = 5):
weights = torch.tensor(w,dtype = torch.float32, requires_grad = True)
num_batches = len(train_loader)//batch_size
for epoch in range(1,epochs+1):
print(f"{5*'-'}>epoch:{epoch}<{5*'-'}")
for i,sample in enumerate(train_loader):
x,y = sample
y_preds = poly(x,weights,batch_size = batch_size)
loss = loss_fn(y,y_preds)
loss.backward() # backpropagation
weights = weights - lr*weights.grad # update - gradient descent
if (i+1) % 100 == 0:
print(f"- Batch:[{i+1}|{num_batches}]{5*' '}Samples:[{(i+1)*num_batches}|{len(train_loader)}]{5*' '}loss:{loss.item():.6f}")
return w
第5步我开始训练了...
epochs = 10
lr = 1e-3
batch_size = 10
degree = 5
train_loader = DataLoader(training_data, batch_size = batch_size,
shuffle = True)
test_loader = DataLoader(test_data, batch_size = batch_size,
shuffle = True)
w = [0]*(degree+1)
w = training_loop(train_loader, w = w, epochs = 30, lr = lr,
batch_size = batch_size)
并出现以下错误
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [40], in <cell line: 10>()
7 test_loader = DataLoader(test_data, batch_size = batch_size,
8 shuffle = True)
9 w = [0]*(degree+1)
---> 10 w = training_loop(train_loader, w = w, epochs = 30, lr = lr,
11 batch_size = batch_size)
Input In [39], in training_loop(train_loader, w, epochs, lr, batch_size, loss_fn, degree)
10 loss = loss_fn(y,y_preds)
11 loss.backward() # backpropagation
---> 12 weights = weights - lr*weights.grad # update - gradient descent
14 if (i+1) % 100 == 0:
15 print(f"- Batch:[{i+1}|{num_batches}{5*' '}Samples:[{(i+1)*num_batches}|{len(train_loader)}]{5*' '}loss:{loss.item():.6f}")
TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
这意味着梯度的计算不会影响变量 weights
,因为它仍然设置为 None
。你知道哪里出了问题吗?
您将在第一个循环迭代中覆盖 weights
变量,该变量将替换为 weights
的副本,而没有 grad
属性.可以使用以下最小代码重现此行为:
>>> weights.grad = torch.ones_like(weights)
>>> for i in range(2):
... print(weights.grad)
... weights = weights - weights.grad
tensor([1., 1.])
None
要解决此问题,您可以使用 in-place 操作更新参数:
weights -= lr*weights.grad # update - gradient descent
我正在尝试使用 PyTorch 实现自定义多项式回归,但在训练过程中我的实现无法计算梯度;即即使在 loss.backward()
命令之后,权重也总是 None
。下面我给出了所有必要的细节。
步骤 1 我使用以下命令生成一些数据点:
import numpy as np
import torch
import matplotlib.pyplot as plt
from torch.autograd import Function
import torch.nn as nn
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
seed_value = 42
np.random.seed(seed_value)
x = np.sort(np.random.rand(1000))
y = np.cos(1.2 * x * np.pi) + (0.1 * np.random.randn(1000))
然后我使用 sklearn 中的 train-test split 将我的数据分成训练集和测试集。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(x,y,train_size = 0.7,
random_state = seed_value)
步骤 2 我创建名为 poly
的自定义函数,其中 returns 多项式 p(x)=w0+w1x+... w5x^5,对于给定的权重 w.
def poly(x,w,batch_size = 10,degree = 5):
x = x.repeat(1,degree+1)
w = w.repeat(batch_size,1)
exp = torch.arange(0.,degree+1).repeat(batch_size,1)
return torch.sum(w*torch.pow(x,exp),dim=1)
第 3 步 我构建了 class custom_dataset
继承自 PyTorch 的数据集来处理我的批处理训练。
class custom_dataset(Dataset):
def __init__(self,X,y):
self.x = torch.from_numpy(X).type(torch.float32).reshape(len(X),1)
self.y = torch.from_numpy(y).type(torch.float32)
def __len__(self):
return len(self.x)
def __getitem__(self,idx):
return self.x[idx], self.y[idx]
第 4 步 我构建处理训练过程的循环。
training_data = custom_dataset(X_train,y_train)
test_data = custom_dataset(X_test,y_test)
def training_loop(train_loader, w, epochs, lr, batch_size,
loss_fn = nn.MSELoss(), degree = 5):
weights = torch.tensor(w,dtype = torch.float32, requires_grad = True)
num_batches = len(train_loader)//batch_size
for epoch in range(1,epochs+1):
print(f"{5*'-'}>epoch:{epoch}<{5*'-'}")
for i,sample in enumerate(train_loader):
x,y = sample
y_preds = poly(x,weights,batch_size = batch_size)
loss = loss_fn(y,y_preds)
loss.backward() # backpropagation
weights = weights - lr*weights.grad # update - gradient descent
if (i+1) % 100 == 0:
print(f"- Batch:[{i+1}|{num_batches}]{5*' '}Samples:[{(i+1)*num_batches}|{len(train_loader)}]{5*' '}loss:{loss.item():.6f}")
return w
第5步我开始训练了...
epochs = 10
lr = 1e-3
batch_size = 10
degree = 5
train_loader = DataLoader(training_data, batch_size = batch_size,
shuffle = True)
test_loader = DataLoader(test_data, batch_size = batch_size,
shuffle = True)
w = [0]*(degree+1)
w = training_loop(train_loader, w = w, epochs = 30, lr = lr,
batch_size = batch_size)
并出现以下错误
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [40], in <cell line: 10>()
7 test_loader = DataLoader(test_data, batch_size = batch_size,
8 shuffle = True)
9 w = [0]*(degree+1)
---> 10 w = training_loop(train_loader, w = w, epochs = 30, lr = lr,
11 batch_size = batch_size)
Input In [39], in training_loop(train_loader, w, epochs, lr, batch_size, loss_fn, degree)
10 loss = loss_fn(y,y_preds)
11 loss.backward() # backpropagation
---> 12 weights = weights - lr*weights.grad # update - gradient descent
14 if (i+1) % 100 == 0:
15 print(f"- Batch:[{i+1}|{num_batches}{5*' '}Samples:[{(i+1)*num_batches}|{len(train_loader)}]{5*' '}loss:{loss.item():.6f}")
TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'
这意味着梯度的计算不会影响变量 weights
,因为它仍然设置为 None
。你知道哪里出了问题吗?
您将在第一个循环迭代中覆盖 weights
变量,该变量将替换为 weights
的副本,而没有 grad
属性.可以使用以下最小代码重现此行为:
>>> weights.grad = torch.ones_like(weights)
>>> for i in range(2):
... print(weights.grad)
... weights = weights - weights.grad
tensor([1., 1.])
None
要解决此问题,您可以使用 in-place 操作更新参数:
weights -= lr*weights.grad # update - gradient descent