🐥

【chatGPT】fine-tuningを使い藤井風を再現し曲を書いてみた

2023/05/08に公開

1. はじめに

藤井風とは? & 記事作成のきっかけ

藤井風さんは言わずもがな、紅白出場、アジアツアーの開催が決定しているなど目覚ましい活躍をしている、日本を代表するミュージシャンの一人です。
https://fujiikaze.com/
僕は彼の音楽が大好きで、かっこいいコード進行、人生2周目かのような歌詞など、、その良さは語り尽くせません

僕も彼のような音楽を作れればと思うのですが、残念ながら彼のような才能はありません、、
そこで巷で話題のchatGPTでなんとかできないのか? と思ったのが今回の記事作成のきっかけです。

2. ChatGPTを使った音楽作曲の流れ

最初の試み

まず藤井風さんの知識を持っているかGPT-4聞いてみようと思います

「ひまわり」、「夜に駆ける」といった曲は発表してないのであってなさそうです。。
chatGPTは2021年までのデータしか持ってないので,2020年の発表曲についても聞いてみます

こちらでも間違っています。。
次に作曲・歌詞についての理解も聞きます


まず歌詞ですがこんなフレーズはないです。また藤井風さんの他の曲にもこのようなフレーズはないです。
次に作曲に関しても(個人的な感想ですが)間違えています。
藤井風はセブンスコードやテンションコード(※1)を織り交ぜて複雑な曲を作るので、シンプルなコード進行のこの曲は全く傾向をとらえてない、と感じます。

よって、現状chatGPTは藤井風の曲についてはかろうじて知っているが、作詞作曲の知見ついてはかなり怪しいレベルであると判断しました。これだと藤井風さんの特徴を捉えた曲は作ってくれなさそうです。
なのでこの辺を試行錯誤することにしました

曲の作成

曲の作成の流れと Start with zero-shot, then few-shot (example), neither of them worked, then fine-tuneについて

chatGPTを提供しているopenAIのドキュメントによると以下のようなことが書かれています
「Start with zero-shot, then few-shot (example), neither of them worked, then fine-tune」
https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api

つまりzero-shotではじめて、few-shot, それでもだめならfine tuningをしろ、ということとです。
zero-shotとはなんの手がかりも与えず、chatGPTに質問を渡すことを指します。

Extract keywords from the below text.
Text: {text}
Keywords:

Few-shotはいくつかの手がかりと質問をchatGPTに渡すことを指します

Extract keywords from the corresponding texts below.

Text 1: Stripe provides APIs that web developers can use to integrate payment processing into their websites and mobile applications.
Keywords 1: Stripe, payment processing, APIs, web developers, websites, mobile applications
##
Text 2: OpenAI has trained cutting-edge language models that are very good at understanding and generating text. Our API provides access to these models and can be used to solve virtually any task that involves processing language.
Keywords 2: OpenAI, language models, text processing, API.
##
Text 3: {text}
Keywords 3:

最後にfine tuningとは 質問例とそれに対する回答例を大量に用意して、AIにそれを学習させることを指します。その後それをもとに回答をより洗練させることができます。

曲の作成に関しては以下のような流れにすることにしました。

  • (1)曲のタイトルの案を作成
  • (2)曲のタイトルから、曲の要約を数行程度で作成
    (例 「タイトル:老夫婦の恋愛」→「はじまりは老夫婦が出会いを思い出すところから始まる」 「はじめはいがみ合っていたがいつしかお互いを信頼するようになる」...と続く」)
  • (3)曲の要約から 歌詞とコードを作成する

今回、(1)(2)に関してはFew-shotを使い、藤井風さんの特徴を数例与えるだけで、いい回答させることができるかと思います。
しかし(3)に関しては、藤井風さんの曲を数例与えるだけでは特徴を捉えた曲はできなさそうです。
できるだけ入力してよりより良い曲を作りたかったので(4)のみfine tuningで問題を解決することにしました。
(Few-shotでは 多くの曲を入力させることはtoken制限(※2)でできないため、多くの曲を入力するとなると自ずとfine tuningを使うことになる)

(1)曲のタイトルの案を作成

以下のようにGPT-4に投げて作成します

曲のタイトルを10個考えてください。タイトルはひらがなを2文字以上使ってください。

曲のタイトル:旅路
##
曲のタイトル:帰ろう
##
曲のタイトル:死ぬのがいいわ
##
曲のタイトル:grace
##
曲のタイトル:きらり
##
曲のタイトル:何なんw
##
曲のタイトル:優しさ
##
曲のタイトル:ガーデン
##
曲のタイトル:青春病
##
曲のタイトル:まつり
##
曲のタイトル:さよならべいべ
##
曲のタイトル:ロンリーラプソディ
##
曲のタイトル:damn
##
曲のタイトル:罪の香り
##
曲のタイトル:それでは
##
曲のタイトル:風よ
##
曲のタイトル:調子のっちゃって
##
曲のタイトル:燃えよ
##
曲のタイトル:やば。
##
曲のタイトル:特にない
##
曲のタイトル:何なんw 
##
曲のタイトル:キリがないから
##
曲のタイトル:へでもねーよ
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:
##
曲のタイトル:

藤井風さんはひらがなかつ単語という曲名がよくあるのですが、
「かげろう」という曲名がとてもそれに近い感じがしたのでこれを採用することにしました。

(2)曲のタイトルから、曲の要約を数行程度で作成

これもFew-shotでやるために、他の曲のタイトルと曲の要約がいくつか必要です。
歌詞の取得には楽器meというサイトを使わせていただきました。
https://gakufu.gakki.me/search/?mode=list&word=AT:藤井風
ここに記載の歌詞に関して10分割して以下のようにopenaiのAPIにrequestします

part_of_lyrics = <歌詞を10分割したものが入る>
response = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=[{
			"role": "user", 
			"content":f"以下の歌詞の内容を説明してください。 簡潔に1文で説明してください。text=\"\"\"{part_of_lyrics}\"\"\""
		}],
                temperature=1,
                top_p=1,
                frequency_penalty=0,
                presence_penalty=0,
                stop=["\n\n"],
            )
print(response["choices"][0]["message"]["content"])

すると「帰ろう」という曲に対しては以下のようにタイトルと10個の要約を作ることができます

曲のタイトル:帰ろう
曲のストーリーの部分ごとの要約:
・夕日と夜明けの間に存在して交わることのできない、運命的な二人の愛を表現している。
・自分には何もなく、恐れるものもない少年がいる。
・歌詞の内容は、聞こえなくなってしまったことや何かを失敗したことがあっても、その先には長い未来が待っているので、全てを忘れて前に進もうというメッセージが込められている。
・傷が痛むけれど、渇きを癒せずにもうどうでもよくなった人が、爽やかな風と柔らかく降る雨に吹き飛ばされて帰ろうとする様子を歌っている。
・別れた相手との憎み合いの果てに、何が生まれるのか不安に感じる女性が、相手よりも早く忘れようと決めるが、相手は弱音を吐き、女性は未練がましく感じている。
・神様になることを望む歌詞であり、「人間はつらい」という意味が含まれている。ただしこの歌詞の表現は、『かたわら見ていた世界』(ヨルシカ)のような変化や進歩のない閉塞感を感じさせる雰囲気があります。
・別れを告げ、一人で町を歩く様子を歌った歌詞。
・死の直前に、何も持たずに全てを与えて帰ろうという決意を歌った歌詞。
・これは「感謝の気持ちを表し、帰る前に幸せな場所に帰ろうと誘う歌詞で、最後には何を持っていくか考えさせられる」という内容です。
・過去の荷物を手放し、憎しみを終わらせて自分自身を取り戻し、明日から新たに生きていこうと決心した女性の歌詞。

これを「帰ろう」「青春病」「きらり」という曲に対して同様に取得し、Few-shotによって
「かげろう」という曲の要約を出力するようにします

曲のタイトルと曲のストーリーの部分ごとの要約を考えてください。

曲のタイトル:帰ろう
曲のストーリーの部分ごとの要約:
・夕日と夜明けの間に存在して交わることのできない、運命的な二人の愛を表現している。
・自分には何もなく、恐れるものもない少年がいる。
・歌詞の内容は、聞こえなくなってしまったことや何かを失敗したことがあっても、その先には長い未来が待っているので、全てを忘れて前に進もうというメッセージが込められている。
・傷が痛むけれど、渇きを癒せずにもうどうでもよくなった人が、爽やかな風と柔らかく降る雨に吹き飛ばされて帰ろうとする様子を歌っている。
・別れた相手との憎み合いの果てに、何が生まれるのか不安に感じる女性が、相手よりも早く忘れようと決めるが、相手は弱音を吐き、女性は未練がましく感じている。
・神様になることを望む歌詞であり、「人間はつらい」という意味が含まれている。ただしこの歌詞の表現は、『かたわら見ていた世界』(ヨルシカ)のような変化や進歩のない閉塞感を感じさせる雰囲気があります。
・別れを告げ、一人で町を歩く様子を歌った歌詞。
・死の直前に、何も持たずに全てを与えて帰ろうという決意を歌った歌詞。
・これは「感謝の気持ちを表し、帰る前に幸せな場所に帰ろうと誘う歌詞で、最後には何を持っていくか考えさせられる」という内容です。
・過去の荷物を手放し、憎しみを終わらせて自分自身を取り戻し、明日から新たに生きていこうと決心した女性の歌詞。
## 
曲のタイトル:青春病
曲のストーリーの部分ごとの要約:
・青春を追い求めて消えていく姿を歌った曲。
・自分が思うほど強くなく、思った通りにやめることもできなかったという歌詞。
・自分を過小評価していた主人公が、彼女の声に支えられていたが、彼女の声を失ったことで立ち直れず絶望するという内容の歌詞。
・歌詞は、人生が一直線ではなく、上下の波があることを表現している。
・青春の病に侵され、儚いものを求める若者たちが、結局は粉になって散ることを歌っている。
・歌詞は、長く別れているのが寂しく苦しいという心情を歌っており、相手の声が頭の中で鳴り響く中、聴き耳を立てているという内容です。
・自分を鼓舞し、走り続けて何かを追い求めることを歌っている。
・瞬く間に過ぎ去る人生の無常さを感じながら、あきらめずに前に進めというメッセージが込められた歌詞。
・泥の中で生きる悲しみと孤独を歌った内容。
・この歌詞は、人生において青春の輝きを感じることができずに過ごしている人が、後悔することなく、今を大切に生きることを訴えている。
## 
曲のタイトル:きらり
曲のストーリーの部分ごとの要約:
・二人で季節の変化を共にし、夕日を見ながら朽ち果てていくことでも最後まで一緒にいることを誓う。
・愛を動機にして戦うことが大切で、新しく探す必要はなく、常に現在に目を向けて生きていこうというメッセージが込められた歌詞。
・恋人と別れた主人公が、過去の人生を回顧しながら、新しい恋人を求めている。彼女は、今まで出会った男性たちに魅力を感じたが、最終的に彼女が求めるのは現在の恋人である。
・主人公が探していた相手を見つけ、彼/彼女と一緒にどこまでも行き、季節や群衆の中でも一緒にいることを表現している。
・過去も未来も流して、今この瞬間を大切に生きようという歌詞。
・自分は夕暮れ時に風に吹かれながら決意を固め、進みたい方向に進むが、成功を保証できない。
・自分が何も知らないことに気づいたが、それを知ることが良かった。新しいことを探し求める必要はなく、常に現在に集中すればよい。
・過去に色々な経験をしてきたが、この目は永遠に輝き続け、生きてきた全てが夢のように感じられる。
・「私はあなたが良い」と言いつつ、探し求めていた相手を残して、彼/彼女をどこまでも追いかける覚悟を表現している。
・季節や群衆の中でも、彼/彼女と一緒なら全てが輝く
## 
曲のタイトル:かげろう
曲のストーリーの部分ごとの要約:

すると以下のような要約が出力されました

良さそうなので、これを使用して歌詞とコードを出力できるようにfine tuningを次に行います

(3)曲の要約から 歌詞とコードを作成する

改めてですが「fine tuningとは 質問例とそれに対する回答例を大量に用意して、chatGPTにそれを学習させて 質問に答えさせること」を指します。
これを行うために 曲の要約(質問) と 歌詞とコード(回答例)を大量に用意する必要があります
このために(2)と同様楽器meというサイトを使わせていただきました。
https://gakufu.gakki.me/search/?mode=list&word=AT:藤井風
サイトでは以下のようなフォーマットで 歌詞とコードが書いてあります

コードA コードB     コードB 
イケてる歌詞 いけてるかし

「イケてる」の部分では 「コードA」を演奏し
「歌詞 いけてる」の部分では 「コードB」を演奏し
「かし」の部分では 「コードC」を演奏する、というフォーマットになっています。

これを藤井風さんの曲23曲に対して、曲を10,12分割したものをchatGPTでfine-tuningできる形式にして保存します。(歌詞の要約は(2)と同様の方法で作成)

{"prompt":"あなたは藤井風のような素晴らしいミュージシャンです。以下の歌詞の要約から、歌詞とコードをつくってください。歌詞とコードのみ出力してください。\ntext=\"\"\"<イケてる歌詞の要約>\"\"\"\n\n###\n\n","completion": "コードA コードB     コードB \nイケてる歌詞 いけてるかし"}

このように分割数を設定したのは fine tuningには 500例以上が必要なためです(※3)
(23 * (10+12) = 506)
https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset

これを 前半20曲を training data, 後半3曲をvalidation dataとして
データをopenAIにアップロード、出力されたファイルIDを使って以下のように学習します

create_args = {
    "training_file": training_id,
    "validation_file": validation_id,
    "model": "davinci",
    "compute_classification_metrics": False,
    "n_epochs": 8,
    "batch_size": 128,
    "learning_rate_multiplier": 0.4
}
resp = openai.FineTune.create(**create_args)

モデルは最高性能の「davinci」を選択しています。
(ここで出てくるハイパーパラメータ等の解説は後述でおこないます。)

ここでできたモデルに関して動作確認をしてみます。
僕はラーメン二郎が好きなのですが(※4)
ラーメン二郎の歌の要約を渡して、藤井風さんっぽく歌詞とコードが出力されるかみてみようと思います

コードに関してや歌詞の「ワンワン」は謎ですが、
言葉を繰り返す感じや、岡山弁が語尾に出てくる感じはとても良さそうです。
このモデルをつかって(2)でできた歌の要約から
歌詞とコードを出力することを目指します。

以下のようにopenAIのAPIにリクエストを投げます

response = openai.Completion.create(
                    model=<finetuningしてできたモデルID>,
                    prompt=f"あなたは藤井風のような素晴らしいミュージシャンです。以下の歌詞の要約から、歌詞とコードをつくってください。歌詞とコードのみ出力してください。\ntext=\"\"\"{<かげろうの曲の要約>}\"\"\"\n\n###\n\n",
                    temperature=0.5, 
                    max_tokens=500,
                    top_p=1,
                    frequency_penalty=0.3,
                    presence_penalty=0.3,
                    stop=["\n\n"],
  • temperature(値域は[0,2])
    生成する文章の多様さを司るパラメータで大きいほど多様性のある回答をします。
    値を大きくすると文章の整合性が取れないものが多く出力されたので低めに0.5を設定しています
  • presence_penalty,frequency_penalty(値域は[-2,2])
    大きい値を設定するとpresence_penaltyはモデルが新しいトピックについて話す可能性を高め、frequency_penaltyはモデルが同じ行を逐語的に繰り返す可能性を減らします
    今回は0.1から1.0を0.1刻みで設定し色々な歌詞とコードを作成するようにします
    https://platform.openai.com/docs/api-reference/completions/create

そしてできた曲が以下です...
https://www.youtube.com/watch?v=o5lpYPJGiwY
(楽譜が見づらかったのでpdfも上げておきます)
https://drive.google.com/file/d/1Dv0l8vMpp31so5i5ZyxoygK0DH1LvUTM/view?usp=share_link

「かげろう」
どんなに綺麗でも夕暮れは来るから
このまま君と時を 過ごすよりいいや
刹那的に愛したあの日の君
今も胸の中で生きてるからこのまま君と時を過ごすよりいいや

美しい夕暮れよ 風に吹かれても刹那の恋を
胸に隠すのは愛なんだ
何があっても貴方は私の風となり行くけど  

かげろうのように消えゆく恋心を 
あなたは自分の中にいる
私は己が中にいるから
この愛を知り尽くして生きることは苦しいのね

できた曲について

すみません、上の動画ですが いくつかズルしています。。
まず、ラーメン二郎の例を見るとわかるように、歌詞とコードの同期が取れていません。
つまり歌詞の上に該当するコードが来るように来てほしかったのですが、今回はそのようにならなかった、ということです。なので今回は歌詞とコードはいいものを自分で抽出して自由な場所に使うようにしました

また今回はコードと歌詞しか出力されないのでメロディはないので、
自分でつけました。

とはいえ中々良い曲ができてると思っていて
コードに関しては、

  • 藤井風さんの曲でで多用されるセブンス・コード, テンションコードが出てくる
  • 藤井風さんの「きらり」のように Aメロ:keyG, Bメロ:keyF, サビ:keyG(Aメロと似たコード進行)

歌詞に関しても

  • 一人称が「私」になっている
  • 人生2周目感(個人的感想)
    のでかなりこのへんは良さそうです

5. 学び

fine tuning について

fine tuningですが、以下のようにハイパーパラメータを設定しました。

  • learning rateをまず学習がうまくいくように設定する
    低すぎても高すぎてもうまく行かないのでLossをみながらここをまず固定させます
    https://qiita.com/yuxzux/items/b14b4302e6fbaef6a3ec
    今回は0.4を設定しました
  • batch sizeは 256を最大としてなるべく大きく設定します
    (またlossが振動していたときはbatchsizeが小さいので大きく設定する必要があります)
    とはいえ openAIの特徴として token数で課金額が決まるためbatch sizeが大きいと
    金額がそれだけかかってしまいます。今回はこの兼ね合いをみつつ128を設定しています
  • epoch数もlossをみながら 決めます
    (このあたりが参考になるかと思います)
    https://www.st-hakky-blog.com/entry/2017/01/17/165137
    epoch数は8を今回設定しました

またハイパーパラメータ以外の学びとして

  • davinciの学習に 今回の設定で$34ほどかかります。なのでcurie等のモデルを始めに学習して学習に誤りがないか等をlossをみながら確認したほうが良いです
  • (あたりまえかもですが)データはtrain, validationごとにシャッフルして使うようにしたほうがよいです
    シャッフルすることでlossの振動が少なくなります

6. まとめ

全体のまとめとして

  • そこそこ良さげな曲ができた
  • #5のような学びを得ることができた

改善点として、

  • 歌詞の出力は8割ほど使える内容だったが、コードは1割 程度しか使えるものがなかった
    • おそらく、日本語を成立させる能力はpre-trainで学習しているが, コードを音楽的に成立させる能力は獲得してないのだと思われる。
      藤井風以外のミュージシャンのデータも学習に大量に入れることでこれを解決できるかもしれない
  • 歌詞とコードの同期がとれなかった
    • 以下の形式をためすなど、入力の方法を色々試してみる、などができるかもしれない
イケてる(コードA)歌詞 いけてる(コードB)かし(コードB )

またその他として

  • 何種類かのミュージシャンを組み合わせてもおもしろいかもしれない(aiko80%, ミスチル20%など)
  • 誰かに演奏してほしい(メロディーは僕がでっちあげたやつなので書き換えても良いので)

7.注釈

  • セブンスコードやテンションコード(※1)
    コードの横に7とか13とか書いてあるコードのこと

  • token制限(※2)
    https://platform.openai.com/docs/models/gpt-3-5

  • 500例以上が必要なためです(※3)
    学習後に気づいたのですが、条件付き生成は500例以上と書いてありますが、
    今回のような文章生成は本来数千程度推奨みたいです..
    「This use case will require a few thousand examples, as it will likely deal with different types of requests, and customer issues.」
    https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset

  • ラーメン二郎が好きなのですが(※4)
    ホームはメグジです

Discussion