浦川通『AIは短歌をどう詠むか』

講談社現代新書って、なんか装丁がおしゃれで、手頃ですっと読めるから昔から好きだったんですけど、まさか友達が単著を出すとは…。

短歌とAIと言語処理を同時に学べる不思議な書。現代の生成AIの仕組みを、ある目的(今回は自然で面白い短歌の生成)に沿って調整してく様を丁寧に書くことによって解説していく書でもある。Procreateでお絵描きするチュートリアルのような形で、AIの短歌出力を調整していくチュートリアルになっていて、それによってAIのクセが実地的に分かっていく感覚があって面白い書だった。

短歌出力をパラメータで調整するということ

短歌らしさを出すために調整をしていく作業は、料理とか難し目の自動機械のパラメータ設定に似た、人間による適切なフィードバックが必要な作業に似ている、と感じた。PID制御のパラメータ調整にも似ている。(ひとつの値の調整で済むならPID制御で世の中のほとんどのニーズは満たされるので『ゼロからはじめるPID制御』を読みましょう。名著中の名著です)出力がクリエイティブなものもあれば、むしろ一定にするために求められるものもあり、不思議な一致である。

ストーリーの普遍的な構造

飛躍とそうでないバランスを生成される文字列単位で調整していく感じは、実際に生体脳で文章を書く際の作業と変わらないと思う。そこをパラメータで数値で示されると、ストーリー作りにおける起承転結のようなグラフを思い起こした。仕事で紹介してもらった『ストーリーマッピングをはじめよう』で示された図を紹介しておこう。

P80より

これは古来より知られていたわけだけど、佐村河内氏の作曲メモでもあるように、時間軸の存在する表現(文章表現もまた読むのに時間が存在するのでこの範疇である)において、このようなカーブは普遍的なものなのだろう。

佐村河内氏の作曲メモ

佐村河内氏の「指示書」を基に制作 時間と楽器は記述なく…― スポニチ Sponichi Annex 芸能 より。

本書で実際に生成AIをパートごとに使って作った短歌を、温度パラメータでグラフ化したものがこちら。

生成時の温度パラメータグラフ。私が作成

温度パラメータは生成のランダムさ、つまり意外性。なので最初の「見えてくる」という人間の入力を温度0と考えてもよいだろう。そうすると、クライマックスに向けて一旦下がるストーリーの典型的なグラフになっていると思う。時代はとうとうストーリーカーブの擬似的だったはずの数値をそのまま機械が解釈して出力する段階まで来てしまった、というわけだ。

おわりに

新書なので、現時点でのある知識を伝えるためのものであり、生成過程を丁寧に追っていくところとかも技術の説明のためにされているはずなのだが、どことなく料理研究家のエッセイみたいなところがあって、そこが実は一番面白いのかもしれない

数種類の振動を作りたいなら専用の振動ドライバーDRV2605Lがおすすめ

AdafuritのDRV2605LモジュールにLRAアクチュエータを載せた

振動で色々試したいなら自分でタイミングと強さを制御するより振動モータードライバのDRV2605Lにある115種類のプリセットから選ぶほうが簡単。I2Cで制御できてアドレスが変えられないものの、I2Cマルチプレクサを使って複数個制御もすんなり出来た。

DRV2605L搭載のモジュール自体は、日本からの入手性だと毎度おなじみAdafruitかsparkfunなんだけど、AdafuritのほうがSTEMMA QT/Qwiicコネクタ(以下Qwiicにします)搭載してて楽ですね。AdafruitからはQwiicコネクタで分岐する8chのI2Cマルチプレクサ(PCA9548搭載)が出ているので、8個まで簡単にQwiicシステムで繋いで制御できる。

Adafruit DRV2605L 触感フィードバックモジュール — スイッチサイエンス
STEMMA QT/Qwiic - PCA9548搭載8チャンネルMux拡張基板 — スイッチサイエンス

SeeedのXIAOと拡張ボードからPCA9548につないでDRV2605Lにつながっている

115種類ってどんなの?

データシートからスクショを載せておきます。引用の範囲でしょう。Adafruitに英語はあるので日本語のやつにしました。自分が使った素子の限界的にはトリプルクリックはトリプルに感じなかった。いくつか同じエフェクトが載っているのは謎。

https://www.ti.com/product/ja-jp/DRV2605L

振動素子自体はERMとLRAのどっちがいいか?

ERMよりもLRAのほうが変な挙動になった時に安全な感じがあった。あと、振動がどちらかといえば上品で小さい振動の表現力が高く感じる。どっちにしろ下手な実装するとマイコンのフラッシュに書き込む部分が死ぬので気をつけてほしい。

実はDRV2605L側でディレイできる

setWaveform関数を使って0.01秒単位から1.27秒までディレイできる。エフェクトが127までで、それ以降の数字を書き込むとディレイって判断されるようになっているので。AdafuritのPythonの方では関数化していたが、なぜかArduinoにはなかったので自分で実装した。もっと良い書き方あると思うのでそこは勘弁して……。

Adafruit_DRV2605 drv;

// 1.27秒までdelay可能 
void driveMotorWithDelay(int effectIndex, float delayTime = 0){
  float dTime = delayTime;
  if(dTime <= 0.01 || dTime >= 1.27) dTime = 0;
  int castedDelay = (int) (dTime*100.0);
  uint8_t delayedVal = 0x80 | castedDelay;
  drv.setWaveform(0, delayedVal);
  drv.setWaveform(1, effectIndex);
  drv.setWaveform(2, 0);
  drv.go();
}

複数個制御するときの注意点

AdafuritのArduino用DRV2605ライブラリを使ったんだけど、Adafruit_DRV2605型を配列にして実装したら、変なエラーがたまに出た。たまに、なのでこれが厄介だった。I2Cマルチプレクサはマイコン側には同一アドレスを提供するのでシンプルに配列をやめて単体の変数にして制御したら問題なかった。最初からそうしておけば……。複数個動かす最低限のコードは多分これ。検証していないので、もし動かなくて修正して体力気力が余っていたらコメントでお知らせしてください。

#define PCAADDR 0x70
#define NUM_DRVS 7
Adafruit_DRV2605 drv;

void setup(){
  Wire.begin();

  for (int i = 0; i < NUM_DRVS; i++) {
    pcaselect(i);
    drv.begin();
    drv.selectLibrary(6);
    drv.useLRA();
    drv.setMode(DRV2605_MODE_INTTRIG);
  }
}

void pcaselect(uint8_t channel) {
  if (channel > 7) return;
  Wire.beginTransmission(PCAADDR);
  Wire.write(1 << channel);
  Wire.endTransmission();
}

void driveMotor(int motorIndex, unsigned char effectIndex){
  if(motorIndex == noMotorIndex || motorIndex < 0) return;

  pcaselect(motorIndex);
  drv.setWaveform(0, effectIndex);
  drv.setWaveform(1, 0);
  drv.go();
}