regression - 在 tf.keras 中理解线性回归模型调优的问题
问题描述
我正在使用合成数据 Colab 练习进行线性回归,它使用玩具数据集探索线性回归。建立和训练了一个线性回归模型,可以使用学习率、时期和批量大小。我很难理解迭代是如何完成的,以及它如何与“epoch”和“batch size”相关联。我基本上不知道如何训练实际模型、如何处理数据以及如何完成迭代。为了理解这一点,我想通过手动计算每个步骤来遵循这一点。因此,我希望每个步骤都有斜率和截距系数。这样我就可以看到“计算机”使用什么样的数据,放入模型中,在每次特定迭代中产生什么样的模型结果以及迭代是如何完成的。我首先尝试获取每一步的斜率和截距,但是失败了,因为只有在最后才输出斜率和截距。我修改后的代码(原版,刚刚添加:)
print("Slope")
print(trained_weight)
print("Intercept")
print(trained_bias)
代码:
import pandas as pd
import tensorflow as tf
from matplotlib import pyplot as plt
#@title Define the functions that build and train a model
def build_model(my_learning_rate):
"""Create and compile a simple linear regression model."""
# Most simple tf.keras models are sequential.
# A sequential model contains one or more layers.
model = tf.keras.models.Sequential()
# Describe the topography of the model.
# The topography of a simple linear regression model
# is a single node in a single layer.
model.add(tf.keras.layers.Dense(units=1,
input_shape=(1,)))
# Compile the model topography into code that
# TensorFlow can efficiently execute. Configure
# training to minimize the model's mean squared error.
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=my_learning_rate),
loss="mean_squared_error",
metrics=[tf.keras.metrics.RootMeanSquaredError()])
return model
def train_model(model, feature, label, epochs, batch_size):
"""Train the model by feeding it data."""
# Feed the feature values and the label values to the
# model. The model will train for the specified number
# of epochs, gradually learning how the feature values
# relate to the label values.
history = model.fit(x=feature,
y=label,
batch_size=batch_size,
epochs=epochs)
# Gather the trained model's weight and bias.
trained_weight = model.get_weights()[0]
trained_bias = model.get_weights()[1]
print("Slope")
print(trained_weight)
print("Intercept")
print(trained_bias)
# The list of epochs is stored separately from the
# rest of history.
epochs = history.epoch
# Gather the history (a snapshot) of each epoch.
hist = pd.DataFrame(history.history)
# print(hist)
# Specifically gather the model's root mean
#squared error at each epoch.
rmse = hist["root_mean_squared_error"]
return trained_weight, trained_bias, epochs, rmse
print("Defined create_model and train_model")
#@title Define the plotting functions
def plot_the_model(trained_weight, trained_bias, feature, label):
"""Plot the trained model against the training feature and label."""
# Label the axes.
plt.xlabel("feature")
plt.ylabel("label")
# Plot the feature values vs. label values.
plt.scatter(feature, label)
# Create a red line representing the model. The red line starts
# at coordinates (x0, y0) and ends at coordinates (x1, y1).
x0 = 0
y0 = trained_bias
x1 = my_feature[-1]
y1 = trained_bias + (trained_weight * x1)
plt.plot([x0, x1], [y0, y1], c='r')
# Render the scatter plot and the red line.
plt.show()
def plot_the_loss_curve(epochs, rmse):
"""Plot the loss curve, which shows loss vs. epoch."""
plt.figure()
plt.xlabel("Epoch")
plt.ylabel("Root Mean Squared Error")
plt.plot(epochs, rmse, label="Loss")
plt.legend()
plt.ylim([rmse.min()*0.97, rmse.max()])
plt.show()
print("Defined the plot_the_model and plot_the_loss_curve functions.")
my_feature = ([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0])
my_label = ([5.0, 8.8, 9.6, 14.2, 18.8, 19.5, 21.4, 26.8, 28.9, 32.0, 33.8, 38.2])
learning_rate=0.05
epochs=1
my_batch_size=12
my_model = build_model(learning_rate)
trained_weight, trained_bias, epochs, rmse = train_model(my_model, my_feature,
my_label, epochs,
my_batch_size)
plot_the_model(trained_weight, trained_bias, my_feature, my_label)
plot_the_loss_curve(epochs, rmse)
在我的具体情况下,我的输出是:
现在我尝试在一个简单的 Excel 表中复制它并手动计算 rmse:
但是,我得到 21.8 而不是 23.1?另外我的损失不是535.48,而是476.82
因此,我的第一个问题是:我的错误在哪里,rmse 是如何计算的?
第二个问题:如何获得每次特定迭代的 rmse?假设 epoch 为 4,batch size 为 4。
这给出了 4 个时期和 3 个批次,每 4 个示例(观察)。我不明白如何通过这些迭代训练模型。那么如何获得每个回归模型和 rmse 的系数呢?不仅针对每个 epoch(所以 4),而且针对每个迭代。我认为每个时代都有 3 次迭代。所以我认为总共有 12 个线性回归模型?我想看看这12个模型。在没有给出信息的情况下,起点使用的初始值是什么,使用什么样的斜率和截距?从真正的第一点开始。我没有具体说明这一点。然后我希望能够了解每一步如何调整斜率和截距。这将来自我认为的梯度下降算法。但这将是超级优势。
更新:我知道初始值(斜率和截距)是随机选择的。
解决方案
基础
问题陈述
让我们考虑一组样本的线性回归模型,X
其中每个样本由一个特征表示x
。作为模型训练的一部分,我们正在寻找w.x + b
使((w.x+b) -y )^2
(平方损失)最小的线。对于一组数据点,我们采用每个样本的均方损失,即所谓的均方误差 (MSE)。代表权重和偏差的w
和b
统称为权重。
拟合线/训练模型
- 我们有一个用于解决线性回归问题的封闭形式的解决方案,并且是
(X^T.X)^-1.X^T.y
- 我们还可以使用梯度下降法来搜索最小化平方损失的权重。tensorflow、pytorch 等框架使用梯度下降来搜索权重(称为训练)。
渐变体面
用于学习回归的梯度体面算法看起来像打击
w, b = some initial value
While model has not converged:
y_hat = w.X + b
error = MSE(y, y_hat)
back propagate (BPP) error and adjust weights
上述循环的每次运行称为一个时期。但是由于资源的限制,计算y_hat
,error
并且 BPP 没有在完整的数据集上执行,而是将数据分成更小的批次,并且一次对一个批次执行上述操作。此外,我们通常会固定 epoch 的数量并监控模型是否收敛。
w, b = some initial value
for i in range(number_of_epochs)
for X_batch,y_batch in get_next_batch(X, y)
y_hat = w.X_batch + b
error = MSE(y_batch, y_hat)
back propagate (BPP) error and adjust weights
Keras 批量实现
假设我们想添加均方根误差,以便在训练时跟踪模型性能。Keras的实现方式如下
w, b = some initial value
for i in range(number_of_epochs)
all_y_hats = []
all_ys = []
for X_batch,y_batch in get_next_batch(X, y)
y_hat = w.X_batch + b
error = MSE(y_batch, y_hat)
all_y_hats.extend(y_hat)
all_ys.extend(y_batch)
batch_rms_error = RMSE(all_ys, all_y_hats)
back propagate (BPP) error and adjust weights
正如您在上面看到的,预测是累积的,RMSE 是根据累积的预测计算的,而不是取所有先前批次 RMSE 的平均值。
keras 中的实现
现在我们的基础很清楚了,让我们看看如何在 keras 中实现相同的跟踪。keras 有回调,所以我们可以挂钩on_batch_begin
回调并累积all_y_hats
and all_ys
。在on_batch_end
回调上 keras 给了我们计算的RMSE
. RMSE
我们将使用我们的累积手动计算all_y_hats
,all_ys
并验证它是否与 keras 计算的相同。我们还将保存权重,以便稍后绘制正在学习的线。
import numpy as np
from sklearn.metrics import mean_squared_error
import keras
import matplotlib.pyplot as plt
# Some training data
X = np.arange(16)
y = 0.5*X +0.2
batch_size = 8
all_y_hats = []
learned_weights = []
class CustomCallback(keras.callbacks.Callback):
def on_batch_begin(self, batch, logs={}):
w = self.model.layers[0].weights[0].numpy()[0][0]
b = self.model.layers[0].weights[1].numpy()[0]
s = batch*batch_size
all_y_hats.extend(b + w*X[s:s+batch_size])
learned_weights.append([w,b])
def on_batch_end(self, batch, logs={}):
calculated_error = np.sqrt(mean_squared_error(all_y_hats, y[:len(all_y_hats)]))
print (f"\n Calculated: {calculated_error}, Actual: {logs['root_mean_squared_error']}")
assert np.isclose(calculated_error, logs['root_mean_squared_error'])
def on_epoch_end(self, batch, logs={}):
del all_y_hats[:]
model = keras.models.Sequential()
model.add(keras.layers.Dense(1, input_shape=(1,)))
model.compile(optimizer=keras.optimizers.RMSprop(lr=0.01), loss="mean_squared_error", metrics=[keras.metrics.RootMeanSquaredError()])
# We should set shuffle=False so that we know how baches are divided
history = model.fit(X,y, epochs=100, callbacks=[CustomCallback()], batch_size=batch_size, shuffle=False)
输出:
Epoch 1/100
8/16 [==============>...............] - ETA: 0s - loss: 16.5132 - root_mean_squared_error: 4.0636
Calculated: 4.063645694548688, Actual: 4.063645839691162
Calculated: 8.10112834945773, Actual: 8.101128578186035
16/16 [==============================] - 0s 3ms/step - loss: 65.6283 - root_mean_squared_error: 8.1011
Epoch 2/100
8/16 [==============>...............] - ETA: 0s - loss: 14.0454 - root_mean_squared_error: 3.7477
Calculated: 3.7477213352845675, Actual: 3.7477214336395264
-------------- truncated -----------------------
达达!断言assert np.isclose(calculated_error, logs['root_mean_squared_error'])
从未失败,因此我们的计算/理解是正确的。
线
最后,让我们根据均方误差损失绘制由 BPP 算法调整的线。我们可以使用下面的代码创建一个 png 图像,其中包含每批学习的线条以及训练数据。
for i, (w,b) in enumerate(learned_weights):
plt.close()
plt.axis([-1, 18, -1, 10])
plt.scatter(X, y)
plt.plot([-1,17], [-1*w+b, 17*w+b], color='green')
plt.savefig(f'img{i+1}.png')
下面是以上图片的gif动画,按学习顺序排列。
学习的超平面(在这种情况下为线)y = 0.5*X +5.2
推荐阅读
- python - TypeError:'int'和'tuple'的实例之间不支持'<'
- c# - C# wpf,如何在 1 秒内更新进度条
- c++ - 为什么在 C++ 中进行强制转换会打印出意想不到的结果?
- python - 如何使用python创建sql db2数据表?
- python-3.x - 有什么方法可以更简洁地重构它吗?特别是第 7-11 行与第 39 行的关系?使用 Pygame
- list - 方案列表作为参数
- r - 如何将公式放入R中的函数中?
- upnp - UPNP 的 AVTransport 服务的 SetCurrentURI 的元数据中“类”属性的所有可能选项是什么
- html - 为什么使用“clear”属性(css)后margin属性在“container3”中不起作用?
- java - 如何将字体设置为 AlertDialog.Builder 的 setMessage 部分?