您好, 访客   登录/注册

用马尔科夫链玩智能作曲

来源:用户上传      作者:

  在本文开头,先给大家介绍一位作曲家,她叫Aiva,才华出众,作品众多,已出版过多个音乐专辑,还有不少作品在音乐厅由交响乐队演奏。但Aiva不是一位人类作曲家,而是一个精通作曲的人工智能程序,将其作品和人类的音乐作品放在一起时,几乎无法辨认。
  教师在人工智能的课堂上,大概不会满足于仅仅欣赏Aiva设计的音乐作品,如果能让学生自己体验一下人工智能的作曲过程,那该多好。Aiva的网站上倒是提供了自助编曲功能,用户设置好音乐风格、乐器和时长等参数后,就可以一键完成音乐作品“创作”,但是,除了让学生体验到“人工智能真厉害”之外,隐藏在“真厉害”背后的原理,却一点儿也无法揭示出来。这也难怪,要想让Aiva写出质量不亚于人类作曲家的作品,不仅需要相当艰深的计算机科学或数学原理的支撑,而且需要大量原始乐谱作为机器学习的材料,毫无疑问,软件设计者还需要专业的音乐创作技能。
  那么,关于人工智能创作音乐的教学,就只能简单地停留在欣赏环节吗?答案当然是否定的。本文试图通过一个教学活动来说明,只要选取了恰当的策略,即便是在不多的课时中,也能实现智能作曲相关的“需求提出—数学原理揭示—计算机算法实现”的完整的教学过程。
  循序渐进,降格以求——从一段难听的音乐引出任务
  这个教学活动的名字叫“用马尔科夫链玩智能作曲”,然而,因为并不是真的要上音乐课,所以要回避音乐创作中节奏安排、旋律发展、乐段结构、和弦配置、乐器配置等内容。作为驱动人工智能学习的任务的目标,可以有策略地将智能生成音乐作品替换成“把难听的旋律变好听”,这样,一方面,为任务达成设定了容易跨越的门槛,另一方面,也为学有余力的学生设定了一个长期的自主学习和探索目标。
  图1所示的这段简单的代码,是利用低音的So、La、Ti和中音的Do、Re、Mi、Fa、So、La这9个音符,随机生成一段旋律序列。代码中用到了pysynth库,这个库的作用是把音符名称转换为声音(Do对应音调c,Re对应音调d,以此类推)。在代码中,notetune列表中添加的,就是随机生成的音符名称,而notedelay列表中存放的,是对应每个音符所持续的时长,为简单起见,每个音符延续的时间都设置成1/4拍。
  程序代码总共只有十多行,用到的流程结构只有循环,数据结构只有列表,可以说十分简单。但由程序随机生成的所谓旋律简直难听无比,于是,怎样才能让随机生成的旋律更优美一些,自然而然就成了探索的课题。
  眼观为实,亲历其境——马尔科夫链的展现
  用来实现智能作曲的计算机的方法很多,如神经网络、自动机模型、贝叶斯学习等,但有一个工具,几乎所有的智能作曲软件都会用到,那就是马尔科夫链。一段旋律的产生,实质是在时间轴上将音符放置到不同的位置,而每一个音符的放置,如果只是随机放置,并不能带给人愉悦的感受,音符的放置必须要参考上一个音符的情况,类似的,某一个乐句或乐段的结构,也肯定和上一个乐句或乐段的结构有关(为简单起见,本文不涉及乐句和乐段结构的变化)。这就涉及了教学活动中重点介绍的马尔科夫链。所谓“弱水三千,只取一瓢”,不仅是因为马尔科夫链在旋律的自动产生中起到重要作用,也同时因为这个模型非常容易用程序代码实现出来,而且能便捷、直观地观察到效果。
  那么马尔科夫链是什么呢?按照数学的定义来说,马尔科夫链是具有马尔科夫性质,且存在于离散的指数集和状态空间内的随机过程,可以用转移矩阵来定义。这段话未免让人看得有些云里雾里,这是因为数学定义需要有很强的严谨性,但如果是拿马尔科夫链来当作解决问题的工具,那只要直观观察一下其工作过程,就很容易知道,为什么这个工具可以用来自动产生旋律了。
  一个形象直观且可交互执行的工具名叫“Markov Chains A visual explanation”,用搜索引擎可以找到其在线运行的地址,也可以将代码下载到本地运行。在这个工具中填写入转移矩阵,就可以看到马尔科夫链的运作过程了(如图2)。
  怎么玩这个转移矩阵呢?想象一下A、B、C玩抛球游戏,A更喜欢自己抛自己接,只是偶尔抛给B和C,玩家B也喜欢抛给自己,偶尔抛给A和C,但玩家C却优先把球抛给B,偶尔抛给A和自己。若将大概率的抛球对象的概率值设为0.8,小概率的抛球对象的概率值设为0.1,就得到了转移矩阵(如下表)。
  将数值填入后,就可以观赏抛球表演了,当然,也可以在转移矩阵中填入其他概率值,然后观察抛球游戏的效果。
  为什么这个模型可用于自动产生旋律呢?想象一下,假如当前音符是中音So,那么从人的欣赏习惯来看,更自然的后续衔接,大概率是中音Do、Mi、La等,偶尔也可能是中音Re、Fa,但概率就小了许多,至于变成低音La,概率就更小了。所以,只要将音符的变化的概率,制作成马尔科夫转移矩阵,就能让程序按特定概率随机生成听上去更自然的旋律了。
  善假于物,物盡其用——将任务融入日常算法和程序教学
  在介绍了马尔科夫链的工作原理后,接下来的难点,是要用学生所掌握的算法和程序知识技能,将智能旋律生成的代码实现出来。整个程序中,用到的都是常用的流程结构和数据结构,唯一困难的地方,就在于状态转移矩阵的建立。
  建立状态转移矩阵的第一步,是获得转移矩阵的概率的数据。照理说,程序应当在大量的乐谱中,通过对音符逐个扫描,计算出转移矩阵的概率,但读取乐谱并计算概率这个工作,并不容易在有限的课时中实现,一个便捷且有趣的方法是,让学生分小组,用哼唱熟悉歌曲并记录的办法,大致将每个音符后续出现音符按出现可能性从大到小排列出来。
  建立状态转移矩阵的第二步,是将转移矩阵变成列表或数组,为了避免复杂的概率上的计算,有一个“投机取巧”的办法,就是在列表中将大概率的音调名称填写得多一些,将小概率的音调名称填写得少一些,举例来说,可以用图3所示的这个二维的列表来代替转移矩阵。
  列表中的第一行,对应的是g3这个音(也就是低音So)最可能出现的后续音符,从列表中可见,g3音后续更可能出现的是a3(低音La)或c4(中音Do),偶尔出现e4(中音Mi)和g3(低音So,也就是它自己),其他音不出现。这个列表是根据先前自由哼唱的大致结果填写的,列表中音符出现多少的变化,就会决定音乐风格的变化。这就意味着,只要“喂”给程序大量不同风格的乐谱,程序就可以统计出不同风格音乐旋律发展变化的概率,从而实现智能自动编曲。
  第二行列表对应的是a3这个音(也就是低音La)最可能出现的后续音符,第三行以及后面若干行以此类推。
  用马尔科夫链自动生成旋律的程序代码也很简短(如图4),程序思路如下:先给出一个c4音(中音Do)加入到旋律列表中,然后,在二维列表中找出对应c4音的后续音的那一行列表,然后随机抽出某个后续音,加入到旋律列表中。运行程序可以发现,生成的旋律果真比刚才好听多了。若是有兴趣再加上节奏变化和乐句间的停顿,就能自动创作出一首儿歌级别的音乐作品啦。
  程序代码中,稍显难解的地方,其实就是根据前一个音符在二维列表中找出对应的后续音符列表。但即便不使用二维列表,只用一维列表和If分支语句,也一样能达到目标,只是代码量稍微大一些而已。这样一来,整个自动生成旋律的任务,除了需要讲解马尔科夫链这个环节,其他内容都可以融入到日常的算法教学中。因此,日常的算法与程序语言的教学,就成了人工智能教学的基础铺垫,而人工智能教学中的任务,也就成了日常算法与程序语言的教学的驱动目标。
转载注明来源:https://www.xzbu.com/9/view-15235133.htm