使用CNN(convolutional neural nets)检测脸部关键点教程(二):浅层网络训练和测试

第三部分 第一个模型:一个隐层结构的传统神经网络

这一部分让我们从代码开始:

# add to kfkd.py
from lasagne import layers
from lasagne.updates import nesterov_momentum
from nolearn.lasagne import NeuralNet

net1 = NeuralNet(
layers=[  # three layers: one hidden layer
    ('input', layers.InputLayer),
    ('hidden', layers.DenseLayer),
    ('output', layers.DenseLayer),
    ],
# layer parameters:
input_shape=(None, 9216),  # 96x96 input pixels per batch
hidden_num_units=100,  # number of units in hidden layer
output_nonlinearity=None,  # output layer uses identity function
output_num_units=30,  # 30 target values

# optimization method:
update=nesterov_momentum,
update_learning_rate=0.01,
update_momentum=0.9,

regression=True,  # flag to indicate we're dealing with regression problem
max_epochs=400,  # we want to train this many epochs
verbose=1,
)

X, y = load()
net1.fit(X, y)


在这个网络中,我们使用了一些参数来初始化,让我们从头梳理:

layers=[  # three layers: one hidden layer
    ('input', layers.InputLayer),
    ('hidden', layers.DenseLayer),
    ('output', layers.DenseLayer),
    ],
# layer parameters:
input_shape=(None, 9216),  # 96x96 input pixels per batch
hidden_num_units=100,  # number of units in hidden layer
output_nonlinearity=None,  # output layer uses identity function
output_num_units=30,  # 30 target values


这里我们定义了input层,hidden层,还有output层。在layers参数下,我们定义了每一层的类型,以及层与层之间的顺序。input_shape , hidden_num_units ,output_nonlinearity ,output_num_units 分别指定了每一层的参数,这些参数通过前缀指定相应的层,如input_shape制定了input层。之所以采用这种稍显奇怪的方式来制定参数,是为了更好的兼容scikit-learn从而更好的利用其优势。

我们将输入的第一个维度设置为None,相当于设定了可变的batch size。

将输出层非线性显示的设置为None。也就是,输出层单元的激活方式是线性的,即隐藏层激活值的线性组合。

Denselayer的默认非线性特性曲线是rectifier,即max(0,x),当先最流行的激活方程。通过不明确的制定隐藏层的激活方程,也就制定了rectifier作为隐层的激活方程。
这里写图片描述
神经网络的权重初始化为某一个区间的均匀分布值,Lasagne已经选好了这个区间。【区间选取参考

还有一些没有介绍的参数,这些参数都以update开头用来表示更新方程(或最优化方法)的参数。更新方程将会在每个batch后更新神经网络的权重。我们使用nesterov_momentum梯度下降这种最优化方法来完成这个工作。Lasagne还为我们实现了一些
其他的方法诸如adagrad和rmsprop。我们选择nesterov_momentum是因为这种方法已经在大量的问题上被证明有效。

# optimization method:
update=nesterov_momentum,
update_learning_rate=0.01,
update_momentum=0.9,


update_learning_rate定义了梯度下降更新权重的步长。我们稍后讨论学习率和momentum参数,现在的话,这种健全的默认值已经足够了。
不同的最优化方法的对比
上图是不同的最优化方法的对比(animation by Alec Radford)。星标位置为全局最优值。注意不添加“势”的随机梯度下降是收敛最慢的,我们在教程中从头到尾都是用Nesterov加速过的梯度下降。

最后两行加载了数据,然后用数据训练了我们的第一个神经网络。

X, y = load()
net1.fit(X, y)


运行这两行会输出一个表格,每次完成一个epoch就输出一行。每一行里,我们可以看到当前的训练损失和验证损失(最小二乘损失),以及两者的比率。NeuroNet将会自动把输入数据X分成训练集和测试集,用20%的数据作验证。(比率可以通过参数eval_size=0.2调整)

$ python kfkd.py
...
  InputLayer          (None, 9216)            produces    9216 outputs
  DenseLayer          (None, 100)             produces     100 outputs
  DenseLayer          (None, 30)              produces      30 outputs

     Epoch  |  Train loss  |  Valid loss  |  Train / Val
    --------|--------------|--------------|----------------
     1  |    0.105418  |    0.031085  |     3.391261
     2  |    0.020353  |    0.019294  |     1.054894
     3  |    0.016118  |    0.016918  |     0.952734
     4  |    0.014187  |    0.015550  |     0.912363
     5  |    0.013329  |    0.014791  |     0.901199
    ...
   200  |    0.003250  |    0.004150  |     0.783282
   201  |    0.003242  |    0.004141  |     0.782850
   202  |    0.003234  |    0.004133  |     0.782305
   203  |    0.003225  |    0.004126  |     0.781746
   204  |    0.003217  |    0.004118  |     0.781239
   205  |    0.003209  |    0.004110  |     0.780738
    ...
   395  |    0.002259  |    0.003269  |     0.690925
   396  |    0.002256  |    0.003264  |     0.691164
   397  |    0.002254  |    0.003264  |     0.690485
   398  |    0.002249  |    0.003259  |     0.690303
   399  |    0.002247  |    0.003260  |     0.689252
   400  |    0.002244  |    0.003255  |     0.689606


在相对较快的GPU上训练,我们能够在1分钟之内完成400个epoch的训练。注意测试损失会一直减小。

现在我们有了一个很好的结果了么?我们看到测试误差是0.0032,和竞赛基准比试一下。注意我们将目标除以了48以将其缩放到-1到1之间,也就是说,要是想计算均方误差和排行榜的结果比较,必须把我们上面得到的0.003255还原到原来的尺度。

>>> import numpy as np
>>> np.sqrt(0.003255) * 48
2.7385251505144153


这个值应该可以代表我们的成绩了。当然,这得假设测试集合的数据和训练集合的数据符合相同的分布,但事实却并非如此。

第四部分 测试刚刚的网络

我们刚刚训练的net1对象已经保存了训练时打印在控制台桌面中的记录,我们可以获取这个记录通过train_history_相关属性,让我们画出这两个曲线。

train_loss = np.array([i["train_loss"] for i in net1.train_history_])
valid_loss = np.array([i["valid_loss"] for i in net1.train_history_])
pyplot.plot(train_loss, linewidth=3, label="train")
pyplot.plot(valid_loss, linewidth=3, label="valid")
pyplot.grid()
pyplot.legend()
pyplot.xlabel("epoch")
pyplot.ylabel("loss")
pyplot.ylim(1e-3, 1e-2)
pyplot.yscale("log")
pyplot.show()

这里写图片描述
我们能够看到我们的网络过拟合了,但是结果还不赖。事实上,我们找不到验证错误开始上升的点,所以那种通常用来避免过拟合的early stopping方法在现在还没有什么用处。注意我们没有采用任何正则化手段,除了选择节点比较少的隐层——这可以让过拟合保持在可控范围内。

那么网络的预测结果是什么样的呢?让我们选择一些样例来看一看。

def plot_sample(x, y, axis):
    img = x.reshape(96, 96)
    axis.imshow(img, cmap='gray')
    axis.scatter(y[0::2] * 48 + 48, y[1::2] * 48 + 48, marker='x', s=10)

X, _ = load(test=True)
y_pred = net1.predict(X)

fig = pyplot.figure(figsize=(6, 6))
fig.subplots_adjust(
    left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

for i in range(16):
    ax = fig.add_subplot(4, 4, i + 1, xticks=[], yticks=[])
    plot_sample(X[i], y_pred[i], ax)

pyplot.show()


第一个模型预测的结果(从测试集抽出了16个样例)
这里写图片描述
预测结果看起来还不错,但是有点时候还是有一点偏。让我们试着做的更好一些。

使用CNN(convolutional neural nets)检测脸部关键点教程(一):环境搭建和数据
使用CNN(convolutional neural nets)检测脸部关键点教程(三):卷积神经网络训练和数据扩充
使用CNN(convolutional neural nets)检测脸部关键点教程(四):学习率,学习势,dropout
使用CNN(convolutional neural nets)检测脸部关键点教程(五):通过前训练(pre-train)训练专项网络

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值