import numpy as np
import torch
'''
Training data
'''
# Input (temp, rainfall, humidity)
inputs = np.array([[73, 67, 43],
[91, 88, 64],
[87, 134, 58],
[102, 43, 37],
[69, 96, 70]], dtype='float32')
# Targets (apples, oranges)
targets = np.array([[56, 70],
[81, 101],
[119, 133],
[22, 37],
[103, 119]], dtype='float32')
# Convert inputs and targets to tensors
inputs = torch.from_numpy(inputs)
targets = torch.from_numpy(targets)
print(inputs)
print(targets)
'''
1.Linear regression model from scratch
'''
# Weights and biases
w = torch.randn(2, 3, requires_grad=True)
b = torch.randn(2, requires_grad=True)
print(w)
print(b)
def model(x):
return x @ w.t() + b
#@ represents matrix multiplication in PyTorch,
#and the .t method returns the transpose of a tensor.
# Generate predictions
preds = model(inputs)
print(preds)
# Compare with targets
print(targets)
'''
Loss function
计算两个矩阵(preds 和 targets)之间的差异;
求这个差异矩阵的所有元素的平方以消除其中的负值;
计算所得矩阵中元素的平均值。
'''
# MSE loss
def mse(t1, t2):
diff = t1 - t2
return torch.sum(diff * diff) / diff.numel()
#torch.sum 返回一个张量中所有元素的和,
#.numel 方法则返回一个张量中元素的数量
# Compute loss
loss = mse(preds, targets)
print(loss)
#平均而言,预测结果中每个元素与实际目标之间的差距大约为 215(46194 的平方根)。
#考虑到我们所要预测的数值的范围本身只有 50-200,所以这个结果实在相当糟糕。
#我们称这个结果为损失(loss),因为它指示了模型在预测目标变量方面的糟糕程度。损失越低,模型越好。
'''
Compute gradients
可以根据权重和偏置自动计算 loss 的梯度和导数,
因为它们已将 requires_grad 设置为 True
'''
# Compute gradients
loss.backward()
#这些梯度存储在各自张量的 .grad 属性中
# Gradients for weights
print(w)
print(w.grad)
#通过调用 .zero() 方法将梯度重置为零。我们需要这么做的原因是 PyTorch 会累积梯度,
#也就是说,我们下一次在损失上调用 .backward 时,新的梯度值会被加到已有的梯度值上,
#这可能会导致意外结果出现
w.grad.zero_()
b.grad.zero_()
print(w.grad)
print(b.grad)
'''
Adjust weights and biases using gradient descent
生成预测
计算损失
根据权重和偏置计算梯度
按比例减去少量梯度来调整权重
将梯度重置为零
'''
# Generate predictions
preds = model(inputs)
print(preds)
# Calculate the loss
loss = mse(preds, targets)
print(loss)
# Compute gradients
loss.backward()
print(w.grad)
print(b.grad)
# Adjust weights & reset gradients
with torch.no_grad():
w -= w.grad * 1e-5
b -= b.grad * 1e-5
w.grad.zero_()
b.grad.zero_()
#我们使用 torch.no_grad 指示 PyTorch 我们在更新权重和偏置时不应该跟踪、计算或修改梯度。
#我们为梯度乘上了一个非常小的数值(这个案例中为 10^-5),以确保我们不会改变权重太多,因为我们只想在梯度的下降方向上迈出一小步。
#这个数值是这个算法的学习率(learning rate)。
#在更新权重之后,我们将梯度重置为零,以免影响后续计算。
print(w)
print(b)
# Calculate loss
preds = model(inputs)
loss = mse(preds, targets)
print(loss)
'''
Train for multiple epochs
'''
# Train for 100 epochs
for i in range(100):
preds = model(inputs)
loss = mse(preds, targets)
loss.backward()
with torch.no_grad():
w -= w.grad * 1e-5
b -= b.grad * 1e-5
w.grad.zero_()
b.grad.zero_()
# Calculate loss
preds = model(inputs)
loss = mse(preds, targets)
print(loss)
# Predictions
preds
# Targets
targets
'''
2.Linear regression using PyTorch built-ins
'''
import torch.nn as nn
# Input (temp, rainfall, humidity)
inputs = np.array([[73, 67, 43], [91, 88, 64], [87, 134, 58],
[102, 43, 37], [69, 96, 70], [73, 67, 43],
[91, 88, 64], [87, 134, 58], [102, 43, 37],
[69, 96, 70], [73, 67, 43], [91, 88, 64],
[87, 134, 58], [102, 43, 37], [69, 96, 70]],
dtype='float32')
# Targets (apples, oranges)
targets = np.array([[56, 70], [81, 101], [119, 133],
[22, 37], [103, 119], [56, 70],
[81, 101], [119, 133], [22, 37],
[103, 119], [56, 70], [81, 101],
[119, 133], [22, 37], [103, 119]],
dtype='float32')
inputs = torch.from_numpy(inputs)
targets = torch.from_numpy(targets)
from torch.utils.data import TensorDataset
# Define dataset
train_ds = TensorDataset(inputs, targets)
train_ds[0:3]
#创建一个 TensorDataset,这让我们可以读取 inputs 和 targets 的行作为元组,
#并提供了 PyTorch 中用于处理许多不同类型的数据集的标准 API
from torch.utils.data import DataLoader
# Define data loader
batch_size = 5
train_dl = DataLoader(train_ds, batch_size, shuffle=True)
#将创建一个 DataLoader,它可以在训练时将数据分成预定义大小的批次。
#它还能提供其它效用程序,如数据的混洗和随机采样。
for xb, yb in train_dl:
print(xb)
print(yb)
break
'''
nn.Linear
'''
# Define model
model = nn.Linear(3, 2)
print(model.weight)
print(model.bias)
# Parameters
list(model.parameters())
#PyTorch 模型还有一个很有用的 .parameters 方法,
#这能返回一个列表,其中包含了模型中所有的权重和偏置矩阵。
# Generate predictions
preds = model(inputs)
preds
'''
Loss Function
'''
# Import nn.functional
import torch.nn.functional as F
# Define loss function
loss_fn = F.mse_loss
loss = loss_fn(model(inputs), targets)
print(loss)
'''
Optimizer
'''
# Define optimizer
opt = torch.optim.SGD(model.parameters(), lr=1e-5)
'''
Train the model
'''
# Utility function to train the model
def fit(num_epochs, model, loss_fn, opt):
# Repeat for given number of epochs
for epoch in range(num_epochs):
# Train with batches of data
for xb,yb in train_dl:
# 1. Generate predictions
pred = model(xb)
# 2. Calculate loss
loss = loss_fn(pred, yb)
# 3. Compute gradients
loss.backward()
# 4. Update parameters using gradients
opt.step()
# 5. Reset the gradients to zero
opt.zero_grad()
# Print the progress
if (epoch+1) % 10 == 0:
print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item()))
#我们使用之前定义的数据加载器来为每个迭代获取数据批次。
#我们没有手动更新参数(权重和偏置),而是使用了 opt.step 来执行更新,并使用了 opt.zero_grad 来将梯度重置为零。
#我们还添加了一个日志语句,能够显示每第 10 个 epoch 的最后一批数据的损失,从而可让我们跟踪训练进程。
#loss.item 会返回存储在损失张量中的实际值。
fit(100, model, loss_fn, opt)
# Generate predictions
preds = model(inputs)
preds
# Compare with targets
targets