深度学习入门(一)介绍神经网络、logistic回归和梯度下降

  学习自吴恩达,深度学习课程。

什么是神经网络(Neural Network)?

   假设需要进行房屋价格预测,给了六个数据<size of the house, price of the house>,为了方便观察他们之间的联系----找到一个合适的函数,将其放在一个二维坐标系中。

  很自然可以看出用一条直线可以拟合(线性回归),当然根据常识,价格不可能为负,所以要改为折线让其归为 0 ,这个拟合函数可以看成是最简单的神经网络了。通常这种开始为0,之后是一条直线的函数称为ReLU函数----修正线性单元(Stands for  Rectified Linear Unit),这里修正就是取不为0的值。

  输入size记为x,经过神经元(中间圆圈,也就是刚刚找到的拟合函数)处理后,输出price记为y。这就是一个单神经网络,简单地说,把多个神经元像搭积木一样堆叠起来就会形成一个神经网络。

  如果现在不仅知道房屋的面积,我们还知道其他信息,例如邮编 zip code可以推测地区富裕程度以及距离工作地点远近,周围居民财富状况wealth可以来推测学校质量,我们就可以更精确地预测房屋价格。

  将这些神经元组合起来,就得到了一个简单的预测器。神经网络的一个强大之处就是输入一个庞大的数据,可以不管中间的处理过程,最终都会主动获得输出结果。如图,左侧是输入层,中间是神经网络,其间被蓝色箭头指向的节点被称为预测神经元,右侧是输出层。

 用神经网络进行监督学习 Supervised Learning

  在例如广告推送方面,一般使用标准神经网络(Standerd NN),在图像方面使用卷积神经网络(CNN),在音频和文字方面使用循环神经网络(RNN),在更复杂的例如自动驾驶方面使用混合神经网络。

   通常我们输入的数据分为结构化数据(Structured Data)和非结构化数据(Unstructured Data),结构化数据是数据的数据库形式,而非结构数据可能是图片、音频、文字,亦或者是其他信号。一般来说人类擅长处理非结构化的数据,计算机擅长处理结构化数据。

二分分类 Binary Classification

  假设我们输入这样一张图片,我们想要识别图中是否有猫,输出 1 代表有猫,0 表示没有猫。

   图片在计算机中是用红绿蓝三原色矩阵来存储表示的,如下图,假设这张猫猫图由三个64*64的矩阵表示,为了将这些矩阵放进一个特征向量里,我们用 x 来表示这个特征向量,我们把三个矩阵的所有值都取出来放入向量 x 中,那么向量 x 的维度就是 nx = 64*64* = 12288,为了方便将 nx 简记为 n 来代表向量维度。

  在二分类问题中,目标是训练处一个分类器,它以图片的特征向量 x 作为输入,预测输出的结果的标签 y 是 1 还是 0. 为了方便后面说明,这里声明一下符号的含义:

  •  (x, y)代表一个独立的样本, x 是 nx维的特征向量,x ∈ Rnx , 标签 y 值为 0 或 1,y ∈ {0, 1}
  • 训练集由 m 个训练样本构成,(x(1), y(1))代表样本一的输入和输出,训练集为 {(x(1), y(1)),  ……, (x(m), y(m))}, m 代表训练样本的个数,有时候为了更精确说明,用 mtrain 来代表训练集样本的个数,用 mtest 来代表测试集样本的个数
  • X 表示输入矩阵,如下图所示,在神经网络计算时,约定使用列堆叠的方式,这会让构建过程简单很多。在 Python 里 X.shape 会输出矩阵的维度 (nx, m)
  • 表示输出矩阵, Y.shape = (1, m)

Logistic 回归

  logistic 回归是一个用在监督学习问题中的学习算法,当其输出 y ∈ {0, 1}时就属于二分分类。

  接着上面猫猫图片的问题,现在我们输入一个 x, 我们想要获得预测值 y-hat =  P(y = 1 | x) ,我们通常想得到一个概率,自然 0 ≤ y-hat ≤ 1。 

  • x ∈ Rnx 
  • 已知 logistic 回归参数 w ∈ Rnx ,也是一个向量,b ∈ R, b 是一个实数

  已知这些后我们可以假设一个线性函数 y hat =  wT x + b ,当然这明显不符合我们的要求,我们期望获得的 y-hat 是一个概率,y hat 的取值范围应该在 0 到 1 之间,所以我们引入 sigmoid 函数。

  sigmoid 函数 : σ (z) = 1 / ( 1 + exp(-z) )

  而这里我们令 z = wT x + b, 则 y hat = σ (z)  = σ (wT x + b) 。参考下图。

Logistic 回归损失函数和代价函数

  现在给了一组训练样本 X ,在上面的logistic函数计算下获得一组预测值 Y-hat,并且想要 Y-hat 尽可能接近训练集中的 Y,为了衡量算法的运行情况,我们对单个样本设置一个损失函数L,函数值越高代表算法运行情况越差。通常我们期望损失函数是凸函数,这样可以方便找得最小值----最优解。 像平方损失函数就不适合,提出一个样例:

  Loss function:L ( y-hat, y ) = - [ y log y-hat + (1 - y) log ( 1 - y-hat ) ]

  代价函数则是衡量函数在全体训练样本上的表现。

  Cost function: J (  w, b ) = 1/m *  ∑ L( y- hat(i) ,  y(i)

  因此在训练logistic回归模型中,我们要找到合适的参数 w 和 b,来使代价函数 J 尽可能的小。


  这里解释下损失函数和代价函数是怎么来的。

  首先约定:

  • 这里 y 只取 0, 1两种情况,二分类问题
  • y-hat = p( y=1 | x ),即算法的输出 y-hat 是在给定训练样本 x 的条件下 y = 1 的概率

  也就是说:

  我们将这两个式子合并成一个: p ( y | x) = y-hat y (1 - y-hat) (1 - y)

  由于 log 函数是严格单调递增函数,那么 最大化 log p (y | x) 就等于最大化 p (y | x),那计算 log p (y | x) 就可化简为 y log y-hat + (1 - y) log ( 1 - y-hat ) 

  损失函数前有个负号是因为log中我们计算的是最大化,而logistic回归中我们需要的是最小化损失函数 L ( y-hat, y )。

  对于代价函数,假设所有样本都是独立同分布的,那么这些样本的联合概率就是每个样本概率的乘积,P = ∏ p(yi | xi),如果想要做极大似然估计,寻找到一组参数,使得给定样本的观测值概率最大,这个概率最大化就等价于令其对数最大化,也就是log P = log ∏ p(yi | xi)= ∑ p(yi | xi)= ∑ L ( y-hat, y ),为了方便计算,还会对其进行适当放缩 1 / m。

 梯度下降法 Gradient Descent

   为了求得最优解的 w 和 b ,我们使用梯度下降法,在凸函数中,我们给w, b一个初始值,并让w 和 b 每次都沿着最陡或者下降最快的方向更新,这样在多次更新后总会取到最优解。 

   为了方便理解,我们暂时只考虑参数w,并且 w 是一维的。那么有这样的更新操作  w =  w - ∝ ( dJ(w) / dw)

  • ∝ 为学习率,用来控制每次更新下降的步长,后面会详细介绍 (这个符号不这么写,但是找不到对于符号,只能先将就一下,可以看图)
  •  dJ(w) / dw 为更新量,实际上就上该点的斜率

  在多元函数中则是偏微分。

  实际上  w = w - ∝( ∂J(w, b) / ∂w), b = b - ∝( ∂J(w, b) / ∂b)

  接下来利用链式求导来计算dw 和 db,一般都把 log 视为 ln。

  • z = wx + b
  • a = y-hat = σ (z) =  1 / ( 1 + exp(-z) )
  • L =   - [ y log a + (1 - y) log a ]

  根据计算我们得到:

  • dL / da  = (1 - y) / (1 - a) - y / a
  • da / dz = exp(-z) / (1 + exp(-z))2 = a(1 - a)
  • dz = (a - y) dL
  • dw = xdz
  • db = dz

  由此我们可以编写代码如下,前提给了m个样本,输入两个特征w1,w2, b,n代表特征w数量:

  

L = 0;
dw1 = 0;
dw2 = 0;
db = 0;
For j = 1 to n:
  For i = 1 to m:
      z[i] = wT x[i] + b;
    a[i] = σ (z[i]);
    L =  - [ y[i] log a[i] + (1 - y[i])) log a[i] ];
    dz[i] = a[i] - y[i];
    dw1 += x1[i] dz[i];
    dw2 += x2[i] dz[i];
    db += dz[i];
  L /= m;
  dw1 /= m;
  dw2 /= m;
  db /= m;

   但是这种在代码里显式使用 for 循环在深度学习(数据量大)里会使算法很低效,由此引入向量化。

向量化

   之前我们说显示的 for 循环性能不如向量化后的结果,下图展示了二者的差距。

  我们已经知道:

  • zi = wi xi + b
  • ai = σ (zi)

  那么有,这里约定加粗字母的代表向量,字母右上角标号代表记号,不是指数

                 向量                                维度

  •  = [ z1,……,zm ]               (1, m)
  •  = [x1, ……,,xnx]                 (nx, 1)
  •  = [x1, ……,xm]                 (nx,m)
  • = [w1, ……,wnx]                      (nx, 1)
  •  = [b, ……,b]                            (1, m)
  •  = [a1, ……,am]                  (1, m)

Z = wTX + b

A = σ (Z)

   在numpy里,z = np.dot(w.t, x) + b    这里的 b 是个实数,python会自动给向量每个的值都加上 b,这种操作称之为广播(Broadcasting).

   同理在计算梯度下降时,就可以

  • dZ  = [dz1, ……, dzm]
  •  = [y1, ……, ym]

dZ = A - Y

dw = 1/m * X dZT

db = 1/m  * ∑im dzi = 1/m * np.sum(dZ)

   这样我们就利用向量化把两次显示循环取代了,新的代码过程如下图右侧,当然还有一个for循环来控制下降次数,这个就没有办法向量化。

  人生不如意的时候,是上帝给的长假,这个时候应该好好享受假期。
  突然有一天假期结束,时来运转,人生才是真正开始了。
原文地址:https://www.cnblogs.com/astonc/p/15466735.html