机器学习笔记(3): 神经网络初步

· 浏览次数 : 0

小编点评

神经网络是一种由多个神经元组成的计算系统,每个神经元接收来自前一层神经元的输入,并根据激活函数产生输出。神经网络可以处理复杂的非线性问题,广泛应用于图像识别、语音识别等领域。 ### 神经元结构 神经元的核心部分是一个加权和激活函数。输入向量 \(\\vec x\) 与权重向量 \(\\omega\) 相乘后加上偏置项 \(b\),得到神经元的净输入 \(z\)。然后通过激活函数 \(f(\\cdot)\) 计算活性值 \(a\),即: \[ z = x \\omega + b \] \[ a = f(z) \] 常见的激活函数包括 Logistic 函数(又称 Sigmoid 函数): \[ \sigma(x) = \frac 1 {1 + \\exp(-x)} \] 以及Tanh函数: \[ \\text{Tanh}(x) = \\frac {\\exp(x) - \\exp(-x)}{\\exp(x) + \\exp(-x)} \] 等等。 ### 网络结构 神经网络主要包括三种类型: 1. **前馈网络**:数据流向单一方向,没有循环连接。前馈网络是最简单的神经网络。 2. **记忆网络**:具有短期记忆能力,如长短时记忆网络(LSTM)。 3. **图网络**:适用于处理结构化数据和有向图数据,如卷积神经网络(CNN)和应用在链接预测等任务上的图神经网络(GNN)。 ### 参数学习 神经网络参数学习通常采用反向传播算法(Backpropagation),通过最小化损失函数 \(J\) 来调整权重矩阵 \(W\) 和偏置向量 \(b\): \[ J = \\text{cost}(y, a^L) \] 其中 \(\text{cost}\) 是基于分类标签的交叉熵损失或其他损失函数。 通过正向传播与反向传播迭代优化权重和偏置,使得预测输出与真实结果之间的差距最小。算法的关键在于计算每层的误差梯度,并进行参数更新。

正文

神经网络应该由若干神经元组成。

前面的每一个神经元都会给到一个参数,将传递的所有参数看作一个向量 \(\vec x\),那么此神经元的净输入为:

\[z = x \omega + b \]

其中 \(\omega\) 称为权重向量

这里认为 \(x\)向量,而 \(\omega\)向量。

神经元还有一个激活函数 \(f(\cdot)\)

\[a = f(z) \]

称为函数的活性值

一般来说,我们使用 Logistic 函数,即 \(\sigma(x) = \frac 1 {1 + exp(-x)}\) 作为激活函数。

激活函数

激活函数有很多很多种,一般来说要满足以下几点:

  1. 连续且可导的非线性函数。
  2. 函数本身和其导数要尽可能简单。
  3. 值域要在一个合适的区间内

这里列举几种常见的函数。

Sigmoid 型

指一类两端饱和的 S 型曲线。

饱和
\(\lim_\limits{x \to -\infty} f'(x) = 0\) 称为左饱和,\(\lim_\limits{x \to \infty} f'(x) = 0\) 称为右饱和。
同时满足则称为两端饱和。

常见的 Sigmoid 型函数有 LogisticTanh

  • Logistic 函数

\[\sigma(x) = \frac 1 {1 + \exp(-x)} \]

其导数:

\[\sigma'(x) = \frac {\exp(-x)}{(1 + \exp(-x))^2} = \sigma(x) (1 - \sigma(x)) \]

  • Tanh 函数

\[{\rm tanh}(x) = \frac {\exp(x) - \exp(-x)}{\exp(x) + \exp(-x)} \]

其可以看作缩放平移后的 \(\sigma\),因为:

\[{\rm tanh}(x) = 2 \sigma(2x) - 1 \]

自然其导数:

\[{\rm tanh}'(x) = 4 \sigma(2x)(1 - \sigma(2x)) = \frac {4}{(\exp(x) + \exp(-x))^2} \]

实际上我们可以通过近似的方法去拟合这个函数,毕竟 \(e^x\) 也不是那么好算的。

  • Hard-LogisticHard-Tanh 函数

\[{\rm hard-\sigma}(x) = \begin{cases} 1 & x > 2 \\ \frac x 4 + \frac 1 2 & x \in [-2, 2] \\ 0 & x < 2 \end{cases} \]

或者利用 \(\min, \max\) 简化:

\[{\rm hard-\sigma}(x) = \max(\min(\frac x 4 + \frac 1 2, 1), 0) \]

类似的:

\[{\rm hard-tanh}(x) = \max(\min(x, 1), -1) \]

ReLU

也就是 Rectified Linear Unit,线性修正单元,定义为:

\[{\rm ReLU}(x) = \begin{cases} x & x \ge 0 \\ 0 & x < 0 \end{cases} \]

也就是 \({\rm ReLU}(x) = \max(x, 0)\)

当然,因为可能出现 死亡 ReLU 问题,所以一般有如下变形:

\[{\rm PReLU}(x) = \begin{cases} x & x \ge 0 \\ \gamma x & x < 0 \end{cases} \]

如果 \(\gamma = 0\) 则退化为 \(\rm ReLU\) 函数,如果 \(\gamma < 1\),那么也可以写为:

\[{\rm LeakyLU(x)} = \max(x, \gamma x) \]

另一个变形是:

\[{\rm ELU}(x) = \begin{cases} x & x \ge 0 \\ \gamma(\exp(x) - 1) & x < 0 \end{cases} \]

还有一个则是:

\[{\rm Softplus}(x) = \log(1 + \exp(x)) \]

Swish 函数

这是一种自控门函数:

\[{\rm swish}(x) = x \sigma(\beta x) \]

网络结构

网络结构分三种:

  • 前馈网络
  • 记忆网络
  • 图网络

这里先讲述前馈网络

这是一个前馈网络的示意图,其中第一层为输入层,最后一层为输出层。

而中间的那些层称为隐藏层。隐藏层可以有多个,而这里只画出了一个。

每一层有若干神经元,而两层间的神经元两两相连。

现在我们定义一些符号:

  • \(L\) 表示总层数,注意这里输入层为第 \(0\) 层,不计入其中;输出层为第 \(L\) 层。
  • \(M_l\) 表示第 \(l\) 层的神经元数量。
  • \(f_l(\cdot)\) 表示第 \(l\) 层的激活函数。
  • \(W^{(l)} \in \mathbb{R}^{M_l \times M_{l - 1}}\) 表示第 \(l - 1\) 层到第 \(l\) 层的权重矩阵(若干权重向量组成)。
  • \(b^{(l)} \in \mathbb{R}^{M_l}\) 表示第 \(l\) 层的偏置。
  • \(z^{(l)} \in \mathbb{R}^{M_l}\) 表示净输入。
  • \(a^{(l)} \in \mathbb{R}^{M_l}\) 表示输出。

对于一组数据 \((\vec x, y)\),前馈神经网络通过如下算法进行传播:

\[\begin{aligned} z^{(l)} &= W^{(l)} a^{(l - 1)} + b^{(l)} \\ a^{(l)} &= f_l(z^{(l)}) \end{aligned} \]

参数学习

参数学习可能略有点复杂,证明过程我懒得写成 \(\LaTeX\),这里就省略了。

我们利用反向传播算法进行学习,其步骤如下:

  • 选取一个数据,计算 \(a^{(l)}\)\(z^{(l)}\)
  • 反向传播每一层的误差 \(\delta^{(l)}\)
  • 计算每一层的偏导数,更新参数

显然的是 \(\delta^{(L)} = a^{(L)} - y\)

经过一番神秘的推导,我们可以得到:

\[\delta^{(l)} = f_l'\left(z^{(l)}\right) \cdot \left( \left( W^{(l + 1)} \right)^T \delta^{(l + 1)} \right) \in \mathbb{R}^{M_l} \]

其中 \(\cdot\) 表示元素一一相乘。

而计算偏导数的公式也不难:

\[\begin{aligned} \frac {\partial}{\partial W^{(l)}} R(W) &= \delta^{(l)} \left( a^{(l - 1)} \right)^T \\ \frac {\partial}{\partial b^{(l)}} R(W) &= \delta^{(l)} \end{aligned} \]

也就是参数更新方式为:

\[\begin{aligned} W^{(l)} &\leftarrow W^{(l)} - \alpha \left( \delta^{(l)} \left( a^{(l - 1)} \right)^T + \lambda W^{(l)} \right) \\ b^{(l)} &\leftarrow b^{(l)} - \alpha \delta^{(l)} \end{aligned} \]

但是值得注意的是,一般我们都会将 \(W^{(l)}\) 的第一列作为 \(b^{(l)}\),也就是不分开,所以在代码实现上要好生注意!

这是吴恩达机器学习 ex4 的部分代码:

function [J grad] = nnCostFunction(nn_params, ...
                                   input_layer_size, ...
                                   hidden_layer_size, ...
                                   num_labels, ...
                                   X, y, lambda)

% Theta1 25 x 401
% Theta2 10 x 26

Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...
                 hidden_layer_size, (input_layer_size + 1));

Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...
                 num_labels, (hidden_layer_size + 1));
                 
temp1 = Theta1;
temp2 = Theta2;
temp1(:, 1) = 0;
temp2(:, 1) = 0;

m = size(X, 1);
         
J = 0;
Theta1_grad = zeros(size(Theta1));
Theta2_grad = zeros(size(Theta2));

% forward propagation
A2 = sigmoid([ones(m, 1) X] * Theta1'); % m x 25
A3 = sigmoid([ones(m, 1) A2] * Theta2'); % m x 10

% caculate cost
Y = zeros(m, num_labels);
for i = 1:m
	Y(i, y(i)) = 1;
end
J -= sum(sum( log(A3) .* Y + log(1 - A3) .* (1 - Y) ));
J += lambda / 2 * (sum(sum(temp1 .* temp1)) + sum(sum(temp2 .* temp2)));
J /= m;

% Back Propagation

D1 = zeros(size(Theta1));
D2 = zeros(size(Theta2));

for i = 1:m
	a1 = X(i, :); % 1 x 400
	a2 = A2(i, :); % 1 x 25
	a3 = A3(i, :); % 1 x 10
	y = Y(i, :); % 1 x 10
	d3 = (a3 - y)'; % 10 x 1
	d2 = (Theta2' * d3) .* [1 a2]' .* (1 - [1 a2])'; % 26 x 1
	d2 = d2(2:end) ; % 25 x 1
	
	D1 += d2 * [1 a1];
	D2 += d3 * [1 a2];
end

Theta1_grad = (D1 + lambda * temp1) / m;
Theta2_grad = (D2 + lambda * temp2) / m;

% Unroll gradients
grad = [Theta1_grad(:) ; Theta2_grad(:)];

end

与机器学习笔记(3): 神经网络初步相似的内容:

机器学习笔记(3): 神经网络初步

神经网络应该由若干神经元组成。 前面的每一个神经元都会给到一个参数,将传递的所有参数看作一个向量 \(\vec x\),那么此神经元的净输入为: \[z = x \omega + b \]其中 \(\omega\) 称为权重向量。 这里认为 \(x\) 是行向量,而 \(\omega\) 是列向量。

VisionPro学习笔记(2)——图像转换工具ImageCovertTool

如果需要了解其他图像处理的文章,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 众所周知,VisionPro是一款功能强大的机器视觉软件,用于开发和部署机器视觉应用程序。其

[转帖]Bash脚本编程学习笔记02:脚本基础和bash配置文件

脚本基础 参考资料:Shell Scripts (Bash Reference Manual) 不严谨地说,编程语言根据代码运行的方式,可以分为两种方式: 编译运行:需要先将人类可识别的代码文件编译成机器可运行的二进制程序文件后,方可运行。例如C语言和Java语言。 解释运行:需要一个编程语言的解释

给大家分享一套非常棒的python机器学习课程

给大家分享一套非常棒的python机器学习课程——《AI小天才:让小学生轻松掌握机器学习》,2024年5月完结新课,提供配套的代码+笔记+软件包下载!学完本课程,可以轻松掌握机器学习的全面应用,复杂特征工程,数据回归,分类,算法的项目实战应用,以小学生的视角和知识储备即可学会。课程名字:AI小天才:

聊聊多任务学习

最近翻译的一篇分享中,主要讲解了多任务学习的各个方面,很多的专业术语与概念都不清楚,因此简单的整理了下相关的知识,做个笔记。 ### 概述 现在大多数机器学习任务都是单任务学习。对于复杂的问题,也可以分解为简单且相互独立的子问题来单独解决,然后再合并结果,得到最初复杂问题的结果。这样做看似合理,其实

[转帖]Redis学习笔记--Redis数据过期策略详解

本文对Redis的过期机制简单的讲解一下 讲解之前我们先抛出一个问题,我们知道很多时候服务器经常会用到redis作为缓存,有很多数据都是临时缓存一下,可能用过之后很久都不会再用到了(比如暂存session,又或者只存放日行情股票数据)那么就会出现一下几个问题了 Redis会自己回收清理不用的数据吗?

Vue学习笔记(十):全局事件总线

之前博客中介绍了prop和调用事件的方式在父-子组件之间进行数据,这种方式在只有一层嵌套层时可以使用,但是路过存在多层嵌套,多层多个“兄弟”组件之间传递数据,就非常麻烦。对此,vue中提供了一种全局事件总线机制,数据传递是通过一个空的Vue实例作为中央事件总线,通过它来触发事件和监听事件,可以实现几...

Qt信号槽与事件循环学习笔记

事件与事件循环 信号槽机制 事件与事件循环 在Qt中,事件(event)被封装为QEvent类/子类对象,用来表示应用内部或外部发生的各种事情。事件可以被任何QObject子类的对象接收并处理。 根据事件的创建方式和调度方式,Qt中事件可分为三类,分别是: 自发事件(Spontaneous even

[转帖]Kafka 核心技术与实战学习笔记(六)kafka线上集群部署方案

一.操作系统-Linux Kafka是JVM系的大数据框架kafka由Scala语言和Java语言编写而成,编译之后的源代码就是普通的".class"文件 使用Linux kafka客户端底层使用Java的selector,selector在Linux上的实现机制是epoll,由于在windows上

第124篇: 期约Promise基本方法

好家伙,本篇为《JS高级程序设计》第十章“期约与异步函数”学习笔记 1.异步编程 同步行为和异步行为的对立统一是计算机科学的一个基本概念。 特别是在 JavaScript 这种单线程事 件循环模型中,同步操作与异步操作更是代码所要依赖的核心机制。 异步行为是为了优化因计算量大而 时间长的操作。如果在