在深度学习和语音处理领域,如何将原始音频信号有效地表示为离散的“Token”序列,是语音识别、音频生成等任务中的关键问题。常见的方法如Mel频谱图+向量量化(VQ)、wav2vec等已经非常成熟,但这些模型通常依赖复杂的神经网络结构。

本文介绍一种轻量级、可解释性强的音频特征提取与“类Token化”编码方法,仅使用余弦相似度、线性回归和归一化技术,即可将一段WAV音频转化为一个整数序列——我们称之为“伪Token”序列。这种方法虽然不能替代现代语音模型,但非常适合用于教学、探索性数据分析或轻量级嵌入式应用。


🎯 目标

我们将实现以下功能:

  1. 读取一段 .wav 音频文件;
  2. 对音频进行预处理(去均值、标准化);
  3. 使用滑动窗口对相邻样本做线性回归分析;
  4. 提取回归斜率与拟合效果(余弦相似度)作为双特征;
  5. 将特征归一化并量化为整数,形成“Token”序列;
  6. 可视化结果并封装成函数。

🔧 核心工具与库

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile

同时为了支持中文标题显示,设置 Matplotlib 的字体:

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

📐 核心算法定义

1. 余弦相似度(Cosine Similarity)

衡量两个向量方向的一致性,反映线性拟合的质量。

def cosine_similarity(a, b):return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

2. 最小二乘法线性回归

手动实现一元线性回归,避免依赖 sklearn

def linear_regression(x, y):n = len(x)sum_x, sum_y = np.sum(x), np.sum(y)sum_xy = np.sum(x * y)sum_x2 = np.sum(x ** 2)slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)intercept = (sum_y - slope * sum_x) / nreturn slope, intercept

3. Min-Max 归一化(防除零)

def min_max_normalize(data):min_val = np.min(data)max_val = np.max(data)return (data - min_val) / (max_val - min_val + 1e-8)

🧪 主流程解析:main() 函数

我们以文件 "sound/cat/1-47819-C-5.wav" 为例,演示整个流程。

1. 音频读取与预处理

_, audio = wavfile.read("sound/cat/1-47819-C-5.wav")
left = (audio - np.mean(audio)) / np.std(audio)  # 标准化

⚠️ 注意:这里假设音频是单声道。如果是立体声,请取某一通道(如 audio[:, 0])。

接着构造“左移-右移”数据对:

left = left[:left.size // 2 * 2]  # 确保长度为偶数
left = left[:-1]                  # 去最后一个元素
right = left[1:]                  # 右移一位

这相当于构建了 (x_t, x_{t+1}) 的时间序列对,可用于分析局部动态变化。


2. 滑动窗口分析

使用大小为 3200 的窗口,每步移动 1600(半重叠),进行局部线性拟合:

for i in range(0, len(left) - 1600, 1600):x, y = left[i:i + 3200], right[i:i + 3200]if len(x) > len(y): x = x[:len(y)]slope, intercept = linear_regression(x, y)sim = cosine_similarity(slope * x + intercept, y)sim_list.append(sim)slope_list.append(slope)
  • x: 当前窗口内的原始信号片段;
  • y: 对应的“下一时刻”信号(右移);
  • 使用线性模型 y ≈ slope * x + intercept 拟合;
  • 计算预测值与真实值之间的余弦相似度,评估拟合质量;
  • 记录每个窗口的 slopesimilarity

3. 特征归一化与“Token化”

将连续特征映射到整数空间,模拟 Token 编码过程:

sim_list = min_max_normalize(sim_list) * 2048
slope_list = min_max_normalize(slope_list) * 2048 + 2048
  • sim_list → [0, 2048]
  • slope_list → [2048, 4096]

然后转换为整型:

sim_list = sim_list.astype(np.int16)

最后将两者交错拼接成一维序列:

tokens = np.hstack([sim_list, slope_list]).reshape([2, -1]).transpose([1, 0]).reshape(-1)

这一步实现了双通道特征的交织编码。


4. 可视化 Token 序列

plt.plot(tokens)
plt.title("音频生成的伪Token序列")
plt.xlabel("Token索引")
plt.ylabel("Token值")
plt.show()

💡 封装函数:wav_to_token(path)

我们将上述逻辑封装为通用函数,适用于任意 .wav 文件:

def wav_to_token(path):_, audio = wavfile.read(path)# 单通道处理if len(audio.shape) > 1:audio = audio[:, 0]left = (audio - np.mean(audio)) / np.std(audio)left = left[:left.size // 2 * 2][:-1]right = left[1:]sim_list = []slope_list = []# 更小的窗口:1600采样点,每800步滑动for i in range(0, len(left) - 800, 800):x = left[i:i+1600]y = right[i:i+1600]if len(x) != len(y):min_len = min(len(x), len(y))x, y = x[:min_len], y[:min_len]slope, intercept = linear_regression(x, y)pred = slope * x + interceptsim = cosine_similarity(pred, y)sim_list.append(sim)slope_list.append(slope)# 归一化到 0~64 范围(2^6)sim_tokens = min_max_normalize(np.array(sim_list)) * 64slope_tokens = min_max_normalize(np.array(slope_list)) * 64sim_tokens = sim_tokens.astype(np.int16)slope_tokens = slope_tokens.astype(np.int16)# 合并为乘积特征(非零过滤)res = sim_tokens * slope_tokensreturn res[res != 0]  # 去除零值

✅ 返回的是一个整数数组,可视为该音频的“特征Token序列”。


📊 方法特点总结

项目描述
优点- 不依赖深度学习框架
- 可解释性强
- 计算开销小
- 可用于边缘设备
局限- 表达能力有限
- 无法捕捉高频语义
- 对噪声敏感
适用场景- 音频分类初筛
- 异常声音检测
- 教学演示
- 低资源环境下的特征提取

🚀 拓展思路

你可以在此基础上进一步改进:

  1. 加入频域特征:对每个窗口做FFT,提取主频作为第三Token维度;
  2. 向量量化(VQ):用KMeans对 (sim, slope) 向量聚类,真正生成离散Token;
  3. 滑动窗口自适应:根据能量或过零率动态调整窗口大小;
  4. 时间对齐编码:引入DTW对齐不同长度的Token序列;
  5. 用于对比学习:计算不同音频Token序列间的距离,做相似性匹配。

📎 完整代码下载

你可以将以下完整代码保存为 audio_tokenizer.py 并运行:

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile# 中文显示支持
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = Falsedef cosine_similarity(a, b):"""计算余弦相似度"""return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))def linear_regression(x, y):"""最小二乘法线性回归"""n = len(x)sum_x, sum_y = np.sum(x), np.sum(y)sum_xy = np.sum(x * y)sum_x2 = np.sum(x ** 2)slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)intercept = (sum_y - slope * sum_x) / nreturn slope, interceptdef min_max_normalize(data):min_val = np.min(data)max_val = np.max(data)return (data - min_val) / (max_val - min_val + 1e-8)def wav_to_token(path):_, audio = wavfile.read(path)if len(audio.shape) > 1:audio = audio[:, 0]  # 取左声道# 标准化left = (audio - np.mean(audio)) / np.std(audio)left = left[:len(left)//2*2][:-1]right = left[1:]sim_list = []slope_list = []for i in range(0, len(left) - 800, 800):x = left[i:i+1600]y = right[i:i+1600]if len(x) != len(y):min_len = min(len(x), len(y))x, y = x[:min_len], y[:min_len]slope, intercept = linear_regression(x, y)pred = slope * x + interceptsim = cosine_similarity(pred, y)sim_list.append(sim)slope_list.append(slope)sim_arr = min_max_normalize(np.array(sim_list)) * 64slope_arr = min_max_normalize(np.array(slope_list)) * 64sim_arr = sim_arr.astype(np.int16)slope_arr = slope_arr.astype(np.int16)res = sim_arr * slope_arrreturn res[res != 0]def main():path = "sound/cat/1-47819-C-5.wav"tokens = wav_to_token(path)plt.figure(figsize=(10, 4))plt.plot(tokens)plt.title("音频生成的伪Token序列")plt.xlabel("Token索引")plt.ylabel("Token值")plt.grid(True)plt.tight_layout()plt.show()if __name__ == "__main__":main()

📣 结语

本文提出了一种新颖而直观的方式,将音频信号通过线性动力学建模 + 特征量化的方式转换为离散序列。虽然它不是真正的“语音Token”,但它启发我们思考:是否可以用更简单的方法逼近复杂模型的部分能力?

这种“白盒”方法有助于理解音频特征的本质,也为轻量级系统提供了一种可行的替代方案。

🔗 后续计划:我们将尝试用这类Token训练一个RNN来“复现”原始音频,敬请期待!


📌 关键词:音频处理、Token化、线性回归、余弦相似度、滑动窗口、Python、信号处理、轻量级模型

📬 欢迎留言交流更多音频特征工程技巧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95161.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95161.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/95161.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue开发准备

vs code VSCode的下载地址https://code.visualstudio.com/Download Node.js node.js的下载地址 https://nodejs.org/zh-cn/download 注意:nodejs安装路径不要和vscode安装到同一个文件夹,两个应用分别装到两个不同的文件夹 npm config set cache &q…

QT6(QFileSystemModel和QTreeView)

QT6QFileSystemModel和QTreeView QFileSystemModel为本机的文件系统提供一个模型,QFileSystemModelt和QTreeView结合使用,可以用目录树的形式显示本机的文件系统,如同Windows的资源管理器一样使用QFileSystemModel提供的接口函数,…

【开题答辩全过程】以 基于Spring Boot的房屋租赁系统的设计与实现为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

构建下一代智能金融基础设施

1. 行业背景:从数字支付到可编程金融的范式跃迁全球数字支付市场正以万亿美元的规模持续扩张,但其底层系统仍受限于传统金融的清算、结算延迟和高昂的中间成本。尽管互联网技术提升了支付的便捷性,但其核心仍是中心化账户体系的延伸。Web3 技…

【C++】深入解析C++嵌套依赖类型与typename关键字

什么是嵌套依赖类型?嵌套依赖类型(Nested Dependent Type)是指在一个模板中,一个类型名称依赖于模板参数,并且是该模板参数内部的嵌套类型。具体来说,当一个类型满足以下两个条件时,它就是嵌套依…

管网信息化监测主要的内容

管网信息化监测是指通过现代信息技术手段对管网系统进行实时监控和数据采集的管理方式。其背景源于城市化进程加快以及基础设施建设规模不断扩大,传统的管网管理模式已无法满足现代化需求。管网信息化监测主要内容包括以下几个方面:█管网运行状态监测&a…

数据泄露代价千万,PII 保护你真的做对了吗?

一、PII—数据隐私的核心概念解析 在大多数数据隐私法律中,可识别个人信息(PII, Personally Identifiable Information)是指任何可以用来识别个人身份的信息。然而,PII 的定义并非由单一法律统一规定,不同国家和地区的法律对其定义略有差异: 各国对 PII 的定义 美国 20…

【数据结构】八大排序之快速排序:分而治之的艺术

文章目录快速排序1.hoare版本算法优化三数取中法小区间优化完整代码如下算法分析时间复杂度空间复杂度2.前后指针法排序过程3.非递归(栈模拟)实现思路总结快速排序 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为…

在ROS中获取并发布UBS式传感器的温湿度

哈喽大家好,我是钢板兽! 今天更新一篇和ROS相关的文章,有个项目需求是在ROS中获取并发布UBS式传感器的温湿度,我使用的温湿度传感器简介如下:DL11- MC-S1 温湿度传感器通过USB 接口采用标准MODBUS RTU 协议通信&#x…

【图论】 Graph.jl 操作汇总

文章目录图论的集合类操作Base.getindexBase.intersectBase.joinBase.reverseBase.reverse!Base.sizeBase.sumBase.sumBase.union图生成与转换Graphs.cartesian_productGraphs.complementGraphs.compute_shiftsGraphs.crosspathGraphs.differenceGraphs.egonetGraphs.induced_s…

【链表 - LeetCode】146. LRU 缓存

146. LRU 缓存 题解&#xff1a; class LRUCache {list<pair<int,int>>v;unordered_map<int,list<pair<int,int>>::iterator>idx;int capacity; public:LRUCache(int capacity):capacity(capacity){}int get(int key) {if(idx.count(key) 0) …

Elasticsearch vs Solr vs OpenSearch:搜索引擎方案对比与索引设计最佳实践

Elasticsearch vs Solr vs OpenSearch&#xff1a;搜索引擎方案对比与索引设计最佳实践 随着大数据和实时分析需求的爆发&#xff0c;搜索引擎已成为许多业务系统中的核心组件。本篇文章将从“技术方案对比分析型”角度切入&#xff0c;重点比较三大主流搜索引擎&#xff1a;El…

光颉科技)Viking)的CS25FTFR009 1225 0.009R/9mR 3W电阻介绍-华年商城

“**华年商城”**小编为您介绍&#xff1a;光颉科技&#xff08;Viking&#xff09;的CS25FTFR009 1225 0.009R/9mR 3W电阻 光颉CS25FTFR009合金电阻&#xff1a;0.009Ω/9mΩ 3W 1%精密采样电阻 光颉科技&#xff08;Viking&#xff09;的CS25FTFR009是一款高性能的电流检测电…

港科大开放世界长时域具身导航!LOVON:足式机器人开放词汇目标导航

作者&#xff1a;Daojie Peng1^{1}1, Jiahang Cao1,2^{1,2}1,2, Qiang Zhang1,2^{1,2}1,2, Jun Ma1,3^{1,3}1,3单位&#xff1a;1^{1}1香港科技大学&#xff08;广州&#xff09;&#xff0c;2^{2}2北京人形机器人创新中心&#xff0c;3^{3}3香港科技大学论文标题&#xff1a;L…

【前端教程】JavaScript 数组对象遍历与数据展示实战

在前端开发中&#xff0c;处理数组和对象是日常工作的基础。无论是篇文章将通过一个具体案例&#xff0c;详细讲解如何使用JavaScript遍历包含对象的数组&#xff0c;并将数据以清晰的格式展示在页面上。我们会从基础语法开始&#xff0c;逐步优化代码&#xff0c;最终实现一个…

无重复字符的最长子串,leetCode热题100,C++实现

题目来源&#xff1a;leetCode 3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&#xff09; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串 的长度。 解法 class Solution { public:int lengthOfLongestSubstring(string s) {unordered_set<…

卷积神经网络中1×1卷积的作用

part I &#xff1a;来源part II &#xff1a;应用part III &#xff1a;作用&#xff08;降维、升维、跨通道交互、增加非线性&#xff09;part IV &#xff1a;从fully-connected layers的角度理解一、来源&#xff1a;[1312.4400] Network In Network &#xff08;如果11…

VMware设置Ubuntu虚拟机桥接模式完整教程

VMware 设置 Ubuntu 虚拟机桥接模式完整教程 下面是一个详细的、避免出错的 VMware Ubuntu 桥接模式设置教程&#xff0c;包含常见问题的解决方案。 准备工作 确保宿主机&#xff08;Windows 11&#xff09;已连接到网络&#xff08;有线或无线&#xff09;确认您有管理员权限关…

浅析NVMe协议:DIF

文章目录概述DIF数据格式盘片支持DIFFormatPILPIMSETLBAF协议命令DIF支持PRACTPRACT0PRACT1PRCHK相关参考概述 NVMe协议将DIF信息作为元数据的一部分进行携带。 DIF数据格式 DIF的PI由多个字段组成&#xff0c;包括&#xff1a; Guard字段&#xff1a;基于逻辑块数据计算的C…

【观成科技】蔓灵花User下载者加密通信分析

概述2025年5月7日&#xff0c;蔓灵花&#xff08;BITTER&#xff09;组织针对巴基斯坦电信公司工作人员发起钓鱼邮件攻击&#xff0c;投递伪装为安全简报的恶意邮件&#xff0c;附件为IQY类型的Web查询文件。该文件在用户执行后通过HTTP协议获取远程CMD指令并执行&#xff0c;进…