さて、このシリーズも4回目に入った。(直前(その3)の原稿を書き上げる前に次を書き始めるのは私の悪い癖です)今回は、金貨のコインの問題で素手で解いたのと同じことをAIのアルゴリズムでやらせる部分を読み解いてみることにしたい。今回のゴールは、武藤先生が論文で紹介されたアルゴリズムをきちんと理解することである。
ここで取り上げる金貨のパズル問題は、2つ前のブログpreprint AI論文を読む(その2)を見てください。
先生の論文の巻末にはPythonを37行のプログラムが掲載されている。
今回は、この37行が何をやっているのかを理解することで、何を与えることで、AIが何をやり
そのAIのために人間が何をやっているのか、AIと人間の境界を探ってゆきたい。
------------Python program 12coins.py ---------
import numpy as np
coins = [0,1,2,3,4,5,6,7,8,9,10,11]
H=np.zeros((12,12))
np.fill_diagonal(H,1)
L=np.zeros((12,12))
np.fill_diagonal(L,-1)
instance=np.append(H,L,axis=0)
def checkRules(B):
for i in instance:
balance=""
for j in B:
if (i[j[0]]+i[j[1]]+i[j[2]]+i[j[3]])>(i[j[4]]+i[j[5]]+i[j[6]]+i[j[7]]):
balance += '>'
elif (i[j[0]]+i[j[1]]+i[j[2]]+i[j[3]])<(i[j[4]]+i[j[5]]+i[j[6]]+i[j[7]]):
balance += '<'
else: balance += '='
rules.append(balance)
balance=""
if len(set(rules))==24:
break
from random import sample,seed
import random
random.seed(8)
for i in instance:
print(i)
for i in range(1000):
b1=sample(coins,8)
b2=sample(coins,8)
b3=sample(coins,8)
B=[b1,b2,b3]
rules=[]
checkRules(B)
if len(set(rules))==24:
コンピュータのプログラム言語は、魔法を解くための呪文と思えばいい
また、その魔法は、料理を作るのと同じやり方で理解できる
上のアルファベットの列を見て、げろげろげえと思われたかたもいるかもしれない。でもご安心。
コンピュータが動くのは機械語のレベルであり、大昔の言語BASICから最近のオブジェクト指向のJAVAや今日取り上げるPythonに至るまで、プログラム言語は、より人間にわかりやすく操作をまとめているにすぎないのである。コンピュータ言語はそうした操作のための手段であり、文法(ルール)である。今回はその文法を理解してゆくと思っていただければ幸いである。
上の37行を魔法の呪文と思って欲しい。
その呪文がどんなことをやろうとしているかをこれから解き明かしてゆきたい。
(難しそうに語る人はたくさんいるが、所詮人間のやっていることであると私は思っています)
上の37行のプログラムをそれぞれ次の3つの箱に分類してゆくことにしましょう。最後にやります。
こうした分類は他の分野、例えば、料理の世界でも使っている。どんな材料とレシピと機材で、どう調理して、何を作るか? 上のプログラムを料理のように解き明かしてゆきたい。
まずは全行の意味を理解する
料理と同じくプログラムの最初では色々な材料を揃えてなければならない。
自分の前にまな板があると思って欲しい、プログラムの最初はまず料理人がそのまな板に色々なものを取り寄せることから始まる。
import numpy as np
import命令は 道具箱(関数)を利用できるように近くに持ってくるための呪文です。
ここでは numpy (ナムパイと読みます)という道具箱(ライブラリー)を持ってきました。
このnumpyという道具箱は、誰でもタダで使える道具(公開されているライブラリー)です。
as np は、持ってきたnumpy をあだ名で np と呼ぼうと言ってます。
(モジュール名を持ってきたと同時に省略名を指定するときに使います)
さてこれを合わせるとimport numpy as npという呪文は
「numpyという道具箱を持ってこよう。ここではnpと呼ぶことにしよう。」という意味になります。
coins = [0,1,2,3,4,5,6,7,8,9,10,11]
ここから少し料理するための準備作業が始まります。プログラム言語にはそれぞれ特徴(癖)があります。その癖と文法を解きほぐし、一つ一つ何をやろうとしているかをみて行きましょう。
この行では、このクイズの対象となる12個の金貨を定義しています。あらかじめ番号をつけていて0番から11番となっています。この12個のコイン(データ)をまとめて表しているのが上の一行です。
「0番から11番までの名前のついた金貨を一つのお皿の上に置いて、そのお皿の名前をcoinsという名前をつけよう」という意味になります。
※Pythonではリストという機能で説明されていて、文字列、数値などと同じく、複数のデータをまとめて扱うときに使います。この機能は非常に便利で、何んかのデータをまとめて処理したいとき、またそのデータを持ってきて処理をしたいときに使います。
H=np.zeros((12,12))
np.fill_diagonal(H,1)
L=np.zeros((12,12))
np.fill_diagonal(L,-1)
さて、対象となる金貨はお皿の上に乗りました。ここからがパズル解きの始まりです。
上の3行目から7行目の4行をまとめて説明したいのでこのまとまりでみてください。
この4行は、人間が素手で考えるのと機械が考えるやり方の違いを端的に表す最初の例です。
それは全てを網羅的に考えるということです。
今回のパズルでは、1個だけ重さが違う金貨は潜んでいる、それは重いのか軽いのかはわからない。それをどう網羅的に表すのでしょうか?順番に見ていきましょう。
頭の中で、1個だけ金貨の重さが違う12個の金貨が並んでいるイメージをして見ます。こんな感じになりませんか? (いちばん最後の青色が違う金貨を表しています)
これが、12個のどれかわからないのですから、それを全部表現してみると次のようになります。
12通りに描けるはずです。
これをプログラム言語の中でどう表現したらいいでしょうか? ここが最初の味噌ですね。
それは行列式を使うということです。
上の12通りの表現を1と0(ゼロ)で表現して見ます。
そして、その上に、1を重いコイン、−1を軽いコイン という意味にすると、
上の組み合わせに加えて、−1を使った場合も表すことができます。
この24通りのパターンのどれかである。まずそれを網羅的に表しています。
H=np.zeros((12,12))
np.fill_diagonal(H,1)
L=np.zeros((12,12))
np.fill_diagonal(L,-1)
さてPythonのプログラムに戻ろう。この4行は上の24通りのパターンを表しています。
H=np.zeros((12,12))
12列×12行の列を作り、そのお皿の名前をHと呼ぶ、そして全ての数値をゼロ(初期化)にします。
※np.zerosは、初期化の関数です。
np.fill_diagonal(H,1)
お皿H の上にある12列×12行のそれぞれの列の対角線の位置にある数値を1に変える
※np.fill_diagonalは対角線上の数値を編集する関数です。
L=np.zeros((12,12))
同じように、12列×12行の列を作り、そのお皿の名前をLと呼び、全ての数値をゼロ(初期化)する
np.fill_diagonal(L,-1)
お皿Lの上にある12列×12行のそれぞれの列の対角線の位置にある数値を−1に変える
そしてその後の1行
instance=np.append(H,L,axis=0)
2つのお皿HとLを一緒にするため、新たにinstanceというお皿に移しかえる。そしてお皿の中のHとLの後ろに新たなスペースを確保する
※np.appendは配列末尾に要素を追加する関数です。
これでお皿の上に24通りのデータが揃ったことになります。
ここまで書いてきて、37行の説明にはかなり時間がかかりそうであることがわかってきました。
3回にに分けて行こう。今回は最初の環境設定(INPUT)までとします。
では、ここまでの部分、難しそうなプログラムを除いて私の解説だけ抽出して見てみましょう。
INPUTのまとめ
・numpyという道具箱を持ってこよう。ここではnpと呼ぶことにしよう
・0番から11番までの名前のついた金貨を一つのお皿の上に置いて、そのお皿の名前をcoinsという名前をつけよう
・coinsを使って12列×12行の列を作り、そのお皿の名前をHと呼ぼう、そして全ての数値をゼロ(初期化)にします
・お皿H の上にある12列×12行のそれぞれの列の対角線の位置にある数値を1に変えます
・同じように、coinsを使って12列×12行の列を作り、そのお皿の名前をLと呼ぼう、そして全ての数値をゼロ(初期化)にします
・お皿Lの上にある12列×12行のそれぞれの列の対角線の位置にある数値を−1に変えよう
・2つのお皿HとLを一緒にするため、新たにinstanceというお皿に移しかえる。そしてお皿の中のHとLの後ろに新たなスペースを確保する
わかったこと
1)プログラム言語で人間の思考と同じことをやらせようとした場合、用意すべきデータは網羅的に準備しないといけないことがわかった。今回は12個のコインが重いか軽いかを場合に分けて24通りのパターンを用意することになる。
(今回は簡単なパズルであるが、現実の世界はこうはいかない、実際用意すべきデータは揃わないのである。ここの部分は別の機会に)
2)またそれをどうプログラムの中で表現するかであるが、縦横のボックス上の0と1の行列式で表現することがわかった。
3)その行列式を使って、場合分けのために、1とか−1というフラグをつけることもわかった。
いよいよ次回は料理そのものに入っていきます。
いやぁ、DEEPですねぇ。
今回の参考図書です。