
按照类型可以进行如下分类
监督分类
非监督分类
强化学习

生物学中,人的大脑是由多个神经元互相连接形成网络而构成的。也就是说,一个神经元从其他神经元接收信号,也向其他神经元发出信号。大脑就是根据这个网络上的信号的流动来处理各种各样的信息的。

如果用数学公式来表示信号的传递,可以通过变量 x x x来表示输入信号,当有信号输入时, x = 1 x=1 x=1; 当无输入信号时, x = 0 x=0 x=0;

如果有多个输入信号, x 1 x_1 x1、 x 2 x_2 x2、 x 3 x_3 x3,每个信号具有各自的权重 ω 1 \omega_1 ω1、 ω 2 \omega_2 ω2、 ω 3 \omega_3 ω3
那么输入信号之和可以如下表示:
ω 1 X 1 + ω 2 X 2 + ω 3 X 3 \omega_1X_1+\omega_2X_2+\omega_3X_3 ω1X1+ω2X2+ω3X3

可以使用如上所示的简化图,这样很容易就能画出大量的神经元,用箭头方向区分输入和输出。为了与生物学的神经元区分开来,我们把经过这样简化、抽象化的神经元称为神经单元(unit)
近两年,由于深度学习网络的非线性计算能力以及深度挖掘数据潜力的优势,在海洋、气象领域产生了许多应用。包括ConvLSTM、GRU等

我将从从以下几个方面进行介绍
什么是神经网络model呢?
它实际上是一组参数 θ \theta θ 指定的函数 f f f
下面是一个关于 x x x的线性预测函数,包含权重 ω \omega ω和偏差 b b b
存在偏差的原因之前在回归分析中也介绍过,原因在于当使用一个线性函数来将预测因子 x x x进行线性组合时,观测值与估测值之间是存在一个随机误差的,因此添加一个 b b b
以下函数表示多个输入值 x x x 与其权重 ω \omega ω 和偏置 b b b 之间的线性组合关系,其实可以理解为一个一元线性回归方程

现在来回答什么是神经网络?

看上面的 Z Z Z,是不是和多元线性回归模型非常类似呢?
假设现在有两个输入值
输入值为:
x
1
=
1
,
x
2
=
−
1
输入值为: x_1=1, \quad\quad x_2=-1
输入值为:x1=1,x2=−1
对应的权重为:
w
11
=
1
,
w
12
=
−
1
,
w
21
=
−
1
,
w
22
=
1
w_{11}=1, \quad\quad w_{12}=-1, \quad\quad w_{21}=-1, \quad\quad w_{22}=1
w11=1,w12=−1,w21=−1,w22=1
偏置为:
b
1
=
1
,
b
2
=
0
b_1=1, \quad\quad b_2=0
b1=1,b2=0
那么
x
1
x_1
x1的线性组合为
z
1
=
w
11
∗
x
1
+
w
21
∗
x
2
+
b
1
=
(
1
∗
1
)
+
(
−
1
)
∗
(
−
2
)
+
1
=
4
z_1 = w_{11}*x_1 + w_{21}*x_2 +b_1 = (1*1) + (-1)*(-2) + 1 = 4
z1=w11∗x1+w21∗x2+b1=(1∗1)+(−1)∗(−2)+1=4
z
2
=
w
12
∗
x
1
+
w
22
∗
x
2
+
b
2
=
1
∗
(
−
1
)
+
(
−
1
)
∗
1
+
0
=
−
2
z_2 = w_{12}*x_1 + w_{22}*x_2 +b_2 = 1*(-1) + (-1)*1 + 0 = -2
z2=w12∗x1+w22∗x2+b2=1∗(−1)+(−1)∗1+0=−2
再假设对于线性组合 z z z添加一个非线性函数 σ \sigma σ,非线性函数为sigmodif 函数: σ ( z ) = 1 / ( 1 + e − z ) \sigma(z) = 1/(1+ e^{-z}) σ(z)=1/(1+e−z)
所以最终输出结果为
$$
\sigma(z_1) = 1/(1+ e^{-z_1}) = 0.98,
\quad\quad
\sigma(z_2) = 1/(1+ e^{-z_2}) = 0.12
$$
sigmoid 可以通过简单的python函数来验证
def sigmoid(x)
sigma = 1/(1+np.exp(-1*x))
return sigma

如果包含多个隐藏层呢?可以通过矩阵的形式来表示以上输入输出。
输入向量 [ 1 − 1 ] T , 输出为 [ 0.62 0.83 ] T \text{输入向量}[1\quad-1]^T,\text{输出为}[0.62\quad0.83]^T 输入向量[1−1]T,输出为[0.620.83]T


当然了,上面的表现形式是一层神经网络的矩阵表达形式,如果我们将第一层输出的结果表示为 a 1 a_1 a1,然后将第一层的输出结果作为下一层的输入向量。如下所示:
多层NN神经网络,计算第一层的输出

按照上面的逻辑,依次迭代,计算所有层的输出

综上所述,机器学习或者说深度学习的一个最主要的目的就是:
如何计算学习参数的数量呢?

下面以一个简单的激活函数示例,激活函数为sigmoid function,该函数为非线性函数,可以将输入的数组映射到
[
0
,
1
]
[0,1]
[0,1]范围内
下面是将线性组合后的三个结果 z 1 z_1 z1, z 2 z_2 z2, z 3 z_3 z3添加激活函数之后得到的结果:

其中,sigmoid激活函数的分布形式为:

当然, sigmoid在分类任务中一般适用于二分类任务;那么,对于多分类分类任务,我们一般会使用softmax激活函数,其计算方式也非常简单。

为什么要存在激活函数?
需要非线性激活来学习复杂(非线性)数据表示

当然,还有其他的激活函数,如下所示:

其中,一般使用比较多的是ReLU,该函数有以下优点(来自gpt):
ReLU是一个非线性的激活函数,能够在神经网络中引入非线性映射,从而使网络能够学习和表示更加复杂的函数关系。
相对于其他常用的激活函数(如sigmoid和tanh),ReLU具有稀疏激活性,即当输入为负数时输出为零,这意味着在训练过程中,部分神经元会变得不活跃,从而降低了参数的相关性,有助于减少过拟合
ReLU的计算非常简单,只需要判断输入是否大于零并输出相应的值,因此在前向传播和反向传播过程中的计算开销较小,尤其在深度神经网络中,这种计算效率的提高非常重要。
在深度神经网络中,使用sigmoid或tanh等激活函数容易导致梯度消失或梯度爆炸问题,而ReLU的导数在正区间恒为1,可以一定程度上缓解梯度消失问题,有助于更有效地进行梯度传播
ReLU在正区间的梯度恒为1,这使得在反向传播过程中梯度可以稳定地传播,不会出现梯度爆炸或梯度消失的情况,从而有助于更好地训练深度神经网络
下面我简单使用python演示了一个逻辑回归二分类任务
找到红蓝点的分界线 | 通过逻辑回归
sigmoid(z)随机设置一些散点,然后根据横纵坐标之和对于散点进行二分类



给出线性回归演示的python代码
import os
import xarray as xr
import glob
import numpy as np
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import cmaps
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import matplotlib.ticker as mticker
import datetime
# Get current date
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
# Get current file name
current_filename = os.path.basename(__file__)
# Your code continues here
# ================================================================================================
# Author: %(Jianpu)s | Affiliation: Hohai
# Email : %(email)s
# Last modified: Created on %(current_date)s
# Filename: %(current_filename)s
# Description:
# =================================================================================================
# 生成随机数据
np.random.seed(0)
x1 = np.random.randn(100)
x2 = np.random.randn(100)
X = np.c_[np.ones(x1.shape[0]), x1, x2]
y = (x1 + x2 >= 0).astype(int)
plt.figure(dpi=200)
plt.scatter(x1,x2)
# 定义Sigmoid函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 定义梯度下降函数
def gradient_descent(X, y, theta, learning_rate, num_iterations):
m = len(y)
cost_history = [] # 用于存储每次迭代的损失
for i in range(num_iterations):
z = np.dot(X, theta)
h = sigmoid(z)
cost = (-1 / m) * np.sum(y * np.log(h) + (1 - y) * np.log(1 - h))
cost_history.append(cost)
gradient = np.dot(X.T, (h - y)) / m
theta -= learning_rate * gradient
return theta, cost_history
# 可视化数据
index_pos = np.where(x1 + x2 >= 0)
index_neg = np.where(x1 + x2 < 0)
x1_pos = x1[index_pos]
x2_pos = x2[index_pos]
x1_neg = x1[index_neg]
x2_neg = x2[index_neg]
plt.figure(dpi=200)
plt.scatter(x1_pos, x2_pos, color='r', label="x1 + x2 >= 0")
plt.scatter(x1_neg, x2_neg, color='b', label="x1 + x2 < 0")
plt.xlabel('x1')
plt.ylabel('x2')
plt.xlim([-3, 3])
plt.ylim([-3, 3])
plt.legend()
plt.grid()
plt.show()
# 定义Sigmoid函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 定义梯度下降函数
def gradient_descent(X, y, theta, learning_rate, num_iterations):
m = len(y)
cost_history = [] # 用于存储每次迭代的损失
for i in range(num_iterations):
z = np.dot(X, theta)
h = sigmoid(z)
cost = (-1 / m) * np.sum(y * np.log(h) + (1 - y) * np.log(1 - h))
cost_history.append(cost)
gradient = np.dot(X.T, (h - y)) / m
theta -= learning_rate * gradient
return theta, cost_history
# 初始化参数
theta = np.zeros(X.shape[1])
# 设置学习率和迭代次数
learning_rate = 0.01
num_iterations = 8000
# 使用梯度下降进行训练
theta, cost_history = gradient_descent(X, y, theta, learning_rate, num_iterations)
plt.figure(dpi=200)
# 绘制损失函数下降曲线
plt.plot(cost_history)
plt.xlabel('Iterations')
plt.ylabel('Cost')
plt.title('Cost Function Decrease Over Time')
plt.grid()
plt.show()
# 绘制等高线图
x1_vals = np.linspace(-3, 3, 100)
x2_vals = np.linspace(-3, 3, 100)
X1, X2 = np.meshgrid(x1_vals, x2_vals)
Z = sigmoid(theta[0] + theta[1] * X1 + theta[2] * X2)
plt.figure(dpi=200)
plt.contourf(X1, X2, Z, levels=[0, 0.5, 1], colors=['blue', 'red'], alpha=0.3)
plt.scatter(x1_pos, x2_pos, color='r', label="x1 + x2 >= 0")
plt.scatter(x1_neg, x2_neg, color='b', label="x1 + x2 < 0")
plt.xlabel('x1')
plt.ylabel('x2')
plt.xlim([-3, 3])
plt.ylim([-3, 3])
plt.legend()
plt.grid()
plt.show()
上面介绍了前向传播Forward Propagation和激活函数:
前向传播
计算损失的梯度(Loss Gradient)
反向传播梯度(Backward Propagation of Gradients)
更新参数(Update Parameters)
后向传播可以帮助我们更好的理解每一个权重是如何影响损失函数的结果 L o s s Loss Loss

那么,如何看影响参数对于 L o s s Loss Loss的影响呢?
Loss实际是关于输入x,权重
ω
\omega
ω,偏置b的线性组合,加上激活函数和损失函数得到Loss结果,那么只需要将Loss对于参数和偏置分布进行求偏导即可。
上面是一层的计算方式,理解清楚的话其实多层神经网络的计算方式同理

下面我将在黑板上举例来演示一个具体的计算过程。
当然,在计算机实际计算时,不需要计算每一个偏导的结果,只需要向后传播梯度即可,这样可以加快计算效率

在计算 L o s s Loss Loss过程后,我们需要
根据输入数据x,通过前向传播求解神经网络模型的计算结果
y
^
\hat {y}
y^,将模型的结果
y
^
\hat {y}
y^与真实结果
Y
Y
Y 进行对比
∣
y
^
−
Y
∣
|\hat {y} - Y|
∣y^−Y∣,计算差距即损失
L
o
s
s
Loss
Loss。为了调整参数使得两者的损失
L
o
s
s
Loss
Loss变小,直至满足我们设置的最小误差精度。
那么,如何来调整参数,使得Loss变小呢?
梯度下降的过程就像是站在山坡上的一个人,想要找到山底最低点的位置。这个人通过观察当前位置的斜率(即梯度),然后朝着斜率下降最陡的方向移动一步。重复这个过程,直到找到山底,也就是损失函数的最小值


当然,这个方法也存在一些缺点
当达到损失表面的局部最小值时,梯度下降算法停止

除了局部极小值问题之外,GD 算法在平台期可能会非常慢,并且可能会卡在鞍点处
梯度告诉我们损失增长最快的方向,但它并没有告诉我们应该沿着相反的方向走多远
选择学习率(也称为步长)是神经网络训练最重要的超参数设置之一
选择合适的学习率对于我们的模型训练效果是显著的,当然,不当的学习率对于模型的计算也会有较大影响,下面是学习率过小或者过大的情况:

对于同一个训练任务,通过改变学习率,对于训练损失会产生较大的影响,下面也是一个自己编写的简单结果。

当然,这里建议一般使用小批量梯度下降,即分batch进行梯度下降

下面是不同的batch对于模型收敛速度的影响

通过控制其他超参数不变,只改变batch的大小
batch对于损失曲线的影响可以发现,当batch=1024时,loss曲线更收敛

一般可以通过loss曲线来判断模型的模拟性能
如下面这张图:

下面这个图片展示了不同学习率对于训练损失曲线的影响,也可以根据损失曲线反过来评估设置的学习率是否合理
高学习率:损失增加或稳定得太快
学习率低:损失下降太慢(需要很多轮才能达到解决方案)

假如输入数据是一个5x5的二维矩阵,为其添加一个3x3的卷积核,以一个步长进行卷积
最终得到一个3x3的特征图矩阵,这就实现了卷积的过程,可以发现在步长为1时,特征图的尺寸大小和卷积核的大小是相同的
这里将在黑板上给大家演示
假如现在有一个2x2的原始矩阵,给他一个3x3的卷积核,将原始矩阵上的每一个点和卷积核上点相乘,这样就能得到4个3x3的特征矩阵,如果按照步长为3这个四个特征矩阵进行拼接,这样就得到了6x6的矩阵。这样就实现了反卷积的过程,类似于 UNet 模型就使用这种方法。
池化层可以缩小卷积特征的空间尺度,降低计算资源,去除噪声。包括
如下显示的是最大池化,假设原始矩阵为4x4,给定一个2x2的池化层,以步长为2进行滑动。将每一个池化层覆盖的原始矩阵中的最大值提取出来作为原始4x4矩阵里面的最显著特征,于是就得到了一个2x2的蕴含局部区域显著信号的输出矩阵。

以卷积层和池化层可以搭建一个简单的卷积神经网络,存在以下优点

一般分为回归任务和分类任务
分类任务常用的损失函数为:Cross-entropy ; 输出层的激活函数为:softmax

回归任务常用的损失函数为:MSE或MAE ; 输出层的激活函数为:Linear (Identity) or Sigmoid Activation

简单画了一个完整的深度学习任务流程:

随便让gpt写了一个训练流程,还是挺完整的:
数据准备:加载MNIST手写数字数据集并进行预处理,包括归一化和添加通道维度。
模型构建:构建一个包含卷积层、池化层和全连接层的CNN模型。
训练模型:使用Adam优化器和交叉熵损失函数对模型进行训练。
模型预测:使用训练好的模型对测试数据进行预测,并使用Softmax函数将输出转换为概率分布。

Mean subtraction, 获得以0为中心的正太分布
Normalization, 标准化
标准化的目的是,对于输入的数据以及标签之前的量级可能不一致,不一致影响模型的收敛速度;为了使其量级一致,提高计算效率。
Underfitting
Overfitting




减少参数量 - 参数共享(convnets, recurrent neural nets)
正则化 - 惩罚模型的权重参数,以限制它们的大小,从而降低模型的复杂度 ∑ j = 1 d W j 2 \sum_{j=1}^dW_j^2 ∑j=1dWj2
batch normalization
Pytorch
tensorflow
caffe2
…

下面举一个运行CNN进行ENSO预报的经典文章


通过本次介绍,需要了解一些知识点
深度|机器学习任务目标:什么是输入?什么是标签 | 输出?
深度学习模型是什么? - 输入数据映射到一些数字
什么是损失函数? - 衡量一个模型的效果
如何训练一个模型? - 基于经验损失总和的小批量 SGD
验证 - 训练的模型是否过拟合
终于,把非线性回归和神经网络的内容都整理完了。画了一周半时间来推导公式和做PPT,密密麻麻推导过程也记了十几页纸。上台前以为自己已经推的很清楚了,到了实际上台讲解的时候发现还是紧张的冒汗。。。果然看懂了和讲清楚之间还是有一段路要走。翻转课堂整一次还是太累了,不过在实际推导公式、听其他同学讲解以及老师补充的过程对于相关知识点也把握更清楚。anyway,总算是给他讲完了,连上三节课可真不容易。马上躺平ing…
深度学习的数学 作者:[日]涌井良幸、涌井贞美 译者:杨瑞龙 https://www.ituring.com.cn/book/2593
Ham, YG., Kim, JH. & Luo, JJ. Deep learning for multi-year ENSO forecasts. Nature 573, 568–572 (2019). https://doi.org/10.1038/s41586-019-1559-7
部分材料来自网络搜集和个人整理