AIの今、日本の未来

こんにちは! 株式会社キスモの大越です。 先日こちらで開催された Midland Incubators' Meetup で登壇させていただき、 キスモの取り組みや描く未来についてお話させていただきました。

f:id:kodamayu:20171218113846j:plain

そこで語りきれなかったことがまだまだ沢山あるので、今回はキスモの取り組みや描く未来について、「AIの今、日本の未来」と題して熱く語りたいと思います!

AIの今 Part1

そもそもAIってなに?

AIが何なのか。なんとなくすごそうというイメージを持っている方は多いと思いますが、実際の中身をわかっている人は少ないと思います。 AIの権威であり、Stanford Universityの教授でもあり、自分が一方的に師匠だと思っているAndrew Ng先生がAIの概念について分かりやすく説明しているので、それを引用させていただきます。

AIが発達する前は、コンピューターにりんごやぶどうを理解させようと思った時に、色やへたの位置や形など、1つ1つに対応したプログラムを書く必要がありました。しかもいちごとりんごのように色や形が似ているものは、新しい判断基準をプログラムしなければいけませんでした。さらに同じりんごでも、画像の明るさによって明るい赤だったり、暗い赤だったり見え方も変わるので、その対応も困難でした。

f:id:kodamayu:20171218113946p:plain

これがAIになると、画像を大量に見せることでりんごやぶどうがどういうものか、勝手に理解してくれます。 これは驚くべき進歩で、これまでと違い、データを大量に見せるだけで画像や音、言語などを理解できるようになったのです!

f:id:kodamayu:20171218113955p:plain

AI と世界5大企業

Google, Facebook, Amazon, Apple, Microsoftら世界5大企業は、今AI開発に本気になっています。 人材獲得競争は激しく、Facebookザッカーバーグは世界的な画像認識コンテストの優勝学生に直接会いにいって口説くほど。Googleは社として「AIファースト」を掲げ、子会社のDeep Mindを中心にAI活用に向けて爆速で動いています。囲碁のプロに勝ったAIもDeep Mindが作っており、その知名度はAI界隈ではNo1の会社でしょう。 また、Amazon EchoGoogle Homeなどの音声AIアシスタントもついに日本で発売され、日々の生活をがらりと変えています。

例えば家に帰って音楽を聞くというシーンを思い浮かべてください。 スマホを開いて、アプリを起動し、ようやく音楽を再生。手が塞がっていたりすると荷物を置いたりと、さらに時間と手間がかかりますよね? Amazon Echo を使うとどうでしょう? 「Alexa, 音楽を流して」 この1言だけで、音楽を再生できちゃうんです! f:id:kodamayu:20171218114003p:plain 天気予報もスマホでいちいち検索しなくても「今日の天気は?」だけで教えてくれ、テレビや電気のリモコン操作も全部声だけでできてしまいます。手での操作は一切必要なし。便利ですよね!

日本の未来 Part1

音声認識

音声認識技術の進歩により実現した、音声AIアシスタント。すでにアメリカでは、その圧倒的便利さから多くの家庭で使われてているようです。

AmazonのCTOであるWerner Vogels氏は先日、今後のテクノロジーに関して「鍵となる破壊的技術は音声だ」と発言しました。 キスモも次の世の中を見据えた時に、AI技術による音声認識こそ時代を変えるテクノロジーだと考えています。今はスマホやパソコンなど指を使った操作が主流で、操作が難しく親しみ辛いところもありますが、これが音声を使ったより直感的操作に変わると、誰もが簡単にテクノロジーを使いこなすことができます。

キスモが描く音声認識の未来

キスモのミッションは「働く楽しさを、より身近に。」というもの。

f:id:kodamayu:20171218114917p:plain

これを実現するために現在は音声認識技術を核としたコールセンター業務の自動化に取り組んでいます。

コールセンターのクレーム対応はすごくストレスがかかり、辛い仕事です。また、定型文による応対もたくさんあります。そんな部分をAIで代替して、オペレーターの方は本当に困っているお客様の対応に専念する。本来やるべき仕事に注力してもらう。ここを目指して、今は取り組んでいます。 取材や会見などの記事を執筆する際も、本来は素晴らしい記事を作る部分に注力したいところだが、まず音声を聞いて全て文字起こしする作業が入ります。この文字起こしの作業は時間も手間もかかります。これもAIで代替できる部分であり、これにより本来注力すべき記事を書く部分に集中できます。

このように人がやらなくてもいい部分や、AIができる部分はどんどんAIに任せて、人は本来やるべきことに集中すべきです。本来やるべきことだからこそ、やりがいを感じ、働く楽しさを感じられるはずです。つまらない単純作業に時間を使うことを無くしていく。そして、より楽しい仕事、やりがいのある仕事に注力する。これが、キスモがまずはじめに目指す未来です。

また、音声認識が発達した先にはもっと素晴らしい世の中が待っているでしょう。 「ホテルを予約して」と言ってホテルを予約することは現在のAIでもそう難しくありません。しかし「来週東京に出張になった」と言って、その裏でやるべきことを汲み取り、ホテルを予約してくれて、電車の時間を調べてくれて、美味しいお店をリストアップしてくれて、寒いから厚着をした方がいいとアドバイスをくれる。こんなAIが実現したら欲しいと思いませんか?こんなワクワクするような、あったら欲しくなるようなAIを今後は作っていきたいなあ、と思っています。

こうして、やらなくていいことをやってくれるAIや会話を汲み取ってサポートしてくれるAIができたらどんな未来になるでしょう? 人は本来やるべきことだけに集中でき、やらなくていいことが増える分、仕事に携わらなければいけない時間というのも必然的に減っていきます。だって、平日の5日仕事、2日プライベートって配分おかしいですよね?普通半分半分にするべきです!

つまりキスモでもこういった世の中を目指しています。描いている未来ではプライベートと仕事の隔たりはありません。働きたい時に働ける世界。その中では3日仕事して4日はプライベートを思う存分楽しむでもいいですし、半年は海外で勉強、半年は日本で仕事でもいいですし、1つの仕事では飽きちゃうよという人は3つ仕事を掛け持ちしてもいいでしょう。とにかく自由に選べる世の中です!これによりプライベートも仕事もバランスよく楽しめ、人生がより豊かに、より楽しくなっていくなあ、とワクワクしています。

f:id:kodamayu:20171218134857j:plain

働く楽しさを、より身近に。その先にある豊かな人生。こんな世界であなたはどんなライフスタイルを選択したいですか?

AIの今 Part2

中国の加速度的な進歩

これまでは「アメリカの5大企業を中心としたAI開発が目覚ましい」というお話をしてきました。しかし、すごいのはアメリカの5大企業だけではありません。 最近は中国が驚異的なスピードでAI活用に着手しているんです! 国の1億7000万台もの監視カメラにAIを搭載されていますし、空港では顔認証AIによる検査、学食にも顔パスによる決済が導入されています。 最先端ですね!

ぜひ1度こちらの動画を見て欲しいです!

http://jbpress.ismedia.jp/articles/-/51826jbpress.ismedia.jp

記者の方が中国を適当に歩いて、監視カメラの映像から発見されるか試したもので、見事にAIを搭載した監視カメラにより、発見されています。 このように監視カメラAIは個人を識別することが可能で、犯罪者が監視カメラに映ったら瞬時に通知し、捕まえることができます。 これまで特定が難しかったひき逃げ犯も、監視カメラAIが車のナンバーで追跡して捕まえることができます。 今中国は世界一犯罪ができない国に、AI技術を以てなろうとしているのです!

監視カメラAIや空港での顔認証、学食での顔パス決済などこうした技術の導入スピードは圧倒的に中国が早いです。というか早すぎます…! さらにビジネスでのAI活用もさながら、研究分野でも世界を引っ張っていて、AI系の論文の発表数もアメリカと中国が常に1位を競っている状況で、進化は止まりません。

日本はAI後進国、テクノロジー後進国。悔しいですがAI企業を立ち上げた今、身をもって痛感しています。

何故中国のAI活用が進むのか?

中国のAI活用がなぜ進むのかについてはこちらの記事がとても分かりやすくまとめています。

president.jp

ここでもこちらの記事に沿ってお話させていただきたいと思います。

記事のタイトルになっている「中国のAIは"大したことはやってない"のか」についてですが、記事にもあるように大したことはやっていないでしょう。 というより、正しくはすごいAIは多くの人が作れてしまうのです。

それはなぜでしょう?

現在AIに関する研究は加速度的に進んでいて、AIで最も有名な国際学会の参加者も指数関数的に増えています。(このまま増えると2035年に全人口を超えるそうですよ)

そしてそういった最先端のコードはオープンソースで公開されています。つまり、誰でもその気になれば最先端のAIを動かすことができるのです。 これはつまり、中国も日本も技術的な差はほんの少ししかないということを示します。もしかしたら全く同じかもしれません。

では改めてなぜ中国はこんなにもAI活用が進んでいるのしょうか?

それは「現場での検証」、「データの数」この2点につきます。

まず1つめの現場での検証とはどういうことでしょう? AIの開発は基本的に検証して、精度を見て、さらにいいものに改善していきます。 f:id:kodamayu:20171218114012p:plain このサイクルを高速にたくさん繰り返すことこそ、いいAIを作るコツです。 AI企業を立ち上げてみて、感じていることとしては始める前から「精度どれくらい出るの?」「事前にわからなきゃできない」そう言った声がすごく多いということです。これが世界最先端のモデルを使っているという説明をしても、その声が変わることはありません。

これが中国では「いいよやってみよう。」に変わります。この差がAI開発においては決定的な違いになり、それが今の日本と中国のAIの圧倒的な差になっているのです。

2つ目の「データの数」も1つ目と近しい考え方になります。AI開発においてデータの量と質は性能のほとんどを決めると言っても過言ではありません。しかし、世の中にはデータが少なかったり全くないことが多いです。こういう時にも中国と日本とでは違いがあります。 日本では例のように、「精度がどれくらい出るかわからないのに、データを作る協力はできない」という声が多いです。

一方、中国では「データ?自由にとっていいよ。」と、こんな感じです。実際記事にもドローンで漁場の画像データを収集して、AIの学習に使っていると書いてありました。

日本の未来 Part2

どうすればAI活用が進むのか

先に見た日本と中国の違いはある種、国民性といってしまえばそれまでかもしれませんが、今後発展していくAIの分野においては、現場での検証こそが重要です。 この記事を読んで少しでも多くの人がAIの活用に向けてチャレンジしてくれるようになれば、嬉しいなと思います。 日本のAIを以て、海外をあっと驚かせましょう!

おまけ

どうしても描きたかったワクワクする技術の話

日本から出たことない自分にとって、アメリカから帰ってきた友人の話というのはとてつもなく刺激的で、ワクワクするような話にあふれていました。 その内容や、世界のテクノロジーは進んでいるんだぞという話をどうしても書きたかったので、ここで書きます。

まず最近デンマークが2030年に紙幣や貨幣の使用を禁止することを決めたというニュースがありました。デンマークだけじゃなくスウェーデンなど北欧の国では、現金を使う場面はほとんどありません。

これはアメリカに行った友人もそうでした。アメリカではvenmoという金融インフラをなすサービスがあります。食事の時の会計や、何か買い物をする時などvenmoで会計を行います。これの何がいいのか?

ずばり割り勘が簡単です!

大学生の自分は飲み会などで割り勘するシーンが増え、金額が合わなかったり、小銭がなくてお釣りのやりとりに困るシーンに多々出くわしました。これがボタン1つ押すだけで割り勘ができたらどうでしょう?「割り勘する」というボタンを押せば、お釣りも気にせずその場で口座から引き落とし。なんと便利なのでしょう! サークルなどの集団における買い物の会計も全てvenmo上で管理し、メンバーにボタン1つで請求することができます。

"venmo me!"

日本ではググるという言葉が普通に使われますが、アメリカではこの"venmo me!"という言葉が普通に使われます。ようは「venmoでお金送っておいて」ということです。 日本はまだまだ法規制とかがあるらしく、実現はまだまだなのかなと感じます。しかしこんな風に誰もが使う金融インフラでボタン1つでお金のやりとりができる未来がきたら、とても便利になりそうで、とってもワクワクしますよね!

venmo.com

また、中国では"WeChat"というサービスがあり、名刺を使わない文化が広まっているそうです。このサービスはいわゆるビジネスチャットのサービスですが、名刺がわりにIDを交換し、仕事のやりとり、書類のやりとり全て"we chat"上で行うそうです。

起業して名刺を渡すシーンが増えましたが、「こんなサービス欲しい!」と日々感じています。まだまだ名刺文化というのは無くなりそうにないですが、いつかそんな世界がきたら、今よりも仕事のやりとりが簡単にでき、そこのコミュニケーションにかかるコストが激減することで、本来必要な仕事の速度が高まっていくと感じています。

www.wechat.com

こんなにテクノロジーが浸透している世界で、日本が今のままでいいはずがありません。

より良い未来、より豊かな未来のためにキスモも活動を続けていきます。

reference

ザッカーバーグ自ら学生を口説く? 米国で激化するAI人材争奪戦

今後は音声を使った人間中心のシステムが主流になる--アマゾンCTO

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

データサイエンティストが知っておくといいpythonコーディングの知識

こんにちは株式会社キスモの役員の寺澤です。2回目の担当となります。 前回は高度な内容になってしまいましたが、今回は機械学習・データサイエンス始めたてでも役立つ内容としました。

今回の内容は、コーディングに関する内容となっております。使用言語はpythonのみで解説しますのでご了承ください。

f:id:kodamayu:20171211133000p:plain

機械学習をする分にはnumpy、pandas、scikit-learn、kerasなど有名なライブラリ、案件次第ではSQLHadoopのような並列分散処理エンジンを使えれば十分です。 新規の機械学習モデルを組む分にも線形代数ベイズの知識があれば、tensorflowなどの有名なライブラリで組むことができます。

過去にkaggleやDeepAnalyticsに関する記事があげられましたが、挑戦したことはあるでしょうか? 例えばこれらのコンペティションで、pythonを使って機械学習モデルの学習・推論をするだけなら、あまりコーディングに関して気にしないでしょう。 kaggleに上がっているコードを見たことあればわかると思いますが、コメントで処理をうまく解説すれば読めるコードにはなります。 githubに上がっているディープラーニングのモデルもその傾向が見られます。

ただし、仕事で機械学習モデルなどデータ処理を組み込んだアプリケーションを作ろうとすれば、それだけでは大変です。 プロダクトを作るにあたっては、コードの保守性(コードが綺麗でデバッグ・アップデートしやすいか)を担保する必要があります。 コーディングに気を使わなければ改善のしづらいプロダクトとなり、開発が円滑に進みません。 あまり関係はありませんが、先日話題になった、データ処理のPDCAを行えばいいやと思ったら、リッチな統計可視化が必要になって、web技術も使い大変だったという話1もありました。 何がいいたいかというと、仕事柄によっては、機械学習だけができればいいということではない、ということです。エンジニアリングスキルも必要となります。

本記事は、 アプリ開発機械学習モデルを組み込むデータサイエンティスト を想定した内容となります。 記事自体は長くなりますが、あまり踏み込んだ話はしませんので読むのには苦労しないと思います。 ドンピシャな人はぜひご覧ください。また、 コードを公開したり人に見せるような方 にも非常に役に立つ内容となりますので、 初心者データサイエンティストにもとても役に立つ内容となっております。

前置きが長くなりましたが、この記事ではpythonで知っておくといいコーディング方法を伝授します。

目次

linterを使おう

linterとは、プログラムの文法をチェックするツールのことをいいます。エラーの検知や書き方に対して自動で注意をするツールです。 pythonにもlinterが存在し、pep8やflake8といったツールがありますが、 flake8がオススメです 。flake8はpep8の拡張版となります。 自動エラーチェックの他にも、pep8に従ったコーディングルールを守れているかをチェックするので、自然とコードが見やすくなります。 flake8はpipでインストールできます。

pip install flake8
flake8 mycode.py # コマンドでチェックできます。

linter全てに言えることですが、大抵emacsvimsublime text、atomvscodeなどの有名なエディタでは、自動でflake8のコードチェックをする機能があります。 これを使えばコーディングにどの行にエラーが起きたかすぐにわかるようになります。入れたら必ず設定しましょう。

コードを書いているうちに「flake8に注意されるけど、コードをいちいち直すのが面倒」と思うこともあるでしょうが、自動で直してくれるツールもあります。 flake8準拠のコード修正ツールとして、autoflake8と言うものがあります。これもpipでインストール可能です。修正が面倒になったらこれを使うのもありですね。

pip install autoflake8
autoflake8 mycode.py # mycode.pyを自動修正したコードを出力

ただし、flake8に従うだけではいいコードが書けるとは限りません。以降で説明するpythonのコードテクニックなどを使えば、より好まれるコードが書けます。

便利な書き方を覚えよう

ここでは、プログラミングの基礎としてはあまり紹介されてはいないものの、pythonに組み込まれている便利な文法や関数を紹介します。

ジェネレータ

ジェネレータとはその名の通り、値を生成するオブジェクト(変数)のことです。 for文で用いることが多く、listと扱いが似てループするたびに指定した変数に値を代入します。 ジェネレータを使えばどういうコードが書けるか、例を挙げて解説します。

例えば、以下のようにwhile文を使う場合です。 while文は処理を書き間違えれば、ループを抜けないなどのバグに直面します。 しかもwhile文のバグはデバッグしづらいです。for文が使える場合はwhile文は好まれません。

import cv2  # opencvを使う前提です。
vid = cv2.VideoCapture(video_path)

frame = 0

while True:
    retval, img = vid.read()
    if not retval:
        break
    # 以降にフレームに対する処理
    frame += 1 # フレームを数える場合は行末に挿入

上記のように処理が長くなければ問題なく動きますが、そうでない場合、例えばframeが思った通りに加算されないバグに直面することも多々あります。 特にwhile文内の処理が長い場合には、コード読みづらく、デバッグも非常にしづらいです。 しかし、ジェネレータを使って処理を分ければ、読みづらさを改善でき、デバッグもしやすくなります。

def vid_iter(vid):
    # この関数がジェネレータ
    while True:
        retval, img = vid.read()
        if not retval:
            break
        yield retval, img

vid = cv2.VideoCapture(video_path)
fps = int(vid.get(cv2.CAP_PROP_FPS))

for retval, img in vid_iter(vid):
    some_process(frame, img) # while文に手をかけずに処理を行える

# 後に紹介するenumerateと合わせるとframeを数えられるようになります
for frame, (retval, img) in enumerate(vid_iter(vid)):
    print(frame / fps) # ループ毎にframeが加算される
    some_process(frame, img)

ジェネレータの書き方としては、関数の返り値に return の代わりに yield を使います。 上記の例では、for文のループ毎に yield の行までの処理を実行します。 yield 行の retvalimgfor 行の retvalimg に代入されます。 ただし、関数内の処理が全て終わらない限りはforループは続きます。 特に while を使う場合はループの終了に注意しなければなりません。デバッグをしやすいよう処理を絞るべきです。 ジェネレータは1ループごとで必要な値を受け取るだけの最小限の関数にしましょう。

ジェネレータにはもう一つの利点があります。 ループ毎に yield の行まで処理を行いますが、次のループまでその処理が停止することです。 画像処理をしたり、one-hotベクトルを作る場合に一度にそういったデータを読み込もうとすると、 読み込み切れずプログラムがエラーを吐くことがあります。 ディープラーニングなどミニバッチごとに学習を行う場合は、一度に読み込む必要はありません。 必要なものを必要な時点だけで読み込めれば、前述のエラーの対策ができます。 それを可能とする方法の一つがジェネレータとなります。読み込みやデータ加工処理をミニバッチごとに yield で返します。 すると各ループごとでのみ各ミニバッチを保持するので、ほとんどの場合は読み込み切れます。

内包表記

pythonではリスト内にfor文を書けます。そういった書き方は内包表記と呼ばれています。

以下のような冗長なfor文をひとまとめにできます。

data = [1, 2, 3, 4, 5, 6]
# 以下を...
new_data = []
for d in data:
    new_data.append(d * 2)
# 以下のように書ける!
new_data = [d * 2 for d in data]

また、内包表記では for を複数書けるので、以下のような複雑な処理も一つのリストに書けます。

# 以下のような複雑な処理に対しては...
for d in data:
    processed1, additional_data = some_process1(d)
    processed2 = some_process2(processed1)
    new_data.append((processed2, additional_data))

# こんな書き方も可能
new_data = [(processed2, additional_data)
            for d in data
            for processed1, additional_data in some_process1(d)
            for processed2 in some_process2(processed1)]

一般に、内包表記が使える場合は、内包表記を使ったコードの方が処理が早いです。

また、内包表記を使ってジェネレータを書くこともできます。前述のデータが読み込み切れないなどの問題に対処ができます。

new_data = (d * 2 for d in data) # タプルにはならないことに注意!
for d in new_data:
    some_process(d)

forを複数書ける性質を利用すれば、二重三重のfor文をひとまとめにでき、コードが見やすくなります。

# 以下のような二重ループも...
for epoch in range(100):
    for batch_X, batch_y in get_batch_data():
      loss = model.forward(batch_X, batch_y)
      print('epoch: ' + str(epoch), end='')
      print(' loss: ' + str(loss))
      model.backward()

# 一つにまとめることが可能(for文の書く順番に注意!)
itr = ((epoch, batch_X, batch_y)
       for epoch in range(100)
       for batch_X, batch_y in get_batch_data())
for i, batch_X, batch_y in itr:
  loss = model.forward(batch_X, batch_y)
  print('epoch: ' + str(epoch), end='')
  print(' loss: ' + str(loss))
  model.backward()

enumerate

リスト内の値とインデックス(順番)を一緒に扱いたくなるときありますよね? その場合に以下のように書かれることがあります。こういう書き方したことありますよね?

data = ['りんご', 'バナナ', 'みかん', 'ぶどう']

for i in range(len(data)):
    print(str(i) + '番目:' + data[i])

range(len(data)) とかちょっと冗長ですね。 この書き方をすると、インデックス i の指定を忘れることもありました。 そこで enumerate です。ループごとに数え上げてくれます。 以下の例では、実質 data のインデックスを数え上げます。

for i, d in enumerate(data):
    # dには for d in data と書いた時と同様、dataの要素を順に代入
    # iには0からスタートする自然数を順に代入
    # 出力は上記と同じ
    print(str(i) + '番目:' + d)
# のちに紹介する、formatを使えばもっと見やすくなります
for i, d in enumerate(data):
    print('{}番目:{}'.format(i, d))

ポイントは数え上げとリストの値を同時に取得できることにあります。 前述のような冗長さやヒューマンエラーを解消できますね。 前述でも紹介しましたが、enumerateはジェネレータに対しても使えます。

zip

zip関数、便利ですよね。すでに使われている方の方が多いと思い、ここでは基本の解説は省略します。 もし使い方のわからなければ、検索すればいくらでも出ますでそちらを。 ここでは応用的なことを解説します。

以下のような、二つの要素を順番に処理する書き方に対して、zip関数が使えます。

parsed_sentence = ['今日', 'は', 'すごく', '美味しい', '牛丼', 'を', '食べ', 'た']

for i in range(len(parsed_sentence) - 1):
    bigram_process(parsed_sentence[i:i+2])

インデックスを使ったfor文ですね。インデックスで調整するのは結構間違えやすいので避けた方がいいです。 それをzip関数で比較的改善できます。

# こう書直せます
for bigram_morph in zip(parsed_sentence[:-1], parsed_sentence[1:]):
    # bigram_morphの中身は ('今日', 'は'), ('は', 'すごく'), ... となる
    bigram_process(bigram_morph)

このコードでもインデックスの調整をしていますが、for文内ではインデックスを使っていません。 ずらして値を取る、最後尾の取り方の2点に着目すればこんな書き方もできます。

range

rangeも同様によく使われていますが、あまり使われていない応用方法も紹介します。 rangeは0から指定した値までを返すだけではなく、開始も指定できたり、いくつか飛ばして数え上げることもできます。

例えば、ミニバッチ学習をするとき、よく使うrangeの書き方は以下のようになります。

batch_size = 32
for i in range(batch_size):
    start = i * batch_size
    end = (i + 1) * batch_size
    fit(data[start:end])

ちょっと冗長ですね。かといって startend の内容を直接最後の行に書いても長くなります。 ここで、飛ばして数え上げる書き方を使いましょう。すると以下のようになります。

for i in range(0, len(data), batch_size):
    # i の中身は、 0, 32, 64, .. と32飛ばしになる
    fit(data[i:i+batch_size]) # 同様に batch_size分の処理が可能!

行数も減りましたし、インデックスの指定もそんなに長くないですね。

map, filter

pythonに標準で組み込まれている、 mapfilter の紹介です。 内包表記でも表現できますが、これらの方が有利な場合もあります。 以下が例となります。

# これらの表現は
new_data = [str(d) for d in data]
new_data2 = [d for d in data if d > 10]

# 同様にこのように書ける
new_data = list(map(str, data))
new_data2 = list(filter(lambda x: x > 10, data))

# mapやfilterはジェネレータなので読み込みの効率もよくなる
for d in map(str, data):
    some_process(d)

mapやfilter内にlambda式を書かなければ内包表記よりも処理が早いそうです。

format

文字列の中に変数の値を入れたいときが多々ありますよね。 文字列を + でつなげると冗長になりますよね。 + を書き忘れてしまうこともあります。 formatを使えば見やすくもなりますし、冗長性も解消できます。 以下が例となります。

# プラスを使った書き方
name = 'John'
print('My name is ' + name + '.')

# formatを使った書き方
print('My name is {} .'.format(name))

# 小数点2桁までの表示も可能
pi = 3.14159265
print('pi = {:.2f}') # pi = 3.14 と出力される

冗長性の解消について議論しましたが、表示の仕方も簡単に変えられます。

型を付けてあげましょう

python3からは型宣言機能がつきました。通常、pythonは「この関数の引数は数値だけ」と宣言しなくても実行できました。 しかし、プロダクトの保守性を考慮すると、宣言してくれた方がエンジニアはデバッグしやすいです。 ディープラーニングモデルなんかをアプリに組み込む時、つけてあげるとエンジニアは幸せになります。

def add(num1: int, num2: int):
    # 入力のnum1とnum2はint型のみを受け付けると言う意味
    return num1 + num2
print(add(1, 2)) # 3 と出力
print(add('寿司', '食べたい')) # 文字列(str)をとっているのでエラー

# 数値だけを受けとる宣言も可能
from typing import TypeVar
Number = TypeVar('Number', int, float) # 引数
def add_extend(num1: Number, num2: Number):
    # num1、num2はintでもfloatでも扱えるようになる
    return num1 + num2
print(add_extend(1, 2.3)) # 3.3 と出力

# クラスを使う場合は型にクラスを指定することも可能
class Hoge(object):
    def __init__(self, num: int):
      self.value = num

def get_num_from_hoge_object(hoge: Hoge):
    return hoge.value

print(get_num_from_hoge_object(Hoge(1))) # 1 と出力

詳しい書き方は公式2で見ることができますが、わかりやすく解説されている記事3もあります。

gitを使おう

gitでは、変更内容を保存できたり、変更前の内容を見返すことができます。 「この行とりあえず消したいけど、後で使うかもしれないし・・・」と思ってコメントアウトしたりしませんか? gitならばそんな行も遠慮なく消せます。そして必要であればすぐに復元できます。 また、複数のバージョンを作ることができるので、日常の解析でも「モデルAを使ったパターンと、モデルBを使ったパターンと、モデルBに特殊なチューニングを加えたパターンと...」 といったようなこともgitを使って複数パターンのコードを管理することもできます。 特に他人に見せるようなコードはgitを使って変更内容を保持しましょう。そしてコメントアウトに頼ったコードを書かないようにしましょう。

基本的なことはウェブにチュートリアルがありますが、使いこなそうとする場合は難しいので、エンジニアに教えてもらいましょう。

ドキュメントを書こう

defやclassといった関数やクラスの宣言の行の次に文字列を宣言しているコードを見たことはありますか? pythonにおいてはドキュメントと呼ばれていて、関数やクラスを説明を示します。 pythonコードの先頭に書く場合もあり、その場合はモジュール自体の説明をします。 ドキュメントを書くことで、pythonのhelp関数でそのドキュメントが読めたり、ipythonやjupyter、エディタの機能でも読むことができます。 特にモジュールとして他の人に使わせる場合にとても便利です。共有するコードには面倒臭がらずに書きましょう。

def add(num1: int, num2: int):
    '''
    自然数の足し算をする

    パラメータ
    num1 (int): 足し合わせる数値
    num2 (int): 足し合わせる数値

    返り値
    int num1とnum2を足し合わせた数値を返す
    '''
    return num1 + num2

開発チームによっては、このドキュメントの書き方が決まっているので、書く時はチーム内で書き方を確認しましょう。

リーダブルコードを読もう

プログラミング全般で、コーディング作法の有名な技術書があります。リーダブルコードです。 聞くところによれば、リーダブルコードはできて当たり前と言うエンジニアチームもあります。というかほとんどのエンジニアチームがそうだと思います。 業務はデータサイエンスだけだというデータサイエンティストも興味があれば買ってもいいと思います。コードを人に見せるために学ぶ場合でも有用です。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

オブジェクト指向プログラミングを覚えよう

ここからは実践的なエンジニアリングの内容となっていきます。 pythonでもオブジェクト指向プログラミングができますが、javaなどとは異なりガチガチなオブジェクト指向を要求される言語ではありません。 pythonは手続き型と呼ぶべきものでしょうか。しかし規模の大きいアプリケーションほどオブジェクト指向でのプログラミングが要求されます。 この記事ではあまり触れませんが、もし勉強したい場合はjavaを使ったプログラミングを学ぶことがオススメです。 ガチガチなオブジェクト指向が強要されるので嫌でも身につきます。 また、ウェブで検索しても基本を学べますし、オブジェクト指向の入門書もあります。

オブジェクト指向でプログラミングすることはディープラーニングモデルを組むことにおいても有用です。 chainerやpytorchではオブジェクト指向でモデルを組むことが前提になりますし、kerasでもサポートされていない層を自分で組む場合に使います。 特にこれらを使うことになった場合は、せめてpythonに置けるオブジェクト指向の基本は覚えておきましょう。

ただし、単にオブジェクト指向でコードが書けることが保守性のコードを書けるとは言えません。 オブジェクト指向の基本を習得したら、デザインパターンと呼ばれる、オブジェクト指向におけるコーディング作法を覚えましょう(前述のリーダブルコードでは紹介されていないので注意)。 特にオブジェクト指向においては、 GoFデザインパターン というものが有名で、現在でも使われています。 同様にあまり触れませんが、検索すればまとまっているサイトもありますし、紹介されています本もあります。

アプリケーション開発現場などに放り込まれそうであったり、既に携わっているデータサイエンティストは是非覚えましょう。

終わりに

かなり長くなりましたがいかがでしょうか。最後辺りの内容はかなりエンジニア寄りの内容になりましたが、flake8と紹介した書き方を使うだけでもコードの書き方が改善されます。

ぜひともご参考に。

参考URL

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

DeepAnalyticsの問題から読み解く機械学習

つい最近までキスモの木のロゴがキスモの頭文字”キ”も由来になっていると思っていたインターン生の内山です!

どうもそれは全く関係ないようです。。笑

 今回で2回目の登場となります。よろしくお願いします!

 

さて、キスモでのインターンでお仕事をさせてもらう中で、ビジネスの場で、

AIがすごいのはわかるけど、実際にどんなデータが使えるのかイメージがつかない」「どういう手順で機械学習は行えるの?」

といった疑問の声をよく耳にします。

 

なので、今回はオプト社が運営しているDeepAnalyticsの”銀行の顧客ターゲティング”問題に挑戦し、人工知能分野の一種である機械学習についてお話させてもらおうと思います!

 

今回取り組む問題の概要

今回の問題は、ある銀行の顧客の属性データを元に、当該のキャンペーンの結果によって口座を開設したかどうかを予測するというものです。

説明変数は下記の16項目が用意されており、27128人分のデータから口座開設の予測モデルを作り、18083人分のテストデータでの予測の精度で順位を競っていきます。

 

f:id:kodamayu:20171201102342p:plain

(画像:Deep Analyticsサイトより引用)

 

今回の予測結果の評価には、AUC(Area under an ROC curve)を用います。

この評価指標によって、実際は口座開設していないのにしたと判定する割合(偽陽性率)を小さくして、なおかつ、実際に口座開設したをしたと判断する割合(真陽性率)を大きくするモデルの価値が高く判断されます。

AUC1に近いほど性能が高いモデルとなり、完全にランダムに予測される場合、AUC0.5となります。

もっと詳しく知りたいという方は、こちらのページがとてもわかりやすいのでご参考にしてください。

www.randpy.tokyo

 

そもそも機械学習の手順って?

機械学習モデル作成の流れは、

  1. 要件定義
  2. データの収集・整形
  3. 学習・推論

の3工程に大きく分けられます。

 

1 要件定義は、どのようなデータを用いて、何をどのくらいの精度で予測するのか、そしてその結果をどう活用していくのかを詰めていく作業です。

最初に要件をしっかり詰めておかないと、せっかく完成した機械学習モデルが求められているものと実は全く違うなんてこともありえます。

大学の授業でも少しこのことを学びましたが、実際にビジネスの場に出ると、この部分がいかに重要かということをひしひしと感じます。

今回の問題では使用データ、モデルの評価方法はあらかじめ決まっているため、要件定義の部分はすでに済んでいると言えます。

 

2 データ収集・整形は、要件定義に沿って必要なデータを集め、それを機械学習モデルに入力できる形に変換する作業です。

基本的にコンピュータは文字を文字のまま読み込んで計算することはできないので、職業や未婚/既婚/離婚などカテゴリに分けて単語で表されているデータは、数値化を行う必要があります。

 

3 学習・推論は、2までの工程で得られたデータを用いて、モデルに学習させ、未知のデータに対して、予測を行う作業になります。

AIは万能でなんでも予測できるというイメージを持たれている方もいるかもしれませんが、

基本的に事前に読み込んだ情報からでないとAIは判断ができないので、この学習というフェーズは必要不可欠な部分となります。

 

機械学習モデルを作る際には、

要件定義:データ収集・整形:学習・推論 =4:4:2

の重要度を占めているというお話を聞いたことがありますが、

まさにそのくらい前半部分の工程は大事になります。

 

データ整形あれこれ

今回はデータはすでに収集されているので、データの整形から入っていきます。

説明変数16項目のうち、カテゴリ分けされているものをone-hotベクトルに変えていきます。

one-hotベクトルとは、単語をベクトル表現する時に用いる方法です。

例えば、職業のカテゴリが「教師、芸能人、パン職人」の3つだった場合、下の図のように3次元のベクトルに表すことで職業を表現できます。

 

f:id:kodamayu:20171201102359p:plain

(one-hotベクトル イメージ図)

 

このone-hotベクトル化をカテゴリで与えられている全ての項目に対して行います。

また、yesnoの2択で与えられているバイナリの項目に関しては、yesなら1noなら0というように数値化して使用します。

 

いよいよ学習・推論へ

一旦全てのデータを数値化したので、ここから学習のフェーズへ入っていきます。

既存手法を用いたいくつかモデルを作成し、比較検討していきます。

今回は、重回帰分析、ランダムフォレストの2手法でモデルを作成していきます。

学習により各変数に対する重みが決まり、その重みを引き継いで、テストデータに対して口座開設するかどうかの予測を行うことができます。

 

推論したデータの評価結果は、

重回帰分析…0.89680

ランダムフォレスト…0.90909

となり、この時点で204位(上位45%)となりました。

 

モデルをさらにより良いものへ

ランダムフォレストの方が良い精度が出たため、ここからはランダムフォレストに特化して、モデルを調整していきます。

手法により数は異なりますが、学習器にはハイパーパラメータと呼ばれる変数が存在します。

これを微調整することで、さらなる精度向上を目指します。

 

今回はグリッドサーチという方法を用いて、ハイパーパラメータを自動調整していきます。(他にも、ランダムサーチやベイズ最適化などなど、様々な方法があります。)

 

グリッドサーチを行い、最適化したモデルで推論をかけると、

評価結果は

0.93560

となり、90位(上位20%)まで向上しました!

 

ここからさらにPDCAサイクルを回していく

一連の流れを経て、目標の上位20%までは到達しました!

今回この問題はここまでしか取り組めませんでしたが、ここからやることとしては、

  • データ整形の方法を見直す
  • 外れ値に当たる学習データを抜き出す
  • 交差検定を行う

などがパッと思いつく限りでも挙げられます。

 

自分の中で仮説を立て、それに基づき修正を加え、再び学習・推論を行うというサイクルを回し続けていきます。

 

最後に

以上が機械学習モデル作成の一連の流れとなります。

ざっくりとではありますが、冒頭ご紹介した疑問の解消の一助となれば幸いです!

これからももっともっと機械学習技術への理解を深め、より有益な情報発信ができればと思いますので、

今後とも弊社技術ブログをよろしくお願いします!!

 

株式会社キスモ

インターン生 内山敦史

www.facebook.com

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

文系の僕がAI開発企業で何をしているか

こんにちは。キスモ取締役の鈴木雄也です。

今日は技術ブログの中でも少し趣向を変え、弊社唯一の文系出身役員である僕が
「文系・非エンジニア・非AI専門家がどうAIに向かい合うか」について、書いてみようと思います。

▶︎ビジネスでのAI開発はチーム戦!?

データサイエンスや人工知能分野の重要性は、みなさんご存知の通りかと思います。
インターネット、スマートフォン、そしてIoTといった分野の発展が世の中に発生するデータ量を圧倒的に増やしており、それを扱うためのデータサイエンス技術は日に日に加速している状況です。

人工知能に関する仕事、といっても実態は非常に多様です。例えば研究職とは違って、ビジネスでは必ずしも先進的な発明が求められません。先進的な技術はあくまで手段であり、目的は顧客の課題解決です。メディアで扱われる人工知能のニュースでは、研究成果とビジネス製品が混同されるように感じますが、実態は別物と捉える方が分かりやすいです。

ビジネスの中でも、職種は多様です。誰も想像するようなデータサイエンティスト、分析の職種以外にも、コンサルタント的な能力、マーケター的な能力、あるいはプロダクトマネジャーやエンジニアリング、デザイナーの能力に加えて法務知識までが求められることがあります。

一言で人工知能のビジネスと言っても、中でやっていることは非常に多様で、これらの能力をすべて持ち合わせた上で高度に両立できる人はほとんどいません。そこで、AI開発は多くの場合、顧客企業の担当者を含めたチーム戦になります。
AI開発がチーム戦だからこそ、非エンジニア、非データサイエンティストの能力が求められることもあるし、文系にとってAI開発は他人事ではなくなってきています。

 

▶︎製品開発で文系ができること

f:id:kodamayu:20171117130539j:plain

エンジニアとの社内ミーティング(イメージ)

ビジネスでのAI開発について、もう少し書いてみます。

人工知能分野に限ったことではないですが、顧客の業務理解と、自社の技術力の狭間に、課題を解決できる製品のアイデアは眠っています。

開発を始めるときには、「そもそも何を創ったらユーザーは喜んでくれるのか?」という問いにまず突き当たります。そしてこの問いに答えを出す能力は、必ずしも技術力の高さに比例しないと感じています。(もちろんあるに越したことはないです!)

そして製品のイメージが立っても、それをビジネスにしようとすれば、戦略や組織、資金など多様な要素を複合的に考えなければなりません。プロダクトマネジャーや事業責任者は、技術だけでなく、こうした多様な要素を組み合わせて考えながら開発の方向性を決め、推進していきます。

そしてこうした能力もまた、技術力の高さとの関連性は必ずしも高くありません。(もちろん技術への理解がないと困ることがたくさんあります!)

 

顧客のニーズを把握し、商売の仕組みをつくる、といった課題に対しては、
文系ができることもたくさんあります。


▶︎営業の場面で文系ができること

人工知能分野に限らず一般的にも、製品開発の初期は特に営業(もしくはマーケティング)と開発が事業の両輪になることが多いと思います。
そのため製品開発と重複する部分も多いのですが、営業の現場でも文系ができることがあります。

AI開発をビジネスにすると、想定するユーザーは企業、つまりBtoBビジネスを前提にした開発になることがほとんどです。

そしてSaaS事業などと似て、顧客の事業、顧客の業務を深く理解することが開発方針の決定には欠かせません。

技術のユニークさを生かして、かなりニッチな業種のニッチな業務を効率化するといった場面もあり、いわゆる顧客理解の能力が必要とされます。

f:id:kodamayu:20171117130717j:plain

営業先でのプレゼン(イメージ)

顧客理解と同じく重要なのは、技術のパフォーマンスを顧客に正しく理解してもらうことです。AI技術に過度な期待をされること、または逆にAI技術の可能性を低く見積もってしまうビジネスパーソンが実際にはほとんどです。こうした認識のズレを放置して開発をしていると後々致命傷になってしまうため、できるだけ入り口で修正することが必要になります。こんな時、技術のパフォーマンスや応用可能性を、概念と実例を交えながら正しく伝え、相手のアイデアをうまく引き出す能力が求められます。

もちろん細かい開発の論点に突っ込んでお話をするときには限界があるので、データサイエンティスト自らが営業に出向くことも少なくありません。しかし営業の現場では、開発の上流フェーズであればあるほど、文系にもやれることがあります。

 

顧客の業務を理解し、顧客に技術を理解してもらう、といった課題に対しては、
文系ができることもたくさんあります。


▶︎結局文系でもAIビジネス、できるのか??

文系でもAIビジネスなんてできるの?ってよく聞かれるのですが、
この問いは「エンジニアじゃなくてもITでビジネスできるの?」って問いに似ていると思います。

 

つまり、文系でもAIビジネスはできます。

 

もちろん技術への最低限の理解は必要で、かつ深ければ深いほど強いのですが、
かといって「文系の自分には縁がないことだ」とAIビジネスへの関わりを諦めてしまうのは、あまりにもったいないと思います。 

日本でAIの社会実装が進むためには、つくる側にも使う側にも、業界の垣根を超えた参画が進んでほしいです。

人工知能を専門家任せにしている時代は終わりました。専門家を中心に置きつつも、もっと多様な専門性の人材が開発に携わることで、可能性はもっと広がります。
例えばAI導入を目指す企業の内部にAIに理解のある意思決定者がいると、プロジェクトの離陸は圧倒的に早くなり、ここから回るPDCAが経験として蓄積することで、大きな資産となるのを見てきました。

 

それと同時に、専門家の知識量や経験に、リスペクトを持つことも重要なことです。
僕自身も業務内外で分からないことが出てきたら、社内のデータサイエンティストを質問攻めにしています。

結局のところ、技術を理解するためには専門家に聞いた方が早いし、専門家と働いたり、専門家に頼んでしまうのが手触りを持って理解できるのだろうと思います。
弊社では、多様な業種の企業様と共に「そもそもAIで何ができるんだ?」といったかなり上流の議論からお付き合いさせて頂いています。

その過程では、非専門家にもやれることがまだまだ多く、そして非専門家の役割はこれからもっと広がるだろうと感じます。

 

AI活用に漠然と興味のある企業様、AIビジネスに漠然と興味のある方は、ぜひ一度ご連絡ください。

 

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

世界一のデータサイエンティストを目指して 〜Kaggle参加レポート〜

みなさんこんにちは。 株式会社キスモ役員の大越です。

みなさんKaggleはご存知ですか? Googleが運営する世界最大のデータサイエンスコンテストサイトで、ユーザー数は2017年6月に全世界で100万人を超えました。 賞金総額1億円を超えるようなコンテストも開かれ、名だたるデータサイエンティストが日々しのぎを削っています。

自分は今回、そんなKaggleで開かれた Porto Seguro’s Safe Driver Predictionというコンテストに参加したので、それをレポートにしたいと思います。(ちなみにまだ終わってないので、もう少しスコア更新目指します。) 構成はKaggleではおなじみ、ランカーインタビューに沿った形式にしてみました!

f:id:kodamayu:20171107115355p:plain

Porto Seguro’s Safe Driver Prediction(Kaggle): https://www.kaggle.com/c/porto-seguro-safe-driver-prediction

◆コンテスト概要

テーマ:車の保険料を正しく見積もるために、翌年にドライバーが自動車保険を請求する確率を推定する。 評価指標:ジニ係数 データ:要素に関する詳細な説明はなかったが、関連する特徴量は名前から判断できるようになっている。

◆Basic

参加前の経歴

名古屋大学情報文化学部4年でコンピューターサイエンスを選考しており、高校時代から統計学やデータサイエンスの研究をしていました。

コンテストに役立つような知識、経験はありますか?

これまでNRIさんのマーケティングコンテストや、Deep Analyticsのコンテストなどにも参加したことがあり、そこで得た経験は活きました。

Kaggleを始めたきっかけは?

これまではプロ野球のドラフト予測や評価指標作成など、野球を題材に自分で分析のテーマを決めて行うことが多かったですが、そこで勉強したことをもう少し実践的に試したいと感じて参加しました! Kaggleは世界規模の大会で、Discussionや情報公開にも積極的で、とても勉強になります。

どのようなきっかけでこのコンテストに参加しましたか?

なにかしらKaggleのコンテストに参加したいと感じていましたが、データサイズ的に参加できないものも多かったです。そんな中でデータサイズが少なく、参加者が多い本コンテストは、自分が参加するにはぴったりだと感じ、参加を決意しました。

◆Let's Get Technical

どのようなアーキテクチャを作成しましたか?

本コンテストは様々な特徴量を用いて、次の年に保険料を請求するか否か、その確率を試算するものでした。他の多くの参加者同様、自分はこの問題に対してアンサンブルの様々な手法を試し、それらをstackすることにしました。 以下が作成したアーキテクチャです。 f:id:kodamayu:20171107115442p:plain

  1. まず、特徴量を2種類作成しました。特徴量1は与えられたデータをそのまま用いて、特徴量2はbinary特徴量以外の各特徴量において平均、中央値と比較した時に値が大きいか小さいかという情報と欠損値の個数を加え、いくつかの特徴量はone hotに変換しました。
  2. 次にモデルの検討を行い、xgboost、LBG、GBDT、catboostを使用、5つにデータを分けて交差検証を行ないジニ係数を用いて評価することに決めました。
  3. 次に各モデルについてパラメーター調整を行いました。パラメーターは公開されているkernelから大体の値を検討し、その周辺をグリッドサーチして決めました。
  4. それらをロジスティック回帰でstackしました。その結果catboostを使用した場合、精度が下がったため、catboostは最終的なアーキテクチャから除きました。

どのような前処理とエンジニアリングを行いましたか?

初めは与えられたデータのみで一通りパラメーターチューニングをして、stackingモデルで0.284というスコアを出しました。 その後、新しい特徴量として基本統計量である平均や中央値と比較して、値が大きいか小さいかという情報を追加して、それもstackingモデルに加えたところ、0.285までスコアが上がりました!

どのようなモデルを作成しましたか?

xgboost、LBG、GBDTというアンサンブルの代表的なモデルを595212個のトレーニング用データを5つに分けてstackしました。 パラメーターはグリッドサーチでそれぞれ最適化を行い、最終的な出力はロジスティック回帰の確率としています。

評価指標で工夫した点はありますか?

ジニ係数で評価されるため、グリッドサーチの際はジニ係数の関数を作成し、そのバリデーションスコアを元に評価を行いました。また、catboostのlossはジニ係数がないため、代わりにLoglossを使用することで対応しました。Loglossについては、ジニ係数の関数を作成していない他の参加者も誤差関数として使用していました。

データに関する考察で重要なことはありますか?

f:id:kodamayu:20171107115539p:plain まずターゲットの値について見た所、大きな偏りがあることがわかりました。そのため、アーキテクチャの設計の際に、単純なaccuracyで評価せずに、ジニ係数を用いるようにしました。

f:id:kodamayu:20171107115516p:plain また、決定木の構造を可視化したものを確認したところ閾値を設定することに効果がありそうだと感じたため、特徴量整形の際に平均、中央値を閾値に設定したフラグを追加しました。

どんなツールを使いましたか?

python3.6と各種アンサンブルのモジュール、sklearnを主に使用しました。

◆Words of wisdom

協議会を通して、何を得ましたか?

今回の協議会で実践して効果を発揮したのが、stackingモデルと平均、中央値を用いた特徴整形でした。これらにより、一時は90位(上位4%)にも入ることができました。 また、自分が参加しながら他の参加者のkernelを見ることで、データに対する見方やコードの書き方まで細かい部分で気づくことがあり、それが今後の業務にも活かせると感じています。

終わりに

一時90位だった順位はあっという間に下がり、現在は3925人中244位(上位7%)です。 もう少し、工夫の余地がありそうなのでそれを実装して残り2週間でさらなる順位アップを狙いつつ、他のコンテストにも参戦し始めたのでそこでも上位を狙っていきたいと思います! Kaggleでの経験を実際の業務にも活かしていきたいですね! みなさんも勉強も兼ねてKaggleを始めてみてはいかがでしょう?

xgboostについて参考にどうぞ

XGBoostの公式githubです。

github.com

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

なるほど!Google翻訳のアルゴリズム

みなさんこんにちは。

株式会社キスモの役員の寺澤です。
 

本日は、精度が高いと言われている、Google翻訳の技術をアルゴリズムの観点で紹介しようと思います。

arxivという国際論文が投稿されているサイトで、今年の6月に、GoogleのデータサイエンティストたちがAttention is All you NeedというタイトルでGoogle翻訳の技術であるTransformerという深層ネットワークを公開しました。

Transformerというとアニメや映画のトランスフォーマーを思い起こしますね。油断して適当に検索したらその作品がでます 笑

この論文は外国のデータサイエンティストの中でもすぐに話題になり、後にGoogleが公式で公開され、日本でも記事となりました。

Google公式の記事(英語注意): https://research.googleblog.com/2017/08/transformer-novel-neural-network.html

日本の記事: http://gigazine.net/news/20170901-transformer-neural-network-language-understanding/  

 

実はこの論文が公開された直後に一度読んでみましたが、当時はあまりアルゴリズムを理解できませんでした。

今回はそのリベンジを含めてアルゴリズムを理解してきましたが、何故かあっさり理解できました 笑

さて、前置きはこれくらいにしておいて、解説に移ります。かなりコアな内容になるので、初心者は要注意です。  

 

Google翻訳の技術、Transformerの構造とは?

前述の記事を読んでいただければ概要は理解できると思いますが、大まかに言うと、

  1. 既存のモデル(RNNベース、CNNベース)のものよりも精度が高く、学習時間の削減にも成功した。
  2. 着想はRNN、CNNベースのものとは変わらず、元の文全体を意識して、翻訳を行うモデルである。
  3. 既存モデルとの他の優位性は、文中の単語の意味を理解していることにある。

3番目に関しては、例えば英文の"it"が何を指すか(動物なのか、あるいは道路なのかなど)を理解した上で翻訳をします。

参考記事中の翻訳タスクでは、英文の"it"をフランス語では動物、道路を指す単語をそれぞれ"qu'il"、"qu'elle"と翻訳する事に成功しています。

Transformerは、Self-Attentionという、CNNに使われる畳み込みにもRNNに使われる再帰構造にも頼らない構造を使っています。

Transformerの動き方は前述の記事で紹介されていましたが、実際のアルゴリズムはどうなっているのか、説明していきましょう。  

 

Transformerのアルゴリズム(概要)

f:id:kodamayu:20171020155722p:plain

Transformerのネットワーク構造は上図となります。本記事では、入力・エンコード・デコード・出力の順に説明します。

図ではそれぞれ下部分、左の灰色部分、右の灰色部分、右上の出力部分となります。  

 

Transformerのアルゴリズム(入力する前に)

まず、入力する文と出力する文(翻訳元の文、翻訳した文両方)は、既存のRNNと違って、単語の位置の情報を与えなければなりません。

これは、Position Embeddingsというアルゴリズムで単語の位置を与えてやります(単語にインデックスを付けるだけですが)。

この手法は、Facebookが今年の5月に公開したCNNベースの翻訳モデルでも用いられました。これをたった1ヶ月で追い上げるGoogleすごいですよね。

論文では、このアルゴリズムをさらに改善したPositional Encodingというアルゴリズムを使って、単語の位置情報を与えます。

数式は以下のようになり、この式を適用したベクトルPEの列とベクトル化した単語列がネットワークへの入力となります。  

 \displaystyle
PE_{(pos, 2i)} = \sin(pos/10000^{2i/d_{model}}) \\
PE_{(pos, 2i+1)} = \cos(pos/10000^{2i/d_{model}})

 

上式のposは単語の位置、iはベクトル化した単語の次元数(インデックス)を指し、交互にsinとcosをとっているようです。

このアルゴリズムを適用する事で、単語の位置を相対的にも考慮して学習する事ができるようです。

しかし、論文の検証結果では、通常のPosition Embeddingsを使ったTransformerのモデルと比較したところ、ほぼ同等のスコアでした(若干提案手法の方が優勢でした)。  

 

Transformerのアルゴリズムエンコードレイヤー)

さて、いよいよ学習・推論のアルゴリズムに入ります。まずは入力する文(翻訳元の文)に対応するエンコードレイヤーについて説明していきましょう。

後のデコード層にも使われますが、基本的には、Multi Head-Attention層とFeed Forward層の二本柱になっていまして、

それぞれの層の直後にresidual層、正規化層が挟まっています。このネットワークを一つのエンコードレイヤーとして扱い、このレイヤーを複数連結したものがエンコード層となります。

residual層は、ResNetを知っている人ならばアルゴリズムは想像つくでしょうが、Multi Head-Attention層はTransformerのコア技術になりますね。

これらの層を順に説明していきましょう。  

 

Multi Head-Attention層

f:id:kodamayu:20171023132956p:plain

Multi Head-Attention層は上図の右のような構造をとります。

Multi Head-Attention層への入力は、図の通り、3つとなっております。入力の最初の層にこれがくる事になりますが、単語の入力をどう3つにするんだと思うでしょう。

実は、今回は、入力ベクトル同じものを3つ入力します。3つの入力はそれぞれ、query、key、valueと呼ばれ、query、keyから重みを作り、その重みを適用したvalueを出力します。

エンコードレイヤー内でのこの層はSelf-Attentionと呼ばれますが、同じ単語ベクトルから計算するためにこう呼ばれているのでしょう。

さらにこの中では、さらにScaled Dot-Product Attentionという層が存在し、Multi Head-Attention層の肝となります。

図では左の構造になります。(図にはMaskという層が現れていますが、後述するデコードレイヤーでのみ用います。)

だいたい図の通りですが、入力ベクトルであるquery、key、valueをそれぞれ、Q、K、Vとすると、Scaled Dot-Product Attentionは以下の数式で計算が行われます。  

 \displaystyle
Attention(Q,K,V) = V softmax(QK^T / \sqrt{d_k})

 

図のScaleに当たる部分が、ハイパーパラメータd_kの平方根を割る箇所となります。

ハイパーパラメータで割るのはチューニング可能にして、調整が効くようにするためでしょうが、どうして平方根を挟むのでしょうか。

ハイパーパラメータd_kに平方根を取る理由ですが、値の大きいd_kで割ってしまったら、勾配が非常に小さくなり、勾配消失問題に繋がるためです。

Multi Head-Attention層ではこのアルゴリズムを用いますが、入力するQ、K、Vはそれぞれ対応する全結合層を挟んだ後、h個のQ、K、Vのペアを並列して、

Scaled Dot-Product Attention層に通します。入力は、処理済みのh個のQ、K、Vのペアを入力としますが、Scaled Dot-Product Attention層は対応するh個だけ用意します。

出力したh個のベクトルは連結し、再び全結合層に通して出力されます。これがMulti Head-Attention層の一連の流れとなります。

ただし、前述の全結合は、論文内では全てパラメータ行列との内積だけで表現されております。同様に参考に読んだgithubのコードでは、通常の全結合層に通し、場合によってはreluも通していました。見た感じですと、論文内では前者以上の説明はありませんでしたが、学習具体によって差し替えるのもありですね。

後に説明する翻訳後の結果に通すデコードレイヤーでは、形を変えてこの層を使います。

 

Feed Forward層

長々とMulti Head-Attention層の説明をしましたが、Feed Forward層は見慣れた構造となっております。

単純に全結合、relu、全結合の順に入力を通していきます。ただし、全結合の代わりにカーネルサイズが1の畳み込み層を用いても良いようです。

参考にしたgithubのコードでも畳み込みを使っていました。  

 

residual層

residual層ではResNet(Residual Network)でも用いられた手法で、入力の残差を学習する事で、ネットワークの層を深くするという着想を元に生まれました。

何が行われているかは単純で、レイヤーに入力したベクトルとその入力をしたレイヤーから出力されたベクトルの和を取るだけです。

ここでは、Multi Head-Attention層への入力と出力の和、Feed Forward層への入力と出力の和を取ります。

論文内では、エンコードレイヤーを6つ連結し、更にエンコードレイヤーと似た構造のデコードレイヤーも6つ用意しているものがベースのモデルとなっています。

そのことを考えると確かに深い構造になりますね。そのことを見据えて用意したのでしょう。  

 

正規化層

正規化です。入力したベクトルの値の平均を1に、分散を0にするものです。

 

Transformerのアルゴリズム(デコードレイヤー)

エンコードレイヤーの説明が長くなりましたが、今度は出力する文(翻訳結果の文)に対応するデコードレイヤーについて説明します。

デコードレイヤーと似た構造を取り、デコードレイヤーに登場した層を使っていきます。ただし、Masked Multi Head-Attention層という層が新たに加わり、Masked Multi Head-Attention層、Multi Head-Attention層、Feed Forward層の順の連結を1つのデコードレイヤーとします。

こちらでも例外なく、各層の出力直後にresidual層と正規化層が現れたり、複数レイヤーの連結も行います。

ここでは、(Masked) Multi Head-Attention層の扱い方がエンコードレイヤーとは変わりますので、それらの説明を行います。

 

Masked Multi Head-Attention層

基本的には、Multi Head-Attention層とは変わりませんが、

Scaled Dot-Product Attention内のsoftmax関数を通す直前の値にマスキングを適用します。式にするとこういう形になるでしょうか。  

 \displaystyle
Attention(Q,K,V) = V softmax(masking(QK^T / \sqrt{d_k}))

 

エンコードレイヤーでは、入力の文全体を意識して学習を行います。しかしデコードレイヤーでは翻訳文が頭から順番に出力され、翻訳した単語とそれ以前に出力した単語列のみを意識しています。

例えば、「私はトムです」は「I'm Tom」と訳せますね。しかしモデルは「最初に"I'm"」が来ても、次に何が来るかを計算しなければなりません。厳密には「最初に"I'm"」が出力するかわからない段階があります。

「それ以前に出力した単語列のみを意識」するとは、"I'm"を翻訳文として出力するべきとは理解したものの、それ以降は何を出力するべきか核心に至っていない状態での意識の事です。

そこで、出力されているはずのない単語(出力する単語を選ぶ前の時点の単語)ベクトルに関しては、上式のようなマスクを適用します(論文内では-\inftyに差し替えています)。  

 

Multi Head-Attention層

Masked Multi Head-Attention層に続く、Multi Head-Attention層では、queryに図で言う、直前のMasked Multi Head-Attention層の出力を受け取り、key、valueエンコードレイヤーの最終出力を受け取ります。いわゆるSelf-Attentionとは違う入力になりますね。

このような入力にする事で、翻訳元の文と、時系列で言う過去の翻訳の出力を加味した学習や推論を行えるようにします。

以上で説明した層を組み合わせネットワークがデコードレイヤーとなります。  

 

Transformerのアルゴリズム(出力)

出力はデコードレイヤーの最終出力を全結合層、ソフトマックス層の順番に通し、出力した単語列に続く次の単語を予測します。

論文内では記載されていないようですが、損失関数は交差エントロピーで問題ないでしょう。  

 

Transformerのアルゴリズム(その他)

このネットワークでも例外なくdropoutは用います。

論文内では、residual層の直前と、Scaled Dot-Product Attentionの最後の内積の直前に適用しています。

 

終わりに

以上がGoogleの翻訳技術であるTransformerの全貌となります。数式や長文ばかりではわかりにくいと思いますので、

一応原論文に加えて私が参考にしたgithubソースコードのURLも置いておきます。

余裕があれば紹介した論文を引用した論文でも紹介しようと思いましたが、こうも長くなってしまったので省略します。

スコアや計算量など、評価に関する部分も論文に任せます。

これを機にGoogleの翻訳技術を再現してみるのはいかがでしょうか。

いずれ余裕ができた時には、Neural Network Consoleなどでの再現実装も検討しようと思います。

以上、寺澤でした。    

   

参考文献

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

Neural Network Console(NNC)を用いたAutoEncoderの作成

杉浦です。株式会社キスモにインターンとして在籍しています。 


機械学習を学んで4ヶ月。

やっと少し分かってきたかなという感じでして、今回はインターンで学んだAutoEncoderを紹介しようと思います。

 

1. そもそも AutoEncoder って?
 f:id:kodamayu:20171017153034p:plain

上図のように、InputとOutputに同じ画像を与えることを考えます。この時、中間層の次元を絞ることで、このニューラルネットは入力画像に対して次元削減を行なっています。つまり、このニューラルネットは入力画像を出力で再現すべく、入力画像の画像らしさを特徴量として抽出することを学習していきます。


この例の場合、入力画像を次元削減することをEncodeと呼び、Encodeしたものに対して、Decodeすることで入力画像の再現を行います。このEncodeする部分をAutoEncoderと言います。

 

2. Fashion-MNIST

f:id:kodamayu:20171017153240p:plain

画像元:https://github.com/zalandoresearch/fashion-mnist

今回用いたDatasetsはFashion-MNISTです。
最近できたDatasetsらしく、MNISTが簡単すぎることや、使われすぎていることから生まれた流行りものです。
今回は、このDatasetsから画像のみを使用しました。

 

3. NNC で AutoEncoder を作ってみる

今回私が試行錯誤を重ねてやっと作った最高のネットがこちら。

f:id:kodamayu:20171017153848p:plain


とは言ってもNNCを使うと、いろんなネットをすぐに試せて非常に楽です。
私がDeep learningを楽に学べている9割はNNCのおかげですね。


このネットの特徴は、Convolution、Poolingによって28x28の大きさだった画像が、一次元のベクトルになっていることです。
そこからDeconvolutionを用いてDecodeすることで入力画像の再現を出力画像とします。

今回学習にはFashion-MNISTから画像を300枚、テストに100枚を用いました。

 

4. 結果

f:id:kodamayu:20171017153939p:plain


これは実際のNNCによるテストデータを用いた、Evaluation結果です。
左が入力、右は出力画像で、靴は靴らしい形をとっていることや、服は装飾が消えていること、なんとズボンは勝手に二股になっていることがわかります。

ちなみに中間層を出すのもNNCなら簡単です。

 

f:id:kodamayu:20171017154046p:plain


この中間層からは、1回目のPoolingでは画像の構造らしきものを捉えており、
2回目のPoolingではだいぶ抽象化され、画像の角を取らえているように見えます。
3回目のPoolingは出力が一次元ベクトルなので、画像としてはグレースケールの濃淡だけになります。

 

5. 感想

このようにNNCを用いると、まだまだ初心者の私でもこんな感じでなんでもできちゃいます。
ですがキスモの社員方々のサポートのおかげでここまで理解することができました。

最後までお付き合いいただきありがとうございました!

 

株式会社キスモ

インターン生 杉浦 太郎

 

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

30秒でネットワークが組める!?Neural Network Consoleを用いた機械学習

キスモインターン生の内山です!

僭越ながら、技術ブログ1発目を務めさせていただきます!

 

本ブログでは、弊社が関心を抱いている技術や日頃の業務から得られた知見などを定期的に紹介していきます。

 

本日ご紹介させていただくのは、8月中旬にSony社がオープンソースとしてリリースしたNeural Network Console(以下、NNC)です。

 

このNNC、本当に革命的です…!

コーディング一切なしで、パズルのように簡単にネットワークが組めちゃうんです。

 

弊社では、

  • モデルのコーディングの時間を減らせること
  • よって要件定義やデータ整形に時間が多く割けること
  • モデルの分析・改変が容易になること
  • 結果の可視化が容易にできること

などを加味して、社内でNNCを活用し始めました!

 

では、NNCを使うと機械学習がどれほど楽になるかをMNISTデータを用いた手書き文字認識で説明していきたいと思います。

 

まずはお馴染みのCNN(畳み込みニューラルネットワーク)のモデルを組んでいきましょう。

畳み込み層、プーリング層、誤差関数などを組み込んでできたモデルがこちら! 

f:id:kodamayu:20171006112109p:plain

CNNの基礎知識さえあれば、コーディングを一切せず、30秒でモデルが組めます。

 

そして1クリックで学習、推論が開始でき、今回のモデルでテストデータに対して、精度98.09%が出ました。

さらに学習結果、推論結果もグラフ、表で自動出力してくれます。

 

f:id:kodamayu:20171006112648p:plain

学習結果

 

f:id:kodamayu:20171006112419p:plain

推論結果


これならプログラミングを学習したことのない人でも、理論の理解さえあれば簡単にMNISTの文字認識で98%の精度を出すことができます。

 

ただ、ここまではコードを書ける人ならさほど難しくないと思います。

実際僕自身もpythonを本格的に勉強し始めて半年ほどですが、ここまでなら問題なく組むことができます。

 

NNCではここからさらにモデルを自動改良してくれる機能が付いています。

これがかなり便利なんです。

 

自動で層を増やしたり、層の形を変えたりして、より精度の高いモデルを探索してくれます。

先ほどのモデルを自動改良させると、最も精度の高いモデルはこのようになりました。

 

f:id:kodamayu:20171006112115p:plain

このモデルの自動改良により、精度は98.79%まで向上しました!

 

一般的に、モデルが複雑になるほど計算量が増えていくため、必ずしも精度が高ければ良いというわけではありません。

扱う題材によって、許容できる計算時間や要求される精度は異なりますよね。

NNCでは計算時間と精度の関係を表すグラフも自動生成されるため、どのモデルを採用するかという議論がしやすくなります。

ありがたい機能ですね。

 

今回ご紹介させてもらったのはNNCの機能の一部ですが、非常に便利なツールだということがお分かりいただけたかと思います。

このNNCの登場によって、ますますデータサイエンスの分野が発展していくと嬉しい限りです。

 

今ご覧いただいている皆さんも、ぜひ一度このツールを使ってみてくださいね!

最後まで読んでいただき、ありがとうございました!

 

株式会社キスモ

インターン生 内山敦史

 

 

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech

技術ブログ、はじめます。

f:id:kodamayu:20170728140542p:plain

こんにちは、

株式会社キスモでデザイナー兼エンジニアをしているkodamayuです。

 

これまで弊社キスモでは、社内勉強会の資料や機械学習のノウハウを公開する場がありませんでした。これらを社内で燻らせているのはもったいない…!

そこで、私たちが考えていること、私たちが持っている知見をみなさんに共有するために、弊社でも技術ブログを書くことになりました。

 

さて、弊社は代表取締役を含め、役員の多くが現役のエンジニアです。

彼らが持つ、今流行りの人工知能機械学習技術から、社内での取り組みまで、弊社の様々な情報をこの場で発信していこうと思っております。

 

どうぞ「kysmo's blog」を宜しくお願いします。

 

 

もっとキスモのことを知りたい方は
こちらをご覧ください!

www.kysmo.tech