16、深度学习中的神经网络架构与应用
深度学习中的神经网络架构与应用
1. 深度学习概述
传统的时间序列分类通常分为两个步骤:
1. 从时间序列中提取有意义的特征,可以使用傅里叶变换或时域描述符。
2. 使用表格分类器对这些特征进行分类,例如在 Edge Impulse 上使用全连接网络,在 Python 中使用随机森林。
近年来,随着深度学习技术的普及和易用性提高,一种不同的方法变得广泛应用:将特征提取嵌入到进行分类的同一个神经网络中。这意味着从手动定义特征向量转变为让机器学习/深度学习模型根据输入数据集的训练过程来构建最佳特征。根据数据集和网络类型,这种方法可能比手动特征提取获得更高的准确率。
不过,深度学习也有其缺点。为了具有更强的表达能力,网络的规模和复杂度会增加。在 TinyML 环境中,资源极其有限,设备可能无法运行一个同时完成特征提取和分类的网络。因此,需要根据具体用例仔细评估采用哪种方法。但也有许多优化措施使在嵌入式硬件上运行更大的模型成为可能,而且深度学习能让廉价、节能的硬件执行仅靠手动特征无法完成的复杂任务。
2. 循环神经网络(RNN)与长短期记忆网络(LSTM)
2.1 RNN 概述
循环神经网络(RNN)具有特别适合处理序列数据的拓扑结构,已成功应用于语言翻译、语音合成、视频分析以及时间序列分类等领域。与普通网络(如全连接网络)不同的是,RNN 的隐藏神经元具有记忆功能。当新输入到来时,神经元会利用其内部状态计算输出,然后根据输入和输出更新该状态。
2.2 LSTM 工作原理
长短期记忆网络(LSTM)是 RNN 中最常用的神经元类型,用于解决学习过程中梯度消失和梯度爆炸的问题,使网络在处理长时间输入时能取得满意的结果。LSTM 细胞的工作原理如下:
1. 每个 LSTM 细胞有一个内部状态(类似于感知机中的权重)和一个记忆状态(另一组权重)。
2. 当接收到新输入时,通过组合输入向量和内部状态计算一个遗忘向量。接近 0 的值表示应遗忘记忆状态中对应的元素,接近 1 的值表示应保留该元素。
3. 计算一个候选向量,用于根据新输入更新记忆状态。新的记忆状态是旧状态、遗忘向量和候选向量的加权和。
4. 最终,记忆状态和输入用于更新内部状态,经过激活函数处理后产生输出。
2.3 训练 LSTM 循环神经网络
以下是训练 LSTM 循环神经网络的代码示例:
from tinyml4all.tensorflow import RNN
from tinyml4all.tensorflow.layers import LSTM, Perceptron
from tinyml4all.time.continuous.classification import TimeSeries
ts = TimeSeries.read_csv_folder("Chapter4/motion")
ts.label_from_source()
# convert TimeSeries to X and Y training data for NN
X, Y = ts.as_windows(duration="1s", shift="250ms")
rnn = RNN()
# two LSTM layers with 12 neurons + one Fully connected
rnn.add(LSTM(12))
rnn.add(LSTM(12))
rnn.add(Perceptron(32))
# display network architecture
print(rnn.compile(X, Y, task="classification"))
训练结果如下:
Model: "sequential"
____________________________________________________________
Layer (type) Output Shape Param#
============================================================
lstm (LSTM) (None, 125, 8) 480
lstm_1 (LSTM) (None, 125, 16) 1600
flatten (Flatten) (None, 2000) 0
dense (Dense) (None, 32) 64032
dense_1 (Dense) (None, 4) 132
============================================================
Total params: 66244 (258.77 KB)
Trainable params: 66244 (258.77 KB)
Non-trainable params: 0 (0.00 Byte)
____________________________________________________________
继续训练并输出准确率报告:
# train neural network and display accuracy plot
rnn.fit(X, Y, epochs=50, plot=True)
# print accuracy on the validation set
print(rnn.classification_report())
准确率报告如下:
precision recall f1-score support
idle 1.00 1.00 1.00 52
shake 1.00 1.00 1.00 91
slide 1.00 0.86 0.92 92
wave 0.88 1.00 0.93 91
accuracy 0.96 326
macro avg 0.97 0.96 0.96 326
weighted avg 0.97 0.96 0.96 326
+-------------------+------+-------+-------+------+
| True vs Predicted | idle | shake | slide | wave |
+-------------------+------+-------+-------+------+
| idle | 52 | 0 | 0 | 0 |
| shake | 0 | 91 | 0 | 0 |
| slide | 0 | 0 | 79 | 13 |
| wave | 0 | 0 | 0 | 91 |
+-------------------+------+-------+-------+------+
最后将模型导出为 Arduino 兼容的 C++ 代码:
rnn.convert_to("c++", class_name="LSTM", save_to="MotionLSTM.h")
2.4 部署 RNN
在 Arduino 上运行 RNN 与运行多层感知机(MLP)类似,无需更改代码。不同之处在于如何创建输入向量。时间序列通常通过将新样本排队并丢弃旧样本来构建。可以手动处理,也可以使用生成的代码自动处理。以下是在 Arduino Nano BLE Sense 上运行导出的 RNN 对加速度计数据进行分类的示例代码:
/**
* Listing 8-4: Classify continuous motion using LSTM model
*
* Required hardware: Arduino Nano BLE Sense
*/
#include "./MotionLSTM.h"
#include <Arduino_LSM9DS1.h>
#include <tinyml4all.h>
// ARENA is the amount of memory to reserve for the model
// larger models needs more memory, but there's not a
// formula to calculate the optimal value
// is a trial-and-error process
#define ARENA 20000
tinyml4all::LSTM<ARENA> lstm;
tinyml4all::LSM9DS1 imu;
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("TensorFlow LSTM demo");
imu.begin();
lstm.begin();
}
void loop() {
// read accelerometer and gyroscope
imu.readAcceleration();
imu.readGyroscope();
// append readings to internal RNN queue
lstm.append(imu.ax, imu.ay, imu.az, imu.gx, imu.gy, imu.gz);
// await until queue is full
if (!lstm.isReady())
return;
// run classification
if (!lstm.predict()) {
Serial.println(lstm.error());
return;
}
// lstm.label holds the name of the predicted class
// lstm.idx holds the numeric id of the predicted class
// lstm.value holds the numeric output (for regression
tasks only)
// lstm.confidence is the probability of the prediction
// (from 0 to 1)
// lstm.confidences is an array with the confidences of
all the classes
// (one for each class for classification)
// lstm.outputsAsString returns each class' score, from
// 0 to 1 (classification only)
Serial.print("Predicted class ");
Serial.print(lstm.label);
Serial.print(" with confidence ");
Serial.println(lstm.confidence);
Serial.print(" > Scores: ");
Serial.println(lstm.outputsAsString());
delay(1000);
}
如果想手动处理输入数组,可以调用
lstm.predict(inputs)
,其中
inputs
是按
At=1, Bt=1, Ct=1, At=2, Bt=2, Ct=2, …
排列的输入值数组,A、B、C 是传感器读数,t 是时间步。
3. 一维卷积神经网络(1D CNN)
3.1 1D CNN 概述
循环神经网络并非处理序列数据的唯一架构,一维卷积神经网络(1D CNN)通常是一种更快、更简洁的替代方案。与 LSTM 细胞不同,1D CNN 没有记忆功能,可能在建模输入数据的长期关系方面表现不佳,但在大多数情况下,数据中最强的连接存在于相邻元素之间,因此这通常不是问题。
一维卷积是一种数学运算,它将输入序列(一组数字)与一组较小的数字(权重,称为滤波器或内核)相结合,生成一个新的序列。具体操作是,内核在输入序列上滑动,每次取与内核长度相同的输入元素与内核元素进行点积运算,然后将结果求和,最终得到一个新的序列。为了构建 1D CNN,将多个这样的内核封装在一个 Conv1D 层中,并将多个这样的层堆叠在一起。在最后一个 Conv1D 层和输出层之间,使用一个或多个全连接层组合提取的特征。学习过程就是找到能使分类准确率最大化(在分类任务中)或使误差最小化(在回归任务中)的最佳内核权重。
3.2 训练 1D CNN
以下是在连续运动数据上训练 1D CNN 的代码示例:
from tinyml4all.tensorflow import CNN1D
from tinyml4all.tensorflow.layers import Conv1D, Perceptron
from tinyml4all.time.continuous.classification import TimeSeries
ts = TimeSeries.read_csv_folder("Chapter4/motion")
ts.label_from_source()
X, Y = ts.as_windows(duration="1s", shift="250ms")
cnn = CNN1D()
# refer to section "2D Convolutional networks" for what
stride is
cnn.add(Conv1D(8, kernel_size=3, strides=2))
cnn.add(Conv1D(16, kernel_size=3, strides=2))
cnn.add(Conv1D(24, kernel_size=3, strides=2))
cnn.add(Perceptron(32))
# display network architecture
print(cnn.compile(X, Y, task="classification"))
网络架构如下:
Model: "sequential"
_______________________________________________________________
Layer (type) Output Shape Param #
===============================================================
conv1d (Conv1D) (None, 109, 8) 152
conv1d_1 (Conv1D) (None, 54, 16) 400
conv1d_2 (Conv1D) (None, 26, 24) 1176
flatten (Flatten) (None, 624) 0
dense (Dense) (None, 32) 20000
dense_1 (Dense) (None, 4) 132
===============================================================
Total params: 21860 (85.39 KB)
Trainable params: 21860 (85.39 KB)
Non-trainable params: 0 (0.00 Byte)
_______________________________________________________________
继续训练并输出准确率报告:
# train neural network and display accuracy plot
cnn.fit(X, Y, epochs=50, plot=True)
# print accuracy on the validation set
print(cnn.classification_report())
准确率报告如下:
precision recall f1-score support
idle 0.97 0.98 0.98 60
shake 0.98 0.97 0.98 104
slide 1.00 1.00 1.00 106
wave 0.97 0.97 0.97 105
accuracy 0.98 375
macro avg 0.98 0.98 0.98 375
weighted avg 0.98 0.98 0.98 375
+-------------------+------+-------+-------+------+
| True vs Predicted | idle | shake | slide | wave |
+-------------------+------+-------+-------+------+
| idle | 59 | 0 | 0 | 1 |
| shake | 1 | 101 | 0 | 2 |
| slide | 0 | 0 | 106 | 0 |
| wave | 1 | 2 | 0 | 102 |
+-------------------+------+-------+-------+------+
最后将模型导出为 C++ 代码:
cnn.convert_to("c++", save_to="CNN1D.h")
3.3 部署 1D CNN
在 Arduino 草图中运行 1D CNN 与运行 LSTM 网络相同,因为它们都处理时间序列数据,且生成的 API 相同,只需将
tinyml4all::LSTM
重命名为
tinyml4all::CNN1D
即可。
4. 二维卷积神经网络(2D CNN)
4.1 2D CNN 概述
二维卷积神经网络(2D CNN)用于处理二维数据,通常是图像或类似图像的数据。类似图像的数据是指以二维形式排列且值在特定范围内的数据,例如:
- MFCC 特征:在某些应用中提取的特征,像素表示随时间的频率贡献,而非空间上的光线。
- 脑电图/肌电图/加速度计数据:任何随时间收集的多维数据都可以重塑为二维窗口。
- 温度/距离图:热成像相机和网格飞行时间传感器产生的二维输出,每个元素表示温度或距离。
如果将像素的概念抽象为涵盖各种类型的数据,那么这些数据都可以表示为图像,从而成为 2D CNN 的合适输入。Conv2D 算子的原理是二维数据在空间上是相关的,每个像素与其相邻像素(称为局部感受野)存在关系,这种关系通过 Conv2D 算子的权重(内核)进行编码,并从输入数据集中学习。通过堆叠多个内核,网络可以学习到不同的模式,如边缘、角落、纹理等。与全连接网络相比,2D CNN 的权重数量大幅减少,且与输入/输出的数量无关。例如,一个 3×3 的 Conv2D 算子无论应用于 96×96 还是 512×512 的图像,始终存储 9 个权重。
4.2 下采样与步长
Conv2D 层通常位于 CNN 的开头,用于从图像中提取特征,后续的感知机将这些特征聚合以产生网络输出。由于图像数据通常包含数千个像素,感知机的权重数量会随着输入数量线性增长,这会导致内存、计算时间和准确率方面的问题。为了解决这个问题,CNN 采用下采样策略,使图像在网络中越深入尺寸越小。下采样带来了以下好处:
- 允许在更深的层中使用更多内核,使网络能够学习更复杂的特征。
- 减少输入数量,缓解过拟合问题。
- 提供平移不变性和噪声抑制,通过聚合局部特征,平滑数据中的小变化,使特征提取对像素噪声或对象的小平移不敏感。
下采样有两种方法:池化和步长。
4.3 池化
池化层通常紧跟在 Conv2D 层之后,用于对其输出进行下采样。它将 Conv2D 输出的小区域(通常是 2×2)聚合为一个值,有效地将输出图像的大小减半。最常用的聚合算子是最大值池化,但也可以计算每个块的平均值。最大值池化在分类任务中更受欢迎,因为它强调最突出的特征,有助于检测明显和尖锐的特征(如边缘)。
4.4 步长
另一种下采样方法是增加 Conv2D 算子的步长。步长表示内核在图像上移动的距离,默认值为 1,但可以调整。例如,将步长设置为 2 可以使输出图像的大小减半。
下表总结了最大值池化和步长为 2 的卷积的区别:
| 标准 | 最大值池化 | 步长为 2 的卷积 |
| — | — | — |
| 关键优势 | 保留最强特征(最大值),通常性能优于步长 | 内核权重在训练时考虑下采样 |
| 信息保留 | 激进地减少数据,可能丢失信息 | 保留更多细微信息,更平滑 |
| 抗噪声能力 | 对噪声更鲁棒,关注最大值 | 可能对噪声或细微变化更敏感 |
| 计算成本 | 需要步长为 1 的卷积,计算量更大 | 计算量是步长为 1 时的 1/4 |
| 理想用例 | 强调尖锐、突出的特征 | 在保留更多信息的同时逐步下采样 |
在 TinyML 环境中,由于资源有限,步长方法比池化更具优势,因为它计算量更小,且中间结果所需的内存更少。
4.5 训练 2D CNN
以下是训练一个 2D CNN 对猫狗图像玩具数据集进行分类的代码示例:
from tinyml4all.tensorflow import CNN2D
from tinyml4all.tensorflow.layers import Conv2D, MaxPooling2D, Perceptron
from tinyml4all.datasets import Pets
cnn = CNN2D(input_shape=(48, 48))
# example of Conv2 + max pooling
# 8 is the number of kernels
cnn.add(Conv2D(8, kernel_size=3))
cnn.add(MaxPooling2D())
# example of Conv2D with stride
cnn.add(Conv2D(16, kernel_size=3, strides=2))
# stride & max pooling
# (result is ¼ the size)
cnn.add(Conv2D(24, kernel_size=3, strides=2))
cnn.add(MaxPooling2D())
# fully connected layer before output
cnn.add(Perceptron(32))
# display network architecture
print(nn.compile(Pets.X, Pets.Y))
网络架构如下:
Model: "sequential"
_______________________________________________________________
Layer (type) Output Shape Param #
===============================================================
conv2d (Conv2D) (None, 94, 94, 8) 224
max_pool2d (MaxPooling2D) (None, 47, 47, 8) 0
conv2d_1 (Conv2D) (None, 23, 23, 16) 1168
conv2d_2 (Conv2D) (None, 11, 11, 24) 3480
max_pool2d_1 (MaxPooling2D (None, 5, 5, 24) 0
flatten (Flatten) (None, 600) 0
dense (Dense) (None, 32) 19232
dense_1 (Dense) (None, 2) 66
===============================================================
Total params: 24170 (94.41 KB)
Trainable params: 24170 (94.41 KB)
Non-trainable params: 0 (0.00 Byte)
_______________________________________________________________
继续训练并输出准确率报告:
# train neural network and display accuracy plot
cnn.fit(Pets.X, Pets.Y, epochs=50, plot=True)
# print accuracy on the validation set
print(cnn.classification_report())
准确率报告如下:
precision recall f1-score support
dog 0.67 0.73 0.70 11
cat 0.62 0.56 0.59 9
accuracy 0.65 20
macro avg 0.65 0.64 0.64 20
weighted avg 0.65 0.65 0.65 20
需要注意的是,这是图像分类任务,模型只能判断图像中是猫还是狗,无法定位它们在图像中的位置。
综上所述,深度学习中的这些神经网络架构各有特点和适用场景,在实际应用中需要根据具体需求选择合适的架构,并进行相应的训练和部署。
5. 不同神经网络架构的对比与选择
5.1 性能对比
为了更直观地展示不同神经网络架构在处理不同类型数据时的性能差异,我们可以从以下几个方面进行对比:
| 架构类型 | 处理数据类型 | 记忆功能 | 长期关系建模 | 速度 | 复杂度 | 适用场景 |
| — | — | — | — | — | — | — |
| RNN(含 LSTM) | 序列数据 | 有 | 较好 | 相对较慢 | 较高 | 语言翻译、语音合成、时间序列分类等需要处理长期依赖关系的任务 |
| 1D CNN | 序列数据 | 无 | 一般 | 较快 | 较低 | 大多数序列数据处理任务,尤其是数据中相邻元素关系较强的场景 |
| 2D CNN | 二维数据(图像或类似图像数据) | 无 | - | 适中 | 适中 | 图像分类、目标检测、图像识别等二维数据处理任务 |
5.2 选择建议
在选择合适的神经网络架构时,可以参考以下流程图:
graph TD;
A[数据类型] --> B{是否为序列数据};
B -- 是 --> C{是否需要建模长期关系};
C -- 是 --> D[选择 RNN(含 LSTM)];
C -- 否 --> E[选择 1D CNN];
B -- 否 --> F{是否为二维数据};
F -- 是 --> G[选择 2D CNN];
F -- 否 --> H[考虑其他架构];
例如,如果要处理时间序列数据,且数据中的长期关系对分类结果有重要影响,那么 RNN(特别是 LSTM)可能是更好的选择;如果数据中的相邻元素关系较强,且不需要特别关注长期关系,1D CNN 可能更合适。如果处理的是图像或类似图像的数据,则应选择 2D CNN。
6. 深度学习在 TinyML 中的挑战与应对策略
6.1 挑战分析
在 TinyML 环境中,深度学习面临着诸多挑战,主要包括:
1.
资源限制
:TinyML 设备通常具有有限的内存、计算能力和能源供应,难以运行复杂的深度学习模型。
2.
模型复杂度
:为了实现更好的性能,深度学习模型往往需要较大的规模和复杂度,这与 TinyML 设备的资源限制相矛盾。
3.
实时性要求
:许多 TinyML 应用需要实时处理数据,因此模型的推理速度至关重要。
6.2 应对策略
针对上述挑战,可以采取以下策略:
1.
模型优化
:
-
剪枝
:去除模型中对性能影响较小的连接或神经元,减少模型的参数数量。
-
量化
:将模型的参数从浮点数转换为低精度的整数,降低内存占用和计算量。
-
架构设计
:选择更轻量级的神经网络架构,如 1D CNN 或简化的 2D CNN。
2.
算法优化
:
-
高效算法
:采用高效的卷积算法和优化的训练算法,提高计算效率。
-
增量学习
:在设备上进行增量学习,减少对大量数据的传输和存储需求。
3.
硬件支持
:
-
专用硬件
:使用专门为 TinyML 设计的硬件,如低功耗的微控制器、加速器等。
-
硬件优化
:对硬件进行优化,提高其计算能力和能源效率。
7. 总结与展望
7.1 总结
本文介绍了深度学习中的几种常见神经网络架构,包括 RNN(含 LSTM)、1D CNN 和 2D CNN,详细阐述了它们的工作原理、训练方法和部署方式,并对不同架构进行了对比分析。同时,探讨了深度学习在 TinyML 环境中面临的挑战及应对策略。
7.2 展望
随着深度学习技术的不断发展和 TinyML 应用的日益广泛,未来可能会出现以下趋势:
1.
更高效的模型架构
:研究人员将继续探索更高效的神经网络架构,以满足 TinyML 设备的资源限制和实时性要求。
2.
融合多种技术
:将深度学习与其他技术(如传感器技术、边缘计算等)相结合,实现更智能、更高效的应用。
3.
广泛的应用领域
:深度学习在 TinyML 中的应用将扩展到更多领域,如智能家居、健康监测、工业自动化等。
总之,深度学习在 TinyML 中的应用前景广阔,但也面临着诸多挑战。通过不断的研究和创新,我们有望克服这些挑战,实现更智能、更高效的 TinyML 应用。
更多推荐



所有评论(0)