
前回の続きです。
今週もほぼ徹夜で世界崩壊少女の開発を続けていました。やっと落ち着けたかなという感じですが、この疲れ取れるまでに時間がかかりそうです。
テキストつけちゃう病 再発
前回の開発記を書いたあと、全体的な実装作業が落ち着き、最後にプロンプトを見直していたところ、テキストつけちゃう病がまた再発!
一度こうなると、まるで仕様がころっと変わったかのようにテキストがつきまくります。
なんでだー、なんでだーと数時間プロンプトを変え続けて、ようやく原因がわかりました。
/* テキストが出まくる書き方 */
image_prompt = (f{prompt} {text}")
/* テキストが出にくい書き方 */
image_prompt = (f"{text} {prompt}")
つまり画像にしてほしい内容を先に伝え、細かな指示はその後、という順番で伝えないとダメなようでした。
写真風画像だから、ロゴやテキストを入れるなって指示してるんだけど
prompt = 指示内容
text = 生成内容
だとして、final_prompt = f”{text} / {prompt}”
だとテキストつけない。final_prompt = f”{prompt} / {text}”
だとつけまくる。まじかよ、こんなんわかるか#openai #dalle pic.twitter.com/OOPggA7o14
— ひょうごくるみ@OpenAI×X✒︎世界崩壊少女『初希アイ』テスト中 (@HYOGOKU_RUMI) February 8, 2025
こうしてまた一つ壁を越えたと思ったら、今度は別の問題が発生しました。
人口光を消せ!
偶然ですが、これまで生成した画像が日中のものばかりだったので気づくのが遅れたのですが、夜の街の画像はほぼ100%、照明が煌々とついていました。
夜の街は街灯が点いているもの、と判断してしまうようで、例えば「月明かり」など夜を示唆する単語が入っている場合も同様です。
世界崩壊少女の世界は太陽光など偶発的な要因を除いて、電力含めインフラは失われた世界なので、これでは矛盾してしまいます。
これもまたどれだけプロンプトを直しても結果に反映されない! 自然光のみ、電気は失われた世界だから人口光は存在しないなど、文言を変えてトライしまくりますがぜんぜんダメ。Okaneyが減っていく!
デバッグ開始から2時間ほどたった頃、chatgptの助言もあてにならないと判断して、発想を転換。
点灯した照明が描かれてしまうのはどうにもできない、それならばと、「照明は全て消灯している」という指示に変えたところ、電気の落ちた街や家屋が描かれるようになりました。
電気が失われているから電気をつけるなって指示と、照明を消灯させろ。どれほどの差があるのかわかりかねますが、適切なプロンプト作りの難しさを痛感しました。
AI創作と人間の創作との違い、その気づき
画像生成用プロンプトのデバッグをしている中で、一つの気づきがありました。
AIの創作は指示に忠実であり、生成されるパターンは人間感覚でみれば無限に等しいです。ただ、指示の範囲に収束するのが実態です。
つまり中央値から最大距離のようなものがあり、それを飛び越えられないわけです。
例えば、「りんご」という単語から物語を創作するとします。人間もAIも、「りんご」を題材にした物語をどんどん作れます。
AIの生産力に人間はもう勝てません。
しかし、人間は「りんご」から「太陽」を想像して物語を書くことができます。
AIはそういう指示がないとできません。(←ここがポイント)
世界崩壊少女のプロジェクトはもともと、「AIにも創作をさせられるんじゃないか」という発想から始まり、その理をようやく言語化できた気がしました。
ただ同時に、足りていないことにも気づくことができました。
結局、決まった処理の上で動いている
投稿文を生成するにあたり、ChatGPTのAPIには「世界観設定」と「キャラクター設定」という2つの静的情報に加え、WEBサイトに投稿されたストーリーを1つランダムに選んで渡しています。
静的な情報からの生成では中央値からの最大距離を超えられませんが、この渡されるストーリーは毎回異なり、動的な情報となるため、中央値を変えることができます。擬似的に最大距離の突破を実現しているわけです。いわば人間とAIの共作です。
それでも、内部的には決まった処理の上で動いていることは変わらないわけです。創作される生成物自体は人間の創作に近いものになりましたが、人間のような創作というイメージからは離れています。
人間は常に変化しているからです。こいつは変化しません。
人間のような創作をさせたいなら、この課題はぜひクリアしたところです。
プログラムを動的に書き換える処理なら?
例えば、プロセス実行中にバージョンアップしたファイルを作成し、入れ替え、次回実行時からバージョンアップした方のファイルで実行されるという処理を組み込めれば、毎回変化している感があって人間っぽくなります。
調べたところ、動的なバージョンアップシステムは、AmazonやGoogleなど大きな会社でも実装している処理のようですね。
これが実装できれば人間のような成長感があり、課題は攻略できるように思えます。
それでも……、世界崩壊少女の初希アイのイメージとはマッチしていないです。毎回変化しているというだけです。
何より、良くなる一方というのがひっかかる。人間は必ずしもそうじゃない。
もっとこう、人間ならでの、気分や調子のような変化が良いです。
その方向性でがちゃがちゃ調べてる間に思いついたのが、お天気情報のRSSから天気をとってきて、天候で気分が変わる処理をいれることでした。晴れの日は元気、雨の日は気が落ちる。それが文章に反映される。人間らしい変化ですね。
temperatureを活用する
ChatGPT APIはサンプルコードでやってきたせいか、ずっと知らなかったんですが、APIを叩く時に指定できるパラメータにはいろんな種類がありました。
注目したのは、この中の“temperature”(テンペラチャー)です。
このパラメータを記述に加えて値を変えることで、以下のように生成されるテキストのランダム性(多様性)を変えることができます。
簡単に言うと、0に近ければ近いほど決まった回答になり、2.0に近ければ近いほど創造的になります。
- 0.0 ~ 0.5 → フォーマル・正確な回答が必要な場合(例: ニュース記事、技術解説)
- 0.7 ~ 1.0 → バランスよく自然な会話をしたい場合(例: チャットボット、一般的な対話)
- 1.5 ~ 2.0 → 創造的な文章が欲しい場合(例: 詩、小説、アイデア出し)
じゃあ、初希アイは天気で気分が変わることにして、RSSから取得した天候の具合を数値に置き換え、その値をtemperatureに設定することにしました。
……この最後のつもりで組み込んだ処理が、本プロジェクト最大の壁になるとは、この時は思ってもみませんでした。
メモリ不足エラー
処理自体はすぐに実装できました。過去にスクレイピングのプログラムを作って仕事でつかっていたこともあり、大きな混乱はありませんでした。
しかし、テスト終了後、本番用コードに差し替えて次の投稿時間を待ってみましたが、いつまで経っても投稿されません。見てみると、GoogleVisionの画像解析のところで見慣れないエラーが出ていました。
文章生成のところを見ただけで、投稿までのテストはしていなかった\(^o^)/
ChatGPTに投げてみると、メモリ不足ということでした。
しかもこのエラー、やるたびに内容が変わります。ある時はスレッドの最大数オーバー、またある時は渡された変数の属性があっていない、その複合……。どれが本当の原因なのか、わかりません。
しかたなく追加した処理を遡りながら1つずつ消してみることにしました。しかし、消しても消してもエラーがなくならない。
念の為、実装前のコードに戻してみると、エラーは起きない。やはり実装したコードの中に原因がある。
とりあえずChatGPTの提案に従い、メモリ解放の手段をとってみることにしました。しかしLolipopのレンタルサーバーの仕様のせいか、フォーマルな方法が使えず、どんどんイレギュラーな記述になっていきます。素人目にも、普通のやりじゃないな感が強くなっていきます。
メモリの値を取得するコードの方式はすぐ見つけられましが、どうしても解放ができない。メモリ解放できるコードを全パターン書いてもらいって試しても、1つもヒットしない。
数時間粘りましたが、メモリ解放はLolipopの仕様上できないのだろうということで、諦めて原因究明の方に戻りました。
しかしこの原因がどうにもさっぱり。
- 追加実装前のコード → エラー発生せず 当たり前だ
- 追加実装したコード → エラー発生 そりゃそうだ
- 追加実装した関数を削除 → エラー発生 ふむ
- 追加実装した変数宣言類を削除 → エラー発生 ふむふむ
- 関数だけを実装 → エラー発生せず ←!?
- 変数宣言類だけを実装 → エラー発生せず ←!?
もう何が原因なのかわからない。投稿文作成用と画像生成用でプロセスを分けるか、最初からコードを全部書き直すしかもう手がありません。
そう思い始めた頃、一箇所見ていないところに気づきました。
それは、モジュールのインポート類です。
まさかね、と思いながら追加で実装するモジュールを消したところ、エラーが発生しなくなったのです。私の1日を潰したエラーの原因はこいつでした。
from bs4 import BeautifulSoup
調べたところ、こいつはめちゃんこメモリを食うらしい。
今回取得するRSSページは固定だったので、ChatGPTに取得するページのソースを渡したところ、比較的メモリを食わない以下のモジュールでも取得できることを教えてもらえたので、これに変えるだけであっさり解決しました。
import requests
import xml.etree.ElementTree as ET
ただ、メモリ使用量の限界が迫っているのは変わりないので、プロセスの分割を視野にいれつつ、メモリを食っている箇所を見つけて改修する作業を今後していくことになりますね。
現在
現在は必要機能はほぼ実装が終わった感があって、今回のメモリ不足について将来的に起こりうる問題も視野に入れつつ改修作業をしていく予定です。今後も本番サービスに向けてやっていきます。
現在はAmazonギフト券プレゼント企画を実施しているのでお気軽にご参加くださいjね。
コメント