お役立ち

Python×生成AI入門|たった4ステップで作る文章生成モデル

Pythonを使って生成AIに気軽に触れられることをご存じですか?実は、Pythonとそのライブラリがあれば、自動で結果を生成してくれるモデルを簡単に作ることができるのです。さらに、今は「Google Colab」というサービスでブラウザ上で今すぐにでも試すことができます。今回は実際に、「文章生成モデル」の作成を試してみます。コピペで簡単にできるので、ぜひ試してみてください。これまでは生成AIを「使う側」だったかもしれませんが、これを試すと「作る側」の裏の仕組みも少しイメージがわくと思います。

そもそも「生成AI」って何だっけ?

生成AIとは?

生成AIとは、テキスト、画像、音声、ビデオなどのさまざまなコンテンツを生成することができるAI(人工知能)のことです。従来のAIは、入力されたデータを分析して分類や予測を行うといった、決められたことを自動化することが目的だったのに対し、生成AIは入力されたことをもとに新しいコンテンツを作り出すことが目的となっています。

身近な生成AIの例

生成AIの応用範囲は広く、例えば次のような活用が行われています。

テキスト生成:記事や小説の自動生成、チャットボット、サポートAIなど

画像生成:新しいイメージの生成、デザインのアイデア、アバター作成など

音声生成:音楽やナレーションの生成、音声アシスタントの自然な応答

動画生成:映像編集の補助や新しい動画コンテンツの生成

生成AIは、新たなものを生み出す作業をサポートしてくれるので、さまざまな分野で革新をもたらしています。一方で、著作権やプライバシーといった問題を抱えており、利用には慎重さが求められています。

簡単に文章生成モデルを作成してみよう

今回は、生成AI実践のための入門編として、「マルコフ連鎖」という方法で自動で文章を生成してくれるモデルを作成してみます。「Google Colab」というブラウザサービスを使って誰でも簡単にできるので、ぜひ試してみてください。

「マルコフ連鎖」とは?

難しい言葉を使うと、マルコフ連鎖は「現在の状態」から「次の状態」を確率的に予測・生成する方法です。もう少し簡単に言うと、「現在の状態をもとにした確率によって、次の状態を予測し、結果を生成する」ということです。

例えば、テキスト生成では「この単語は次にどの単語につながりやすいか」を確率で予測し、自然な文章を生成します。

もう少しわかりやすくするため、次の3つの文章を図に表してみます。

私はコーヒーが好きだ

彼はミルクティーが飲みたい

彼女はコーヒーが苦手だ 

「私」「彼」「彼女」のあとには必ず「は」が来て(3/3の確率)、「は」のあとには「コーヒー」か「ミルクティー」が来て(1/2の確率)…と、それぞれの単語のつながりと確率が見えてきます。

それにもとづいて文章を作るのがマルコフ連鎖なのです。この例では、「私はミルクティーが飲みたい」という文章も作ることができますね。

この仕組みをもとに、マルコフ連鎖はテキスト生成やランダムなシミュレーションといったものの基礎に使われることが多くあります。また、このマルコフ連鎖のシミュレーションは、Pythonを使って簡単に実装することが可能です。

ブラウザで簡単に試せる「Google Colab」の使い方

Google Colabとは、Google アカウントを使用してブラウザでPythonを実行できるサービスです。基本無料で使うことができ、本来はさまざまな手順を踏まなければならない環境構築がほぼ不要なので、初心者でもすぐにPythonを始めることができます。

今回はこちらを使って、文章生成モデルを作成してみます。それにあたり、簡単に使い方を解説します。

 

(1)Google アカウントにログインし、Google Colabにアクセスする

(2)上のメニューバーから「ファイル」、「ドライブの新しいノートブック」をクリックして、新しいノートブックを作成する

 

(3)コードの実行

コードを入力したら、枠の左側にある三角のボタンを押すと実行

(4)コードやテキストの追加

入力欄のすぐ下の空白部分にカーソルを置くと、「+コード」「+テキスト」のボタンが表示され、追加したい方をクリックする

 

モデル作成の手順

まずは、現在の状態だけで次の状態を決定する「1階マルコフ連鎖(単純マルコフ連鎖)」と呼ばれるものを用いて、文を生成する方法を紹介します。この方法では、テキストのパターンを学習し、それにもとづいて新しい文章を生成してくれます。

(0)下準備:ライブラリのインストール

(1)学習するためのテキストの準備

(2)テキストの前処理:トークン化

(3)マルコフ連鎖のモデルを構築する

(4)文章を生成する

 

下準備:ライブラリのインストール

さまざまなライブラリがありますが、今回はトークン化(後で解説)のための「MeCab」とそれをPythonから使用するための「mecab-python3」をインストールして使用します。

また、トークン化の際に、文中の単語を調べるための辞書が必要なので、「UniDic」という辞書もインストールします。

まずは以下のコードを実行します。

!pip install mecab-python3

!pip install unidic

 

左上のマークが四角から三角に戻ったらインストール完了です。数秒かかるので、少し待ちましょう。続いて、UniDicの「download.py」ファイルを実行して、辞書データをダウンロードします。

!python -m unidic download

 

こちらも、数十秒で実行が完了しました。

(1)学習するためのテキストを準備

モデルが学習するためのテキストを用意します。自分で考えたもの、ChatGPTに作ってもらったもの、本の一節や歌の歌詞などなんでも問題ありません。今回は、分かりやすいように、簡単な3文を例に用います。

あるところに勇敢な騎士がいました。その騎士は多くの戦いに勝ち、多くの人に称賛されました。ある日、騎士は王様から新たな任務を命じられました。

(2)テキストの前処理:トークン化

Pythonにおけるテキストの前処理とは、テキストデータをコンピュータにとって意味を把握しやすい形に変換する作業のことです。小文字化などさまざまな方法がありますが、これから行う「トークン化」においては、テキストを単語ごとにスペースで分割し、マルコフ連鎖で次に来る単語のパターンを学習できるような形に変換します。

このトークン化が必要なのは、日本語は文中の単語を区切るものがないからです。英語などの言語は、単語ごとに空白で区切られているので、単語の識別が簡単にできます。しかし、日本語には空白がないので、明確に区切ってあげる処理が必要なのです。そして、分割した単語と単語の間に空白を含めて書き下すことを「分かち書き」と言います。

今回は、(0)でインストールしたライブラリを使って、次のような処理を行います。

 

・3つの文からなる1つの文字列を分かち書きにする

・分かち書きの結果を句点「。」で区切って、1つ1つの文に分割する(’。’を’。\n’に置換する)

・それぞれの文を半角空白文字で区切って、文の構成要素に分割する

・Pythonの辞書とリストを使って、各構成要素の次の構成要素を記録していく

 

実行するコードが以下の通りです。

import MeCab

import unidic

txt_data = 'あるところに勇敢な騎士がいました。その騎士は多くの戦いに勝ち、多くの人に称賛されました。ある日、騎士は王様から新たな任務を命じられました。'

wakati = MeCab.Tagger("-Owakati")

txt_data = wakati.parse(txt_data).replace('。 ', '。\n').rstrip()

print(txt_data)

 

ライブラリを読み込んでから、用いるテキストを変数に格納します。そして、MeCab.Taggerクラスのインスタンス生成時に「-Owakati」オプションを指定して、分かち書きを行います。

ここで、MeCabによって「。」のあとに挿入される半角空白文字を削除するようにしています。また、行末の改行文字も削除しています。これによって、テキストが次のように変換されました。

 

ある ところ に 勇敢 な 騎士 が い まし た 。

その 騎士 は 多く の 戦い に 勝ち 、 多く の 人 に 称賛 さ れ まし た 。

ある 日 、 騎士 は 王 様 から 新た な 任務 を 命じ られ まし た 。

 

(3)マルコフ連鎖のモデルを作成する

次に、変換したテキストをもとにモデルを作成します。ここでは、空白文字で文字列を区切って単語の組み合わせのリスト(モデル)を作成します。コードは以下の通りです。

def make_1state_model(txt_data):
    model = {}
    txt_data = txt_data.split('\n')
    for sentence in txt_data:
        if not sentence:  # 空行などは処理しない
            break
        eos_mark = '。!?' # end of sentence
        if sentence[-1] not in eos_mark:  # 行末が。!?でなければ処理しない
            print('not process:', sentence)
            continue
        words = sentence.split(' ')
        previous_word = 'BoS'  # begin of sentence
        for word in words: # 辞書に要素を追加
            if previous_word in model:
                model[previous_word].append(word)
            else:
                model[previous_word] = [word]
            previous_word = word
    return model

model = make_1state_model(txt_data)
model

 

すると、次のような結果が生成されました。

 

{‘BoS’: [‘ある’, ‘その’, ‘ある’],

 ‘ある’: [‘ところ’, ‘日’],

 ‘ところ’: [‘に’],

 ‘に’: [‘勇敢’, ‘勝ち’, ‘称賛’],

 ‘勇敢’: [‘な’],

 ‘な’: [‘騎士’, ‘任務’],

 ‘騎士’: [‘が’, ‘は’, ‘は’],

 ‘が’: [‘い’],

 ‘い’: [‘まし’],

 ‘まし’: [‘た’, ‘た’, ‘た’],

 ‘た’: [‘。’, ‘。’, ‘。’],

 ‘その’: [‘騎士’],

 ‘は’: [‘多く’, ‘王’],

 ‘多く’: [‘の’, ‘の’],

 ‘の’: [‘戦い’, ‘人’],

 ‘戦い’: [‘に’],

 ‘勝ち’: [‘、’],

 ‘、’: [‘多く’, ‘騎士’],

 ‘人’: [‘に’],

 ‘称賛’: [‘さ’],

 ‘さ’: [‘れ’],

 ‘れ’: [‘まし’],

 ‘日’: [‘、’],

 ‘王’: [‘様’],

 ‘様’: [‘から’],

 ‘から’: [‘新た’],

 ‘新た’: [‘な’],

 ‘任務’: [‘を’],

 ‘を’: [‘命じ’],

 ‘命じ’: [‘られ’],

 ‘られ’: [‘まし’]}

(4)文章を生成

最後に、(3)で作成したモデルを使って、確率的に次の単語を選択しながら文章を生成します。ここでは「generate_sentence」関数を使い、最初の単語から次の単語を選択しながら文章を生成していきます。組み合わせの中で単語がランダムに選択されるため、バリエーションのあるさまざまな文章が生成されます。

from random import randint

def generate_sentence(model):
    eos_mark = '。!?'
    key_list = model['BoS']
    key = key_list[randint(0, len(key_list)-1)]
    result = key
    while key not in eos_mark:
        key_list = model[key]
        key = key_list[randint(0, len(key_list)-1)]
        result += key
    return result

for _ in range(5):
    print(generate_sentence(model))

 

「。」「!」「?」(eos_mark)が来るまでループし、結果を生成します。また、「for _ in range(5):」の数字を変えることで生成する文章の数を変更することができます。実行結果は次のようになりました。

 

その騎士がいました。

その騎士は多くの戦いに称賛されました。

その騎士は多くの人に勝ち、多くの戦いに勇敢な任務を命じられました。

ある日、騎士がいました。

ある日、騎士は多くの戦いに勝ち、多くの人に称賛されました。

より精度の高い結果を得るためには

ここまでの例では、シンプルな文章を用いてマルコフ連鎖の基本的な仕組みを紹介しましたが、工夫次第でさまざまなテキスト生成モデルに応用することができます。

生成した文章を見ていただくと分かるように、自然な文章もあれば少し不自然な文章もあります。もう少し自然な文章ができるようにするには、固い文章よりももっと話し言葉のような文章を学習させると改善できる可能性があります。

例えば、新聞や論文、小説といった文章は文章が固く、単語の順番や構成も非常に重要です。一方で、歌詞やSNSでの投稿、会話といった文章は、日常会話においてもそうであるように、多少単語の組み合わせや順番が違ってもそこまで違和感がありません。

実際、Xのbotでもポストをもとに学習して自動でつぶやいているアカウントも存在していますが、「こういうポストあるよね」と思えるような自然な文章を投稿しています。学習させるテキストをいろいろ試してみると、どれも結果や精度が異なって面白いかもしれませんね。

また、今回のモデルは「次に来る単語のみ」を考慮しているため、生成された文章はあまり自然でない場合があります。より高い精度のモデルを作成するためには、重要なことを記憶し、いらない情報は忘れることができる「LSTM」(参考:https://nlab-notebook.com/entry/rnn_lstm_v1)や、ある言語単位の 連続をマルコフモデルで表した「n-gramモデル」(参考:https://ocw.u-tokyo.ac.jp/lecture_files/is_01/6/notes/ja/langinfo6.pdf)なども活用してみると良いでしょう。Pythonのライブラリを使って試せるものもあるので、ぜひいろいろチャレンジしてみてください。

まとめ

今回は「マルコフ連鎖」を使って、文章を生成する簡単なモデルを作成してみました。AIの裏側や仕組みが少しイメージできたでしょうか。私たちがどのように活用するかによって、精度が変わってくることもイメージできたかと思いますが、まさに今必要なのがAIを適切に活用できる力です。この実践を通じて、AI活用のイメージが明確になったり、AIを試すきっかけとなったりしたら嬉しく思います。

 

[参考]

IT media「[文章生成]MeCabをインストールして分かち書きを試してみよう」

https://atmarkit.itmedia.co.jp/ait/articles/2102/05/news027.html

 

IT media「[文章生成]マルコフ連鎖で文を生成してみよう」

https://atmarkit.itmedia.co.jp/ait/articles/2102/19/news026.html