Generate...|

园龄:粉丝:关注:

2022-10-27 14:29阅读: 58评论: 0推荐: 0

用numpy实现最简单的前馈神经网络——神经网络架构篇

  • 基础知识

    梯度(高等数学)、矩阵运算(线性代数)、numpy(ndarray)、python基础语法

  • 目录

    1. 神经网络架构

    2. 神经网络建立

      先用比较简单的正向传播建立好框架,再用反向传播改变算法

    3. 实例:学习mnist手写数字数据集

神经网络架构

  • 矩阵
  • 拟合
  • 梯度

矩阵运算

我们可以把矩阵看作一个特殊的函数,它的作用是将长度为n的向量(如下图 AA)转化为长度为 m 的向量(如下图 ZZ)。

将输入看作一个包含 n 个元素的向量,就可以通过多次矩阵运算转化为长度为 m 的输出了。

虽然此时输入矩阵(AA)在变换矩阵(WW)的右侧,但是这是可以改变的,在mnist学习实例中我就会将 AA 放在 WW 左侧(当然此时 mn 会发生一些变化)。

(w11w12w1nw21w22w2nwm1wm2wmn)[a1a2an]+(b1b2bm)=[z1z2zm]

ZZm=WWm×nAAn+BBmZZm=F(AAn)

在Python中,使用矩阵进行向量化编程也是加快学习速度的必要手段

拟合——深度学习的目的

最简单的拟合——线性回归

我们在中学中曾经学习的用一系列数据对来得出一条线性拟合曲线,还使用了最小二乘法。事实上,深度学习做的也是类似的事情——建立拟合函数。

y^=ax+b.

深度学习中的拟合

不同的是深度学习中不仅需要线性的拟合,也需要非线性的拟合。(这很正常因为自然界很多事不是线性的)

因此我们需要引入非线性的函数来变换向量,就需要激活函数(下图 α 就是一种激活函数),因为如果只有线性的函数的话,就不可能获得非线性的拟合。

y(i)=α(x1(i)w1+x2(i)w2++xn(i)wn+b(i))α(z)=11+ez

provided f(x) and g(x) is linear,it's easy to get that f(g(x)) is linear

同时我们需要一个标准来衡量拟合的贴合度,就得到了损失函数

均方误差函数

(i)(a,b)=12(y^(i)y(i))2(a,b)=1ni=1n(i)(a,b)=1ni=1n12(ax(i)+by(i))2

交叉熵损失函数

(i)=1NL(i)=1Ni[y(i)log(y^(i))+(1y(i))log(1y^(i))]

平均损失最小——梯度下降法

和线性回归中相同,要使拟合最贴合,就是在给定输入(A)时,调整参数(W、B)使损失函数最小

w1,w2,,wn,b=argmin{(w1,w2,,wn,b)}.

使用高等数学的知识,要如何使某个函数取得最小值呢?

画图?求极值点再求最小值点?可惜的是这些方法在这里都行不通(想想那复杂的表达式和万亿计的自变量吧)

最小二乘法也是求损失函数最小值的一种方法

因此我们只能退而求其次,求得一个局部最小值,希望也能拟合得不错,这也就是梯度下降法(偏导数求最小值法)。

让自变量不断沿着梯度的反方向移动,就能获得极小值

f(x,y)=x2+y2,(Δx,Δy)=η(fx,fy).

不妨使用 f(x,y)=x2+y2 演示梯度下降法,在 jupyter notebook 中运行如下代码

%matplotlib notebook
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from pprint import pprint
def f(x, y):
"""待求函数"""
return x ** 2 + y ** 2
def grad(func, *args):
"""求梯度"""
h = 1e-6
args = list(args)
grad = [None for _ in range(len(args))]
for i, arg in enumerate(args):
args[i] = arg + h
f1 = f(*args)
args[i] = arg - h
f2 = f(*args)
args[i] = arg
grad[i] = (f1 - f2) / 2 / h
return grad
fig = plt.figure()
ax = Axes3D(fig)
# 图像范围
a = np.arange(-50, 50, 0.1)
b = np.arange(-50, 50, 0.1)
# 作出完整图像
X, Y = np.meshgrid(a, b)
Z = f(X, Y)
# 记录每一步的x, y, z值
xs = [50]
ys = [43]
zs = [f(xs[-1], ys[-1])]
step_length = 0.03 # 学习率,每一步的步长
step_num = 50 # 学习次数
for _ in range(step_num):
x = xs[-1]
y = ys[-1]
dx, dy = grad(f, x, y) # 变化量
x -= dx * step_length
y -= dy * step_length
xs.append(x)
ys.append(y)
zs.append(f(x, y))
ax.scatter3D(xs, ys, zs, cmap="Blues") # 散点图
ax.plot_surface(X, Y, Z, cmap="rainbow") # 三维曲面
pprint(list(zip(xs, ys, zs)))

可以看到蓝点一步步的走向极小值。

当然,局部最小值就是极值点,这种方法有可能会陷入某个极小值,错过了最小值。(可以尝试修改一下代码来看看这种情况,比如更改代求函数和学习率)

反向传播和链式法则

反向传播法其实就是利用链式法则用更快的方法求偏导数。但和正向一样使用梯度下降来求损失函数最小值

forward propagation: Δx=fx=limh0f(x+h)f(xh)2h,back-propagation: Δx=fx=(fy,yx).

激活函数和损失函数的选择

def sigmoid(x):
"""激活函数"""
return 1 / (1 + np.exp(-x))
def cross_entropy_error(result, labels):
"""损失函数"""
return -(np.sum(np.log(result[np.arange(labels.size), labels] + 1e-5)))
def soft_max(x):
"""输出函数"""
t = np.exp(x - x.max())
y = np.sum(t, axis=1).reshape(t.shape[0], 1)
return t / y

在 mnist 实例中,我会使用上面三个函数。根据概率论的某个原理,soft_max()cross_entropy_error() 是 best match

总结

  1. 明确输入和输出
  2. 选择合适的各种函数
  3. 矩阵激活函数建立起从输入到输出的拟合函数
  4. 正向传播或反向传播获得损失函数的偏导数(注意对一定的数据集来说自变量为 WWAA 固定)
  5. 梯度下降法努力使损失函数最小

本文作者:violeshnv

本文链接:https://www.cnblogs.com/violeshnv/p/16832055.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Violeshnv  阅读(58)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 とおいよびごえ 凋叶棕
  2. 2 かぜのねいろ 凋叶棕
  3. 3 Milky Way Train 流派未階堂
  4. 4 nostalgia 流派未階堂
  5. 5 桜花繚乱 はちみつれもん
  6. 6 胡蝶之夢 はちみつれもん
  7. 7 色は散りゆく はちみつれもん
  8. 8 暮色蒼然 はちみつれもん
  9. 9 追想、桜ノ國 はちみつれもん
  10. 10 意にそぐわぬリターニー 凋叶棕
かぜのねいろ - 凋叶棕
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.