前言:
2016年12月的一天,我翻着网易云音乐的“我喜欢的歌曲”,看到里面500+首各类歌曲,心想着要是网易出个自动整理的功能就好了,于是萌发了给歌单做聚类的想法,就此又开了一个云音乐相关的坑。
这一次,我们来试试歌曲风格。
先上成品Demo
http://www.jayveehe.com/musictaster
备用地址:http://api.jayveehe.com/musictaster
包含的功能:
- 对指定歌单进行聚类,并可视化。
- 针对若干个歌曲,找出最相似的其他歌曲。
【由于备案问题,域名现在可能需要跳转至国外服务器,所以会有些卡,发起请求后敬请等待响应】
可惜,网易云音乐未提供开放的创建歌单API,因此无法做到自动整理歌曲,权当娱乐吧。
限于服务器机能,当前的模型只存储了22W+的歌曲向量,基本涵盖大部分歌曲,部分冷门歌曲暂时无法计算相似度。
【目前的使用场景】
【1】想看看自己或者他人的歌单大致包含哪几类歌曲?
- 打开感兴趣的歌单详情页,如:http://music.163.com/#/playlist?id=3659853
- 复制该网址并粘贴到输入框内,确认。
- 在弹出的对话框内任意拖动、放大浏览聚类结果。
【2】有一首歌我特别喜欢,能帮我找出类似的歌曲吗?
- 在输入框内输入歌名,回车确认。
- 如有多首喜欢的歌曲,可以再次键入确认。
- 操作很直观就不废话了,点击确认看结果。
- 后期其实可以考虑直接点击结果歌名,跳转至相应的歌曲页,目前精力有限就不做了。
更详细的API文档
为方便其他开发者,API文档如下,顺求其他有趣的应用场景。
https://github.com/JayveeHe/MusicTaster/wiki/Music-Taster-Demo-API-Doc
一、脑洞+思路
1.1 如何量化歌曲风格?
说起歌曲风格,我们首先会想到常见的音乐基本分类:古典、流行、摇滚、轻音乐、New Age等等。
显然,利用一些乐理知识对歌曲进行分析,似乎是一个比较科学的选择,但是这样也需要更多的专业知识,例如识别出音乐在节拍、小节等一堆我不太了解的特征上的差异。从音频的角度进行特征提取,就要大致走FFT(快速傅里叶变换)等频域分析的方法,虽然我是学通信出身,但是也不想碰这块硬骨头了……
因此,这一次我打算利用群体智慧——歌单。歌单是普通用户创造的一类歌曲专辑,用户将自认为的符合歌单主题的歌曲凑到一起,因此同一个歌单下的歌曲大都拥有同一类歌曲风格。
作为一名NLP选手,立马就觉得歌单很符合“词袋模型”的设定,因此用LDA主题模型的方法肯定可以达到比较Fancy的效果。不过这一次想尝试一下更新的理论工具,即词嵌入(Word2Vec)的方法,将每首歌按照风格映射为一个特征向量。
1.2 Song2Vec
Word2Vec的原理在此不做赘述,总而言之可以解释为:Word2Vec可以利用一个滑动窗口学习出单词在句子中的语义角色(基于Skip-Gram和CBOW),我们可以通过一个简单的对应关系直接套用Word2Vec的理论:每个歌单相当于一个句子,每首歌相当于一个词,在训练时输入大量歌单“句子”即可学习到相应的歌曲向量。
1.3 方案需求
- 首先,需要大量抓取歌单信息;
- 其次,需要训练一个Song2Vec模型;
- 最后,搭建一个服务器提供相应的API。
二、方案实现
2.1 歌单信息准备
出于避险目的,在此不详细介绍歌单的具体爬取方法,请大家闷声发大财。
主要是通过抓包+测试获取了部分云音乐的官方API调用方法,部分请求的加密方式参考了项目网易云音乐命令行版本。
分别在MongoDB中建立了歌曲、用户、歌单三个Collection,以确保爬取最详细的数据。
2.2 模型训练
使用Python中的gensim
工具库进行Song2Vec的模型训练。gensim是一个很成熟的主题模型工具库,附带包括LDA、word2vec、doc2vec在内的多种模型工具。在此直接使用Word2Vec的相关方法训练Song2Vec模型,主要调节的参数有:向量大小-size
、迭代次数-iter
、窗口大小-min_win
、最少出现次数-min_count
等。
根据当前服务器的机能(主要受限于2GB的内存),最终使用近8w+个歌单、22w+歌曲分别训练出了50维的Song2Vec模型(约280MB)和Artist2Vec模型(约70MB)
2.3 API WebServer
使用轻量的Flask
框架提供API,启动时加载模型。
顺带提供Demo的前端服务,基于jQuery
、Bootstrap
和Flat-UI
做基础布局,D3.js
做布点可视化。
前端无力,就此凑合吧。
三、补充说明
关于Song2Vec的语义加减性
本来一开始采用Word2Vec模型时,是想利用其有趣的语义加减性做相应的歌曲推荐的。如Word2Vec原始论文给出的例子:king - man + woman = queen
一样,我希望能够做出晴天 - 周杰伦 + 林俊杰 = 江南
的效果。
但事实是,在训练歌曲向量时所作的类比过于粗暴,没有一个很好的方式将歌手与歌曲同时放到一个模型中训练(我想如果要做的话,就要改动相应的模型损失函数了),当时分别采用了两种方案:
- 在训练词向量时,每一首歌名后面都跟上相应的歌手名。这样的结果是歌手与相应歌曲的距离的确很近,但是歌手和歌曲却拥有一样的权重,在做向量加减法时会有一些不想要的损失。
- 分别训练两个模型(即歌曲向量与歌手向量),在做向量加减法时分别从两个模型中选取向量,并给不同类别的向量赋予不同的权重。这样有一个很大的问题,两个模型在向量分布上会完全不同,即各向量的相对距离可能差别不大,但方向性却大不相同(如周杰伦与林俊杰的向量距离可能约等于晴天与江南的距离,但是二者在向量的绝对角度上会有很大差别,因为是两个独立的训练过程了)。
基于以上两个不是很好表达出来的原因,目前API所提供的歌曲、歌手同时进行的语义加减会存在一定的问题,效果仅供娱乐。但是在单类别的加减上(如纯歌手的加减或纯歌曲的加减)还是可以一看的。
关于本次的风格界定
本次的歌曲风格是基于歌单训练的,因此在此的“风格相似”很大程度上体现了歌曲之间在使用场景上的相似性。一个典型的例子是歌曲“爱情转移”,与它相似的歌曲前几名为:
|
|
这个结果可能在某种程度上与预期的“陈奕迅的歌曲”有些出入,但是它却体现了部分“影视主题曲”歌单的风格。因此,本Demo给出的相似性结果很大程度上是体现了歌曲之间的收听场景相似度。
四、Future Work?
正如上文所述,受制于云音乐本身的歌单管理API,无法做到自动对歌单进行归类整理。因此本次实践仅实现了聚类和相似计算这两种玩法。相应地,词向量本身在NLP中的角色也是作为其他任务的输入,Song2Vec的其他应用还需各位继续脑洞。
欢迎留言表达你的痛点与想法。