通过可视化梯度下降来调整超参数的简单方法
本文将展示一种通过使用Keras中的回调访问机器学习模型权重来调整超参数的简单方法。
应用机器学习是一个经验过程,您需要尝试不同的超参数设置,并推断哪些设置最适合您的应用。这种技术通常称为超参数调整。这些超参数可以是学习率(alpha),迭代次数,mini batch size等。
目标
调优通常是通过观察连续迭代中成本函数的趋势来执行的。好的机器学习模型具有持续降低的成本函数,直到达到一定的最小值。
本文将展示一种简单的方法,可以在Keras模型的帮助下绘制成本函数的最小化。
在我们的示例中,我们将考虑一个单变量线性回归问题,该问题基于广告支出的金额来预测特定产品的销售。
注意:虽然选择的问题非常简单,但这种技术也适用于深度神经网络。
介绍
成本函数是衡量机器学习模型误差程度的指标,用于估算输入与相应输出之间关系的能力。
梯度下降是通过重复更新网络参数值来最小化成本函数的技术。梯度下降的目标可以被认为是“迭代调整参数,直到达到局部最小值”。
Python实现
Advertising.csv()文件(http://www.kankanyun.com/data/Advertising.csv)包含分配给各种来源(电视、广播、报纸)的广告预算及其对特定产品销售的影响。
由于我们的重点是单变量回归,我们只考虑分配给电视的预算作为我们的自变量。
导入Python库
from tensorflow import keras from keras.layers import Dense from keras.models import Sequential from keras import optimizers from sklearn.model_selection import train_test_split import pandas as pd import numpy as np import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation from numpy.random import seed seed(2) from tensorflow import set_random_seed set_random_seed(2)
加载数据并删除所有不必要的列
df = pd.read_csv('Advertising.csv') df.drop(['Unnamed: 0','radio','newspaper'],axis = 1 , inplace=True) df.head()
最终的dataframe看起来像
将数据分成训练和测试集
X = df['TV'] Y = df['sales'] X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2)
定义线性回归模型
def LinearRegression(): model = Sequential() model.add(Dense(1, activation = 'linear', use_bias = True, input_dim = 1)) model.compile(optimizer = optimizers.RMSprop(lr = 0.01), loss = 'mean_squared_error', metrics = ['mae']) return model model = LinearRegression()
请注意Keras没有明确提供类似scikit-learn的线性回归模型。但是我们可以使用具有单个神经元的密集层来模拟线性回归。
设计的模型看起来像
在Keras中定义回调
Keras回调可以帮助您更快地修复bug并构建更好的机器学习模型。
“回调是在训练过程的给定阶段应用的一组函数。您可以使用回调来获取训练期间内部状态和模型统计信息的视图。“
weight_history = [] bias_history = [] class MyCallback(keras.callbacks.Callback): def on_batch_end(self, batch, logs): weight, bias = model.get_weights() B = bias[0] W = weight[0][0] params = [W, B] weight_history.append(W) bias_history.append(B) callback = MyCallback()
创建的回调与输入和输出一起传递,用于训练机器学习模型。
MODEL = model.fit(X_train, Y_train, epochs = 10, batch_size = 10, verbose = True, callbacks=[callback])
训练模型,我们得到一个预测图
area = np.pi * 1**2 fig, ax = plt.subplots() ax.scatter(X_train,Y_train,s = area, color = 'red') ax.plot(X_test,model.predict(X_test),'b') ax.spines['left'].set_position('zero') ax.spines['right'] ax.yaxis.tick_left() ax.spines['bottom'].set_position('zero') ax.spines['top'] ax.xaxis.tick_bottom() plt.xlabel("TV advertising budget") plt.ylabel("Sales") plt.show()
显示机器学习模型的最终权重
weight_matrix,bias_matrix = model.get_weights() weight_matrix[0][0] bias_matrix[0]
0.08625534
-0.021305896
通过迭代更新权重的列表
weight_history[:5]
[0.602684, 0.58524895, 0.5707742, 0.5589197, 0.5513936]
bias_history[:5]
[-0.03162277, -0.04938902, -0.065991394, -0.07906431, -0.08885604]
绘制成本函数
线性回归的成本函数由下式给出
从等式中可以清楚地看出,我们对可视化成本最小化的要求是每次迭代后更新的层的权重(和偏差)。
如果我们能以某种方式访问图层的权重,我们将能够轻松地将成本最小化/梯度下降可视化。Keras为用户提供get_weights()函数以访问网络层的权重。但是该函数在训练后返回模型的最终权重(和偏差)。我们需要一种方法来在每次迭代(或每个批次)结束时访问权重。为此,我们需要使用回调。
%matplotlib nbagg def costfunction(x,y,theta): m = np.size(y) h = np.dot(x,theta) J = float(np.dot((h - y).T,(h - y))/(m*2)); return J; X = np.array(X_train.tolist()) Y = np.array(Y_train.tolist()) X_1 = np.vstack((np.ones(len(X)), X)).T #Setup of meshgrid of bias(T0)/weight(T1) values T0, T1 = np.meshgrid(np.linspace(-100,100, 10),np.linspace(-0.8,0.8,7)) #Computing the cost function for each weight/bias combination zs = np.array( [costfunction(X_1, Y.reshape(-1,1),np.array([t0,t1]).reshape(-1,1)) for t0, t1 in zip(np.ravel(T0), np.ravel(T1)) ] ) #Reshaping the cost values Z = zs.reshape(T0.shape) x = bias_history y = weight_history fig = plt.figure() ax = fig.add_subplot(1, 1, 1) cp = ax.contour(T0, T1, Z, 30, cmap = 'jet') ax.clabel(cp, inline=True, fontsize=10) plt.xlabel("Bias") plt.ylabel("Weight") graph, = plt.plot([], [], 'r-') def animate(i): graph.set_data(x[:i], y[:i]) return graph anime = FuncAnimation(fig, animate, frames=np.arange(0,100), interval=100) anime.save('cost.gif', dpi=80, writer='imagemagick') plt.show()
权重历史
%matplotlib inline plt.xlabel("No. of iterations") plt.ylabel("Weight") plt.plot(weight_history)
偏差历史
%matplotlib inline plt.xlabel("No. of iterations") plt.ylabel("Learned bias") plt.plot(bias_history, 'orange')
成本的迭代
%matplotlib inline cost_func = MODEL.history['loss'] plt.plot(cost_func) plt.ylabel("mean squared error") plt.xlabel("No. of iterations")