百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

深度信号处理:利用卷积神经网络测量距离

ztj100 2025-01-01 23:49 42 浏览 0 评论


在信号处理中,有时需要测量信号某些特征(例如峰)之间的水平距离。 一个很好的例子就是解释心电图(ECG),这在很大程度上取决于测量距离。 我们将考虑下图中只有两个峰的平滑信号的一个样例。

解决这个问题很简单,可以通过找到峰值,然后减去它们的X坐标来测量它们之间的水平距离来解决。这可以通过使用可用的工具和库有效地完成。然而,我们的目标是训练一个神经网络来预测两个峰之间的距离。一旦我们证明了神经网络可以处理这一任务,我们就可以在更复杂的端到端学习任务中重用相同的架构,而测量距离只是学习更复杂关系的一种手段。这源于深度学习的理念,即我们应该尝试让神经网络学习特征,而不是让工程师手工编码特征并希望这些特征是最相关的。如果我们能证明神经网络可以学习距离特征,我们就可以在更复杂的网络中使用它,在这些网络中,最终结果将取决于距离以外的许多其他因素。这些任务的典型例子是解释心电图或天文数据。

生成数据

在我们的实验中,我们将使用生成训练和测试数据的生成器函数生成如上图所示的信号。

def get_signal_generator(batch_size, n_points, mean_distance, std_distance, 
mean_width, std_width): 
def generate_one(): 
first = np.random.uniform(0, n_points /4) 
second = first + np.random.normal(mean_distance * n_points, std_distance * n_points) 
if second > n_points * 0.95: 
second = n_points * 0.95 
distance = second - first 
first_width = max(np.random.normal(mean_width * n_points, std_width * n_points), n_points * std_width) 
second_width = max(np.random.normal(mean_width * n_points, std_width * n_points), n_points * std_width) 
data_range = np.arange(n_points) 
signal = norm.pdf(data_range, first, first_width) + \ 
norm.pdf(data_range, second, second_width) 
return signal, distance 

def generate(): 
sanity=100000 
for _ in range(sanity): 
all_data = [generate_one() for _ in range(batch_size)] 
yield np.vstack([element[0] for element in all_data]), np.vstack([element[1] for element in all_data]) 

return generate()

这是一个python生成器函数,意味着它使用yield关键字而不是return。 每次在生成器上调用next()函数时,都会产生下一个结果。此功能生成正好具有两个峰值的信号。所有信号的长度完全相同。第一个峰值的位置均匀分布在信号的第一象限中,但是第二个峰值的位置呈正态分布,但是我们还要确保它不会超出范围。峰的宽度也呈正态分布。我们分批返回峰,这对神经网络的训练和评估很有用。

请注意,此生成器实际上会生成无限量的数据! 因此,对于我们的示例可以尝试实现尽可能高的精度。

找到峰值

现在我们有了生成器函数,我们可以使用标准信号处理库来找到峰值之间的距离。我们将使用scipy库和函数find_peaks()来查找峰值。我们使用R2评分来评估模型。如下图所示,我们得到了近乎完美的分数,预测误差主要是由于数字舍入误差造成的。

def predict_distance(batch): 
def compute_distance(row): 
peaks = find_peaks(row)[0] 
if len(peaks) < 2: 
return 0 
return abs(peaks[1] - peaks[0]) 

return np.vstack([compute_distance(batch[i,:]) for i in range(batch.shape[0])]) 

np.random.seed(2128506) 
data_generator = get_signal_generator(500, 1000, 0.7, 0.1, 0.03, 0.01) 
batch_x, batch_y = next(data_generator) 

predictions = predict_distance(batch_x) 
print('Baseline performance: ', r2_score(batch_y, predictions)) 

Baseline performance: 0.9999812121197582

使用CNN来测量距离

在设计神经网络时,想象一个人类操作员会做什么通常是很有用的。在我们的例子中,操作是测量,测量的工具是一把尺子。在我们的例子中,我们使用一个一维卷积层来模拟标尺,并将内核大小设置为信号的最大长度。这样做原因是,如果层的值从0,1,2,3,4,…当乘以信号,它将准确地给我们的位置的峰值。我们使用了两个滤波器来测量两个峰值的位置,然后添加两个全连接层,让神经网络学习如何获取这两个测量值之间的差异。

我们使用Tensorflow和Keras实现神经网络。 请注意,由于Conv1D需要三维张量,因此我们添加了一个Reshape图层,该图层添加了尺寸1的第三个尺寸。批量尺寸是隐式假定的。 对于卷积层,我们不使用任何激活函数,因为我们希望该层的行为类似于标尺。 注意,我们不使用任何下采样机制(最大池化或平均池化)。 我相信这些不是必需的,实际上会降低精度,因为它们会使测量变得不那么精确。 在将数据发送到Dense层之前,我们添加Flatten层以将尺寸(批处理尺寸除外)折叠为单个尺寸,因为这是Dense层所期望的。

model = Sequential([ 
Input(shape=(1000,)), 
Reshape((-1,1)), 
Conv1D(filters=2, kernel_size=1000, activation=None), 
Flatten(), 
Dense(16, activation='relu'), 
Dense(16, activation='relu'), 
Dense(1) 
]) 
model.compile(optimizer=Adam(lr=0.7), loss='mse') 
model.summary()

结果如下:

Model: "sequential_26" 
_________________________________________________________________ 
Layer (type) Output Shape Param # 
================================================================= 
reshape_26 (Reshape) (None, 1000, 1) 0 
_________________________________________________________________ 
conv1d_33 (Conv1D) (None, 1, 2) 2002 
_________________________________________________________________ 
flatten_25 (Flatten) (None, 2) 0 
_________________________________________________________________ 
dense_63 (Dense) (None, 16) 48 
_________________________________________________________________ 
dense_64 (Dense) (None, 16) 272 
_________________________________________________________________ 
dense_65 (Dense) (None, 1) 17 
================================================================= 
Total params: 2,339 
Trainable params: 2,339 
Non-trainable params: 0 
_________________________________________________________________

正如我们所看到的,这个模型只有2339个参数,所以它是一个非常简单的模型。我们在50个伦茨内训练模型,但是我们也添加了早期停止回调,以便在模型停止改进时停止执行。我们添加另一个回调函数TerminateOnNaN,如果梯度或损失变成NaN,它将停止训练过程。我们将一个生成器函数传递给fit()方法。这是现在推荐的将数据传递给模型的方法,特别是当数据量很大时。在我们的例子中,生成器不断地生成随机的例子,实际上是无限的例子!由于我们的生成器函数没有epoch的概念,我们需要定义一个参数stepsperepoch,否则模型将认为所有批次都属于第一个epoch,并且训练将永远不会结束。

np.random.seed(2128506)
tf.random.set_seed(2128506)
data_generator = get_signal_generator(500, 1000, 0.7, 0.1, 0.03, 0.01)
model.fit(data_generator, epochs=50, steps_per_epoch=100, callbacks=[EarlyStopping(monitor='loss'), TerminateOnNaN()])

训练过程如下:

Epoch 1/50 
100/100 [==============================] - 16s 157ms/step - loss: 55010.6915 
Epoch 2/50 
100/100 [==============================] - 16s 161ms/step - loss: 186.3050 
Epoch 3/50 
100/100 [==============================] - 16s 160ms/step - loss: 89.9977 
Epoch 4/50 
100/100 [==============================] - 16s 159ms/step - loss: 229.8199

下面我们看一下结果:

time.sleep(1) 
batch_x, batch_y = next(data_generator) 
predictions = model.predict(batch_x) 
print('R^2 score: ', r2_score(batch_y, np.squeeze(predictions))) 

R^2 score: 0.996036173273703

在训练一个模型后,我们看到测试集的分数确实令人印象深刻。虽然我们承认进一步改进算法是可能的,但我们得到的结果证明了我们的简单方法确实有效。

总结

在设计一个神经网络时,想象人类的感知和认知是如何工作的往往是成功的关键。我们如何产生高层次的特征和概念通常能够指导我们进行神经网络的架构搭建。这种方法的示例之一是注意力机制,注意力机制是根据我们根据阅读的文本进行归纳总结时的注意力进行建模的。在这个问题中,代表了人类活动指导神经网络构建的另一个示例。 尽管使用CNN来测量距离(与Attention机制一样)本身并没有用,但是只要我们相信水平距离起作用,就可以将此结构并入更大的神经网络来解决更复杂的任务。

本文代码:github/mlarionov/deep-signal-example/blob/main/two-peaks.ipynb

作者:Michael Larionov, PhD


deephub翻译组

相关推荐

SpringBoot整合SpringSecurity+JWT

作者|Sans_https://juejin.im/post/5da82f066fb9a04e2a73daec一.说明SpringSecurity是一个用于Java企业级应用程序的安全框架,主要包含...

「计算机毕设」一个精美的JAVA博客系统源码分享

前言大家好,我是程序员it分享师,今天给大家带来一个精美的博客系统源码!可以自己买一个便宜的云服务器,当自己的博客网站,记录一下自己学习的心得。开发技术博客系统源码基于SpringBoot,shiro...

springboot教务管理系统+微信小程序云开发附带源码

今天给大家分享的程序是基于springboot的管理,前端是小程序,系统非常的nice,不管是学习还是毕设都非常的靠谱。本系统主要分为pc端后台管理和微信小程序端,pc端有三个角色:管理员、学生、教师...

SpringBoot+LayUI后台管理系统开发脚手架

源码获取方式:关注,转发之后私信回复【源码】即可免费获取到!项目简介本项目本着避免重复造轮子的原则,建立一套快速开发JavaWEB项目(springboot-mini),能满足大部分后台管理系统基础开...

Spring Boot的Security安全控制——认识SpringSecurity!

SpringBoot的Security安全控制在Web项目开发中,安全控制是非常重要的,不同的人配置不同的权限,这样的系统才安全。最常见的权限框架有Shiro和SpringSecurity。Shi...

前同事2024年接私活已入百万,都是用这几个开源的SpringBoot项目

前言不得不佩服SpringBoot的生态如此强大,今天给大家推荐几款优秀的后台管理系统,小伙伴们再也不用从头到尾撸一个项目了。SmartAdmin...

值得学习的15 个优秀开源的 Spring Boot 学习项目

SpringBoot算是目前Java领域最火的技术栈了,除了书呢?当然就是开源项目了,今天整理15个开源领域非常不错的SpringBoot项目供大家学习,参考。高富帅的路上只能帮你到这里了,...

开发企业官网就用这个基于SpringBoot的CMS系统,真香

前言推荐这个项目是因为使用手册部署手册非常...

2021年超详细的java学习路线总结—纯干货分享

本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础...

jeecg-boot学习总结及使用心得(jeecgboot简单吗)

jeecg-boot学习总结及使用心得1.jeecg-boot是一个真正前后端分离的模版项目,便于二次开发,使用的都是较流行的新技术,后端技术主要有spring-boot2.x、shiro、Myb...

后勤集团原料管理系统springboot+Layui+MybatisPlus+Shiro源代码

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目描述后勤集团原料管理系统spr...

白卷开源SpringBoot+Vue的前后端分离入门项目

简介白卷是一个简单的前后端分离项目,主要采用Vue.js+SpringBoot技术栈开发。除了用作入门练习,作者还希望该项目可以作为一些常见Web项目的脚手架,帮助大家简化搭建网站的流程。...

Spring Security 自动踢掉前一个登录用户,一个配置搞定

登录成功后,自动踢掉前一个登录用户,松哥第一次见到这个功能,就是在扣扣里边见到的,当时觉得挺好玩的。自己做开发后,也遇到过一模一样的需求,正好最近的SpringSecurity系列正在连载,就结...

收藏起来!这款开源在线考试系统,我爱了

大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!今天小编推荐一款基于Spr...

Shiro框架:认证和授权原理(shiro权限认证流程)

优质文章,及时送达前言Shiro作为解决权限问题的常用框架,常用于解决认证、授权、加密、会话管理等场景。本文将对Shiro的认证和授权原理进行介绍:Shiro可以做什么?、Shiro是由什么组成的?举...

取消回复欢迎 发表评论: