自动微分:
import torch
import numpy as np
from matplotlib import pyplot as plt
# 关闭科学计数法
# np.set_printoptions(suppress=True)
torch.set_printoptions(sci_mode=False)
# 叶子节点:
# 用户直接创建的张量,并且requires_grad=True
def test01():
x = torch.tensor(5.0, requires_grad=True)
y = x ** 2
z = y.sum()
print(x.is_leaf)
print(y.is_leaf)
print(z.is_leaf)
print(y.requires_grad)
print(z.requires_grad)
# 反向传播
def test02():
x = torch.tensor(1.0, requires_grad=True)
y = torch.tensor(2.0)
z = x ** 2 + y ** 2
# 反向传播,自动求导,计算x的梯度
z.backward()
# 获取x的梯度
print(x.grad)
print(y.grad)
# 向量反向传播,计算梯度
def test03():
x = torch.tensor([1, 2, 3], dtype=torch.float, requires_grad=True)
y = x ** 2
# loss = y.sum()
loss = y.mean()
# 反向传播
# y.backward(torch.tensor([1.0, 1.0, 1.0]))
loss.backward()
print(x.grad)
# 多标量反向传播计算梯度
def test04():
x = torch.tensor(1.0, requires_grad=True)
y = torch.tensor(2.0, requires_grad=True)
z = x ** 2 + y ** 2
z.backward()
print(x.grad)
print(y.grad)
# 多向量反向传播计算梯度
def test05():
x = torch.tensor([1, 2, 3], dtype=torch.float, requires_grad=True)
y = torch.tensor([4, 5, 6], dtype=torch.float, requires_grad=True)
z = x * y
loss = z.sum()
loss.backward()
print(x.grad)
print(y.grad)
# 设置张量不参与梯度计算
def test06():
x = torch.tensor(1.0, requires_grad=True)
y = x ** 2
print(y.requires_grad)
# 通过with梯度上下文控制,使y不参与梯度计算(常用)
# torch.no_grad():控制张量不参与梯度计算
with torch.no_grad():
y = x ** 2
print(y.requires_grad)
# 通过装饰器
@torch.no_grad()
def fn():
y = x ** 2
return y
y = fn()
print(y.requires_grad)
# 全局控制(谨慎使用)
torch.set_grad_enabled(False)
y = x ** 2
print(y.requires_grad)
# 梯度累加
def test07():
x = torch.tensor([1, 2, 3], dtype=torch.float, requires_grad=True)
# 循环计算梯度时,默认梯度是累加的
for _ in range(3):
y = x ** 2
z = y.sum()
z.backward()
print(x.grad)
# 梯度清零
if x.grad is not None:
x.grad.zero_()
z.backward()
print(x.grad)
# 求函数最小值
# 绘制曲线函数,帮助分析数据
def test08():
x = np.linspace(-10, 10, 100)
y = x ** 2
plt.plot(x, y)
plt.show()
# 通过反向传播计算最小值
def test09():
lst = []
# 初始化x值
x = torch.tensor(3.0, requires_grad=True)
# 迭代检索
epochs = 25
# 学习率
lr = 0.1
for epoch in range(epochs):
y = x ** 2
# 反向传播
y.backward()
# 梯度下降计算时,x不需要参与梯度计算
with torch.no_grad():
x -= lr * x.grad
# 梯度清零
x.grad.zero_()
print(f"epoch: {epoch}, x:{x.item()}, y:{y.item()}")
lst.append((x.item(), y.item()))
x_lst = [t[0] for t in lst]
y_lst = [t[1] for t in lst]
plt.scatter(x=x_lst, y=y_lst)
plt.show()
if __name__ == '__main__':
# test01()
# test02()
# test03()
# test04()
# test05()
# test06()
# test07()
# test08()
test09()
组件:
import torch
from torch import nn, optim
# 线性层组件
def test01():
# nn.Linear():线性层组件
# 参数:
# in_features:输入的特征数
# out_features:输出的特征数
model = nn.Linear(20, 30)
x = torch.randn(100, 20)
y = model(x)
print(y.shape)
# 优化器
def test02():
# 学习率
lr = 0.1
# y = x ** 2
# 定义线性模型,w和b做了随机初始化
model = nn.Linear(20, 10)
# 定义损失函数
criterion = nn.MSELoss()
# 定义优化器,主要做梯度下降,更新模型参数
optimizer = optim.SGD(model.parameters(), lr=lr)
# 初始化输入数据
x = torch.randn(100, 20)
# 标签数据
y = torch.randn(100, 10)
# 预测值
y_pred = model(x)
# 损失函数
loss = criterion(y_pred, y)
# 反向传播
loss.backwrad()
# 梯度下降,更新模型参数
optimizer.step()
# 梯度清零
optimizer.zero_grad()
print(loss.item())
print(model.weight)
print(model.bias)
if __name__ == '__main__':
# test01()
test02()
数据构建和加载:
import torch
from torch.utils.data import Dataset, TensorDataset, DataLoader
torch.manual_seed(0)
# 自定义数据构建类
# 1.继承Dataset抽象类
# 2.必须实现__len__和__getitem__方法
class MyDataset(Dataset):
def __init__(self, data, label):
self.data = data
self.label = label
def __len__(self):
return len(self.data)
def __getitem__(self, index):
data = self.data[index]
label = self.label[index]
return data, label
def test01():
x = torch.randn(100, 10)
y = torch.randn(100, 1)
my_dataset = MyDataset(x, y)
print(my_dataset[0])
# TensorDataset():是Dataset的一个实现类
# 可以将data和label作为参数传输给TensorDataset()生成数据集
def test02():
x = torch.randn(100, 10)
y = torch.randn(100, 1)
my_dataset = TensorDataset(x, y)
print(my_dataset[0])
# 数据加载器:DataLoader,是一个迭代器
# 参数:
# batch_size:批量加载数据,将多个样本打包成一个批量,加载器每次加载一个批量的数据
# shuffle:为True表示打乱数据顺序
def test03():
x = torch.randn(100, 10)
y = torch.randn(100, 1)
my_dataset = MyDataset(x, y)
dataloader = DataLoader(my_dataset, batch_size=4, shuffle=True)
for data, label in dataloader:
print(data)
print(label)
if __name__ == '__main__':
# test01()
# test02()
test03()
重构线性回归:
import torch
from torch import nn, optim
from sklearn.datasets import make_regression
import random
from torch.utils.data import Dataset, DataLoader, TensorDataset
input_features = 5
def build_data():
noise = random.randint(1, 3)
bias = 14.5
x, y, coef = make_regression(
# 样本数量
n_samples=1000,
# 每个样本包含的特征数量
n_features=input_features,
# 输出标签个数
n_targets=1,
# coef若为True,则返回真实系数(权重)
coef=True,
# 随机数种子
random_state=42,
# 添加噪声
noise=noise,
# 设置偏移值
bias=bias
)
x = torch.tensor(x, dtype=torch.float)
y = torch.tensor(y, dtype=torch.float)
coef = torch.tensor(coef, dtype=torch.float)
bias = torch.tensor(bias, dtype=torch.float)
return x, y, coef, bias
def train():
x, y, coef, bias = build_data()
# 封装数据集
dataset = TensorDataset(x, y)
# 数据加载器
dataloader = DataLoader(dataset, batch_size=16, shuffle=True)
# 定义线性模型
model = nn.Linear(input_features, 1)
# 定义损失函数
criterion = nn.MSELoss()
# 定义优化器
optimizer = optim.SGD(model.parameters(), lr=0.1)
epochs = 500
# 开始训练
for epoch in range(epochs):
loss_sum = 0
for train_x, train_y in dataloader:
# 获取预测值
y_pred = model(train_x)
# 损失计算
loss = criterion(y_pred, train_y.view(-1, 1))
# 反向传播
loss.backward()
# 更新参数(梯度下降)
optimizer.step()
# 梯度清零
optimizer.zero_grad()
# 损失值累加
loss_sum += loss.item()
# print(f"Epoch: {epoch}, Loss: {loss.item()}")
print(f"Epoch: {epoch}, Loss: {loss_sum / len(dataloader)}")
w = model.weight.detach()
b = model.bias.detach().item()
print(f"真实w: {coef}, 训练w: {w}")
print(f"真实偏置(b): {bias}, 训练偏置: {b}")
if __name__ == '__main__':
train()