import random
import torch
def syntheticData(w:torch.Tensor, b:float, numExaples:int)->tuple[torch.Tensor]:
'''
生成y=Xw+b+噪声
'''
X:torch.Tensor = torch.normal(0, 1, (numExaples, len(w)))
y:torch.Tensor = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
trueW:torch.Tensor = torch.tensor([2.0, -3.4])
trueB:float = 4.2
features, labels = syntheticData(trueW, trueB, 1000)
def dataIter(batchSize:int, features:torch.Tensor, labels:torch.Tensor):
numExamples:int = len(features)
indices:list[int] = list(range(numExamples))
random.shuffle(indices)
for idx in range(0, numExamples, batchSize):
batchIndices:torch.Tensor = torch.tensor(
indices[idx:min(idx+batchSize, numExamples)])
yield features[batchIndices], labels[batchIndices]
initW:torch.Tensor = torch.normal(0.0, 0.01, size=(2, 1), requires_grad=True)
initB:torch.Tensor = torch.zeros(1, requires_grad=True)
def linearRegModel(X:torch.Tensor, w:torch.Tensor, b:torch.Tensor)->torch.Tensor:
'''
线性回归模型
'''
return torch.matmul(X, w) + b
def squaredLoss(PreY:torch.Tensor, TrueY:torch.Tensor)->torch.Tensor:
'''
均方损失函数
'''
return (PreY-TrueY.reshape(PreY.shape))**2/2.0
def SGD(params:list[torch.Tensor], lr: float, batchSize:int):
'''
小批量随机梯度下降法
params: 模型参数集 合
lr: 学习率,确定每一步更新的大小
batchSize: 批量样本大小
'''
with torch.no_grad():
for param in params:
param -= lr*param.grad/batchSize
param.grad.zero_()
lr:float = 0.03
numEporchs:int = 3
batchSize: int = 10
net = linearRegModel
loss = squaredLoss
for epoch in range(numEporchs):
for X, y in dataIter(batchSize, features, labels):
l = loss(net(X, initW, initB), y)
l.sum().backward()
SGD([initW,initB], lr, batchSize)
with torch.no_grad():
train_l = loss(net(features, initW, initB), labels)
print(f'epoch {epoch+1}, loss {float(train_l.mean()):f}')
print(f'w的估计误差: {trueW - initW.reshape(trueW.shape)}')
print(f'b的估计误差: {trueB - initB}')