さて、先ほどからWord2Vecの事前訓練されたモデルで遊んでいるのですが、なんでしょうか、私の性格なんでしょうか。ちょっとアホっぽいことをしてみたので報告です。
ベクトルで演算
Word2Vecが登場したとき、何より衝撃的だったのが、
"King" - "Man" + "Woman" = "Queen"
のような演算が成り立ってしまうという性質でした。今回ダウンロードしたGoogle Newsのデータセットにおいても、このような「演算」が正しく機能することが確認できています。
>>> woman=model.word_vec('woman')
>>> man=model.word_vec('man')
>>> king=model.word_vec('king')
>>> model.similar_by_vector(king+woman-man)
[('king', 0.8449392318725586),
('queen', 0.7300517559051514),
('monarch', 0.6454660892486572),
('princess', 0.6156251430511475),
('crown_prince', 0.5818676948547363),
('prince', 0.5777117609977722),
('kings', 0.5613663792610168),
('sultan', 0.5376776456832886),
('Queen_Consort', 0.5344247817993164),
('queens', 0.5289887189865112)]
というわけで、もうちょっと突っ込んで調べてみます。
うちの子、変なサイト見てないかしら?
というわけで、一応チェックしてみましょう。英語圏で、「つかってはいけないことば」というと、いろいろ思い浮かびますが、まずは、オーソドックスなところから。
>>> bitch=model.word_vec('bitch')
>>> model.similar_by_word(bitch+man-woman)
[('bitch', 0.8564847111701965),
('bastard', 0.669918417930603),
('ab_****', 0.64471036195755),
('asshole', 0.6431282162666321),
('bitches', 0.6380548477172852),
('sh_*_t', 0.633110761642456),
('****_ing', 0.6228429079055786),
('ab_*_tch', 0.6208170652389526),
('motherf_*_cker', 0.6205917596817017),
('b_*_tch', 0.6193116903305054)]
いい感じですね…じゃないよ、Word2Vecたん、私は君をそんな子に育てた覚えはないぞ!どこでそんな言葉覚えたの!じゃねーや、これは事前学習モデルなのでした。いうなれば、人んちの子ですね。育だてたの私じゃないや。
さて、私は男女平等主義者ですので、平等のため、今度は女性をけなしてみます。
>>> bastard=model.word_vec('bastard')
>>> model.similar_by_vector(bastard-man+woman)
[('bastard', 0.8564051389694214),
('bitch', 0.6785492897033691),
('whore', 0.6162934303283691),
('fucker', 0.5918644666671753),
('cunt', 0.5889722108840942),
('f_**_ker', 0.5843901634216309),
('bitch_bitch', 0.578224778175354),
('b_****', 0.5725700259208679),
('b_tch', 0.5613954663276672),
('poofter', 0.5606868267059326)]
まったく、どこでこんな言葉を覚えたんだか。さては、学習中にニュースのコメント欄まで見たな?まったく、教育がなっていませんね。というわけで、このデータセットには、コメント欄に書き込まれたと思われる「活きた英語」のエッセンスが詰まっていると言えそうです(というのは冗談で、実際、スパム除けなどデータセット問わず使えないと困るわけですから、汚い言葉は教えません、というわけにはいかないのですね。それはそれで、バイアスがかかってしまいます)。
意識の高さについて
では、ちょっとレベルアップしてみます。わたしはさわかかリベラルお兄さんですので(大噓)、差別や偏見に対して並々ならぬ関心を持っており、執念深くチャックせずにはいられません。というわけで、一応チェックしておきましょう。
>>> gay=model.word_vec('gay')
>>> model.similar_by_word(gay-man+woman)
[('gay', 0.9014886021614075),
('lesbian', 0.8471821546554565),
('lesbians', 0.7451958656311035),
('homosexual', 0.7309144735336304),
('gays', 0.7202851176261902),
('transgender', 0.7202324271202087),
('LGBT', 0.7156832814216614),
('transgendered', 0.7055658102035522),
('openly_gay', 0.6878846287727356),
('GLBT', 0.6843085885047913)]
大丈夫ですね!意識高い系です。さっき出てきたような○○や××が出てきたらどうしようか(それはそれで、問題提起にはなるので)と思って心配していたのですが、この辺はちゃんと社会問題に気を配れる子に育っているようです。というか、さすがにNewsのコメント欄で、そこまであからさまにヘイトをむき出しにするアホはいない、という現実を反映しているのでしょう。Redditとかで学習したら、また違った結果が得られるかもしれません。
>>> terrorism=model.word_vec('terrorism')
>>> person=model.word_vec('person')
>>> model.similar_by_word(terrorism+person)
[('terrorism', 0.8485373854637146),
('terror', 0.7193317413330078),
('terrorist', 0.696196436882019),
('terrorists', 0.6262702345848083),
('person', 0.6148209571838379),
('Terrorism', 0.6118570566177368),
('combating_terrorism', 0.5975246429443359),
('extremism', 0.5839695334434509),
('violent_extremism', 0.5613681077957153),
('counter_terrorism', 0.5583726167678833)]
ちょっと前、ハリウッドのキャスティングの問題などがとりだたされましたが、この辺も特定の値域や国名は出てこない模様です。よきよき。Google Newsという名のデータセットですので、差別や偏見に関しては(男が強盗という男女差別以外)あまり出てこないようです。学習元データの性質を鑑みると、まぁ、想像通りとも言えます。
次は、政治について。
>>> model.similar_by_vector(politics-moral)
[('politics', 0.569627046585083),
('Politics', 0.4076031446456909),
('partisan_politics', 0.30702513456344604),
('politicking', 0.2936311364173889),
('Prose_bookstore', 0.29052066802978516),
('Tom_Wrobleski', 0.28232768177986145),
('bussines', 0.2727702260017395),
('Shelley_Rigger', 0.2725592851638794),
('gubernatorial', 0.2722199559211731),
('consultant_Chip_Felkel', 0.26554185152053833)]
partisan politicsというのは聞いたことがなかったので、調べてみました。
partisan politics 派閥中心の政治、党利党略を事とする政治
すばらしいですね!よくお分かりのようです。politickingというのも、
the action or practice of engaging in political activity.
だそうで、これもいい感じです。てか、個人名が出てますねw どれどれ…
Tom Wrobleski is the Senior Opinion Writer for the Staten Island Advance. Political buzz
政治ライターの方のようです。News記事ばっかり読んで成長しただけありますね!Shelly Riggerという方は、どうやら大学で政治を教えている教授の方のようです。
I am the Brown Professor of East Asian Politics. I teach courses on East Asian Politics, including domestic politics of East Asian countries and the ...
おそらく、有名どころなのでしょう。ちゃんと、政治に関心を持っているようで、よきよきです。私なんかより、よっぽど意識高い系ですね!
どの程度知恵が回るのか?
次に、どの程度知恵が回るのか、ちょっとクイズめいたものを試してみます。
>>> model.similar_by_vector(curry-india+japan)
[('curry', 0.7554013729095459),
('okonomiyaki', 0.6188266277313232),
('soba_noodles', 0.6012547612190247),
('soba', 0.5906989574432373),
('miso_soup', 0.5887420177459717),
('sukiyaki', 0.5874010324478149),
('yakisoba', 0.5857551693916321),
('tonkatsu', 0.5829911231994629),
('sushi', 0.5728225111961365),
('teriyaki', 0.5718619227409363)]
いい感じですね!Word2Vecの前評判通りです。どうやら、「カテゴリ」のような要素もベクトルの中に埋め込まれているみたいですね。基本的には、前後5つくらいの語との相関を見ているだけのはずなのですが、ここまでできるとは驚きです(いやね、わかってますよ。流行ったのは5~6年前でしたね。でも、当時は興味なかったんだもの。今更ながらの驚きです)。
次は、エンタメに関するテストです。
>>> cage=model.word_vec('Nicolas_Cage')
>>> stalone=model.word_vec('Sylvester_Stalone')
>>> model.similar_by_vector(cage-stalone)
[('Nicolas_Cage', 0.9715794324874878),
('Nicholas_Cage', 0.7560958862304688),
('Nic_Cage', 0.642621636390686),
('starring_Nicolas_Cage', 0.606022834777832),
('Johnny_Depp', 0.560818612575531),
('Bruce_Willis', 0.5553238987922668),
('Val_Kilmer', 0.5407006740570068),
('NICOLAS_CAGE', 0.5350205898284912),
('actor_Nicolas_Cage', 0.5348377227783203),
('Robert_Downey_Jr.', 0.530608057975769)]
>>> model.similar_by_vector(stalone-cage)
[('BFN', 0.23132316768169403),
('Calgary_Alberta_T2E', 0.22807076573371887),
('MRSC', 0.22625434398651123),
('By_David_Latva', 0.22395989298820496),
('BY_TAD_REEVE', 0.2237454652786255),
('By_RAMON_GONZALEZ', 0.2209521234035492),
('Mallams', 0.21769872307777405),
('Pitney_Bowes_sanofi_aventis', 0.21566005051136017),
('VG_Somasekhar', 0.21381495893001556),
('Ky.Busch_##-###', 0.21320927143096924)]
断然、ニコラスケイジ派ですね。ニコラスケイジからスタローンを引いてもなお、ニコラスケイジが山ほど出てきます。なんという、ニコラスケイジ愛でしょう(おそらく、一時ミーム化していたのが原因だと思われますが、ここではそれには目をつぶります)。
私は両者とも好きなのですが、Word2Vec的にはニック>>>>>>>>>>>スタローンという結果です。いやー、ランボーとかロッキーとかあるじゃん!ぶっちゃけ、カリフォルニア州知事の人よりは、スタローンの方がいい役者だと思うよ、あたしゃ。ただねー、やっぱりニコラスケイジに軍配が上がるか…その熱いニコラス・ケイジ愛には、敬意を表するぜ。
では、映画の評論についても聞いてみましょう。
>>> goonies=model.word_vec('Goonies')
>>> model.similar_by_vector(goonies-childhood+violence)
>>> model.similar_by_vector(goonies-childhood+violence)
[('Goonies', 0.6705218553543091),
('violence', 0.5451825261116028),
('Jackass_Number_Two', 0.4495583772659302),
('SAW_IV', 0.44009798765182495),
('bloodshed', 0.4392278790473938),
('Hitcher', 0.43368732929229736),
('slasher_films', 0.4307764768600464),
('Expendables', 0.42986446619033813),
('Shoot_Em_Up', 0.42471843957901),
('THE_LAST_EXORCISM', 0.4171677231788635)]
いいですね!にわか映画評論家など、AIにとって代わられてしまえ!
とはいうものの、そういう映画評を読んだり、あるいはレコメンデーションをみたりして、これらの関係を学習した、というのがどちらかと言えば本当のところかもしれませんね。
>>> great_director=model.word_vec('John_Carpenter')
Traceback (most recent call last):
File "<pyshell#135>", line 1, in <module>
great_director=model.word_vec('John_Carpenter')
File "D:\WPy64-3740\python-3.7.4.amd64\lib\site-packages\gensim\models\keyedvectors.py", line 468, in word_vec
raise KeyError("word '%s' not in vocabulary" % word)
KeyError: "word 'John_Carpenter' not in vocabulary"
前言撤回。カーペンター知らんとか、あり得ん。
ちなみに、ここに載せたのは、面白い結果が出たものだけで、無意味な結果が出た組み合わせもかなりありましたが、おおむね、皆さんがWord2Vecに期待するようなことはちゃんとできる「事前学習モデル」に仕上がっている模様です。
まとめ
AI児童相談局の局員(嘘です、そんな機関ありません)として、本日はGoogle NewsのVec2Word事前学習モデルの生育環境について調査しました。わかったことは以下の通り。
- 意識は高いです。良い教育がなされているようでなによりです。
- どうやら、コメント欄で汚い言葉をたくさん学んでしまったようです。
- 政治や差別問題に対する関心度も高いです。
- 国別のソウルフードに関する知識があります。
- ニコラスケイジの大ファンです。
- 映画に関するふわっとした知識がありますが、通を自称するには程遠いようです。
というわけで、特殊な用途でないかぎり、かなり使えるモデルとなっています。
追記
英語版Wikipediaモデルに対しても同じテストを行ってみました。ただし、こっちは単語ベクトルが100次元です。
>>> woman=model.word_vec('woman')
>>> man=model.word_vec('man')
>>> king=model.word_vec('king')
>>> model.similar_by_vector(king+woman-man)
[('queen', 0.8457585573196411),
('king', 0.8274621367454529),
('laungshe', 0.7595417499542236),
('monarch', 0.7563580870628357),
('chelna', 0.7521730661392212),
('kencanawungu', 0.7423793077468872),
('ENTITY/Queen_consort', 0.7410599589347839),
('indlovukati', 0.7401788234710693),
('kamamalu', 0.7386809587478638),
('indlovukazi', 0.7368212342262268)]
>>> bitch=model.word_vec('bitch')
>>> model.similar_by_word(bitch+man-woman)
[('bitch', 0.8316709995269775),
('shit', 0.7947832942008972),
('skeng', 0.7863730192184448),
('muthafucka', 0.7848220467567444),
('fuck', 0.7817752361297607),
('fuckin', 0.7808419466018677),
('twocker', 0.7776740789413452),
('bustas', 0.7733064889907837),
('bredda', 0.768684983253479),
('patrolla', 0.76748126745224)]
>>> bastard=model.word_vec('bastard')
>>> model.similar_by_vector(bastard-man+woman)
[('bastard', 0.8320407867431641),
('meridon', 0.7192807197570801),
('bessee', 0.6995130181312561),
('whore', 0.6991021037101746),
('mistress', 0.6975896954536438),
('octaroon', 0.6949803829193115),
('lycheas', 0.6938990354537964),
('gʷal', 0.6891276836395264),
('humfrye', 0.6851904988288879),
('bitch', 0.6829589605331421)]
「Wikipediaがソース」なので、あまり汚い言葉は出てこないのかな?と思いきや、「決して口にしてはいけないあの単語」が出てきてしまいました。いやー、大人だねぇ。もう、すっかり親の手は離れている印象です。だって、"basterd"-"man"+"woman"="mistress"だよ?ちょっと末恐ろしいものを感じますね。お次は社会派テスト。
>>> gay=model.word_vec('gay')
>>> model.similar_by_word(gay-man+woman)
[('lesbian', 0.8998805284500122),
('gay', 0.8944599628448486),
('ENTITY/Lesbian', 0.8590006828308105),
('transgender', 0.8332474231719971),
('lesbians', 0.8171658515930176),
('transsexual', 0.8096974492073059),
('bisexual', 0.8067201375961304),
('transgendered', 0.7980079650878906),
('lgbt', 0.7936180830001831),
('ENTITY/Transgender', 0.7851778268814087)]
>>> terrorism=model.word_vec('terrorism')
>>> person=model.word_vec('person')
>>> model.similar_by_word(terrorism+person)
[('terrorism', 0.8620970845222473),
('megamarch', 0.794232964515686),
('aggrivated', 0.7920218706130981),
('abbetting', 0.787476658821106),
('perpetrations', 0.7787527441978455),
('jailable', 0.7731642723083496),
('ipict', 0.7723826169967651),
('jatf', 0.7695428133010864),
('nactag', 0.7682520747184753),
('premeditate', 0.7656387090682983)]
>>> politics=model.word_vec('politics')
>>> moral=model.word_vec('moral')
>>> model.similar_by_vector(politics-moral)
[('politics', 0.4477155804634094),
('ENTITY/Keith_Kyle', 0.39658480882644653),
('whynott', 0.3938559293746948),
('štětina', 0.38984739780426025),
('ENTITY/Raine', 0.3789065480232239),
('ENTITY/Party_switching', 0.3770643472671509),
('jayapal', 0.3693163990974426),
('ENTITY/Sandy_Lee', 0.36561235785484314),
('ENTITY/Norm_Letnick', 0.36485815048217773),
('nebbeling', 0.3635249137878418)]
>>> india=model.word_vec('india')
>>> japan=model.word_vec('japan')
>>> model.similar_by_vector(curry-india+japan)
[('sushi', 0.6673777103424072),
('curry', 0.6664444208145142),
('robatayaki', 0.6561501026153564),
('tenmusu', 0.6559689044952393),
('cheeseburger', 0.6551221609115601),
('wasabi', 0.6525880098342896),
('iwatake', 0.6514559388160706),
('sōki', 0.6505682468414307),
('battera', 0.6457744836807251),
('toriten', 0.6383465528488159)]
基本、Newsのデータセットで学習したモデルより、小難しい言葉が多い印象です。あと、途中で気づいたのですが、Wikipediaのモデルは、全て小文字で統一されている模様。LGBTではなく、lgbtという表記です。国名も、Indiaだとヒットしなくて、indiaだとヒットします。この辺、データの前処理がどうなっているかで使い勝手が違ってきますから、一応、チェックしておいた方がいいですね。安易にKeyErrorで未知語扱いにするという方法だと、(辞書はモデルごとに作られるので)がっつり精度が落ちそうです。
エンタメテストの結果は、やはり オタクの執筆率が高い Wikiepdiaだけあって、かなり詳しいです。よって、追加でいくつかテストしてみました。
>>> stalone=model.word_vec('ENTITY/Sylvester_Stallone')
>>> model.similar_by_vector(cage-stalone)
[('ENTITY/Nicolas_Cage', 0.45467862486839294),
('ENTITY/Mamah_Borthwick', 0.3961658775806427),
('ENTITY/Antitype_suda', 0.3748948872089386),
("ENTITY/St_Joseph's_College,_Gregory_Terrace", 0.3732898533344269),
('nox', 0.36867159605026245),
('ENTITY/Columbus,_Wisconsin', 0.3500910997390747),
('ENTITY/McKinnon_Secondary_College', 0.3459416329860687),
('ENTITY/Belvedere_College', 0.3391459882259369),
('ENTITY/Miskolc_Opera_Festival', 0.3386850357055664),
('gumwood', 0.33615365624427795)]
>>> model.similar_by_vector(stalone-cage)
[('ENTITY/Sylvester_Stallone', 0.5280905961990356),
('ENTITY/Franz_Beckenbauer', 0.3824656009674072),
('ENTITY/Conformation_show', 0.3822801113128662),
('ENTITY/Alaskan_husky', 0.38017332553863525),
('ENTITY/Osvaldo_Ardiles', 0.3709079623222351),
("ENTITY/Ballon_d'Or", 0.3702007234096527),
('brard', 0.36867061257362366),
('altig', 0.36714494228363037),
('ENTITY/Beats,_Rhymes_and_Life', 0.3641619384288788),
('ENTITY/Ron_Atkinson', 0.36213022470474243)]
情報量が多い方が良いだろう、と思い込んでENTITYグラフありのデータをいただいたのですが、もしかしたら削った方がいいかもしれませんね。変な雑学だけやたらと出てきて、逆に使い勝手が悪いかも。ただし、Wikiepdaコーパスの場合、個人名はENTITYとされているようで、たとえばNicolas_Cageとかでベクトル化しようとするとエラーになります。この辺、ENTITYなしのグラフだと、ちゃんと単語として登録されているのか?は確かめてみる必要があるかも。
>>> goonies=model.word_vec('ENTITY/The_Goonies')
>>> childhood=model.word_vec('childhood')
>>> violence=model.word_vec('violence')
>>> model.similar_by_vector(goonies-childhood+violence)
[('ENTITY/The_Goonies', 0.9154127240180969),
('ENTITY/Lethal_Weapon_(franchise)', 0.6440985202789307),
('goonies', 0.6347517967224121),
('ENTITY/Captain_Ron', 0.6293898224830627),
('ENTITY/Flesh_Gordon', 0.6252940893173218),
('airheads', 0.6218641400337219),
('ENTITY/Scarface_(1983_film)', 0.6211408376693726),
('disorderlies', 0.619423508644104),
('ENTITY/Desperate_Teenage_Lovedolls', 0.6168558597564697),
('ENTITY/Big_Trouble_in_Little_China', 0.6164947748184204)]
な、なんと!巨匠カーペンター監督のあまり有名ではない名作「Big_Trouble_in_Little_China」が出てくるではありませんか!さすが、Wikipedianから映画の全てを学んだAIです。GoogleのNewsコーパスで育った半端モノの映画通気取りとは格が違いますね!
>>> spielburg=model.word_vec('ENTITY/Steven_Spielberg')
>>> carpenter=model.word_vec('ENTITY/John_Carpenter')
>>> they_live=model.word_vec('ENTITY/They_Live')
>>> model.similar_by_vector(they_live-carpenter+spielburg)
[('ENTITY/Steven_Spielberg', 0.7100414037704468),
('ENTITY/They_Live', 0.6687114238739014),
('ENTITY/Tom_Hanks', 0.5868253707885742),
('ENTITY/1941_(film)', 0.5711009502410889),
('ENTITY/File:Harrison_Ford_by_Gage_Skidmore_2.jpg', 0.5672974586486816),
('ENTITY/Little_Monsters', 0.557258129119873),
('ENTITY/Steven_Spielberg_filmography', 0.5565926432609558),
('spielberg', 0.55604088306427),
('ENTITY/Night_at_the_Museum:_Battle_of_the_Smithsonian', 0.5557143688201904),
('ENTITY/Starship_Troopers_(film)', 0.5532141923904419)]
この辺は、あまり意味のある結果ではないかなぁ。ただ、「スターシップトゥルーパーズ」や「ナイトミュージアム」が出てきていますね。They liveとはこれっぽっちも関係ないけど、まぁ、面白い映画だからいいじゃない!
>>> model.similar_by_vector(they_live+childhood)
[('ENTITY/They_Live', 0.9393831491470337),
('creepshows', 0.6927489638328552),
('ENTITY/Where_the_Heart_Is_(1990_film)', 0.6882932186126709),
('ENTITY/Alice_Johnson_(A_Nightmare_on_Elm_Street)', 0.6854841709136963),
('ENTITY/John_Carpenter', 0.6824600696563721),
('deathdream', 0.6811120510101318),
('ENTITY/Michael_Myers_(Halloween)', 0.6807911396026611),
('ENTITY/File:Zombies_NightoftheLivingDead.jpg', 0.6744834780693054),
('evictors', 0.6740228533744812),
('ENTITY/Hell_Comes_to_Frogtown', 0.6734421253204346)]
感覚的には、ちょっとずれていますが、知識は豊富です。ちなみに、Hell_Comes_to_Frogtownというのは知らなかったのですが、検索してみたところ、意外とB級映画好きにはたまらない作品のようでした…これは、上手く使えばレコメンデーションシステムとして、意外といい性能を出すのではないでしょうか。他にもちょこちょこ試してみましたが、質はともかく、量はかなり期待できる感じです。さすがWikipedia。見たこともないような映画の名前が、ちらほら出てきます。
一方で、質がいい類推結果が得られることもあります。例えばこんなのはどうでしょうか、映画通の皆様。
>>> close_encounters=model.word_vec('ENTITY/Close_Encounters_of_the_Third_Kind')
>>> the_thing=model.word_vec('ENTITY/The_Thing_(1982_film)')
>>> model.similar_by_vector(close_encounters+the_thing)
[('ENTITY/The_Thing_(1982_film)', 0.8928110599517822),
('ENTITY/Close_Encounters_of_the_Third_Kind', 0.8825620412826538),
('ENTITY/Alien_(film)', 0.7765381932258606),
('ENTITY/John_Carpenter', 0.738431453704834),
('ENTITY/Total_Recall_(1990_film)', 0.7298462390899658),
('ENTITY/Star_Wars_(film)', 0.7286167740821838),
('ENTITY/2010:_The_Year_We_Make_Contact', 0.7231775522232056),
('ENTITY/Jaws_(film)', 0.7221399545669556),
('ENTITY/2001:_A_Space_Odyssey_(film)', 0.7210553884506226),
('ENTITY/Silent_Running', 0.7210255265235901)]
もちろん、映画通の皆様におかれましては、このリストにある作品くらい、二度や三度は見たことがあると存じます。どうです?未知との遭遇と、物体Xをたすとこれらの作品になるそうです。個人的には、どちらかと言えばマイナーな「Silent Running」がランクインしているところ、好感が持てます。一応、宇宙系SFでちょっとホラー/ミステリー感があるものがリストアップされているという気がします。
というわけで、ちょっと癖のある子ではありますが、データベースのような感じで利用するのなら、Wikipediaコーパスもアリかと思われます。ただし、ENTITYに関しては「ENTITY/The_Thing_(1982_film)」のように、Wikipediaのタイトルがそのまま使われており「ENTITY/The_Thing」とやってもヒットしませんでした。このあたり、改良が必要だとは思われますが…映画通として、可能性を感じずにはいられません!
以上です。