神经网络
基本概念
神经网络,模拟生物神经网络,节点称为神经元。神经网络分层命名,直接接收输入数据的是输入层,输出结果的是输出层,输入层与输出层之间的是隐藏层。
前向传播:数据从输入层开始,逐层向前传播计算,直到输出层得到输出结果。
反向传播:将输出层输出的结果与真实值进行比较,得到一个差异(损失函数值),根据这个差异逐层调整网络中的参数,方向与前向传播相反。
神经网络中的参数:以输入层和第一个隐藏层为例。假设输入数据是一个\(m\)维向量\(x\)(即输入层有m个神经元),给定第一个隐藏层有\(n\)个神经元,层之间数据的传递过程是一个基于权重\(\omega\)和偏置\(b\)的线性运算,\(\omega\)是一个\(n*m\)维矩阵,\(b\)是一个\(n\)维向量,计算过程为 \(z=\omega*x^T+b\),\(z\)是该隐藏层神经元的输入值(除了输入层神经元外其余层的神经元均有一个输入和输出值),\(\omega\)在图里就是神经元之间的连线。
整个训练神经网络的过程本质就是不停地在各层前向传播、计算误差并反向传播来得到一组较好的网络参数(各层之间的权重和偏置)。
激活函数:前面提到除了输入层神经元外其余层的神经元均有一个输入\(z\)和输出值\(f(z)\),\(f\)是该神经元的激活函数,目的是引入非线性关系(如果没有这个激活函数,那么无论有多少隐藏层,最后得到的整个系统输入输出关系本质还是一个线性的)。
损失函数:分类问题的结果是离散值,平方损失函数如果用于分类问题,分类正确的误差都是一样的,分类错误的误差都是一样,不具有距离的意义,在分类错误的情况下无法判断优化的好坏。并且平方损失误差还和预测结果错误的样本有联系,在分类问题中只关注分类正确的结果。所以 平方损失函数不适用于分类问题。交叉熵损失函数针对只分类正确的预测结果,和分类错误的预测结果没有联系,而分类任务中很少考虑分类错误的结果,主要考虑让正确的分类尽可能大。而在回归中,考虑错误的结果就很必要了,需要让回归的函数尽可能满足所有的样本包括错误的样本,所以交叉熵损失函数不适合回归。
常用的激活函数:
关于Sigmoid
\[\begin{align} s&=sigmoid(x)=\frac{1}{1+exp(-x)}\\ \frac{\alpha s}{\alpha x}&=\frac{1}{1+exp(-x)}·\frac{exp(-x)}{1+exp(-x)}=s·(1-s)\\ \end{align} \] 关于Softmax函数及其导数:
\[\begin{align} s_i&=softmax(x_i)=\frac{exp(x_i)}{\sum_{N \atop j=1}{exp(x_j)}}\\ \frac{\alpha s_i}{\alpha x_j}&=s_i-s_j^2 \quad\quad(i=j)\\ \frac{\alpha s_i}{\alpha x_j}&=-s_i·s_j \quad\quad(i \neq j) \end{align} \]传播过程
以如下网络为例分析传播过程。
\(x_i\)表示输入层的输入,$\delta_i \(表示隐藏层输入,\)\beta_i\(表示\)\delta_i\(经过激活函数之后的值,\)z_i \(表示输出层的输入,\)\hat{y}i\(表示\)z_i\(经过激活函数之后的值即整个网络最终的输出,用\)y_i\(表示真实值。\)\omega_1\(是输入层与隐藏层之间的权重矩阵,\)b_1\(是偏置,\)\omega_2\(是隐藏层与输出层之间的权重矩阵,\)b_2\(是偏置,具体对应神经元之间的权重和偏置用\)\omega,b_{k-ij}\(表示。激活函数用\)f$表示。
前向传播
\(x = [x_1,x_2,x_3]\),\(\delta=[\delta_1,\delta_2,\delta_3]\)
输入数据后传播一层
\[\delta = x*\omega_1+b_1 \] 经过激活函数\(f\)后
\[\beta = f(\delta) \] 传播到下一层
\[z = \beta*\omega_2+b_2 \] 经过激活函数\(f\)后
\[\hat y = f(z) \]计算损失
以交叉熵损失函数为例进行说明。\(y_{ij}\)表示第\(i\)个样本的真实标签的第\(j\)个类别的值(0或1),\(\hat{y}\)表示模型预测的第\(i\)个样本的第\(j\)个类别的概率,\(N\)为样本数量。
\[L =- \frac{1}{N} \sum_{i}^{N} \sum_{j}^{classNum}y_{ij}\log(\hat{y}_{ij}) \] \(y\)用向量表示时
\[L =- \frac{1}{N} \sum_{i}^{N} y_{i}\log(\hat{y}_{i}) \] 调整参数(权重矩阵和偏置):让损失尽可能快的降低,需要沿着损失函数的其梯度下降,给出学习率\(η\)作为下降的步长,\(Δω\)和\(Δb\)分别是\(Loss\)对\(ω\)和\(b\)的导数。
\[ω=\omega-η*Δω \]\[b=\omega-η*Δb \]调整隐藏层和输出层的参数
权重参数的变化量
\[\begin{align} Δ\omega_2&=\frac{\alpha L}{\alpha \omega_2}=\frac{\alpha Loss}{\alpha \hat{y}}·\frac{\alpha \hat{y}}{\alpha z}·\frac{\alpha z}{\alpha \omega_2}\\ \frac{\alpha L}{\alpha \hat{y}}&= -\frac{1}{N}\sum_{i=1}^{N}\frac{y_i}{\hat{y}_i}\\ \frac{\alpha L}{\alpha \hat{y}}·\frac{\alpha \hat{y}}{\alpha z_j}&= -\frac{1}{N}\sum_{i=1}^{N}\frac{y_i} {\hat{y}_i}\frac{\alpha \hat{y_i}}{\alpha z_j}\\&=-\frac{1}{N}[\frac{y_j}{\hat{y}_j}·(\frac{\hat{y}_j}{z_j}+\sum_{i \neq j}^{N}\frac{\hat{y}_i}{z_j})]\\&=-\frac{1}{N}[({y_i}-{\hat{y}_i{y_i}})-\sum_{i \neq j}^{N}{\hat{y}_i}{y_i}]\\&=\frac{1}{N}(\hat{y}_i-y_i)\\ \frac{\alpha z}{\alpha \omega_2}&=\beta\\ Δ\omega_2 &= \frac{1}{N}(\hat{y}_i-y_i)·\beta\\ \end{align} \] 同理可得偏置参数的变化量
\[Δb_2 = \frac{1}{N}(\hat{y}_i-y_i) \]调整隐藏层和输出层的参数
\[\begin{align} Δ\omega_1&=\frac{\alpha L}{\alpha \omega_1}=\frac{\alpha Loss}{\alpha \hat{y}}·\frac{\alpha \hat{y}}{\alpha z}·\frac{\alpha z}{\alpha \beta}·\frac{\alpha \beta}{\alpha \delta}·\frac{\alpha \delta}{\alpha \omega_1}\\ \frac{\alpha z}{\alpha \beta} &= \omega_2\\ \frac{\alpha \beta}{\alpha \delta} &= \frac{\alpha f(\delta)}{\alpha \delta}=f'(\delta)=f(\delta)(1-f(\delta))\quad对于sigmoid\\ \frac{\alpha \delta}{\alpha \omega_1} &= x\\ \end{align} \] $\frac{\alpha Loss}{\alpha \hat{y}}·\frac{\alpha \hat{y}}{\alpha z} $S 是上一个反向传播的Layer梯度的一部分,从这一计算过程中可以发现,我们在做反向传播进行计算的过程也存在梯度的逐层传播。
那么这里定义
\[gradient_1= \frac{1}{N}(\hat{y}_i-y_i) \] 即
\[\begin{align} Δ\omega_2&=gradient_1·\beta\\ Δb_2&=gradient_1\\ \end{align} \] 那么
\[\begin{align} Δ\omega_1&=gradient_1·\omega_2·f'(\delta)·x\\ Δb_1&=gradient_1·\omega_2·f'(\delta)\\ \end{align} \] 定义
\[gradient_2=gradient_1·\omega_2·f'(\delta) \] 则
\[\begin{align} Δ\omega_1&=gradient_2·x\\ Δb_1&=gradient_2\\ \end{align} \] 至此,一轮传播已经完成。
递推一般情况
激活函数记为\(f\),假设隐藏层\(n\)与隐藏层\(n+1\)之间各参数已知,即\(gradient_n\)、\(w_n\)等,则反向传播至隐藏层\(n-1\)与隐藏层\(n\)时
\[\begin{align} Δ\omega_{n-1}&=gradient_n·\omega_n·f'(\delta)·x\\ Δb_{n-1}&=gradient_n·\omega_n·f'(\delta)\\ gradient_{n-1}&=gradient_n·\omega_n·f'(\delta) \end{align} \] \(x\)表示这个Layer的输入,\(gradient_n\)表示前一个Layer的梯度,\(\omega_n\)表示前一个Layer的权重,\(\delta\)是当前Layer的输出(通过激活函数之前)。
优化梯度过程
The method computes individual adaptive learning rates for different parameters from estimates of first and second moments of the gradients. 该方法通过估计梯度的第一阶矩和第二阶矩来计算不同参数的个体自适应学习率
结合两种方法实现:AdaGrad很好地处理稀疏梯度,RMSProp很好地处理在线和非平稳环境
Adam的一些优点是参数更新的大小对梯度的重新缩放是不变的,它的步长大约由步长超参数限定,它不需要一个平稳目标,它与稀疏梯度一起工作,并且它自然地执行一种步长退火形式。
当我们使用 \(m\) 和 \(v\) 来更新参数时,目的是为了根据历史梯度信息来调整学习率,以便更好地指导参数的更新方向和步长。具体地说,\(m\) 反映了梯度的变化趋势,而 \(v\) 反映了梯度的变化幅度。因此,将 \(m\) 除以根号 \(v\) 可以使得参数更新的步长更加稳定,并且能够在梯度变化幅度较大时缩小步长,在梯度变化幅度较小时放大步长,从而提高了优化算法的性能和收敛速度。
在更新参数时,我们希望能够在梯度变化较大的方向上小步快跑,在梯度变化较小的方向上大步慢跑。\(m/\sqrt{v}\) 的形式可以很好地实现这一目标,因为它同时考虑了梯度的变化趋势(\(m\))和变化幅度(\(\sqrt{v}\)),从而使得参数更新更加智能和适应性。如图蓝色虚线表示使用优化器之前的效果,红色为使用优化器后
代码实现
代码链接
链接:https://pan.baidu.com/s/1bFJ8k7ZoV3ki5yOVHMgdQg?pwd=q9ei
提取码:q9ei
NetWork.m
classdef NetWork
% 网络
properties
shape % 各层神经元
layers % 神经元之间的权重偏置
end
methods
function obj = NetWork(network_shape)
obj.shape = network_shape;
obj.layers = cell(1, length(network_shape) - 1);
for i = 1:length(network_shape) - 1
obj.layers{i} = Layer(network_shape(i), network_shape(i+1));
end
end
function outputs = network_forward(obj, inputs)
addpath("functions\");
outputs = cell(1, length(obj.layers) + 1);
outputs{1} = inputs;
for i = 1:length(obj.layers)
layer_out = obj.layers{i}.layer_forward(outputs{i});
if i < length(obj.layers)
layer_output = Normalize(sigmoid(layer_out));
else
layer_output = Normalize(SoftMax(layer_out));
end
outputs{i+1} = layer_output;
end
end
function [opts,obj] = network_backward(obj, outputs, target_vector, lr, opts, method, epoch)
% 网络的反向传播
% outputs: 每一层的输出
addpath("functions\");
if method == "SGD" % 随机梯度下降,每次只选一个数据
dataRange = randi([1,height(outputs{1})]);
elseif method == "MBGD" % 最小批次随机梯度下降,每次只选一个batch的数据
batchSize = 32; % 定义批次大小
% 整个程序中未使用batch,故随机选择batchSize个数据进行梯度下降
dataRange = randi([1, height(outputs{1})], 1, batchSize);
else % 批量梯度下降,每次用所有数据
dataRange = 1:height(outputs{1});
end
for i = length(obj.layers):-1:1
opts(i) = opts(i).zero_gard();
if i == length(obj.layers)
gradient = (outputs{end}(dataRange,:) - target_vector(dataRange,:)) / size(target_vector(dataRange,:), 1); % 计算输出层的梯度
else
sigmoid_derivative_value = outputs{i+1}(dataRange,:).*(1- outputs{i+1}(dataRange,:));
gradient = sigmoid_derivative_value .* (gradient * obj.layers{i+1}.weights'); % 使用当前层的权重矩阵来计算梯度
end
opts(i) = opts(i).optimize(gradient, epoch);
obj.layers{i} = obj.layers{i}.update_weights_and_biases(lr, opts(i).grad,outputs{i}(dataRange,:));
end
end
end
end
Layer.m
classdef Layer
% Class representing a neural network layer
properties
weights
biases
end
methods
function obj = Layer(n_input, n_neurons)
obj.weights = randn(n_input, n_neurons);
obj.biases = randn(1, n_neurons);
end
function output = layer_forward(obj, inputs)
output = inputs * obj.weights + obj.biases;
end
function obj = update_weights_and_biases(obj, lr, gradient, layerInput)
delta_weights = layerInput' * gradient;
delta_biases = mean(gradient, 1);
obj.weights = obj.weights - lr * delta_weights;
obj.biases = obj.biases - lr * delta_biases;
end
end
end
Adam.m
classdef Adam
% Adam算法优化器
% 在梯度变化较大的方向上小步快跑,在梯度变化较小的方向上大步慢跑
properties
beta1 % 动量项参数1
beta2 % 动量项参数2
mt % 一阶矩估计
vt % 二阶矩估计
grad % 优化后的梯度
end
methods
function obj = Adam(beta1,beta2)
% 初始化
obj.beta1 = beta1;
obj.beta2 = beta2;
obj.mt = 0;
obj.vt = 0;
end
function obj = optimize(obj,gt,t)
% 更新一阶矩和二阶矩参数
% gt是当前梯度
epsilon = 1e-8; % 微小值,防止分母为0
%obj = obj.update_moment(gt,epoch);
obj.mt = obj.beta1 * obj.mt + ( 1 - obj.beta1 ) * gt;
obj.vt = obj.beta2 * obj.vt + ( 1 - obj.beta2 ) * (gt.*gt);
mt_hat = obj.mt / ( 1 - obj.beta1^t );
vt_hat = obj.vt / ( 1 - obj.beta2^t );
obj.grad = mt_hat ./ (sqrt(vt_hat)+epsilon);
end
function obj = zero_gard(obj)
% 清空梯度
%obj.mt = 0;
%obj.vt = 0;
obj.grad = 0;
end
end
end
标签:基于,frac,hat,end,人工神经网络,obj,alpha,omega,MATLAB
From: https://www.cnblogs.com/hair-is-decreasing/p/18191394