通过可视化梯度下降来调整超参数的简单方法

KyrieHe 2019-06-09

本文将展示一种通过使用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")

通过可视化梯度下降来调整超参数的简单方法

通过可视化梯度下降来调整超参数的简单方法

相关推荐