Tim*_*nen 5 python numpy linear-regression pytorch
我在这里掌握了 pytorch,并决定实现非常简单的 1 对 1 线性回归,从身高到体重。
获得数据集: https: //www.kaggle.com/datasets/mustafaali96/weight-height,但任何其他数据集都可以。
让我们导入有关女性的库和信息:
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_csv('weight-height.csv',sep=',')
#https://www.kaggle.com/datasets/mustafaali96/weight-height
height_f=df[df['Gender']=='Female']['Height'].to_numpy()
weight_f=df[df['Gender']=='Female']['Weight'].to_numpy()
plt.scatter(height_f, weight_f, c ="red",alpha=0.1)
plt.show()
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好。
让我们制作数据加载器:
class Data(Dataset):
def __init__(self, X: np.ndarray, y: np.ndarray) -> None:
# need to convert float64 to float32 else
# will get the following error
# RuntimeError: expected scalar type Double but found Float
self.X = torch.from_numpy(X.reshape(-1, 1).astype(np.float32))
self.y = torch.from_numpy(y.reshape(-1, 1).astype(np.float32))
self.len = self.X.shape[0]
def __getitem__(self, index: int) -> tuple:
return self.X[index], self.y[index]
def __len__(self) -> int:
return self.len
traindata = Data(height_f, weight_f)
batch_size = 500
num_workers = 2
trainloader = DataLoader(traindata,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers)
Run Code Online (Sandbox Code Playgroud)
...线性回归模型...
class linearRegression(torch.nn.Module):
def __init__(self, inputSize, outputSize):
super(linearRegression, self).__init__()
self.linear = torch.nn.Linear(inputSize, outputSize)
def forward(self, x):
out = self.linear(x)
return out
model = linearRegression(1, 1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.00001)
Run Code Online (Sandbox Code Playgroud)
..让我们训练它:
epochs=10
for epoch in range(epochs):
print(epoch)
for i, (inputs, labels) in enumerate(trainloader):
outputs=model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Run Code Online (Sandbox Code Playgroud)
给出 0,1,2,3,4,5,6,7,8,9 现在让我们看看我们的模型给出了什么:
range_height_f=torch.linspace(height_f.min(),height_f.max(),150)
plt.scatter(height_f, weight_f, c ="red",alpha=0.1)
pred=model(range_height_f.reshape(-1, 1))
plt.scatter(range_height_f, pred.detach().numpy(), c ="green",alpha=0.1)
Run Code Online (Sandbox Code Playgroud)
为什么要这样做?为什么坡度不对?始终错误的斜率,我可能会添加无论我改变什么,优化器,批量大小,时代,女性到男性..它给了我这个非常错误的斜率,我真的不明白 - 为什么?
编辑2:决定进行一些探索,并使用sklearn进行回归:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
X_train, X_test, y_train, y_test = train_test_split(height_f, weight_f, test_size = 0.25)
regr = LinearRegression()
regr.fit(X_train.reshape(-1,1), y_train)
plt.scatter(height_f, weight_f, c ="red",alpha=0.1)
range_pred=regr.predict(range_height_f.reshape(-1, 1))
range_pred
plt.scatter(range_height_f, range_pred, c ="green",alpha=0.1)
Run Code Online (Sandbox Code Playgroud)
t = torch.from_numpy(height_f.astype(np.float32))
p=regr.predict(t.reshape(-1,1))
p=torch.from_numpy(p).reshape(-1,1)
w= torch.from_numpy(weight_f.astype(np.float32)).reshape(-1,1)
print(criterion(p,w).item())
Run Code Online (Sandbox Code Playgroud)
但是在这种情况下 criteria=100.65161998527695
Pytorch 自己又收敛到 210 左右
编辑 3 将优化从 SGD 更改为 Adam:
#optimizer = torch.optim.SGD(model.parameters(), lr=0.00001)
optimizer = torch.optim.Adam(model.parameters(), lr=0.5)
Run Code Online (Sandbox Code Playgroud)
我认为你的问题源于数据不以零为中心。
请参阅此线程的另一个示例,其中在训练之前“居中”数据对 SGD 优化的收敛具有巨大影响。
TL;DR
这都是关于标准化/初始化的。
详细来说:
您的数据不是以 0 为中心,也没有“很好”地缩放。这使得 SGD(及其所有其他变体)很难进行优化。
在这个答案中,我展示了如何集中训练数据(减去平均值并由标准差决定)解决这个问题。
在这里,我将向您展示如何保持数据不变,但更改权重的初始化来解决您的问题。
令m_x, s_x
为 的均值和标准差X
,并且m_y, s_y
为 的均值和标准差y
。当 pytorch 初始化线性层的
权重a
和时,它假设和 的均值和单位方差为零。这里的情况并非如此。离得很远。 因此,我们需要对初始进行相应的
重新调整。
这是它的数学计算:
b
y = aX + b
X
y
a
b
和代码:
mu_x, sig_x, mu_y, sig_y = traindata.X.mean().item(), traindata.X.std().item(), traindata.y.mean().item(), traindata.y.std().item()
# just for fun, here are the values:
# (63.7087, 2.6962, 135.8601, 19.0225)
# start a fresh model and adjust its initial values:
model = linearRegression(1, 1)
model.linear.weight.data *= (sig_x / sig_y)
model.linear.bias.data = sig_y * (-(mu_x/sig_x)+(mu_y/sig_y))
# now you are good to go! continue optimizing like you originally did:
# init an optimizer
optimizer = torch.optim.SGD(model.parameters(), lr=0.00001)
# optimize for 10 epochs (now you don't need this much, you can even increase the learning rate...)
epochs=10
for epoch in range(epochs):
print(epoch)
for i, (inputs, labels) in enumerate(trainloader):
outputs=model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Run Code Online (Sandbox Code Playgroud)
In []: loss.item()
Out[]: 100.9453125
Run Code Online (Sandbox Code Playgroud)
与 的类似sklearn.linear_model.LinearRegression
。
绘制数据预测: