5.gif

d556f5f6

DLSite 音声区 Audfprint 音频特征库(项目暂停)

氦,初次见面。注册 South-Plus 四年了才发了第一个贴。

目前我正在给我能找到的 DLSite 音声作品建立一个音频特征库。我想打造一个逆向搜索 DLSite 音声作品的一个搜索引擎。但是由于我写的下载/索引脚本太烂了,途中索引了 7TB ,但是脚本抛出的错误过多,需要索引的数据量又非常大,导致我在跑脚本的中途就决定停止索引了。目前准备休息一阵子(差不多两到三个月左右)然后重构项目。

先唠唠我为啥要做这个:

在 2018 年左右我在 B 站找到一个日语系的 ASMR 音声,人声很可爱,效果音也感觉不错,我很喜欢,所以我就下载下来了。
我并不知道当初我接触的是啥,不过很好听,我什么也没想就收藏了。一年后,回顾看一看,B 站整顿,我收藏的视频没了。我也没看评论区是否有这个作品的来源。由于网络上也没有针对 ASMR 音频的逆向搜索,顶多只有 Shazam 音乐搜索,我就直接放弃了。也许未来有缘我能找到呢,我当初就是这么想的,就把这下载的文件留在我的硬盘里。

数年后,我在黑橘 P 站找到 DLSite 音声,这次我发现了一个类似的音频,就是这次除了 ASMR 还加了色色。一看简介,几个关键词飘过去,"DLSite"和一串RJ开头的神秘号码。此时我想到我当初下载的那个音频,可能就是 DLSite 上面发布的音声作品。仔细搜索资源,发现了 ASMR 线上听等一大堆资源站。

而且在今年,由于纸飞机的下载站的出现,让我觉得自己建立一个 DLSite 音声作品的音频特征库好像是可行的。所以今年我决定研究如何建立一个像 Soutubot 类似,基于局部内容的逆向搜索引擎。首先就是建立特征库。

想做搜索引擎,我参考了 lolishinshi/imsearch 的搜索流程,从内容中提取特征向量,存入到一个数据库 (RocksDB/SQLite),最后通过 FacebookResearch/Faiss 建立一个允许快速召回的索引。
存储和索引这方面没问题,毕竟已经有现成的解决方案了,比如 milvus-io/milvus。或者现成的数据库解决方案然后装上向量扩展 (Postgres, MySQL, ElasticSearch)。
这方面问题不大,甚至我还搜索到一个教程 https://milvus.io/docs/audio_similarity_search.mdhttps://github.com/towhee-io/examples/tree/main/audio/audio_fingerprint
基本上就是手把手教你怎么搭建音频逆向搜索引擎。我下载了大概 7 个 ASMR 音声作品后,根据教程使用 NFFP 作为特征提取方法。

尝试索引,CUDA Out of Memory,音频太长了,需要分片切段,我切了,虽然花了一点时间,但成功索引了。实际搜索的话... 结果是不行的,经常会有其他不同的结果混进来,而且匹配分数还不低。这个根本没法拿来用。所以我又试了试其他的基于 AI 的音频特征提取方法:wav2vec, VGGIsh, PANNs
Towhee 上面通过 AI 提取的方法我基本上都试过了个遍,全部都不行。抵达到这一步的时候已经花费了我数周时间。由于我起初其实下载了差不多 300 多个 ASMR 作品,我花费了好几天尝试写一个多线程的音频特征提取器,最终以失败告终。所以我决定选少一点的音声作品研究各种搜索方法的结果和可行性。

当我把所有基于 AI 的特征提取方法都试过了一边后,再不重新训练 AI 的情况下,全部无果。
我就在考虑是否有开源版的 Shazam,还有 Shazam 的特征提取算法。甚至我把目光转向了音乐搜索看看有没有任何线索,读了几篇论文后:

Efficient music identification using ORB descriptors of the spectrogram image
Accuracy comparisons of fingerprint based song recognition approaches using very high granularity

发现了几个开源的音乐逆向搜索项目,我对 Shazam 的具体算法感到了兴趣

一番搜寻后发现 Shazam 的搜索算法后:是基于频谱图提取能量级别高的“顶点”,然后通过顶点与其他顶点的相对位置,计算出一个专属于这个音频的特征。我记得哪一处给这个算法起了个名字叫做“星系特征搜索法”,因为特征点的关系连起来就像星系一样。我在 GitHub 上面真的找到了开源版(就是上面论文给出的连接),还有其他人基于同样的星系特征搜索法出过视频:

https://github.com/JorenSix/Olaf
https://github.com/JorenSix/Panako
https://www.youtube.com/watch?v=a0CVCcb0RJM
https://github.com/dpwe/audfprint

在 JorenSix/Olaf 的 GitHub 上我看了看 ReadMe 发现 Shazam 的算法当初注册过专利:https://patents.google.com/patent/US7627477B2/en
然后一看专利状态:Status - Expired - Lifetime,今年竟然过期了,真是天助我也。

尝试这些工具索引,Olaf 索引很慢,Panako 我没有试过,但是根据论文,Panako 就是 Olaf 和 Shazam 的算法的升级版,YouTube 视频那位自己用 Go 语言造 Shazam 的那位兄弟的项目,没法通过正常方法索引任何本地音频,至少我没有找到不对源代码进行大改造的情况下对任何音频索引的方法。而且我不会写 Go 代码。Audfprint 这个倒是更像一个正常的应用。

我试过 Olaf 和 Audfprint,两个匹配效果都非常完美,不该出现的结果一条都没有,就算出现了可能也就只有一两条错误的结果,错误结果的匹配度极低。

因为 Olaf 用起来太慢,Panako 只有 Linux 能用,最终我的选择是 Audfprint,唯一的问题就是这个项目上一次更新是在好几年前,但是其功能(能只提取特征而不建立数据库和索引,多核提取特征,通过 FFMpeg 解码/预处理音频)十分完备,我决定使用dpwe/audfprint,这里面用的也是星系特征搜索法。

虽然我对星系特征搜索法的所有细节不熟,但是这个工具提供的 CLI 我觉得就能提供我建立整个特征库了。这是个大突破,意味着工具有了,接下来就是要写一个下载作品/提取特征的脚本了。
我又花了一周时间写脚本(而且还是每天熬夜),写了差不多 1k 行的 Python 代码后,我觉得脚本能用。就算出错了我也打算修修补补给索引脚本打补丁。我预计会花上好几天对纸飞机下载站上面 100TB 的作品进行索引。

执行脚本开始索引,错误真的是多到让我怀疑人生,我能理解我写脚本不行,但是丢出来的 Exception 还是好多啊。我计划让脚本能在 Linux 和 Windows 两个平台都能运行,可是每个平台都会丢平台专属的错误,而且每次出错,要恢复到出错前的进度都得花一个小时(就是把出错前的整个解压缩/特征提取流程给跑一遍)。就算是半夜挂着不管,脚本一出错,就卡在那里,什么进度都没有。

起初要命的是下载部分的代码,那部分的逻辑解决后,是解压缩的代码出问题,差不多 70% 的时间都花在解压缩那个被层层打包的文件了,RAR/ZIP基本上都混杂在一起,ZIP压缩格式在编码文件名的时候一般不是用 Unicode 编码,而是各个计算机的本地区域的编码,日本来的基本上就是CP932 Shift-JIS 之类的了,起初我还打算自己手动指定用什么编码解读,但是压缩包的量多起来,我就表示算了,通通 CP932。

之后还得修补一些奇怪的 Bug,比如 Windows 把压缩文件解压出来后,音频特征提取完后,如果再删除解压出来的文件有几率会遇到拒绝访问,这个要手动更新权限。或者从纸飞机下载站那边的某个音声作品,我起初以为所有的作品只被收录一次,然后脚本出错的时候被打脸,单个作品解压出来也会有不同版本,比如特典。只能继续修修补补修修补补。

之后就是得把文件分类,我最初的手段是用文件扩展名... 对,扩展名来分类,通过一个 JSON 文件建立一个查询表,MP3对应音频,JPG对应图片,加入一些比较热门的格式后,以防万一可能会有更多奇奇怪怪的格式,我让脚本遇到不认识的扩展的时候停下来,等我手动添加定义。结果就是每次晚上挂机去睡觉的时候,脚本就卡死在等待我定义未知扩展名。晚上基本上睡不着觉。最终我用 file 和 libmagic 自动添加未知的文件扩展,部分解决了这个问题(当 file/libmagic 也遇到奇怪的文件格式,我也会让脚本停下)。

我希望我的项目不只是单纯的建立一个音频特征库就完事了,我还计划对文件内容进行一些简单的元数据分析,比如时长,采样率,位深,MP3 ID3,MIME格式,压缩包内容这种元数据。顺便检测到的图片给留着,放着未来喂给图片逆向搜索。结果这部分的代码又害了我好几遍。首先就是音频里面的ID3元数据,这个玩意和 ZIP 一毛一样,没有任何标准的文本编码,日本来的 MP3 全部都是 Shift-JIS 编码的元数据,用 MediaInfo 或者 ExifTool 读出来全是乱码。而且 MediaInfo 和 ExifTool 我也找不到任何内置的参数能更改读取的编码,就算找到了(比如 ExifTool 允许不同编码的ID3元数据),却不支持 CP932,我就想算了,反正 MediaInfo 读出来的元数据如果通过 Latin-1 编码乱码得到原来的二进制数据,我再通过 Shift-JIS 解码就没问题了,能正常显示。然后我给提取元数据的部分上多线程,上 Linux 测试好家伙:malloc(): Invalid Size (Unsorted),然后 Python 就崩溃了。

原本我以为代码给我丢 Exception 就算了,我能理解我写的脚本不行,结果操作系统 malloc() 都跑过来骂我写的什么傻逼脚本。我就心想就不给 Linux 继续开发了,我继续在 Windows 上开发。

接下来不出意外的又要出意外了,Windows 在运行 Audfprint 的时候,有个长音频突然需要占非常多的内存资源,结果 Windows 表示不让占用这么多的 RAM,然后直接丢 Exception 不继续提取音频特征了,Audfprint 有忽略错误的选项,我也打开了,但即使打开忽略错误,不能忽略无更多闲置内存的 Exception,这个时候我就怒了。到底还要丢多少个错误,我还要失眠几次才好。

我尝试在 Windows 设置里面手动分配更多的虚拟内存,很可惜,还是同样的错误,音频特征提取到一半的时候,Windows 突然表示没有更多内存了,然后 Audfprint 就停止了。Linux 在这部分我查询了 StackOverflow 后,Linux 允许 Memory Overcommit,那我换回 Linux,然后刚刚对文件做元数据分析部分的代码给我丢 malloc() 错误。两边都有问题,这种奇怪的错误我也不知道除了重构自己代码和降低多线程分配的核心数,都不知道从哪里开始除错。此时我真的没心情继续了。我需要再次提醒每次恢复到出错前的进度都要花一两个小时,我非常后悔当初写脚本的时候为什么没有考虑会出这么多次错误,写一个更模块化的脚本,然后允许错误恢复的代码呢。

抵达这一步又花了6天,我电脑已经连续开着6天了,这六天基本上是啥都不想干,每天想着脚本是不是又出错了。最终我受够了。然后停止了继续索引。
目前我已经完整索引了差不多 7TB 的数据了。但说实话,脚本出错太多了,我原本还打算搞分布式计算,但是考虑到目前的代码出错的频率,我实在不敢把脚本交给别人。再这么下去也要把我整成神经病。所以我停下来了。



接下来怎么办?

考虑到脚本现在的模样,我准备对脚本进行一次彻底的重构,变成一个更模块化,允许错误恢复和分布式计算的程序。但是我准备等几周后再开始重构,特别是多线程这一块。多线程坑了我太多遍了。

我也在考虑把 Audfprint 给重写一遍,但是我目前的知识水平还不够让我从零编写一个音频特征提取器/搜索程序,即使是参考别人源代码 (Olaf, Panako) 我也写不出来。想重写的原因是因为 Audfprint 的数据库格式,这个是原作者自己手搓 HashTable,然后直接把数据通过 Pickle 存储下来的,不是任何通用的数据库(如SQLite),原作者的数据库会出现特征存储到一定量后开始丢特征,DLSite 的作品太多了,丢特征的话就可能需要把数据库分成数百个分段才可以用,我想解决数据库分太多段的问题。

最主要的是下载/索引脚本要整个重构,我写的代码真的是太他妈烂了。等个几周后再说吧。

我会公开我索引到的结果(大约 10GB),由于留的图片的大小过大(>60G),我就只公布 Audfprint 的 AFPT(在数据库中以 Blob 方式存储),和随机2000张图片,我 Mega 存不下那么多东西。
如果有其他人正在做或者计划做和我一样的事情,或者有更好的音频特征搜索工具或者笔记,欢迎留言。如果有问题的话我会尽量回答。

此帖售价 0 SP币,已有 13 人购买
若发现会员采用欺骗的方法获取财富,请立刻举报,我们会对会员处以2-N倍的罚金,严重者封掉ID!

1372560.jpg

xiangjile

B1F  2025-07-06 05:24
(芜湖)

8.gif

Rivers77

B2F  2025-07-06 05:58
(诸君……我喜欢肛肛乐。)
ADHD患者的日常.jpg

none.gif

e4bc0177

是基于音频片段找出处吗?

如果有AI内容分析+建立数据库就好了,再加类似内容推荐、声纹检测是谁

现在的tag实在太差了

5.gif

d556f5f6

回 3楼(e4bc0177) 的帖子

正确,我的目标是通过音频片段查找出处(作品)。声纹检测是我觉得可以通过反推出作品后寻找作者的 C.V.,但要是声优换个马甲就是另外一回事情了。

AI内容分析的话,目前我能想到的只有通过 Whisper + LLM 让 LLM 解释字幕里头发生了什么,或者通过 Wav2vec 提取 Embedding 让 LLM 解释发生了什么,问题就是 Whisper 或 LLM 推理需要吃掉非常大量的时间和电力,所以以我的能力来说大幅超出我的范围了。PANNs 和 VGGIsh 倒是能通过音频推理出音频内出现什么样的音效,但仅是对于声效的表面解说,不是基于音声作品的剧本情节做出的解释(结果像是:Women Moaning/女性呻吟 [0.9], whispering/小声说话 [0.6], pain/痛苦 [0.4] 这样的表面解释)。

很可惜像图片领域 CLIP 或者 DeepDanBooru 这样的图片输入,Tag 输出。输入音声作品然后输出 DLSite Tag 这种的目前还不存在。只能依靠人们手动打 Tag,ASMR 在线听我记得有社区打 Tag 选项和推荐系统,论 Tag 的话目前只能依靠社区打标签了。

none.gif

e4bc0177

Re:回 3楼(e4bc0177) 的帖子

引用
引用第4楼d556f5f6于2025-07-06 07:20发表的 回 3楼(e4bc0177) 的帖子 :
正确,我的目标是通过音频片段查找出处(作品)。声纹检测是我觉得可以通过反推出作品后寻找作者的 C.V.,但要是声优换个马甲就是另外一回事情了。

AI内容分析的话,目前我能想到的只有通过 Whisper + LLM 让 LLM 解释字幕里头发生了什么,或者通过 Wav2vec 提取 Embedding 让 LLM 解释发生了什么,问题就是 Whisper 或 LLM 推理需要吃掉非常大量的时间和电力,所以以我的能力来说大幅超出我的范围了。PANNs 和 VGGIsh 倒是能通过音频推理出音频内出现什么样的音效,但仅是对于声效的表面解说,不是基于音声作品的剧本情节做出的解释(结果像是:Women Moaning/女性呻吟 [0.9], whispering/小声说话 [0.6], pain/痛苦 [0.4] 这样的表面解释)。

很可惜像图片领域 CLIP 或者 DeepDanBooru 这样的图片输入,Tag 输出。输入音声作品然后输出 DLSite Tag 这种的目前还不存在。只能依靠人们手动打 Tag,ASMR 在线听我记得有社区打 Tag 选项和推荐系统,论 Tag 的话目前只能依靠社区打标签了。



嗯,剧情上的内容分析太吃力,如果能分析出 play内容已经不错了

如果能区分是在说话、还是口还是舔耳,还是吼,的话也算有一定实用性了

声音的比起图片还是麻烦啊

之前也看到过有人分析出现词语频率的

5.gif

d556f5f6

回 5楼(e4bc0177) 的帖子:字词频率分析

虽然通过 Whisper 推理出音频字幕由于数据量过大而且非常吃运算量而不太可行,但是从现有的字幕文件 (SRT/VTT/LRC) 做词语频率应该可行,我在下个版本的元数据分析里会研究研究。感谢反馈。

不过我从来没对汉语和日语做过词语频率分析,毕竟像德/西/法/英语这种只要从空格分割开来就可以进行字词统计,汉语和日语的情况更复杂一些。

67c191312bb8d.png

Paper Plane (Mk.I)

B7F  2025-07-06 18:10
(高負荷状態中)
那我能说什么呢,你加油