简介
本实验将指导你使用 Scikit-learn 的 MLPClassifier 来比较不同随机学习策略(包括随机梯度下降(SGD)和 Adam)的性能。MLPClassifier 是一个神经网络分类器,它使用反向传播来优化网络权重。本实验的目的是展示不同的随机学习策略如何影响 MLPClassifier 的训练损失曲线。我们将使用几个小数据集进行这个示例,尽管这些示例中显示的一般趋势似乎也适用于更大的数据集。
虚拟机使用提示
虚拟机启动完成后,点击左上角切换到“笔记本”标签,以访问 Jupyter Notebook 进行练习。
有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。
如果你在学习过程中遇到问题,可以随时向 Labby 提问。课程结束后提供反馈,我们会及时为你解决问题。
导入必要的库
首先,我们需要导入必要的库,包括 MLPClassifier、MinMaxScaler、datasets 和 matplotlib.pyplot。我们还将导入 ConvergenceWarning 以在训练期间忽略收敛警告。
import warnings
import matplotlib.pyplot as plt
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import MinMaxScaler
from sklearn import datasets
from sklearn.exceptions import ConvergenceWarning
定义不同的学习策略
接下来,我们需要定义想要比较的不同学习策略。我们将定义几种不同的学习率调度和动量参数,包括恒定学习率、带动量的恒定学习率、带 Nesterov 动量的恒定学习率、逆缩放学习率、带动量的逆缩放学习率、带 Nesterov 动量的逆缩放学习率以及 Adam。我们还将定义标签和绘图参数,以便稍后在绘图中使用。
## 不同的学习率调度和动量参数
params = [
{
"solver": "sgd",
"learning_rate": "constant",
"momentum": 0,
"learning_rate_init": 0.2,
},
{
"solver": "sgd",
"learning_rate": "constant",
"momentum": 0.9,
"nesterovs_momentum": False,
"learning_rate_init": 0.2,
},
{
"solver": "sgd",
"learning_rate": "constant",
"momentum": 0.9,
"nesterovs_momentum": True,
"learning_rate_init": 0.2,
},
{
"solver": "sgd",
"learning_rate": "invscaling",
"momentum": 0,
"learning_rate_init": 0.2,
},
{
"solver": "sgd",
"learning_rate": "invscaling",
"momentum": 0.9,
"nesterovs_momentum": True,
"learning_rate_init": 0.2,
},
{
"solver": "sgd",
"learning_rate": "invscaling",
"momentum": 0.9,
"nesterovs_momentum": False,
"learning_rate_init": 0.2,
},
{"solver": "adam", "learning_rate_init": 0.01},
]
labels = [
"恒定学习率",
"带动量的恒定学习率",
"带 Nesterov 动量的恒定学习率",
"逆缩放学习率",
"带动量的逆缩放学习率",
"带 Nesterov 动量的逆缩放学习率",
"Adam",
]
plot_args = [
{"c": "红色", "linestyle": "-"},
{"c": "绿色", "linestyle": "-"},
{"c": "蓝色", "linestyle": "-"},
{"c": "红色", "linestyle": "--"},
{"c": "绿色", "linestyle": "--"},
{"c": "蓝色", "linestyle": "--"},
{"c": "黑色", "linestyle": "-"},
]
定义一个绘制学习曲线的函数
接下来,我们需要定义一个函数,该函数将为每个数据集上的每种学习策略绘制学习曲线。该函数接受数据集(X,y)、要绘制的轴以及数据集的名称。我们将使用 MinMaxScaler 对数据进行缩放,并使用 MLPClassifier 训练神经网络。我们将使用每种学习策略训练网络,忽略收敛警告,并在同一图上为每种策略绘制学习曲线。
def plot_on_dataset(X, y, ax, name):
## 对于每个数据集,绘制每种学习策略的学习情况
print("\n在数据集 %s 上进行学习" % name)
ax.set_title(name)
X = MinMaxScaler().fit_transform(X)
mlps = []
if name == "digits":
## digits 数据集较大,但收敛相当快
max_iter = 15
else:
max_iter = 400
for label, param in zip(labels, params):
print("训练:%s" % label)
mlp = MLPClassifier(random_state=0, max_iter=max_iter, **param)
## 从图中可以看出,一些参数组合不会收敛,因此在这里被忽略
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", category=ConvergenceWarning, module="sklearn"
)
mlp.fit(X, y)
mlps.append(mlp)
print("训练集得分:%f" % mlp.score(X, y))
print("训练集损失:%f" % mlp.loss_)
for mlp, label, args in zip(mlps, labels, plot_args):
ax.plot(mlp.loss_curve_, label=label, **args)
加载或生成小型数据集
现在,我们需要加载或生成用于此示例的小型数据集。我们将使用鸢尾花数据集、手写数字数据集,以及使用 make_circles 和 make_moons 函数生成的两个数据集。
iris = datasets.load_iris()
X_digits, y_digits = datasets.load_digits(return_X_y=True)
data_sets = [
(iris.data, iris.target),
(X_digits, y_digits),
datasets.make_circles(noise=0.2, factor=0.5, random_state=1),
datasets.make_moons(noise=0.3, random_state=0),
]
绘制每个数据集的学习曲线
最后,我们可以使用 plot_on_dataset 函数为每个数据集绘制学习曲线。我们将创建一个 2x2 的图,并在单独的轴上绘制每个数据集。
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
for ax, data, name in zip(
axes.ravel(), data_sets, ["鸢尾花", "手写数字", "圆圈", "月亮"]
):
plot_on_dataset(*data, ax=ax, name=name)
fig.legend(ax.get_lines(), labels, ncol=3, loc="upper center")
plt.show()
总结
在本实验中,我们使用了 Scikit-learn 的 MLPClassifier 来比较不同随机学习策略(包括 SGD 和 Adam)在几个小型数据集上的性能。我们定义了不同的学习率调度和动量参数,然后使用每种策略训练 MLPClassifier。我们在每个数据集上绘制了每种策略的学习曲线,并观察了不同策略如何影响训练损失曲线。我们展示了为数据集和手头任务选择正确学习策略的重要性。