国立科学博物館「恐竜博2016」に行ってきました
先週末、日頃から不足している文学的な素養を摂取するため、上野で行われていた国立科学博物館「恐竜博2016」に行ってきました。
http://www.kahaku.go.jp/exhibitions/ueno/special/2016/dino2016/
足を運んだ6/12は奇しくも博覧会の最終日でした。そのためか入場者も非常に多く、50分待ちでようやく中に足を踏み入れることがきできました。
今回はスピノサウルスとティラノサウルスの二大共演、ということで、彼ら二人にスポットが当てられていました。スピノサウルスの寡聞にして知らなかったので、展示を見てみると、どうやらティラノサウルスの大きさをさらに上回る最大の肉食恐竜だということです。非常に学びばせていただきました。
展示の中で、恐竜の鳥盤類と竜盤類の違いを示してくれる、骨盤のイラストがあったのですが、素人目にはどちらが鳥盤類で、どちらが竜盤類なのか、はっきりとはわかりませんでした。しかも鳥盤類、残念ながら鳥類に進化することができず、竜盤類にその座を奪われるのですが、実は羽が生えていた鳥盤類もいた、みたいな混乱しか生まない説明があって、当時の恐竜たちの切磋琢磨の様子が垣間見えました。
それら以外では、パラサウロロフスの子供は頭の突起が親より短い、ゆえに親とは鳴き声がこんなふうに異なるんだよ、という展示があり、突起についての素晴らしい知見が貯まりました。
帰りには常設展にて、茸、その他の菌類等のオブジェも見学することができ、菌類についての今後の執筆の糧とすることができそうです。また一つ、上野の奥深さを知れました。やはり上野は最高ですね。
オライリー書籍風の表紙が作れるという「O RLY Cover Generator」を使って文学フリマ前日に同人誌を作成した
はてブにオライリー風の画像作成ツールの記事が上がっていたので、これを使って実際に同人誌を作成してみた。
今までにも本サークルではオライリーっぽい表紙を使った同人誌を作成しており、その作成法についても
に書いていたのだが、このジェネレータの存在を知れたおかげで超速で同人誌の表紙を作れるようになった。感謝しかない。
しかしこのジェネレータ、残念ながら日本語に対応していないらしく、上の画像を見てもらえばわかるがタイトルと著者名が出力された画像に埋め込まれていない。そこで、仕方がないのでSketchを使ってちゃちゃっと編集した結果、表紙画像が完成。
(勢いのある熊)
とりあえずいつものように入門舞城王太郎とか言いながら全然舞城王太郎に入門できない冊子(TensorFlow記事 + 小説数本)を配布することとなった。2016/05/01 の第22回文学フリマ東京ではケ-21にいるので、ご興味ある方は足を運んでください。
TensorFlowを用いた舞城王太郎の正体の類推
(これは第22回文学フリマ東京の原稿用に作成した記事です)
舞城王太郎は現代作家の中でも特異な地位を築いている。デビューは2001年、推理小説の文学賞であるメフィスト賞だが、2003年には純文学の賞である三島由紀夫賞を受賞している。文章は独自のスピード感のある文体で、デビュー作の『煙か土か食い物』では、アメリカ帰りの主人公の心情描写を、スラングを多用した文章により上手く表現していた。そんな舞城王太郎であるが、現在まで本名・性別等が不明の覆面作家であり、その正体を知る方法は現段階で存在しない。そこで本記事では、Google製の機械学習フレームワークであるTensorFlowを用い、舞城王太郎の正体をその文章から類推していく。
TensorFlow
TensorFlowはGoogleが開発した機械学習フレームワークで、特にディープラーニングをターゲットにしたものになっている。ディープラーニングとはニューラルネットワークの一形態であり、その分類タスクにおける識別率の高さから、近年注目を集めている。
まずはざっくりとニューラルネットとはなにかを紹介するため、以下のPythonコードで一層のニューラルネットの例を示す。
import math # 入力層: 単語に任意のインデックスをつけたもの # 入力A # 私 の 好き な もの は 寿司 だ 。 A = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 入力B # 私 の 好き な もの は ドッグフード だ 。 B = [1, 2, 3, 4, 5, 6, 10, 8, 9] # 出力: ノード数2 A_OUT = [1, 0] B_OUT = [0, 1] def softmax(xs): # ソフトマックス関数を定義 # 0から1までの間の連続値を得られる e = [math.exp(x) for x in xs] sum_e = sum(e) return [x/sum_e for x in xs] def hoge(inputs): weights = [0.1, -0.2] # 更新される適当な値 bias = 0.001 # 更新される適当な値 ret = [] for w in weights: # それぞれの入力値に重みをかけた値を加算 h = sum([input * w for input in inputs]) + bias ret.append(h) return softmax(ret) y1 = hoge(A) # -> これをA_OUTに近づけたい! y2 = hoge(B) # -> これをB_OUTに近づけたい!
ここで、関数hogeは入力値と重みとの計算を担っている。この関数に任意の長さのベクトルを入力することで、それぞれの入力値に対して重みをかけた和が計算され、例えば[0.91, 0.09]のような出力が得られる。このように、多数の入力に対して制限された出力が得られることが、実際の神経細胞の挙動とのアナロジーになっている。この際に、Aを入力した場合は出力A_OUT [1, 0]、Bを入力した場合は出力B_OUT[0, 1]となるように、重みwを設定すれば、入力値を分類することができる。(上のコードでは重みwの値を適当な値に設定している)。その重みwを決定する手法については様々なものが存在する。適切な結果を得るためには、その中から最も解決したいタスクにあてはまる損失関数や最適化手法を選び出し、結果を比較して、......と煩雑な手順を追う必要がある。そこで、それらの関数がパッケージングされたTensorFlowを用いることで、その手間を省くことができる。それでは、TensorFlowを用いた場合のコードを以下に抜粋する。
ph_x = tf.placeholder(tf.float32, [None, width]) ph_y = tf.placeholder(tf.float32, [None, NUM_CLASSES]) # 初期化 output_W = tf.Variable(tf.random_uniform([width, NUM_CLASSES], -1.0, 1.0)) output_b = tf.Variable(tf.zeros([NUM_CLASSES])) # 推定値の計算 --- 上記の式は実質この部分のみ! predicted_y = tf.nn.softmax(tf.matmul(ph_x, output_W) + output_b) # 交差エントロピーの計算 x_entropy = tf.nn.softmax_cross_entropy_with_logits(predicted_y, ph_y) # [Dimension(None), Dimension(4)] cross_entropy = tf.reduce_mean(x_entropy) # 急降下勾配法 learning_rate = 0.1 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cross_entropy) # 精度の計算 correct_prediction = tf.equal(tf.argmax(predicted_y, 1), tf.argmax(ph_y, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) num_epochs = 1000 batch_size = 100 init = tf.initialize_all_variables() sess = tf.Session() sess.run(init) for i in range(num_epochs): log("Start {0} epoch.".format(i)) random.shuffle(train_data) _train_x, _train_y = zip(*train_data[: batch_size]) sess.run(optimizer, feed_dict={ph_x: _train_x, ph_y: _train_y}) print(sess.run(accuracy, feed_dict={ph_x: test_x, ph_y: test_y}))
以上のように、TensorFlow組み込みの関数を用いることで、自分の手で最適化関数等を実装することなく、重みwの値を計算することができる。ところで、以上のコードを実行しても、残念ながら高い精度を得ることは出来ない。これは、テキストデータが、[4, 33, 2, 198, 67, 32, 1, 0, 0, 0, 0, 0, ... , 0]と隣り合った値同士の間が滑らかに変化しない(スパース)ことが原因のひとつである。この問題を解決する方法として、単語の埋め込み表現を用いる手法がある。これについては(http://tkengo.github.io/blog/2016/03/14/text-classification-by-cnn/)に詳しい。以下、引用先の作者が公開している関数を改変したコードにて、実際に小説の分類を行っていく。
舞城王太郎小説の分類
ここでは青空文庫から適当に取得した "坂口安吾"、"江戸川乱歩"、"折口信夫", "夢野久作"の4作家の作品から、いずれの作家の文章が舞城王太郎の文章に近いか、分類を行う。データについてはそれぞれ、青空文庫からスクレイピングしたものを用いた。それらのテキストについて、各作品毎に一文単位で分割を行い、それらを分かち書きしたものを使用してベクトルデータを作成した。それらのデータについて前述の分類器を作成した結果、0.5程度の精度を得ることができた(単純にランダムだと1/4 = 0.25程度の値になるはずだ)。以下にその学習過程をTensorBoardに出力したものを示す。
縦軸が精度で横軸がステップ数だが、15回付近からは精度の上昇が見られない。実際これ以上学習を続けても精度は0.4 ~ 0.6の間に収まるようだった。
ひとまずこの分類器を用いて、舞城王太郎『世界は密室でできている』を分類する。テキストはOCRを用いて抽出し、変換に失敗している箇所については目視で修正した。それを上記のような前処理を行い、ベクトル化した。そのデータについてランダムに100個分類器に入力し、出力値を平均した。すると、
# ["坂口安吾"、"江戸川乱歩"、"折口信夫", "夢野久作"] [ 0.63965601 0.14899535 0.12311091 0.08823783]
という値が得られた。この結果はビットが立った(1に近い)ラベルに対して分類されていることを示すので、少なくともこの四人の作家の中では、舞城王太郎の文章は坂口安吾の文章に近いことが推定される。実際に『世界は密室でできている』と坂口安吾の『織田信長』の出だしを見比べてみると、
舞城王太郎
何とかと煙は高いところが好きと人は言うようだし父も母もルンパパも僕に向かっ てそう言うのでどうやら僕は煙であるようだった。
坂口安吾
立入左京亮たてりさきょうのすけが綸旨二通と女房奉書をたずさえて信長をたずねてきたとき、信長は鷹狩に出ていた。
そうでもないような気もするが、安吾も推理小説を書いていたことだし、妥当な気もする。つまり、舞城王太郎の正体はなんと、坂口安吾であった(完)。
おわりに
以上、TensorFlowを用いて舞城王太郎の正体の類推を行った。今回は入手性の良い青空文庫の小説データを用いたが、現代作家の小説データを用いることによって、別の面白い結果が得られるかもしれない。小説に対する新しい切り口が欲しい、あるいはプログラミングや機械学習に興味の有る方は、これを機にこれらのツールを利用してみることをお勧めしたい。
- 作者: 舞城王太郎
- 出版社/メーカー: 講談社
- 発売日: 2005/04/15
- メディア: 文庫
- 購入: 8人 クリック: 39回
- この商品を含むブログ (179件) を見る
- 作者: 坂口安吾
- 出版社/メーカー: 角川書店
- 発売日: 2006/10
- メディア: 文庫
- 購入: 7人 クリック: 46回
- この商品を含むブログ (39件) を見る
- 作者: 岡谷貴之
- 出版社/メーカー: 講談社
- 発売日: 2015/04/08
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (10件) を見る
Python機械学習プログラミング 達人データサイエンティストによる理論と実践 (impress top gear)
- 作者: Sebastian Raschka,株式会社クイープ,福島真太朗
- 出版社/メーカー: インプレス
- 発売日: 2016/06/13
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
Pythonでカクヨムから小説のデータを拾ってきてMongoDBに入れるやつ作った
Pythonでカクヨムから小説のデータを拾ってきてMongoDBに入れるやつ作った。
といっても、BeautifulSoupでhtmlをパースしただけなので、まあ、それだけの内容。一応タグ検索もできるようにしておいた。あと、念の為分かち書きもしておいた。どう使うかはまだ未定。
青空文庫と違ってエピソード毎に別ページになっているので、データ取るのにurlを追っていく必要があったのが若干面倒だった。また、MongoDBは初めて使ったので、まだあまりどういうクエリ投げたら良いのかよくわかっていない。とりあえず、IntelliJのMongo pluginが便利っぽいということがわかった。GUI便利。
(Mongo pluginの見た目はこんなかんじ。葉っぱが可愛い。)
- 作者: Kyle Banker,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/12/14
- メディア: 大型本
- 購入: 5人 クリック: 55回
- この商品を含むブログ (8件) を見る
JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック
- 作者: クジラ飛行机
- 出版社/メーカー: ソシム
- 発売日: 2015/08/31
- メディア: 単行本
- この商品を含むブログ (2件) を見る
『入門 舞城王太郎』構成メモ
第二十二回文学フリマ東京にて出品予定の、『入門 舞城王太郎』の構成メモです。現状原稿が3%くらいしかできていませんが、自らを追い詰めるためにとりあえず公開してみます。おもしろい本ができるといいですね。
## イベント当日
2016/5/1(Sun)
## 原稿締め切り
+ 原稿〆
4/11
↓編集後
+ 印刷〆
4/18
## 全体構成
1000文字 / 1ページくらいの計算で、
+ 表裏表紙 4ページ
+ 前文 1 or 2ページ
+ 目次 1 or 2ページ
+ 本文 24 or 28ページ
## タイトル
入門 舞城王太郎
(実態は別に入門書でもなんでもない)
## レビュー 4ページ(舞城)
400 文字 * 8
or 800文字 * 4
### 手元にあるやつ
+ スクールアタック・シンドローム
+ 熊の場所
+ 好き好き大好き
+ 世界は密室でできている
+ コールドスナップ(番外)
### 既読
+ 煙か土か食い物
+ 暗闇の中に子供
+ 九十九十九
+ ディスコ探偵水曜日
+ みんな元気
+ スピードボーイ
+ 阿修羅ガール
+ 山ん中の獅見朋成雄
## 自由創作 16ページくらい?
短編 or 掌編
## 技術文書
8ページくらい?
(舞城王太郎の正体を当てる(無理))
## 料金
予算¥10000ぐらいとすると、(4 + 28)ページ * 40部 + 送料¥1000 でちょうどぐらい。
¥500で20部売ると印刷代相殺。30部売るとイベント代相殺。
金を積むとページ数と部数が増やせる。
(最近のは全然読んでないので辛みがある)
テーマ小説:「一行目に死体」(森田さえ)
メンバー全員が同じテーマで小説を書いています。今回のテーマは「一行目に死体」です。
あることの罪(テーマ:一行目に死体)
森田さえ
ワカバくんを殺した。
ワカバくんというのは私の実家近くにあった大きいスーパー『ひなげし屋』のマスコットキャラクターで、ある日仕事から帰宅したらハムを食べていた。私の冷蔵庫から、私のハムを取り出して食べていた。
続きを読む