卷积、循环神经网络与氧浓度测量研究
卷积网络训练与超参数
在训练网络时,有如下代码:
for i in range(0, train.shape[0], batch_size):
x_batch = train[i:i + batch_size,:]
y_true_batch = labels_[i:i + batch_size,:]
sess.run(optimizer, feed_dict={x: x_batch, y_true: y_true_batch})
train_accuracy += sess.run(accuracy, feed_dict={x: x_batch, y_true: y_true_batch})
train_accuracy /= int(len(labels_)/batch_size)
dev_accuracy = sess.run(accuracy, feed_dict={x:dev, y_true:labels_dev_})
运行这段代码,在我的笔记本上大约需要十分钟。仅经过一个 epoch,训练准确率就能达到 63.7%,经过十个 epoch,训练准确率能达到 86%(在验证集上也是如此)。之前我们开发的简单网络,在第三章中只有一层五个神经元,使用小批量梯度下降法,准确率达到了 66%。这里我们只训练了十个 epoch,如果训练更长时间,准确率会更高。而且,我们还没有进行任何超参数调整,如果花时间调整参数,结果会更好。
每次引入卷积层时,都会为每一层引入新的超参数:
- 核大小
- 步长
- 填充
为了获得最佳结果,需要对这些超参数进行调整。通常,研究人员倾向于使用针对特定任务的现有架构,这些架构已经被其他从业者优化过,并且在论文中有详细记录。
循环神经网络(RNN)简介
RNN 与 CNN 有很大不同,通常用于处理顺序信息,即数据的顺序很重要的情况。典型的例子是句子中的一系列单词,句子中单词的顺序会产生很大的影响。例如,“the man ate the rabbit”和“the rabbit ate the man”意思不同,唯一的区别就是单词的顺序。
RNN 可以用于预测句子中的后续单词。例如,对于“Paris is the capital of.”,很容易用“France”完成句子,这意味着句子中前面的单词编码了关于最后一个单词的信息,RNN 正是利用这些信息来预测序列中的后续项。“循环”这个名字来源于这些网络的工作方式:它们对序列中的每个元素应用相同的操作,积累关于前面项的信息。总结来说:
- RNN 利用顺序数据,并使用序列中项的顺序所编码的信息。
- RNN 对序列中的所有项应用相同类型的操作,并建立序列中前面项的记忆,以预测下一项。
RNN 有以下重要应用场景:
- 文本生成:根据前面的一组单词预测单词的概率。例如,可以用 RNN 生成类似莎士比亚风格的文本。
- 翻译:将一种语言的一组单词转换为另一种语言的单词。
- 语音识别:根据一系列音频信号(单词)预测组成所说单词的字母序列。
- 图像标签生成:与 CNN 结合,用于为图像生成标签。
- 聊天机器人:以一系列单词作为输入,尝试生成对输入的回答。
RNN 的符号表示
以句子“Paris is the capital of France”为例,这个句子将一次一个单词地输入到 RNN 中。在这个例子中:
- “Paris”是序列的第一个单词:w1 = ‘Paris’
- “is”是序列的第二个单词:w2 = ‘is’
- “the”是序列的第三个单词:w3 = ‘the’
- “capital”是序列的第四个单词:w4 = ‘capital’
- “of”是序列的第五个单词:w5 = ‘of’
- “France”是序列的第六个单词:w6 = ‘France’
单词将按照 w1, w2, w3, w4, w5, w6 的顺序输入到 RNN 中。不同的单词将被网络依次处理,通常说如果单词 w1 在时间 t 被处理,那么 w2 在时间 t + 1 被处理,w3 在时间 t + 2 被处理,以此类推。这里的时间 t 与实际时间无关,只是表示序列中的每个元素是顺序处理而不是并行处理。在阅读论文、博客或书籍时,可能会遇到以下符号:
- xt:时间 t 的输入。例如,w1 可以是时间 1 的输入 x1,w2 是时间 2 的输入 x2,以此类推。
- st:表示时间 t 的内部记忆,包含了序列中前面项的累积信息。
- ot:时间 t 网络的输出,即直到时间 t 的序列中的所有元素(包括元素 xt)都输入到网络后得到的输出。
RNN 的基本思想
在文献中,RNN 通常用图 8 - 15 最左边的部分表示。图中的符号只是示意,x 表示输入,s 表示内部记忆,W 和 U 分别表示两组权重。实际上,这个示意图只是描述网络真实结构的一种方式,真实结构可以在图 8 - 15 的右边看到,有时这被称为网络的展开版本。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A([输入序列]):::startend --> B(x1):::process
B --> C(s1):::process
C --> D(o1):::process
E(x2):::process --> F(s2):::process
F --> G(o2):::process
I(x3):::process --> J(s3):::process
J --> K(o3):::process
C --> F
F --> J
第一个神经元在时间 t 进行评估,产生输出 ot 并创建内部记忆状态 st。第二个神经元在时间 t + 1 进行评估,输入是序列中的下一个元素 xt + 1 和前一个记忆状态 st,然后生成输出 ot + 1 和新的内部记忆状态 st + 1。第三个神经元(图 8 - 15 最右边的那个)的输入是序列的新元素 xt + 2 和前一个内部记忆状态 st + 1,以此类推。
通常,每个神经元使用以下公式生成新的内部记忆状态:
[s_t = f(Ux_t + Ws_{t - 1})]
其中 f() 是激活函数,如 ReLU 或 tanh。st 可以理解为网络在时间 t 的记忆。可以使用的神经元数量(或时间步长)是一个新的超参数,需要根据问题进行调整。研究表明,当这个数量太大时,网络在训练过程中会遇到很大的问题。
需要注意的是,在每个时间步,权重不会改变,每次评估只是改变输入。另外,在图中每个步骤都有输出,但通常只需要最终输出。
为什么叫“循环”
内部记忆状态 st 是使用时间 t - 1 的记忆状态计算的,而时间 t - 1 的记忆状态又依赖于时间 t - 2 的记忆状态,以此类推,这就是“循环”这个名字的由来。
学习计数
为了展示 RNN 的强大能力,我们来看一个 RNN 擅长而标准全连接网络不擅长的基本例子:教网络计数。问题是,给定一个由 15 个元素组成且只包含 0 和 1 的向量,构建一个能够计算向量中 1 的数量的神经网络。
对于标准网络来说,这是一个难题。以区分 MNIST 数据集中的 1 和 2 为例,学习是因为 1 和 2 的黑色像素位置有根本不同,网络可以识别这些差异并进行清晰的识别。但对于向量计数问题,例如一个只有五个元素的向量,1 恰好出现一次的情况有五种:[1,0,0,0,0]、[0,1,0,0,0]、[0,0,1,0,0]、[0,0,0,1,0] 和 [0,0,0,0,1],这里没有明显的模式可检测,也没有简单的权重配置可以同时覆盖这些情况。
以下是创建向量的代码:
import numpy as np
import tensorflow as tf
from random import shuffle
nn = 15
ll = 2**15
train_input = ['{0:015b}'.format(i) for i in range(ll)]
shuffle(train_input)
train_input = [map(int,i) for i in train_input]
temp = []
for i in train_input:
temp_list = []
for j in i:
temp_list.append([j])
temp.append(np.array(temp_list))
train_input = temp
我们想要得到 15 个元素的向量中 0 和 1 的所有可能组合,一种简单的方法是将所有小于 2^15 的数字转换为二进制格式。以四个元素为例,使用以下代码可以得到所有可能的组合:
['{0:04b}'.format(i) for i in range(2**4)]
结果如下:
['0000',
'0001',
'0010',
'0011',
'0100',
'0101',
'0110',
'0111',
'1000',
'1001',
'1010',
'1011',
'1100',
'1101',
'1110',
'1111']
对于我们的例子,将使用 15 位数字,即所有小于 2^15 的数字。上述代码的其余部分是将字符串转换为列表并连接所有可能的组合。输出数组的维度为 (32768, 15, 1),每个观察值是一个维度为 (15, 1) 的数组。
接下来准备目标变量,即计数的 one - hot 编码版本。如果向量中有四个 1,目标向量将是 [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0]。目标变量的代码如下:
train_output = []
for i in train_input:
count = 0
for j in i:
if j[0] == 1:
count += 1
temp_list = ([0]*(nn + 1))
temp_list[count] = 1
train_output.append(temp_list)
然后将数据集分为训练集和验证集:
train_obs = ll - 2000
dev_input = train_input[train_obs:]
dev_output = train_output[train_obs:]
train_input = train_input[:train_obs]
train_output = train_output[:train_obs]
训练集的维度为 (30768, 15, 1),验证集的维度为 (2000, 15, 1)。
以下是构建网络的代码:
tf.reset_default_graph()
data = tf.placeholder(tf.float32, [None, nn,1])
target = tf.placeholder(tf.float32, [None, (nn + 1)])
num_hidden_el = 24
RNN_cell = tf.nn.rnn_cell.LSTMCell(num_hidden_el, state_is_tuple=True)
val, state = tf.nn.dynamic_rnn(RNN_cell, data, dtype=tf.float32)
val = tf.transpose(val, [1, 0, 2])
last = tf.gather(val, int(val.get_shape()[0]) - 1)
W = tf.Variable(tf.truncated_normal([num_hidden, int(target.get_shape()[1])]))
b = tf.Variable(tf.constant(0.1, shape=[target.get_shape()[1]]))
prediction = tf.nn.softmax(tf.matmul(last, W) + b)
cross_entropy = -tf.reduce_sum(target * tf.log(tf.clip_by_value(prediction,1e-10,1.0)))
optimizer = tf.train.AdamOptimizer()
minimize = optimizer.minimize(cross_entropy)
errors = tf.not_equal(tf.argmax(target, 1), tf.argmax(prediction, 1))
error = tf.reduce_mean(tf.cast(errors, tf.float32))
训练网络的代码如下:
init_op = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init_op)
mb_size = 1000
no_of_batches = int(len(train_input)/mb_size)
epoch = 50
for i in range(epoch):
ptr = 0
for j in range(no_of_batches):
train, output = train_input[ptr:ptr + mb_size], train_output[ptr:ptr + mb_size]
ptr += mb_size
sess.run(minimize,{data: train, target: output})
incorrect = sess.run(error,{data: test_input, target: test_output})
print('Epoch {:2d} error {:3.1f}%'.format(i + 1, 100 * incorrect))
运行代码的结果如下:
| Epoch | Error |
| — | — |
| 0 | 80.1% |
| 10 | 27.5% |
| 20 | 8.2% |
| 30 | 3.8% |
| 40 | 3.1% |
| 50 | 2.0% |
仅经过 50 个 epoch,网络的正确率就达到了 98%。如果训练更多的 epoch,精度会更高。经过 100 个 epoch,误差可以达到 0.5%。尝试用标准全连接网络进行计数训练会发现这是不可能的。通过以上内容,我们对 CNN 和 RNN 的工作原理和操作原则有了基本的了解。
卷积、循环神经网络与氧浓度测量研究
研究项目:利用深度学习提取传感参数
深度学习的应用领域极为广泛,除了常见的图像识别、语音识别等,还能应用于不太传统的问题,比如传感应用中的参数提取。接下来将介绍如何利用深度神经网络解决测量介质(如气体)中氧气浓度的问题。
问题描述
许多传感设备的工作原理基于对一个容易测量的物理量(如电压、体积或光强)的测量,这个物理量必须与另一个难以直接测量的物理量(如温度或气体浓度)密切相关。如果知道这两个物理量之间的相关性(通常通过数学模型),就可以从第一个物理量推导出第二个物理量。
本研究项目利用“发光猝灭”原理来测量氧气浓度。一种染料物质与待测量氧气含量的气体接触,用激发光(通常是蓝光)照射染料,染料吸收部分光后,会在不同光谱部分(通常是红光)重新发射光。发射光的强度和持续时间与气体中的氧气浓度密切相关。如果气体中有氧气,染料发射的部分光会被抑制,即“猝灭”。项目的目标是开发新算法,根据测量的激发光和发射光之间的相移来确定氧气浓度。
相关原理与概念
- 发光测量设置 :典型的发光测量设置如图 9 - 1 所示,用于获取验证数据集的数据。包含发光染料物质的样品被激发光(图中的蓝光)照射,激发光由发光二极管或激光发射,并通过透镜聚焦。发射的发光(图右侧的红光)由探测器通过另一个透镜收集。样品架包含染料和待测量氧气浓度的气体。
- 发光衰减与相移 :探测器收集的发光强度随时间下降,下降速度取决于氧气含量,通常用衰减时间 τ 来量化。最简单的描述是单指数衰减函数 (e^{-t/τ})。常用的确定衰减时间的方法是调制激发光的强度,其频率 (f = 2πω),其中 ω 是角频率。重新发射的发光强度也会被调制,并且具有相移 θ,相移与衰减时间 τ 的关系为 (tanθ = ωτ)。可以将光简单表示为 (sin(ωt + θ)),其中 θ 是波的相位常数。激发光的相位常数为 (θ_{exc}),发射光的相位常数为 (θ_{emitted}),测量的就是相移 (θ = θ_{exc} - θ_{emitted}),因为这个相移受气体中氧气含量的强烈影响。
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A([激发光]):::startend --> B(透镜):::process
B --> C(染料样品):::process
C --> D(发射光):::process
D --> E(透镜):::process
E --> F(探测器):::process
实际情况的复杂性
在实际情况中,光的相移不仅取决于调制频率 ω 和气体中的氧气浓度 (O_2),还非线性地取决于染料分子周围的温度和化学成分。而且,光强度的衰减通常不能只用一个衰减时间来描述,大多数情况下至少需要两个衰减时间,这进一步增加了描述系统所需的参数数量。给定激光调制频率 ω、温度 T(摄氏度)和氧气浓度 (O_2)(以空气中氧气的百分比表示),系统会返回相移 θ。
研究思路与目标
本研究项目的思路是无需为传感器的行为开发理论模型,而是利用深度神经网络从人工创建的数据中学习给定相移下的氧气浓度,然后将模型应用于实际实验数据。具体步骤如下:
1. 数据准备 :收集不同条件下(调制频率、温度、氧气浓度等)的相移数据,构建数据集。
2. 模型构建 :选择合适的深度神经网络架构,如多层感知机、卷积神经网络或循环神经网络。
3. 模型训练 :使用准备好的数据集对模型进行训练,调整模型参数以最小化预测误差。
4. 模型评估 :使用验证集评估模型的性能,选择性能最佳的模型。
5. 实际应用 :将训练好的模型应用于实际实验数据,预测氧气浓度。
总结
通过以上内容,我们了解了卷积神经网络和循环神经网络的基本原理和应用,以及如何将深度学习应用于传感参数提取的研究项目。卷积网络和循环网络在处理不同类型的数据和问题时具有独特的优势,而传感应用中的参数提取问题展示了深度学习在解决复杂非线性问题方面的潜力。未来,可以进一步探索不同的网络架构和训练方法,以提高模型的性能和准确性。同时,也可以考虑将深度学习与其他技术相结合,如传感器技术、信号处理技术等,以实现更高效、更准确的传感应用。
超级会员免费看

3495

被折叠的 条评论
为什么被折叠?



