Stimulator

機械学習とか好きな技術話とかエンジニア的な話とかを書く

xonshのPROMPTにdatetimeを表示する

- はじめに -

xonshで作業をしているとつい時間を忘れてしまうので、時間を表示してやるメモ。

POWERLINEで良くみるやつをxonshrcで実装。


 

- timeを表示する -

コンソール上の右側に表示するにはこんな感じ

from time import strftime
$RIGHT_PROMPT = lambda: strftime('[ %H:%M:%S ]')

f:id:vaaaaaanquish:20180316235141p:plain
こんな感じ


xonshrcを書く - Stimulatorでも書いた通り、コマンド前は$PROMPT、右は$RIGHT_PROMPT、下にバー状に出しておきたければ$BOTTOM_TOOLBARに関数を突っ込む。


上記をlambda使わずに書くと以下
文字列を返す関数をPROMPT系の変数に突っ込んでおけば、キー入力時に評価される。

from time import strftime
def get_time():
    def prompt():
        return strftime('[ %H:%M:%S ]')
    return prompt
$RIGHT_PROMPT = get_time()
$UPDATE_PROMPT_ON_KEYPRESS=True

文字色や背景色などのフォーマットは、xonshのprompt-toolkitの普通のやつと似たような感じにすれば良い。


 

- datetimeを出す -

右にあっても見なさそうだったのでPROMPTに出す。

from datetime import datetime as dt
prompt = " {INTENSE_RED}{user}{INTENSE_GREEN}@{INTENSE_BLUE}{hostname}{INTENSE_YELLOW} [ {cwd} ] {GREEN}$ "
$PROMPT = lambda: dt.now().strftime('[ %Y-%m-%d %H:%M:%S ]')  + prompt
$UPDATE_PROMPT_ON_KEYPRESS=True

キー入力ごとに更新される。
f:id:vaaaaaanquish:20180317003150g:plain


以下参考
https://github.com/xonsh/xonsh/blob/adcd20f72fcbe6962533cb3ad78a4a9ec396e150/xonsh/readline_shell.py
https://github.com/xonsh/xonsh/blob/72f3bc0d089ea91d4e5288bb1c44ebfbe81db43e/xonsh/ptk/shell.py

 

- おわりに -

xonshにはそもそもxonsh.tools内に時間表記のメソッドがあったりするが、イマイチだったのでtime、datetimeを入れてきた方が早そう。
(Tools (xonsh.tools) — xonsh 0.8.3 documentation)


リアルタイムに表示したくなって数日試したけど、あんまり良い方法がなかったのでアイデアが欲しい。
xonshではなくprompt-toolkit側を見ないとダメそうなのでちょっとしんどそう


 

Qiitaの特定記事やタグ付記事をいいね、ストックしているユーザを見るPythonスクリプト

- はじめに -

Qiitaは、プログラミングに関する知識を記録・共有するためのサービスです。

Qiitaアカウントには企業情報が紐付いている場合があり、Qiitaの様々な記事から情報を取得し分析する事で「機械学習を記事を多くストックしている勉強熱心な会社はここだ!」等といった事が分かるのではないかという思いから、Qiitaのアカウント情報を取得するスクリプトを書きました。

その時のただのメモです。


 

- Qiita API -

QiitaにはAPIが存在します。

以下のQiita記事でAPIPythonクライアントを書いている人が既に居たので、こちらを利用します。
Qiita API v2のPythonラッパー実装した - Qiita

pipで導入します。

pip install qiita_v2

以下から「個人用アクセストークン」にread権限を付けて発行します。
https://qiita.com/settings/applications

その際表示されるtokenをメモしておきます。

これで後はいいね数を取得するだけなのですが、実際にこのPythonクライアントの中を見てみると、APIに存在する「いいね数の取得」に対応していませんでした。
qiita_py/client.py at master · petitviolet/qiita_py · GitHub

仕方ないので以下のようにメソッドを追加しつつ、記事のID(stock_id)に対していいねしたユーザとストックしたユーザを取得するスクリプトを書きました。

from qiita_v2.client import QiitaClient

def list_item_likes(self, item_id, params=None, headers=None):
    return self.get("/items/{}/likes".format(item_id), params, headers)
QiitaClient.list_item_likes = list_item_likes

stock_id = ''
token = ''
client = QiitaClient(access_token=token)

# いいねしたユーザ
res = client.list_item_likes(stock_id)
like_users = [x["user"]['id'] for x in res.to_json()]
for i in range(int(int(res.result_count)/20)):
    res = client.list_item_likes(stock_id, params={"page":i+2})
    like_users += [x["user"]['id'] for x in res.to_json()]

# ストックしたユーザ
res = client.list_item_stockers(stock_id)
stock_users = [x["id"] for x in res.to_json()]
for i in range(int(int(res.result_count)/20)):
    res = client.list_item_stockers(stock_id, params={"page":i+2})
    stock_users += [x['id'] for x in res.to_json()]

APIの制限は認証している状態で1000回/時、そうでなければIPアドレスごとに60回/時です。
数記事であれば大丈夫でしょう。


 

- ユーザ情報の取得 -

list_item_likes、list_item_stockersのresponseとなるjsonには""organization""なるキーが含まれています。

しかし、Qiitaプロフィールで表示されるものには「organization」と「Organizations」が存在しており、Qiita Organizationに登録されていない会社は前者、登録されている会社は後者に含まれ、APIでは前者しか取得できないのが現状です。

データ分析のため、後者のOrganizationsを取得したい事からユーザ情報取得のスクリプトを書きました。

import requests
from bs4 import BeautifulSoup
import time

def get_accounts_org(accounts):
    data = {}
    for account in accounts:
        res = requests.get("https://qiita.com/{}".format(account))
        bs = BeautifulSoup(res.text, "lxml")
        organization = [y.attrs["content"] for y in [x.find("meta") for x in bs.findAll("li", attrs={"itemprop":"memberOf"})]]
        host = [x.text.strip() for x in bs.findAll("div", attrs={"class": "newUserPageProfile_info_body"}) if x.find("i", attrs={"class": "fa-building-o"}) is not None]
        data.update({account: {"org":organization, "host":host}})
        time.sleep(5)
    return data

like_orgs = get_accounts_org(like_users)

like_usersリストに入っているユーザ情報から「organization(host)」「Organizations(org)」を取得する事ができました。


 

- 実際に見てみる -

実際に「記事にいいねしたユーザ」について見てみました。

テストとして以下の記事を選びました。
技術共有サービスQiitaで開催されていた2017年Advent Calenderにて、いいね獲得数ランクによってIBM、Greenという会社から表彰された記事ですので、いいね数もそれ相応かと思います。
qiita.com

集計は適当にCounterで

from collections import Counter

d = Counter()
for y in [(k,v) for k,v in like_orgs.items() if v["org"] or v["host"]]:
    for x in y[1]["org"]:
        d[x]+=1
    for x in y[1]["host"]:
        if x not in y[1]["org"]:
            d[x]+=1
for x in d.most_common(10):
    print(x)

結果は以下のようになりました

('株式会社リブセンス', 21)
('株式会社ミクシィ', 5)
('フューチャーアーキテクト株式会社', 4)
('フリーランス', 4)
('スタディプラス株式会社', 4)
('株式会社オールアバウト', 3)
('株式会社モバイルファクトリー', 3)
('アイレット株式会社(cloudpack)', 3)
('IBM Japan', 3)
('株式会社ゆめみ', 3)

記事の著者もリブセンスという会社ですが、やはり同僚の記事はいいねしたくなる傾向にあるのでしょうか。
私も社内SNSに「アイツの記事バズってるよww」みたいに同僚の記事を貼る人間を見たことがあるので、そういう影響もあるでしょう。

いかんせん、データ数が少ないので何も言えませんが、取得して見るまではできました。


 

- Qiitaの特定タグのついた記事を集める -

Qiitaには、記事にタグを付ける機能があります。

特定のタグがついているAPIを叩くため、上記と同じくQiitaClientに新しくメソッドを追加して実行します。

from qiita_v2.client import QiitaClient

def get_tag_items(self, item_id, params=None, headers=None):
    return self.get("/tags/{}/items".format(item_id), params, headers)
QiitaClient.get_tag_items = get_tag_items

tag_name = '機械学習'
token = 'hoge'
client = QiitaClient(access_token=token)

res = client.get_tag_items(tag_name)


ひとまず機械学習タグのついた記事を100 * 20 件分取得してみます。
QiitaのAPI制限を考えると、一度取得した情報はcacheしておくのが正解だと思います(以下では一切やっていません)。

ids = []
users = []
for i in range(100):
    res = client.get_tag_items("機械学習", params={"page":i+1})
    ids += [x["id"] for x in res.to_json()]
    users += [x["user"]["id"] for x in res.to_json()]

上記スクリプトにより、機械学習タグのついた記事を投稿しているユーザ、投稿された記事のidリストが取得できました。


 

- 機械学習記事を投稿、いいねしたユーザ情報を見てみる -

前述したget_accounts_org関数を利用して、機械学習タグ付き記事を投稿したユーザが属する企業、機械学習タグ付き記事をいいねしたユーザが属する企業について、Countをとってみます。

以下が直近2000記事で見た「機械学習タグのついた記事」を多く投稿する社員のいる企業です。

('TIS株式会社', 6)
('株式会社トップゲート', 5)
('株式会社ブレインパッド', 4)
('Team AI', 4)
('株式会社リブセンス', 4)
('株式会社 ドワンゴ', 4)
('Nuco Inc.', 4)
('株式会社Nextremer', 4)
('株式会社アカツキ', 3)
('株式会社クラウドワークス', 3)

Qiitaで機械学習記事といえば、あのアカウントとあのアカウントとあのアカウントかな…?という一覧になりました。
データが増加してもQiita活動家が社内に居るか居ないか、に寄ってしまいそうです。

これ以下はほぼ1~2だったので面白い結果を得るまで数を増やすのは少し大変そうです。
 
 
以下は直近2000記事で見た「機械学習タグのついた記事」にいいねを多くした社員のいる企業です。

('株式会社リブセンス', 31)
('Fringe81株式会社', 24)
('株式会社クラウドワークス', 22)
('TIS株式会社', 21)
('株式会社VASILY', 16)
('株式会社リクルートライフスタイル', 12)
('Retty株式会社', 12)
('フューチャーアーキテクト株式会社', 11)
('P&D – Planning and Development – ', 11)
('株式会社アカツキ', 11)
('Shinonome, inc.', 11)
('株式会社LIFULL', 10)
('株式会社トップゲート', 10)
('株式会社オールアバウト', 10)
('株式会社ゆめみ', 9)
('フリーランス', 8)
('株式会社 ドワンゴ', 8)
('株式会社Nextremer', 8)
('株式会社ACCESS', 8)
('株式会社エイチームライフスタイル', 8)
('株式会社エイチームブライズ', 8)
('株式会社BitStar', 8)
('The University of Tokyo', 7)
('株式会社div(ディブ).', 7)
('株式会社WACUL', 6)
('株式会社Fusic', 6)
('Kyoto University', 6)
('株式会社Rosso', 6)
('株式会社サイバーエージェント', 6)
('エムスリー株式会社', 6)

リブセンスという会社はQiitaに相当な時間を使っているという事がわかりました。
こちらも上位は「あのアカウントかな…」と個人が見え隠れする結果となりました。

こちらは、東大、京大やフリーランスがトップ30に入ってきた辺りを見るに、データが集まれば少し改善しそうです。


 

- おわりに -

APIの制限数によって1日ではこの程度でした。

多くデータを集めた上で、「機械学習タグのついた記事にいいねするユーザ」の数を企業単位で集計することで、特定の技術に興味関心が強い企業が見られるかも…という結果になりました。

Qiita APIではユーザに紐付いたLinkedinやFacebookTwitterのIDも取得できるため、次回はそれらを含めた集計を出せればと思います。


 

『人工知能プログラミングのための数学がわかる本』が機械学習研究入門書としてとても良さそうだった

- はじめに -

本を読んで筆者に媚を売る記事シリーズです。

人工知能プログラミングのための数学がわかる本」という書籍を筆者の石川 聡彦(Aidemy)@akihiko_1022さんから譲り受けました。

人工知能プログラミングのための数学がわかる本

人工知能プログラミングのための数学がわかる本

明日2/24発売ですが、筆者である石川さんがCEOを務めるAidemyさんと人工知能機械学習のイベントにてご縁があり頂く形になりました。


そもそもAidemyは、Python及び機械学習のための知識と実装に関する学習を行えるWebサービスです。

aidemy.net

似たサービスではUdemy(https://www.udemy.com/jp/)というアメリカのサービスがかなりのシェアを誇っています。

Aidemyは後発ですが、丁寧な日本語解説と内容の質の高さから、機械学習界隈でも「Aidemyは良い」という声を聞く程優良なサービスです。
こういった初学者向けのサービスの僅かなミスを論う意地の悪い界隈でも評判が良いのがすごい。

私自身も最初のコースだけやりましたが、よく出来たWebエディタと正しい導き方を見て素晴らしいなと思いました。


筆者がそのAidemy CEOの石川さんという事で、丁寧な導きと潔い切り口で書かれた本でした。


 

- どんな人が読むと良さそうか -

個人的には以下のような人にオススメです
- 機械学習の研究室に入りたい、研究をはじめたい
- 機械学習の論文が読みたい
- 機械学習における数式を噛み砕いて理解したい
- 高校、大学数学の知識を呼び戻したい
- これからMLPシリーズや高レベルな書籍を読む

とにかく「機械学習の研究室に一冊あるとめっちゃ捗る」。
これだけは間違いなく声を大にして言えます。
研究入門として素晴らしい構成です。

以下書籍の雰囲気です。

f:id:vaaaaaanquish:20180223211609j:plainf:id:vaaaaaanquish:20180223211600j:plain
めっちゃ丁寧できれい

本当に高校数学から大学における確率、線形代数までこの優しさで解説されているのでGoodです。

 
対して「機械学習を業務でやる」「データサイエンスの知識が欲しい」人には直結して学習効果の高い本ではなさそうです。

直結して効果が薄い、というのは実際の業務や実装では「これくらい知ってて当然」という場合が多々あると思われるからです。私の知っている機械学習エンジニア各位なら、10分で読了して、内容に準じた小テストまでこなせるでしょう。
ただそういった人達でも、自分の復習と理解の落とし込みのためであればかなり良い書籍であるという事は間違いないと思いました。

加えて「数学、線形代数をより理解したい」という人は満足できないでしょう。高校、大学数学の基礎から、機械学習への導入の持っていき方が素晴らしい書籍であって、定義を明確に数式を展開していくものではないです。


 

- 書籍の良かったところ -

前述の通り、高校、大学数学の基礎から、機械学習への導入の持っていき方は非常に滑らかに感じました。

数学といっても本当に2次方程式平方根、指数関数といったレベルから説明が入ります。
三角関数、集合、行列、ベクトル、確率、…と進み総復習のような形です。

それらの説明に対し全ての節に「人工知能ではこう使われる!」という説明が入っています。
これがなかなか一般的な書籍にない所で、「この為に勉強してるんだ」という実感が持てる所が、入門書としての格を上げています。

f:id:vaaaaaanquish:20180223230129j:plain:w400
こう使われる!

また、数式内にも色や線を利用して丁寧に解説が挟まれていたり、イメージの図もより優しい表現が使われています。

 
機械学習の仕組みを読み解く上での基礎となるワードが配置されているかつ、実際の機械学習に使われる箇所まで説明される書籍というのはなかなか無く、研究をはじめる前に読んでおくことで他の少しレベルを上げた書籍が一気に読みやすくなるでしょう

そういった点からタイトルを「機械学習研究入門として良さそう」としています。

 
加えて、最後の章では実際に「Boston Housing Dataset」「青空文庫」「MNIST」といった入門向けデータセットを利用してデータ分析、自然言語処理、画像認識の実体験を進める事ができます。

これらもコードがGithubで見られるようになっており、実際に学んだ知識を使いながらスムーズに体験できる所が最も素晴らしい所だと思います。

 
あと以下の記事の時にも書きましたが、こういった書籍のコラムは本当に良いです。

vaaaaaanquish.hatenablog.com

機械学習界隈で使われるワード」というのは意外と外に出回るものではありません。
機械学習界隈の人間同士の会話の中で自然に出てくるワードの知見が得られるのも書籍の良いところだと改めて感じました。


 

- 書籍で足りないところ -

導入までが素晴らしい書籍ですが、「じゃあこの本で得た定義で機械学習の研究室や勉強会でドヤ顔できるか」と言われたらできないでしょう。

最終章でDeep Learningニューラルネットワーク誤差逆伝播法、勾配法をピックアップしてより詳しく説明していますが、それでもさらに話を進めて研究レベルに持っていくには一歩足りないイメージです。
ただ「連続とは何か」みたいなレベルから書いていたら辞書みたいなサイズになってしまうので、どこかで情報を切らないといけない訳ですが、そういう意味では潔い書籍であるとも言えます。
さらに深く学ぶにはより専門的な書籍を探しましょう。

(これはつまり「この後Aidemyをやれ」という事なのかも…)

 
個人的にはこれ以上批判すべき所がなく「面白くねえな…」「これ普通に高専で研究始める前とかに読みたかったわ…」となりました。


 

- おわりに -

「松尾豊氏推薦!」という強めのワードと、なかなか可愛い表紙が特徴的な一冊です。

あと姑息な宣伝ですが、そんなAidemyの石川さんと私が登壇するMANABIYAというイベントがあるらしいです。
石川のハンズオンは既に満員みたいですが是非私の与太話を聞きに来て下さい。
manabiya.tech


今回Aidemyのステッカーも貰ったので、さらに媚を売るためにPCに貼った写真で終わりにしたいと思います。

f:id:vaaaaaanquish:20180223205736j:plain:w400
かわいい表紙

普通に研究室や会社に一冊あると、ふとした時に復習できる良書籍だと私は思いました。

 

人工知能プログラミングのための数学がわかる本

人工知能プログラミングのための数学がわかる本

 

共同通信と朝日新聞の記事URLを含むツイートを削除するPythonスクリプト

- はじめに -

この記事の起点となったのは、2018年1月25日、共同通信が配信した「山中氏、科学誌創刊に深く関与か」というタイトルの記事が、同日午後8時頃「山中所長が給与全額寄付」というタイトルの記事に書き換えられていた件である。

下記ツイートの通り、追記や編集の知らせ無しにネットメディアが大幅に修正された場合、記事公開当初と意見の辻褄が合わず、自身の発言に責任が取れなくなる場合がある。


自身が良いと共有した記事が卑猥、卑劣な記事になっている場合を防ぐため、特定のメディアの記事に言及していたツイートを削除するスクリプトについてメモしておく。


事前に必要な要件は以下の通り


 

- スクリプト -

最初に全体のスクリプト

API周りのKeyは、http://phiary.me/twitter-api-key-no-japanese から電話番号をアカウントに紐付けた後、https://apps.twitter.com/ にて取得する。

全ツイート情報を含むCSVは、Twitter公式のSettingsから、全ツイート取得の申請を出すと登録しているメールアドレスに30分程でダウンロードリンクが送られてくる。

f:id:vaaaaaanquish:20180126231631p:plain:w300

import tweepy
import urllib
import csv
import urllib.request

CONSUMER_KEY = ''
CONSUMER_SECRET = ''
ACCESS_TOKEN = ''
ACCESS_SECRET = ''
CSV_PATH = 'tweets.csv'
DOMAIN_LIST = ["this.kiji.is", "www.asahi.com"]

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
api = tweepy.API(auth)


def expand(url):
    req = urllib.request.Request(url, method='HEAD')
    resp = urllib.request.urlopen(req)
    return resp.url


def expand_url(url):
    eurl = expand(url)
    while eurl != url:
        url = eurl
        eurl = expand(url)
    return eurl


def main():
    with open(CSV_PATH, 'r') as f:
        reader = csv.reader(f)
        header = next(reader)
        for i, row in enumerate(reader):
            flag = False
            for x in list(set(row[9].split(","))):
                if x != "":
                    try:
                        y = expand_url(x)
                        for domain in DOMAIN_LIST:
                            if urllib.parse.urlparse(y).netloc == domain:
                                flag = True
                    except KeyboardInterrupt:
                        raise
                    except:
                        pass
            if flag:
                api.destroy_status(row[0])

if __name__ == '__main__':
    main()

print等は適宜。

ツイートが削除されるスクリプトなので確かめながら使う。


 

- 適当な色々 -

以下は駄文である。

このスクリプトを書くにあたっての実験的な色々とか。

短縮URLの展開がurllibだけでできるようになってた

短縮URL 展開 Python」みたいに適当にググると、Python2系のhttplib.HTTPConnectionを使ってHEADメソッド投げるスクリプトが沢山でてくるのは知ってたけど、3系からurllib.request.RequestでHEADできるの知らなかった。

Python3系で短縮URLを展開するのは以下みたく

import urllib.request
root_u = "http://hogehoge"

def expand(url):
    """curl --head url"""
    req = urllib.request.Request(url, method='HEAD')
    resp = urllib.request.urlopen(req)
    return resp.url

def expand_url(url):
    """短縮URLをできるだけ展開する"""
    eurl = expand(url)
    while eurl != url:
        url = eurl
        eurl = expand(url)
    return eurl

print(root_u, expand_url(root_u))

個人的には使い所は今のところないがハッピーな気がする

 

CSVの読み込み

CSVは大体30分くらいでメールが来て、ツイート数226Kで40Mくらいのzipになってた。
前回ダウンロードした時より大分大きくなってる気がした。

試しに1000件くらいやってみたけど、割りと接続できないURLがあったので、そちらも削除した方が良いような気がした。

import urllib
import csv
with open('tweets.csv', 'r') as f:
    reader = csv.reader(f)
    header = next(reader)
    for i, row in enumerate(reader):
        # 複数URLはカンマ区切り
        for x in list(set(row[9].split(","))):
            if x != "":
                try:
                    y = expand_url(x)
                    print("base: {}\nexpanded: {}\ndomain: {}".format(x, y, urllib.parse.urlparse(y).netloc))
                except KeyboardInterrupt:
                    raise
                except:
                     print("Not Found : ", x)
        if i > 1000:
            break

headerはtweet_idとexpanded_urlsしか使ってないけど、textとか時間も考慮した方が良い気がした。

 

記事の書き換えについて

全体を通して嫌な気分になる話だったが、解決方法が見当たらず難しい問題だと思う。

日本の今の社会形態からして、記者が常に誠実かつ知識を多く習得し続けるというのは難しいだろうし、それらを補正するには専門家の意見を割く事になる。
記者側としても「スピード感持って数多くの読まれる記事を出したい」という気持ちは強いだろうし時間の制約は大きい。

その点ネットでは公開直後から意見が集まる訳なので、今回あくまで修正方法が下衆だったという話にして、今後「指摘があったので修正しました」「間違っていたので差し止めます」が気軽に言える社会になっていけば良いなと思う。

法律の範囲内であれば、間違う事自体は決して悪い事ではない。


 

- おわりに -

花金の飲み会おわりの勢いで書いた。

間違ってたら修正すればええねん。


 
追記 2018/01/27 0:14 :
ミスを指摘されたのでサイレントで修正しました。


 

自動運転シミュレータのCARLAを動かす

- はじめに -

Python APIを備えた自動車運転シミュレータである「CARLA: An Open Urban Driving Simulator」を動かすまでの記事です。

CARLAはConference on Robot Learning 2017でも発表された、Unreal Engine 4を使ったシミュレータパッケージです。
自動運転技術開発のための様々なカメラ、センサー情報をPythonで取得し、車操作に反映する事ができます。

とやかく言っても仕方ないので以下YouTubeの動画を一回参照して下さい。

www.youtube.com

本記事はCARLAの導入と触りまでを記述するものです。

特に物を作ってどうこうしてるアレではありません。

 

- CARLAについて -

CARLAは、CoRL2017発表論文のAbstにもあるように、自動運転技術の発展のためのOSSです。

作者

作者はAlexey Dosovitskiy、German Ros、Felipe Codevilla、Antonio Lopez、Vladlen Koltunらで、IntelTOYOTAの研究所、Computer Vision Centerのメンバーです。
(Toyota Research Instituteなのでシリコンバレーの方だと思います)

 

競合

競合パッケージではMicrosoftのAirSimが一番有名だと思います

CARLAと同じくUE4を利用しており、C++, Python, C# and Javaのクライアントがあります。
また、CARLA同様、カメラ画像情報だけでなく深度やSegmentationのセンサー情報を利用できます。
車だけでなくドローンも対応しており、Windowsバイナリもあるのでパパっと始められる点で優位です。

強いてCARLAを使った理由は環境(天気とか)が変えられる事くらいです。
正直buildしんどかったのでAirSimの方が良いのかなと思ったりしています。

あと他にもUdacityの教材リポジトリもありました。
GitHub - udacity/self-driving-car-sim: A self-driving car simulator built with Unity
こちらはUnityを直接触る内容のようです。
こういうのがちらほらあります。

 

CARLAパッケージ情報

Github
github.com

Document:http://carla.readthedocs.io/en/latest/

CoRL2017発表論文:http://vladlen.info/papers/carla.pdf

 

動作環境

Documentには、WindowsLinuxの項目がありますが、現在Windows版の説明部分はComing Soonとなっています。
How to build on Windows - CARLA Simulator


Linuxでは、Ubuntu 16.04かそれ以降のバージョンを推奨しています。
How to build on Linux - CARLA Simulator

他に環境構築をしていて気になった点は以下です

  • pyenvやvirtualenv環境下のPythonではPATH周りで死ぬ
    • 素直にaptでpython3-dev入れるのが現状良い
  • ストレージがそれなりに必要
    • UnrealEngine本体のbuildと素材のダウンロード
    • 50GBでやったら足りませんでした
  • sudoersアカウント欲しい
  • Unreal Engine 4がOpenGL 3.x or 4.xを使う
  • 別途Windowsが必要
    • Winからしかダウンロードできないパッケージを使う
    • .NETFrameworkも必要
    • UE4の権利関係の問題


正直注意点が多いのでクリーンでストレージも多いUbuntu 16.04が入ったハード1つ用意出来るならそれがベストです。
その中でVMWindows動かすとかが良いでしょう。


 

- CARLAインストール -

buildしていきます。
一応ドキュメントに従っていきますが、まあまあ大変です。
How to build on Linux - CARLA Simulator

 

私の環境

一応私の環境を書いておきます

MacbookPro上のVMware Fusion
Ubuntu 16.04
python3-dev
ストレージ 100GB
コア数 4
メモリ 8GB
(UE4のEditor開くだけでもmmapで1.5GBくらい確保してたのでそれなりに必要)

別途適当なWindows10端末

 

依存パッケージのインストール

CARLA依存パッケージは以下コマンドで導入
途中でrequestsが必要になったのでここでインストールしています。

sudo apt-get install clang-3.9 cmake ninja-build python-dev tzdata sed curl wget unzip autoconf libtool python3-dev libxml2-dev libxslt-dev git build-essential python3-pip python3-requests
pip3 install protobuf requests


以下を参考にUnrealEngineのbuildの依存パッケージを導入
Building On Linux - Epic Wiki

# Ubuntu 16.04
sudo apt-get install mono-mcs mono-devel mono-xbuild mono-dmcs mono-reference-assemblies-4.0 libmono-system-data-datasetextensions4.0-cil libmono-system-web-extensions4.0-cil libmono-system-management4.0-cil libmono-system-xml-linq4.0-cil cmake dos2unix clang-3.5 libfreetype6-dev libgtk-3-dev libmono-microsoft-build-tasks-v4.0-4.0-cil xdg-user-dirs


各Setupスクリプトでchmodコマンドが幾つか使われているので、自身のアカウントをsudoersに入れておく。
Ubuntuでsudoersに自身を入れるには以下

sudo gpasswd -a {アカウント名} sudo


Unreal Engineとの依存関係と互換性問題を解決するには、コンパイラC++ runtime libraryを全て統一する必要がある。
今回は素のUbuntuが用意できたのでドキュメントの通り、clang3.9とLLVMのlibc++を使用した。

sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/lib/llvm-3.9/bin/clang++ 100
sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-3.9/bin/clang 100

update-alternativesによってclang提供のメッセージが出ればOK

 

Unreal Engine 4のインストール

UnrealEngineをcloneしてくるが、EpicGamesのGithubリポジトリはcloseしているため、開発者として登録する必要がある。

以下URLの右上からサインアップしてGithubアカウントをProfileに記載する必要がある。
https://unrealengine.com

ここ
f:id:vaaaaaanquish:20180105214109p:plain:w400

サインアップしたら登録したメールアドレスの認証も行っておく(認証してないと後述の自動車素材がダウンロードできない)


サインアップ後、右上に人型アイコンができるのでそこから開発者用Profileページへ。
「接続済みアカウント」に行って下にスクロールしていくと、Githubアカウントを記載するフォームがあるので書く。
f:id:vaaaaaanquish:20180105214406p:plain:w400


https://github.com/EpicGamesとか適当にgithubページに行くと招待状が届いている。
invitationを表示してjoin memberする
f:id:vaaaaaanquish:20180105214423p:plain:w400
(背景が黒いのは自分が拡張しているから)


これでやっと以下スクリプトが通るようになるので、clone時にGithubアカウント認証して設定スクリプトを走らせてmakeする。

makeでは[x/N]みたいな表示が何回か出るし、素材ダウンロードもあるので適当なマシンでやると4時間くらいかかる。
最初適当に50GBくらいVMで容量設定したが、make時足りなくなって途中で止まったのでGPartedを久々に使う事になった。
ストレージは多めに見積もる必要がある。

git clone --depth=1 -b 4.17 https://github.com/EpicGames/UnrealEngine.git ~/UnrealEngine_4.17
cd ~/UnrealEngine_4.17
./Setup.sh
./GenerateProjectFiles.sh
make

 
Setup.shでは、「Success」となっていてもその下にエラーメッセージが表示されている場合がある(大抵権限周りで)。
~/.configを触る権限がないとかなのでsudoersでやり直し。

Setup.shの真のSUCCESSは以下画像参照
f:id:vaaaaaanquish:20180105215246p:plain:w400


makeする時もsudoersに入ってないアカウントで作業して、sudo等の扱い間違えると権限の関係で以下辺りで死ぬ。
chmodやchownコマンドで権限を読み書きできるようにして無理やり通しても、後続のCARLAビルドする時に死ぬので諦めてやり直すのが吉。

Refusing to run with the root privileges. (rootじゃmakeできないよー)
Access to the path "~~~~~" is denied (Access権限足りんよー)
CrushReport-linux-Shippingのレシピで失敗しました

  
権限周りを丁寧にやっていてもUE4Editorのレシピだけ失敗する場合がある。

Makefile:188: commands for object 'UE4Editor' failed
 make: *** [UE4Editor] Error 137

依存パッケージのビルド順の問題だったので以下のように1つ1つ愛のある手作業でビルドしていくと通った。

make ShaderCompileWorker
make UnrealLightmass
make UnrealPak
make UE4Editor
make CrashReportClient-Linux-Shipping RequiredTools UnrealFrontend

UnrealFrontend-Linux-Shippingじゃないの…と思ったけどUnrealFrontendっぽい。
参考:Compilation error: make: *** [UE4Editor] Error 137 - UE4 AnswerHub


もしUEのbuildをやり直したい時はmake cleanがないので以下のようにARGSを設定する
(Building On Linux - Epic WikiのEnhancing the Makefile)

make ARGS=-clean

 

CALRAのインストール

CARLAをcloneしてきてbuildする。
~/CARLA/Unreal/CarlaUE4/Contentへの追加や色々ダウンロード等が入るので、これもまた1時間ほどかかる。

(後で知ったけどCompiled versionもダウンロードできるっぽい…)
Release CARLA 0.7.0 · carla-simulator/carla · GitHub


Windows端末が必要な作業が後半にあるので、Setup中に出来る所までやっておくと吉。

ここでpyenv使ってる人はfaildやskippedが出たり、protobufやpyconfig.hが見つからないよと出る。
pyenv global systemして、UE4の関連パッケージインストールからやり直せば大丈夫。

git clone https://github.com/carla-simulator/carla ~/CARLA
cd ~/CARLA
./Setup.sh

SUCCESSとなったら設定おわり
f:id:vaaaaaanquish:20180105215841p:plain:w400

 
この後まさかのWindows端末が必要になる。
これも時間がかかるのでSetup中に出来る所まで以下やっておくと吉。

~/CARLA/Unreal/CarlaUE4/Content/配下に、追加で手動で自動車素材となるAutomotiveMaterialsを入れる作業である。
http://carla.readthedocs.io/en/latest/how_to_add_automotive_materials/

WindowsにAutomotive Materialsを追加したダミーのプロジェクトを作り、プロジェクト内にあるAutomotiveMaterialsディレクトリをLinux端末にコピーしてくる(現状ライセンスの関係で自分で入れる形になっているらしくこの方法の改善に取り組んでいるらしいが…)

 
以下URLからパッケージを0$で購入してダウンロードする訳だが、そのダウンロードがWindowsのLauncherアプリからしかダウンロードできない。
Automotive Materials by Epic Games in Epic Showcase,Materials - UE4 Marketplace

Windows端末で上記のパッケージのURLにアクセスして、右上の「ダウンロード」からEpic Games Launcher自体のインストールためのInstallerを落としてくる。

そしてInstaller起動してよしなにWindowsにインストール。
インストールできたらLauncherを起動して「次へ」をおしながら、.NETFrameworkが必要だったりするので、ウィンドウの表示に従ってポチポチしていけば良い。

起動したらLauncher内でマーケットプレイスに行けるので移動して、Automotiveで検索。
バージョンを4.17に合わせてプロジェクトを作成する(最新が4.18になってたので注意)。
f:id:vaaaaaanquish:20180105220528p:plain:w400
プロジェクト作成したらダウンロードがはじまる。

上記作業が終わったら、Windowsの「プロジェクト作成」で作ったプロジェクト配下にある{プロジェクト名}/Content/AutomotiveMaterialsディレクトリをコピーして、scp等でどうにかLinuxマシンに移動する。


Linuxに送信したら、Linux端末の~/CARLA/Unreal/CarlaUE4/Content/配下に送信してきたAutomotiveMaterialsディレクトリを丸々コピーする。
(ContentディレクトリはSetup.shによって生成される)

以下のようにPathを設定しておく

echo 'export UE4_ROOT=~/UnrealEngine_4.17' >> ~/.profile
source ~/.profile


Rebuildスクリプトを走らせて、素材ファイルのリンクと周辺のビルドをする。
OpenGL 3.x環境の場合はUE4Editorの起動時の引数に-opengl3が必要になるので、Rebuild.shの編集が必要。

Rebuild.sh 最後の方(65行目くらい)にある以下を変更
- ${UE4_ROOT}/Engine/Binaries/Linux/UE4Editor "${PWD}/CarlaUE4.uproject"
+ ${UE4_ROOT}/Engine/Binaries/Linux/UE4Editor -opengl3 "${PWD}/CarlaUE4.uproject" 
UE4_ROOT=~/UnrealEngine_4.17 ./Rebuild.sh


リンク作業のためにUE4Editorが起動する(ここでOpenGLが3以上でないと詰む)
初回起動時は初期化が入るのでそれなりの時間を要する。

f:id:vaaaaaanquish:20180105221116p:plain:w400
死んでいる様子

リンク作業は以下参照
http://carla.readthedocs.io/en/latest/how_to_add_automotive_materials/

コンテンツブラウザでContent/Static/Vehicles/GeneralMaterials/MaterialRedirectorsに行って「RedirectorInstance」を開き検索フォームで「Parent」を検索。DummyCarをM_Carpaintに名前を変えて上書き保存して終わり。
https://carla.readthedocs.io/en/latest/img/materials_screenshot_00.png
https://carla.readthedocs.io/en/latest/img/materials_screenshot_01.png

多分この作業で失敗すると人や車が表示されないので何度かやってみる。

 
以下のようにxbuild周りでエラーが出た場合は、UEのmakeをやり直すか権限設定を見直す。

ERROR: UBT ERROR: Failed to produce item
not found xbuild


 

- CARLA Serverの実行と操作 -

CARLAの操作はServerを建ててPython Clientから操作という形になる

具体的にはC lang APIを叩いており、ドキュメントにある図で言うとこんな感じ
https://carla.readthedocs.io/en/latest/img/carlaserver.svg

http://carla.readthedocs.io/en/latest/how_to_run/

ドキュメントの通りbuildに成功していれば~/CARLAディレクトリ直下に以下スクリプトができているので実行すると、UE4が起動しCarla Serverが動き始める。

./CarlaUE4.sh /Game/Maps/Town01 -carla-server -benchmark -fps=15

ない場合はbuild失敗してるか、compile済みのlatestから取ってくるか。

操作用のクライアントsampleを動かのに必要なパッケージを入れる

sudo pip3 install numpy Pillow pygame

別コンソールを開いて~/CALRA/PythonClient/内にあるsampleを動かせばひとまず操作できるようになる。

python3 ~/CALRA/PythonClient/manual_control.py

f:id:vaaaaaanquish:20180109215835p:plain:w400

manual_controlの操作は以下の通り

    W  : 進む
    S  : ブレーキ
    A  : 左
    D  : 右
    Q  : バッグ
    Space : ハンドブレーキ
    R   : restart

とりあえず楽しいです。


 

- おわりに -

ひとまず動作させるまでで終わりです。

本当は年末年始でAirSimも試し、クライアント作りまでやって設定色々書こうくらいまで思っていましたが、UE4のbuildに何回も失敗したり、Ubuntuが死んだり、CARLAが起動しても人Moduleが表示されなかったりとまあまあ辛かったのでここまでになりました。


CARLAが動けばAirSimも動くはずなのでチャレンジします。


次は自身で自動運転操作するまでの工程とか、CARLAのパラメータsettingについて書いていきたいと思います。

がんばるぞ。

 

Xonshのconfigを書く

- はじめに -

//------------------------
追記 2018/06/22:

以下の通り、config.jsonはサポートされなくなり、xonshrcになりました。

WARNING! old style configuration
(/Users/xxx/.config/xonsh/config.json)
is no longer supported. 
Please migrate to xonshrc.

xonshrcは以下にまとめました
vaaaaaanquish.hatenablog.com

//------------------------


この記事は、Xonsh Advent Calendar 2017 - Qiita 21日目の記事です。

xonshには.xonshrcに加えて、staticなjson形式のconfigファイルで設定するパラメータがある。

本記事では、config.jsonの書き方について記載する。


xonshrcについては以下
vaaaaaanquish.hatenablog.com


 

- config.jsonとは -

config.jsonはデフォルトでは ~/.config/xonsh/config.json に配置する。

より正確なPathは $XONSH_CONFIG_DIR/config.json である。

このファイルは、xonshrcより前に読み込まれ、外部シェルからのデータロードや、xonshrc内でも採用されるような重要な環境変数の設定、xontribの記載などを行うものである。

以下参考
http://xon.sh/xonshconfig.html


 

- configを書く -

現状keyとして読み込まれるのは、envxontribsforeign_shellsの3つ。

ここに書いておくと良い点も含めて下記に示す。

 

env

xonshrcファイルでも設定できるけど環境変数

静的なjsonファイルというだけなので、現状xonshとしてenv設定出来てメリットがあるのは以下くらいか。

{
    "env": {
        "XONSH_DEBUG": 1,
        "FOREIGN_ALIASES_OVERRIDE": True
     }
}

XONSH_DEBUGでデバッグ設定しておけば、xonshrc等のデバッグができる。
FOREIGN_ALIASES_OVERRIDEは、外部のShellのエイリアスを優先するかどうか。

Examples等では$EDITORとか設定してるけど、xonshrcの方が管理しやすい良い気がする。
Windowsなら$ALLUSERSPROFILEにrcファイルへのPathを書いておいてもよい。
Python系ならjupyterやpyenvへのPathなんかはここで書いても良い(気がする)。

 

xontribs

xontribsは、xonshの拡張であるxontribをlistで書いておくところ。

xonshrcでは以下のようにloadしないといけない所、パッケージ名をlistで書くだけになるのでちょっと楽。

xontrib load hoge

Sampleで自分のやつ。
名前を書いておくだけでよい。

{
    "xontribs": ["z","docker_tabcomplete","fzf-widgets"]
}

xontribは以下で書いたので参考に
vaaaaaanquish.hatenablog.com

 

foreign_shells

foreign_shellsでは、subprocessで呼び出す外部シェルの情報が記述できる。

より正確には、以下で呼び出されるforeign_shell_data()内で、subprocessとしてshellが一度起動され、該当shellのenvとaliasを読み込んでくる。
xonsh/foreign_shells.py at adcd20f72fcbe6962533cb3ad78a4a9ec396e150 · xonsh/xonsh · GitHub

 
list形式でdictを設定していく。dict中のkeyとしては以下が設定できる。
http://xon.sh/xonshconfig.html#foreign-shells

{
    "foreign_shells":[
        {
            # 起動したいshell
            "shell": "/bin/zsh",
            # 対話起動するか(しなくてもenv読み込めるshellなら不要)
            "interactive": True,
            # ユーザとしてlogin必要か
            "login": False,
            # 起動shellにおけるenvコマンド
            "envcmd": "env",
            # 起動shellにおけるaliasコマンド
            "aliascmd": "alias",
            # 起動するshellの引数(str)
            "extra_args": [],
            # 手動で起動shellにenv設定するためにdict
            "currenv": {},
            # 例外を安全に処理するか(Falseにするとraiseされる)
            "safe": True,
            # 色々読み込む前後にshellで実行させるコマンド
            "prevcmd": "",
            "postcmd": "",
            # 呼び出すshellのrcみたいなもん(以下参考に)
            # https://github.com/xonsh/xonsh/blob/adcd20f72fcbe6962533cb3ad78a4a9ec396e150/xonsh/foreign_shells.py#L33:title
            "funcscmd": "",
            # 呼び出したshellでsourceするファイル
            "sourcer": "",
            # 該当shellでスクリプトを実行する時のコマンド
            "runcmd": "",
            # 該当shellでexit-on-errorを設定するためのコマンド
            # "set -e"や"if errorlevel 1 exit 1"
            "seterrprevcmd": "",
            "seterrpostcmd": ""
        }
    ]
}

foreign_shellsで既に設定しているshell(xonshに乗り換える前に使っていた色々)をそのまま流用できたりする。


 

おわりに

あんまり書く機会がないかも知れないが、configについて記述した。

env、xontribs、foreign_shellsしか今の所書く事はないがxonshrcがちょっと簡略化される所がメリットか。


ひとまずアドベントカレンダー埋めた感じです。

qiita.com


 

Pythonモジュールの遅延import

- はじめに -

この記事は、Xonsh Advent Calendar 2017 - Qiita 18日目の記事です。

Pythonのmoduleのloadを実際に利用する前に遅延してやろうというTipsです。

加えて、xonshのxonshrcに記載する事で、xonshの起動も早くしようという話を書いています。


アジェンダ

 

- 遅延importを実現する -

遅延させて、使いたい時にpythonスクリプトをロードしたりするには大抵importlibを使います。

そこでimportlibでxonshの起動爆速化を狙おうとしていた所、同僚に「lazyasdっていうのがあるよ」と言われて調べたら大体それで出来たので、これで良いやという感じでした。

以下には一応どちらも記述しています。

 

importlibで動的ロード -

Pythonでモジュールをスクリプト上で動的にロードするにはimportlibを使います。

31.5. importlib — The implementation of import — Python 3.6.6rc1 documentation

import importlib

os = importlib.import_module("os")
print(os.listdir("."))

machineryを使えばimportのタイミングをhookできます。
https://docs.python.org/3.6/library/importlib.html#module-importlib.machinery

遅延してロードさせる場合は、Python3.5にて追加されたimportlib.util.LazyLoaderを使うと良いです。
31.5. importlib — The implementation of import — Python 3.6.6rc1 documentation


参考:Python: モジュールを動的にロードする - CUBE SUGAR CONTAINER


 

lazyasdを使った遅延import

同僚が「xonsh使ってるならxonsh.lazyasdの中にLazyObjectやBackgroundModuleLoaderがあるのでそれ使うと良いよ」と教えてくれました。

Lazy & Self-destructive Objects (xonsh.lazyasd) — xonsh 0.6.7 documentation


その後、調べてみるとlazyasdだけパッケージとして切り離されているようです。

GitHub - xonsh/lazyasd: Lazy & self-destructive tools for speeding up module imports

pipでinstallできるのでやります

pip install lazyasd


lazyasdで一番簡易にモジュール使う時ロードを実現できるのはデコレータを付けることです。

import importlib
from lazyasd import lazyobject

@lazyobject
def os():
    return importlib.import_module('os')

# importが発生するのはココ
print(os.listdir("."))

実際にモジュールを利用する時にimportする事が割りと簡単にできました。

 
compile済みの正規表現も遅延させて読み込めます。

import re
from lazyasd import lazyobject

@lazyobject
def hoge_re():
    return re.compile('hoge')

print(hoge_re.search("hoge piyo str") is not None)

 
より良い方法として、別スレッドで読み込むload_module_in_backgroundもあります。

from lazyasd import load_module_in_background

os = load_module_in_background('os')
print(os.listdir("."))

引数のreplacementsも便利です。

 
関数を引数に取るためlambda使ったりとちょっと面倒ですが、LazyObjectLazyDictといったClassも用意されています。

from lazyasd import LazyObject
from lazyasd import LazyDict
import re

# 最初にosを使う時にglobalにosをimportする
os = LazyObject(lambda: importlib.import_module('os'), globals(), 'os')
print(os.listdir("."))

# 一回目に使う時に正規表現をcompileする
RES = LazyDict({
        'dot': lambda: re.compile('.'),
        'all': lambda: re.compile('.*'),
        'two': lambda: re.compile('..'),
        }, globals(), 'RES')
print(RES["dot"].search("hogehoge.text") is not None)

「使うか分からないので、もし使うなら最初にロードしたいな」という時に使えます。


多分以下を見るかソースコードを見ると良いです。
Lazy & Self-destructive Objects (xonsh.lazyasd) — xonsh 0.6.7 documentation


 

- xonshrcに書いていく -

ここからはxonshrcに書いておいてxonsh起動までを爆速にしてやろうという話です。

xonshであればpip installする必要もなく、xonsh.lazyasdを利用できます。

使うか分からないがimportを忘れがちなやつを全部こうしてやります

from xonsh.lazyasd import lazyobject

@lazyobject
def os():
    return importlib.import_module('os')

 
全部listに突っ込んでおけば、execしてくれるSampleです。
import asのようにしたい場合は、dictか何かにしてformat第一引数xをよしなにやれば良いです

from xonsh.lazyasd import lazyobject
import importlib

# list版
lazy_module_list = ["requests", "numpy", "pandas", "matplotlib",...]
for x in lazy_module_list:
    t = "@lazyobject\ndef {}():\n    return importlib.import_module('{}')".format(x, x)
    exec(t)

# dictならこんな感じか
lazy_module_dict = {
    'requests': 'requests',
    'sys': 'sys',
    'random': 'random',
    'shutil': 'shutil',
    'pd': 'pandas',
    'np': 'numpy',
    'plt': 'matplotlib.pyplot',
    'Path': 'pathlib.Path',
        }
for k,v in lazy_module_dict.items():
    t = "@lazyobject\ndef {}():\n    return importlib.import_module('{}')".format(k, v)
    exec(t)

これをxonshrcに書いて優勝です


いやいや、絶対コンソール使ってたら使うでしょという物はbackgroundでimportしてやりましょう。

from lazyasd import load_module_in_background

background_module_list = ["os", "sys", "random", "shutil", "linecache",...]
for x in background_module_list:
    exec("{}=load_module_in_background('{}')".format(x, x))


参考:Lazy & Self-destructive Objects (xonsh.lazyasd) — xonsh 0.6.7 documentation


 

- おわりに -

lazyasd便利なので、環境に合わせてロードするやつとかも拡張として書いていきたい所。

importlibのLoader周りはあんまりExamplesもなくて厳しいですが、まあなんとか。


Xonshアドベントカレンダーの方もよろしくお願いします。

Xonsh Advent Calendar 2017 - Qiita