传送门:
BF神经网络(一)算法原理与实现
BF神经网络预测共享单车使用情况
BF实现算法基础
BF神经网络算法的原理及实现参考前一篇博客:http://ihoge.cn/2018/DL_BFNN.html
加载和准备数据
构建神经网络的关键一步是正确地准备数据。不同尺度级别的变量使网络难以高效地掌握正确的权重。我们在下方已经提供了加载和准备数据的代码。你很快将进一步学习这些代码!
1 | %matplotlib inline |
1 | data_path = 'Bike-Sharing-Dataset/hour.csv' |
1 | rides.head() |
数据简介
此数据集包含的是从 2011 年 1 月 1 日到 2012 年 12 月 31 日期间每天每小时的骑车人数。骑车用户分成临时用户和注册用户,cnt 列是骑车用户数汇总列。你可以在上方看到前几行数据。
下图展示的是数据集中前 10 天左右的骑车人数(某些天不一定是 24 个条目,所以不是精确的 10 天)。你可以在这里看到每小时租金。这些数据很复杂!周末的骑行人数少些,工作日上下班期间是骑行高峰期。我们还可以从上方的数据中看到温度、湿度和风速信息,所有这些信息都会影响骑行人数。你需要用你的模型展示所有这些数据。
1 | rides[:24*10].plot(x='dteday', y='cnt') |
虚拟变量(哑变量)
下面是一些分类变量,例如季节、天气、月份。要在我们的模型中包含这些数据,我们需要创建二进制虚拟变量。用 Pandas 库中的 get_dummies()
就可以轻松实现。
1 | dummy_fields = ['season', 'weathersit', 'mnth', 'hr', 'weekday'] |
调整目标变量
为了更轻松地训练网络,我们将对每个连续变量标准化,即转换和调整变量,使它们的均值为 0,标准差为 1。
我们会保存换算因子,以便当我们使用网络进行预测时可以还原数据。
1 | quant_features = ['casual', 'registered', 'cnt', 'temp', 'hum', 'windspeed'] |
将数据拆分为训练、测试和验证数据集
我们将大约最后 21 天的数据保存为测试数据集,这些数据集会在训练完网络后使用。我们将使用该数据集进行预测,并与实际的骑行人数进行对比。
1 | # Save data for approximately the last 21 days |
我们将数据拆分为两个数据集,一个用作训练,一个在网络训练完后用来验证网络。因为数据是有时间序列特性的,所以我们用历史数据进行训练,然后尝试预测未来数据(验证数据集)。
1 | # Hold out the last 60 days or so of the remaining data as a validation set |
开始构建网络
下面你将构建自己的网络。我们已经构建好结构和反向传递部分。你将实现网络的前向传递部分。还需要设置超参数:学习速率、隐藏单元的数量,以及训练传递数量。
该网络有两个层级,一个隐藏层和一个输出层。隐藏层级将使用 S 型函数作为激活函数。输出层只有一个节点,用于递归,节点的输出和节点的输入相同。即激活函数是 $f(x)=x$。这种函数获得输入信号,并生成输出信号,但是会考虑阈值,称为激活函数。我们完成网络的每个层级,并计算每个神经元的输出。一个层级的所有输出变成下一层级神经元的输入。这一流程叫做前向传播(forward propagation)。
我们在神经网络中使用权重将信号从输入层传播到输出层。我们还使用权重将错误从输出层传播回网络,以便更新权重。这叫做反向传播(backpropagation)。
提示:你需要为反向传播实现计算输出激活函数 ($f(x) = x$) 的导数。如果你不熟悉微积分,其实该函数就等同于等式 $y = x$。该等式的斜率是多少?也就是导数 $f(x)$。
你需要完成以下任务:
- 实现 S 型激活函数。将
__init__
中的self.activation_function
设为你的 S 型函数。 - 在
train
方法中实现前向传递。 - 在
train
方法中实现反向传播算法,包括计算输出错误。 - 在
run
方法中实现前向传递。
1 | class NeuralNetwork(object): |
1 | def MSE(y, Y): |
单元测试
运行这些单元测试,检查你的网络实现是否正确。这样可以帮助你确保网络已正确实现,然后再开始训练网络。这些测试必须成功才能通过此项目。
1 | import unittest |
.....
----------------------------------------------------------------------
Ran 5 tests in 0.008s
OK
<unittest.runner.TextTestResult run=5 errors=0 failures=0>
训练网络
现在你将设置网络的超参数。策略是设置的超参数使训练集上的错误很小但是数据不会过拟合。如果网络训练时间太长,或者有太多的隐藏节点,可能就会过于针对特定训练集,无法泛化到验证数据集。即当训练集的损失降低时,验证集的损失将开始增大。
你还将采用随机梯度下降 (SGD) 方法训练网络。对于每次训练,都获取随机样本数据,而不是整个数据集。与普通梯度下降相比,训练次数要更多,但是每次时间更短。这样的话,网络训练效率更高。稍后你将详细了解 SGD。
选择迭代次数
也就是训练网络时从训练数据中抽样的批次数量。迭代次数越多,模型就与数据越拟合。但是,如果迭代次数太多,模型就无法很好地泛化到其他数据,这叫做过拟合。你需要选择一个使训练损失很低并且验证损失保持中等水平的数字。当你开始过拟合时,你会发现训练损失继续下降,但是验证损失开始上升。
选择学习速率
速率可以调整权重更新幅度。如果速率太大,权重就会太大,导致网络无法与数据相拟合。建议从 0.1 开始。如果网络在与数据拟合时遇到问题,尝试降低学习速率。注意,学习速率越低,权重更新的步长就越小,神经网络收敛的时间就越长。
选择隐藏节点数量
隐藏节点越多,模型的预测结果就越准确。尝试不同的隐藏节点的数量,看看对性能有何影响。你可以查看损失字典,寻找网络性能指标。如果隐藏单元的数量太少,那么模型就没有足够的空间进行学习,如果太多,则学习方向就有太多的选择。选择隐藏单元数量的技巧在于找到合适的平衡点。
1 | import sys |
Progress: 100.0% ... Training loss: 0.092 ... Validation loss: 0.186
1 | plt.plot(losses['train'], label='Training loss') |
检查预测结果
使用测试数据看看网络对数据建模的效果如何。如果完全错了,请确保网络中的每步都正确实现。
1 | fig, ax = plt.subplots(figsize=(8,4)) |
可选:思考下你的结果(我们不会评估这道题的答案)
请针对你的结果回答以下问题。模型对数据的预测效果如何?哪里出现问题了?为何出现问题呢?
注意:你可以通过双击该单元编辑文本。如果想要预览文本,请按 Control + Enter
请将你的答案填写在下方
问题1:Dec 24 开始至Dec 28这四天的预测误差比较大的原因?