写给程序员的机器学习入门 (三) - 线性模型,激活函数与多层线性模型

生物神经元与人工神经元

在了解神经元网络之前,我们先简单的看看生物学上的神经元是什么样子的,下图摘自维基百科:

(因为我不是专家,这里的解释只用于理解人工神经元模拟了生物神经元的什么地方,不一定完全准确)

写给程序员的机器学习入门 (三) - 线性模型,激活函数与多层线性模型

神经元主要由细胞体和细胞突组成,而细胞突分为树突 (Dendrites) 和轴突 (Axon),树突负责接收其他神经元输入的电流,而轴突负责把电流输出给其他神经元。一个神经元可以通过树突从多个神经元接收电流,如果电流没有达到某个阈值则神经元不会把电流输出,如果电流达到了某个阈值则神经元会通过轴突的突触把电流输出给其他神经元,这样的规则被称为全有全无律。输入电流达到阈值以后输出电流的状态又称为到达动作电位,动作电位会持续 1 ~ 2 毫秒,之后会进入约 0.5 毫秒的绝对不应期,无论输入多大的电流都不会输出,然后再进入约 3.5 毫秒的相对不应期,需要电流达到更大的阈值才会输出,最后返回静息电位。神经元之间连接起来的网络称为神经元网络,人的大脑中大约有 860 亿个神经元,因为 860 亿个神经元可以同时工作,所以目前的计算机无法模拟这种工作方式 (除非开发专用的芯片),只能模拟一部分的工作方式和使用更小规模的网络。

计算机模拟神经元网络使用的是人工神经元,单个人工神经元可以用以下公式表达:

写给程序员的机器学习入门 (三) - 线性模型,激活函数与多层线性模型

其中 n 代表输入的个数,你可以把 n 看作这个神经元拥有的树突个数,x 看作每个树突输入电流的值;而 w (weight) 代表各个输入的权重,也就是各个树突对电流大小的调整;而 b (bias) 用于调整各个输入乘权重相加后的值,使得这个值可以配合某个阈值工作;而 g 则是激活函数,用于判断值是否达到阈值并输出和输出多少,通常会使用非线性函数;而 y 则是输出的值,可以把它看作轴突输出的电流,连接这个 y 到其他神经元就可以组建神经元网络。

我们在前两篇看到的其实就是只有一个输入并且没有激活函数的单个人工神经元,把同样的输入传给多个神经元 (第一层),然后再传给其他神经元 (第二层),然后再传给其他神经元 (第三层) 就可以组建人工神经元网络了,同一层的神经元个数越多,神经元的层数越多,网络就越强大,但需要更多的运算时间并且更有可能发生第一篇文章讲过的过拟合 (Overfitting) 现象。

下图是人工神经元网络的例子,有 3 输入 1 个输出,经过 3 层处理,第 1 层和第 2 层各有两个神经元对应隐藏值 (中间值),第 3 层有一个神经元对应输出值:

写给程序员的机器学习入门 (三) - 线性模型,激活函数与多层线性模型

神经元中包含的 w 和 b 就是我们需要通过机器学习调整的参数值。

如果你觉得图片有点难以理解,可以看转换后的代码:

h11 = g(x1 * w111 + x2 * w112 + x3 * w113 + b11) h12 = g(x1 * w121 + x2 * w122 + x3 * w123 + b12) h21 = g(h11 * w211 + h12 * w212 + b21) h22 = g(h11 * w221 + h12 * w222 + b22) y = g(h21 * w311 + h22 * w312 + b31)

很多痴迷人工神经元网络的学者声称人工神经元网络可以模拟人脑的工作方式,做到某些领域上超过人脑的判断,但实际上这还有很大的争议,我们可以看到人工神经元的连接方式只会按固定的模式,判断是否达到阈值并输出的逻辑也无法做到和生物神经元一样(目前还没有解明),并且也没有生物神经元的不应期,所以也有学者声称人工神经元不过只是做了复杂的数学运算来模拟逻辑判断,需要根据不同的场景切换不同的计算方法,使用这种方式并不能达到人脑的水平。

单层线性模型

在前一篇文章我们已经稍微了解过机器学习框架 pytorch,现在我们来看看怎么使用 pytorch 封装的线性模型,以下代码运行在 python 的 REPL 中:

# 导入 pytorch 类库 >>> import torch # 创建 pytorch 封装的线性模型,设置输入有 3 个输出有 1 个 >>> model = torch.nn.Linear(in_features=3, out_features=1) # 查看线性模型内部包含的参数列表 # 这里一共包含两个参数,第一个参数是 1 行 3 列的矩阵分别表示 3 个输入对应的 w 值 (权重),第二个参数表示 b 值 (偏移) # 初始值会随机生成 (使用 kaiming_uniform 生成正态分布) >>> list(model.parameters()) [Parameter containing: tensor([[0.0599, 0.1324, 0.0099]], requires_grad=True), Parameter containing: tensor([-0.2772], requires_grad=True)] # 定义输入和输出 >>> x = torch.tensor([1, 2, 3], dtype=torch.float) >>> y = torch.tensor([6], dtype=torch.float) # 把输入传给模型 >>> p = model(x) # 查看预测输出值 # 1 * 0.0599 + 2 * 0.1324 + 3 * 0.0099 - 0.2772 = 0.0772 >>> p tensor([0.0772], grad_fn=<AddBackward0>) # 计算误差并自动微分 >>> l = (p - y).abs() >>> l tensor([5.9228], grad_fn=<AbsBackward>) >>> l.backward() # 查看各个参数对应的导函数值 >>> list(model.parameters())[0].grad tensor([[-1., -2., -3.]]) >>> list(model.parameters())[1].grad tensor([-1.])

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjsdx.html