深度学习基础课: “判断性别”Demo需求分析和初步设计(下2)

大家好~我开设了“深度学习基础班”的线上课程,带领同学从0开始学习全连接和卷积神经网络,进行数学推导,并且实现可以运行的Demo程序

线上课程资料:
本节课录像回放1

本节课录像回放2

加QQ群,获得ppt等资料,与群主交流讨论:106047770

本系列文章为线上课程的复盘,每上完一节课就会同步发布对应的文章

本文为第二节课:“判断性别”Demo需求分析和初步设计(下2)的复盘文章

本课程系列文章可进入索引查看:
深度学习基础课系列文章索引

回顾相关课程内容

  • 第二节课:“判断性别”Demo需求分析和初步设计(下1)
    • 为什么引入损失函数?
    • 损失函数的表达式是什么?
    • 有了损失函数,如何具体判断得到一组权重、偏移是合适的呢?
    • 什么是随机梯度下降?
    • 更新权重、偏移的梯度下降公式是什么?

主问题:如何求梯度

  • 对于“判断性别”的Demo,𝐸可以是什么函数?
    答:image

  • 如何求\(\frac{dE}{dw_{53}}\)
    答:image
    image
    参考上面的公式,可知:
    image

  • 如何求\(\frac{dE}{db_{5}}\)
    答:与上面类似

  • 如何求\(\frac{dE}{dw_{31}}\)
    答:image

任务:根据梯度下降算法实现训练

  • 标签、特征是什么?
    标签是我们要预测的事物,即男/女;
    特征是输入变量,即身高和体重;

  • 已知4个有标签样本(同时包含特征和标签)用于训练,2个无标签样本用于推理

  • 请根据梯度下降算法,实现NeuralNetwork_train的train函数?

    • 如何判断是否达到了希望的结果(即收敛)?
      答:打印损失函数返回的误差loss,如果小于0.1,则收敛
    • 如何实现?
      答:答案:NeuralNetwork_train_answer
  • 请运行程序

    • 有什么问题?
      第一轮开始的loss就无限大

任务:改进训练,使其收敛

  • 请找出loss无限大的原因?
    答:输出(y5)太大
  • 应该如何改进?
    答:改进激活函数,使用sigmoid替代线性函数:
    image
    image
    它的导数为:
    image
  • 修改代码,运行结果?
    答:修改后的相关代码为:
let _activateFunc = x => {
  1. /. (1. +. Js.Math.exp(-.x))
}

let _deriv_Sigmoid = x => {
  let fx = _activateFunc(x)

  fx *. (1. -. fx)
}

修改后的完整代码为:NeuralNetwork_train_fix_activate_answer

运行结果:loss一直不变

(补充:完整代码有bug:Neural_forward_answer->_activateFunc应该使用sigmoid函数。修改后的完整代码为:NeuralNetwork_train_fix_activate_answer_fix。修改后的运行结果是loss会先下降到0.25然后就不变了,而不是一直不变)

  • 为什么loss一直不变?
    答:输入太大->隐藏层的激活函数的导数为0->梯度为0->loss不变

  • 应该如何改进?
    答:将样本零均值化

  • 修改代码,运行结果?
    答:修改后的相关代码为:

let _mean = values => {
  values->ArraySt.reduceOneParam((. sum, value) => {
    sum +. value
  }, 0.) /. ArraySt.length(values)->Obj.magic
}

let _zeroMean = features => {
  let weightMean = features->ArraySt.map(feature => feature.weight)->_mean->Js.Math.floor->Obj.magic
  let heightMean = features->ArraySt.map(feature => feature.height)->_mean->Js.Math.floor->Obj.magic

  features->ArraySt.map(feature => {
    weight: feature.weight -. weightMean,
    height: feature.height -. heightMean,
  })
}

let features = features->_zeroMean

let state = state->train(features, labels)

let featuresForInference = [
  {
    weight: 89.,
    height: 190.,
  },
  {
    weight: 60.,
    height: 155.,
  },
]

featuresForInference->_zeroMean->Js.Array.forEach(feature => {
  inference(state, feature)->Js.log
}, _)
这里的内容是错误的,可忽略

运行结果:loss可能会逐渐增大

  • 为什么会出现loss逐渐增大的情况?
    答:学习率太大
    如下图所示:
    image
    因为步长过大,可能会跨过谷底
  • 如何解决?
    答:有两个方法:
    减小学习率,增加轮数;
    使用优化算法动态调整学习率。
    这里使用前者
  • 修改代码,运行结果?
    答:修改后的相关代码为:
let train = (state: state, features: array<feature>, labels: array<label>): state => {
  //let learnRate = 0.1
  //let epochs = 1000

  let learnRate = 0.001
  let epochs = 100000
...

修改后的完整代码为:NeuralNetwork_train_fix_zeroMean_answer

运行结果:大部分情况下loss会收敛

(补充:完整代码仍然有同样的bug:Neural_forward_answer->_activateFunc应该使用sigmoid函数。修改后的完整代码为:NeuralNetwork_train_fix_zeroMean_answer_fix。修改后的运行结果是loss基本上都会收敛,所以基本上不会出现“loss可能会逐渐增大”的情况,所以就不需要“减小学习率,增加轮数;”)

总结

  • 请回答所有主问题?
  • 如何根据梯度下降算法实现训练代码?
  • 会出现什么问题?如何解决?

参考资料

posted @ 2022-09-06 09:37  杨元超  阅读(78)  评论(0编辑  收藏  举报