线性回归模型代码
以下代码来自 d2l.ai/chapter_lin…
只是加上我自己的认知的注释:
import tensorflow as tf
import matplotlib.pyplot as plt
# d2l 的命名 dive into deeplearning
from d2l import tensorflow as d2l
class LinearRegressionScratch(d2l.Module): #@save
"""The linear regression model implemented from scratch."""
def __init__(self, num_inputs, lr, sigma=0.01):
super().__init__()
self.save_hyperparameters()
w = tf.random.normal((num_inputs, 1), mean=0, stddev=0.01) # 随机生成num_inputs行,1列满足正态分布的矩阵,mean=0是均值,steddev是标准差
b = tf.zeros(1) # 生成一个(1,) 张量
self.w = tf.Variable(w, trainable=True) # w 和 b 标记为可训练变量, 那就在训练的时候会更新它的值
self.b = tf.Variable(b, trainable=True)
# forward 方法通常用于定义模型的前向传播过程。在机器学习和深度学习中,前向传播是指将输入数据通过模型的计算过程,得到输出结果的过程
# 线性模型相当于一个最简单的神经元
@d2l.add_to_class(LinearRegressionScratch) #@save
def forward(self, X):
return tf.matmul(X, self.w) + self.b
# 定义损失函数
@d2l.add_to_class(LinearRegressionScratch) #@save
def loss(self, y_hat, y):
l = (y_hat - y) ** 2 / 2 # y_hat 表示预测值,y 表示真实值
return tf.reduce_mean(l) # reduce_mean 表示讲损失的张量,降维成标量,然后计算平均值。常见就是整个张量求和取平均
# 定义随机梯度算法用来最小化损失函数
class SGD(d2l.HyperParameters): #@save
"""Minibatch stochastic gradient descent."""
def __init__(self, lr):
self.save_hyperparameters() # 保存一些超参数之类的学习率,批量大小,迭代次数,正则化参数;lr 是学习率表示每次batch调参的幅度
def apply_gradients(self, grads_and_vars): # 用于优化器中得到应用梯度更新。
for grad, param in grads_and_vars:
param.assign_sub(self.lr * grad)
# 给线性模型提供优化算法
@d2l.add_to_class(LinearRegressionScratch) #@save
def configure_optimizers(self):
return SGD(self.lr)
@d2l.add_to_class(d2l.Trainer) #@save
def prepare_batch(self, batch):
return batch
@d2l.add_to_class(d2l.Trainer) #@save
def fit_epoch(self):
# 一个epoch 指将整个数据集训练完,tensorflow 库里面默认就是这段线性的fit_epoch代码
# 模型进入训练模式
self.model.training = True
for batch in self.train_dataloader:
# 每次使用一个batch 的训练数据
with tf.GradientTape() as tape:
# 使用模型的中 training_step, MSE 均方误差如上定义
loss = self.model.training_step(self.prepare_batch(batch))
# tape.gradient 损失函数 相对于w, b求导(梯度)
print(self.model.trainable_variables)
grads = tape.gradient(loss, self.model.trainable_variables)
# 设置了梯度裁剪的阈值(gradient_clip_val)则在这一步对梯度进行裁剪。
# 梯度裁剪是为了防止梯度爆炸的问题,即梯度值过大导致训练不稳定
if self.gradient_clip_val > 0:
grads = self.clip_gradients(self.gradient_clip_val, grads)
self.optim.apply_gradients(zip(grads, self.model.trainable_variables)) # 用更新后的梯度和训练数据优化
self.train_batch_idx += 1
if self.val_dataloader is None:
return
self.model.training = False
# 用来定义模型在验证集上的验证过程
for batch in self.val_dataloader:
self.model.validation_step(self.prepare_batch(batch))
self.val_batch_idx += 1
plt.savefig('my_plot.png')
##################################### 主流程 #########################################
# 定义线性模型
model = LinearRegressionScratch(2, lr=0.03)
# 默认生成 2000 组数据加上噪声的,其中 1000 组数据用来训练,1000 组数据用来验证。
data = d2l.SyntheticRegressionData(w=tf.constant([2, -3.4]), b=4.2)
# 打印出来是个 2000*2 的矩阵
# print(data.X)
# 2000 * 1 矩阵
# print(data.y)
# 创建训练器
trainer = d2l.Trainer(max_epochs=3)
# 开始训练,fit 大致内容
# 1. prepare_data(data)
# 1.1 self.train_dataloader = data.train_dataloader() # 训练数据加载到 self.train_dataloader
# 1.2 self.val_dataloader = data.val_dataloader() # 验证数据加载到 self.val_dataloader
# 加载后 2000 组数据会被分成 32 batch batch大小在SyntheticRegressionData定义
# 2. self.prepare_model(model)
# 3. 训练 max_epochs=3 轮fit_epoch,fit_epoch 需要用户去实现。
trainer.fit(model, data)
# 计算误差
print(f'error in estimating w: {data.w - tf.reshape(model.w, data.w.shape)}')
print(f'error in estimating b: {data.b - model.b}')