How to Install pyrouge

要約

pyrouge を入れるのに手間取ったのでメモ

pyrouge とは文書要約タスクで利用される評価指標である ROUGE を Python で計算するモジュールです.今回は Docker で環境構築しております.

最初に答えを述べておくと,以下の Dockerfile で pyrouge がインストールできます. ベースが pytorch/pytorch:0.4.1-cuda9-cudnn7-devel なのは私の都合です.

FROM pytorch/pytorch:0.4.1-cuda9-cudnn7-devel

RUN apt-get update && apt-get install -y libxml-parser-perl && apt-get clean
RUN git clone https://github.com/bheinzerling/pyrouge /opt/pyrouge && cd /opt/pyrouge && python setup.py install
RUN git clone https://github.com/andersjo/pyrouge.git /opt/rouge && pyrouge_set_rouge_path /opt/rouge/tools/ROUGE-1.5.5
RUN cd /opt/rouge/tools/ROUGE-1.5.5/data/ && rm WordNet-2.0.exc.db  && ./WordNet-2.0-Exceptions/buildExeptionDB.pl ./WordNet-2.0-Exceptions ./smart_common_words.txt ./WordNet-2.0.exc.db

解説

第一章:始まり

最初は pip install pyrouge しかしていませんでしたが,

FileNotFoundError: [Errno 2] No such file or directory: '/root/.pyrouge/settings.ini'

が出て怒られました.

instllation をよく読むと, pyrouge_set_rouge_path /absolute/path/to/ROUGE-1.5.5/directory とあります.ROUGE-1.5.5 てなんや?と思ってググると,どうやら これ のことで,pyrouge はその Python ラッパーのようです. ということで,

$ git clone https://github.com/andersjo/pyrouge.git /opt/rouge
$ pyrouge_set_rouge_path /opt/rouge/tools/ROUGE-1.5.5

しました. 結果はダメで,

FileNotFoundError: [Errno 2] No such file or directory: 'pyrouge_write_config_file.py': 'pyrouge_write_config_file.py'

と怒られました.

第二章:ソースからインストール

困りながらググっていると,この記事に出会いました.どうやらソースからインストールすればいいようです.pip で入れた pyrouge を消して,以下のようにしてみました.

$ git clone https://github.com/bheinzerling/pyrouge /opt/pyrouge
$ cd /opt/pyrouge
$ python setup.py install
$ pyrouge_set_rouge_path /opt/rouge/tools/ROUGE-1.5.5

結果はダメで,エラーをよく読むと

Can't locate XML/Parser.pm in @INC (you may need to install the XML::Parser module) (@INC contains: /opt/rouge/tools/ROUGE-1.5.5 /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 /usr/local/share/perl/5.22.1 /usr/lib/x86_64-linux-gnu/perl5/5.22 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.22 /usr/share/perl/5.22 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base .) at /opt/rouge/tools/ROUGE-1.5.5/XML/DOM.pm line 41.

とありました.どうやら perlXML::Parser モジュールがないようです.

第三章:xml パーサのインストール

XML::parser のインストールは ここ を参考にしました.

$ apt-get update
$ apt-get install -y libxml-parser-perl

結果はまたダメで,

Cannot open exception db file for reading: /opt/rouge/tools/ROUGE-1.5.5/data/WordNet-2.0.exc.db

と怒られました.

最終章:WordNet-2.0.exc.db 作り直し

この issue を参考に,もともとある WordNet-2.0.exc.db を消して作り直しました.

$ cd /opt/rouge/tools/ROUGE-1.5.5/data/
$ rm WordNet-2.0.exc.db
$ ./WordNet-2.0-Exceptions/buildExeptionDB.pl ./WordNet-2.0-Exceptions ./smart_common_words.txt ./WordNet-2.0.exc.db

結果,ようやく python -m pyrouge.test が通りました.長い戦いだった.

終わりに

エラーから何が問題かわかりにくいやつは特に解決するのに手間取りました. 今回はどうしても pyrouge を使いたかったので環境構築を頑張りましたが,ROUGE スコアは n-gram の Recall ベースのスコアで複雑な処理はなさげなので,自分で実装してしまってもいいかもしれないです.

PyTorch で GPU 並列をちょっと詳しく

要約

PyTorch でマルチ GPU してみたけど,色々ハマったので記録に残しておく.データ並列もモデル並列(?)もやった.

メインターゲット

  • PyTorch ユーザ
  • GPU 並列したい人

前提知識

.

並列化したコード

どのようなコードを並列化したのかの説明を軽くしておく.必要なければ読み飛ばしてもらって構わない.

この論文 の自前実装.テキストを入力に画像を生成するモデル.テキスト→オブジェクト位置→オブジェクトの形→画像 の順に予測・生成していく. このモデルを訓練するスクリプトを並列化した.

モデル

主なコンポーネント
Component input output
box_generator テキスト オブジェクトの位置とラベルのペア(以後オブジェクト)の列
shape_generator テキスト,オブジェクト列 オブジェクトの形の列
image_generator テキスト,オブジェクトの形の列を一つの画像にまとめたやつ(セマンティックレイアウト) 画像
補助的なコンポーネント
Component input output
text_encoder (pretrained) テキスト(単語列) テキストベクトル
shape_discriminator テキスト,オブジェクトの形の列 そのオブジェクトが正例か shape_generator が生成したものかの 2 値
image_discriminator テキスト,画像 その画像が正例か image_generator が生成したものかの 2 値
vgg_model (pretrained) オブジェクトの形 or 画像 入力画像の内部表現(本来は画像分類モデルだが,今回は内部表現を利用する)
モデル図

f:id:ensyu3-141592653589793238:20190603172452p:plain
Hong et al., CVPR2018

特筆事項
  • box_generator は RNN な構造を持つ.shape_generator は RNN な構造を持つし,CNN も持つ.
  • vgg_model は vgg19 を利用.結構でかい.CNN.

.

並列化1:DataParallel

1 バッチを各 GPU に割り振る.例えば 4 GPU で DataParallel でバッチサイズ 256 のを回すと,一つの GPU がバッチサイズ 64 のバッチを処理する.

実装方法

PyTorch には DataParallel モジュールが用意されている.使い方はめっちゃ簡単. Document

device_ids = range(torch.cuda.device_vount())
model = DataParallel(model, device_ids=device_ids)

DataParallel が何をやってるかをちょっと詳しく

discuss.pytorch.org

同期更新型のデータ並列.以降,勾配計算のみを行う複数個の GPU を子 GPU,勾配の集約を行う唯一の GPU を親 GPU と言う. ※親 GPU 自身も勾配計算を行う.

1. Forward
  1. ミニバッチを各 GPU に均等に割り当てる.
  2. GPU に乗っているモデルのパラメータ情報等を各子 GPU にコピーする.
  3. GPU にて Forward プロセスを行う.
  4. Forward 結果を親 GPU に集約する.
2. 親 GPU にてロスを計算
3. Backward
  1. ロスを各 GPU に割り当てる.
  2. GPU にて Backward プロセスを行う.
  3. Backward 結果の勾配情報を親 GPU に集約する.
4. 親 GPU のモデルパラメータを更新

DataParallel に向かない設定

パラメータの多いモデル

イテレーションごとにモデルのコピーが発生するので,パラメータの多いモデルはコピーのオーバーヘッドが大きく,DataParallel の恩恵を受けられない.全結合層だけで構成されるモデルとかがその例.

基本的に畳み込み層で構成されていて,最終層だけ全結合層とかの場合は,全結合層を DataParallel の対象から外すというハックを行うことで大幅な高速化が期待できるそう.参考コード

自分でも全結合層を DataParallel の対象から外す処理を試してみた.イテレーションが 42秒から 40秒になるという,微妙な差.

小さいバッチサイズ

バッチサイズが小さくても,パラメータのコピーに対して Forward/Backward の計算が少なくなるので,DataParallel に向かない.十分なバッチサイズが確保できるよう,大きすぎないモデル設計を心がけるか,とてもメモリの大きい GPU を用意するかしよう.

RNN(特に LSTM)

DataParallel するには,batchFirst である必要がある.その他,色々とエラーが出て闇が深そう. さらに,LSTM はセルが複雑なことをするので速くならないらしい.説明をめちゃくちゃ端折ったので,興味がある人はこちらの議論を見てください.

.

並列化2:モデル並列 & multiprocessing

今回並列化したモデルは box_generator/shape_generator and shape_discriminator/image_generator and image_discriminator の 3 つに計算グラフを完全に分離できる.したがって,これらを別々の GPU に乗せたうえで各 GPUイテレーションを並列実行することが割と簡単にできる. 計算グラフが切れないガチのモデル並列は一つ下のレイヤからいじる必要があって闇が深いので,この世のどんな GPU にも乗り切らないめっさでかいモデルを絶対に動かさなきゃいけない事情がない限り避けたほうがいいと思う.

実装方法

1. 各モデルを別々の GPU に載せる

以下のようにすれば良い.

device0 = torch.device("cuda:0")
device1 = torch.device("cuda:1")
device2 = torch.device("cuda:2")

model.box_generator.to(device0)
model.shape_generator.to(device1)
model.image_generator.to(device2)

box_input_tensor = box_input_tensor.to(device0)
shape_input_tensor = shape_input_tensor.to(device1)
image_input_tensor = image_input_tensor.to(device2)

ただし,全てのテンソルをちゃんと正しい GPU に割り当てる必要があるので,内部で .cuda() とかで雑に初期化していると別々の GPU にあるテンソルで演算しようとしてんじゃねぇよエラーが出る.頑張って修正しよう.

2. multiprocessing

モデルを別々の GPU に乗せただけでは並列に実行されないので,並列に実行するために multiprocessing する必要がある.Python の multiprocessing の PyTroch ラッパーがあるので,それを使う.

Document にサンプル実装がある.訓練フェーズを関数化して,multiprocessing.Process に渡せば,その訓練が fork されて独立に動き出す.

CUDA initialization error が発生する場合は,mp.set_start_method('spawn')torch.manual_seed(args.seed) の前で宣言すると回避できる.参考

spawn は子プロセスを開始する方式の一種で,指定しない場合は多分 fork だった気がする.デフォルトでは子プロセスの中でも CUDA の初期化を行ってしまうせいでエラーが発生するらしい.(CUDA の初期化は 1 回しかしちゃダメ)

spawn はプロセスを一度 Pickle 漬けにするので,lambda などのPickle 漬けできない書き方を解消する必要がある.また,Pickle 漬け処理が重たいので,遅い.悲しい.

.

2 種類の並列化を試した結果と感想

どちらも lab のサーバだとそんなに速くならなくて悲しかった.それぞれ,「batch_size が小さすぎる」「spwan が遅すぎる」というネックがあり,それを解消できなかった. ABCI で試したところ,DataParallel で 1.3 倍くらいには速くなったので,それでやっていくことにした.

PyTorch の DataParallel は基本的に CV 系のモデルを想定していて,NLP 系のモデルに向いていないのが悲しかった.使う分には楽なので,使えるところで局所的に使うのが賢そう. multiprocessing はそもそも PyTorch でそこまでサポートされていなくて,エラー回避が大変だったし,効果が薄かった. DataParallel を(上手く)使うことをオススメする.

.

リファレンス

Hong et al., CVPR2018: S. Hong, D. Yang, J. Choi and H. Lee,``Inferring Semantic Layout for Hierarchical Text-to-Image Synthesis,'' In proc. of CVPR2018. pdf

flask プロジェクトの PyCharm 実行でハマった

PyCharm で flask プロジェクトを作って,PyCharm 上で実行したら,スクリプトで指定している設定が反映されなくて困った.

.

経緯

flask プロジェクトを作成

PyCharm で flask プロジェクトを作った.

pleiades.io

スクリプトを編集

app.py のメイン内で debughost の設定をいじった.

from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

実行 & 問題発生

PyCharm で app.py を実行した.

FLASK_APP = app.py
FLASK_ENV = development
FLASK_DEBUG = 0
In folder /Users/nomotoeriko/PycharmProjects/untitled
/Users/nomotoeriko/.pyenv/versions/3.5.0/bin/python -m flask run
 * Serving Flask app "app.py"
 * Environment: development
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

明らかに host="0.0.0.0" が反映されていないことがわかる.

.

真相

どうやら app.py を直接実行しているわけではないらしく,メインが呼ばれていなかった.開発環境とかその辺のアレで PyCharm がよしなにやってくれているのかなぁ.知らんけど.

.

対処

真面目な対処法

公式によれば,

Flaskサーバーの実行/デバッグ設定の対応するパラメータを編集することにより、Flask固有の変数を変更することができます。

とのこと.以下のページから,flask run のパラメータに --host があること,Flask デバッグモードの有効化には FLASK_DEBUG にチェックをつければ良いことがわかる.

pleiades.io

ということで,Edit Configurations から設定をいじる. f:id:ensyu3-141592653589793238:20190515002358p:plain

Additional options からホストを設定.FLASK_DEBUG にチェック.

動く ✌︎('ω'✌︎)

FLASK_APP = app.py
FLASK_ENV = development
FLASK_DEBUG = 1
In folder /Users/nomotoeriko/PycharmProjects/untitled
/Users/nomotoeriko/.pyenv/versions/3.5.0/bin/python -m flask run --host 0.0.0.0
 * Serving Flask app "app.py" (lazy loading)
 * Environment: development
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 285-077-691

雑な対処法

PyCharm の Terminal から app.py を叩く.

あとがき

思わぬ落とし穴だった.まぁ公式をよく読みましょうってことですね.でも Hello World までを自動生成してくれるのはさすが JetBrains という感じ.便利.

一緒に原因を考えてくれた I 氏と執筆にご協力してくれた T 氏に深く感謝いたします.

RandomCrop とかを入力画像と正解画像で統一する方法

経緯

PyTorch で画像系の学習をするときに, RandomFlipRandomCrop をよく使う.最近研究関連で,オブジェクト位置,セグメンテーション,画像を順に生成していく既存モデルを構築しており,それらのデータでランダムな部分を統一する必要があった.なかなかいい感じの記事に出会えずどうやるか調べるのに苦労したので結論をまとめておく.

.

想定する読者

  • PyTorch で画像物体検知を実装しようとしている人
  • クラスの継承がわかる人

.

.

RandomCrop とかを入力画像と正解画像で統一する方法

RandomCrop とかを継承して,__call__ だけ上書きする.

from torchvision import transforms
from torchvision.transforms import functional as F


class UnitedRandomCrop(transforms.RandomCrop):

    def __call__(self, *args, **kwargs):
        img, segms, bboxes = args
        i, j, th, tw = self.get_params(img, self.size)
        cropped_img = F.crop(img, i, j, th, tw)
        cropped_segms = [F.crop(segm, i, j, th, tw) for segm in segms]
        cropped_bboxes = [self.crop_bbox(bbox, i, j, th, tw) for bbox in bboxes]
        return cropped_img, cropped_segms, cropped_bboxes

    @staticmethod
    def crop_bbox(bbox, i, j, th, tw):
        x, y, bw, bh = bbox
        start_x = max(0, x - j)
        start_y = max(0, y - i)
        stop_x = min(tw, x + bw - j)
        stop_y = min(th, y + bh - i)
        cropped_bbox = [start_x, start_y, stop_x - start_x, stop_y - start_y]
        return cropped_bbox

.

詳細

get_params でランダムなパラメータを取得している.このパラメータを使って,__call__ 内でデータに必要な変換を記述して返す.基本的には本家の記述に従えば OK.

get_paramsこの issue で導入が検討された関数.オブジェクト検知タスクにおいて,ランダム部分を入力画像と正解画像(セグメンテーション)で統一したいという欲求が発生し,様々な議論がなされていた所,fmassa さんがいい感じにまとめて問題提起を行ったのがこの issue .この議論の結論は RandomCrop とかのクラスで,パラメータ作成と実際の画像の変換を分け,また,画像変換部分は関数として提供することである.これによってユーザが自由にサブクラスや関数を作れるようになるとのこと.

全ての RandomHoge クラスに get_params が実装されているわけではないので,注意が必要.執筆時点(2019/04/08)で get_params メソッドを持つのは RandomCrop RandomResizedCrop ColorJitter RandomRotation RandomAffine.例えば RandomFlip には get_param メソッドがない.確かに単純すぎて分けるほどではない気がする.

.

あとがき

英語の issue ツリーを読むの疲れた.

もしもっといい方法があるならぜひ教えてください!

ディープラーニング分散学習ハッカソン参加報告

経緯

研究室のお金でディープラーニング分散学習ハッカソンに参加してきました.

www.cc.u-tokyo.ac.jp

 

 

想定する読者

  • 深層学習してる人
  • 分散深層学習をやってみようと思っている人

 

 

イベントの概要

要旨:参加者が持ち寄った深層学習のコードを強いメンターたちに助けられながら分散深層学習のコードに書き換えていく.

共催:

  • 東京大学情報基盤センター
  • 株式会社Preferred Networks
  • TensorFlow User Group
  • エヌビディア合同会社
  • PCクラスタコンソーシアム(実用アプリケーション部会)

期間:2019/01/24--2019/01/25 の 2 日間

場所:東京大学情報基盤センター

計算機:情報基盤センターの Reedbush-H

フレームワーク:Chainer か Tensorflow

プログラム:

  1. 主催側からのプレゼン(各組織 20 分ずつ)
  2. 参加者自己紹介
  3. 各自作業
  4. 成果報告

分散深層学習基礎講座

Nvidia さまから 分散学習基礎講座 というタイトルのプレゼンがあったので,その内容を私なりにまとめる.詳細は元スライドを参照のこと.

分散深層学習とは

深層学習を,複数の GPU を使って行うこと.データ並列/モデル並列 や 同期更新/非同期更新,パラメータサーバ方式/P2P方式 などの分類がある.

データ並列とモデル並列

データ並列

モデルをコピーして,パラメータを共有した状態でそれぞれ別のサンプルで訓練する並列化方法.GPU ごとに別々のデータで勾配を計算させるので,モデル更新時にはうまいことパラメータを一致させる必要がある.

同期更新と非同期更新

パラメータの更新方式は同期更新と非同期更新に分けられる.

同期更新 GPU の勾配計算完了を待ってモデルを更新する.GPU 性能に差がある場合無駄が出る.
非同期更新 一部の GPU の勾配計算が終わったらモデルを更新する.後述の Staleness 問題が発生する.

 

パラメータサーバ方式と P2P 方式

GPU 間の通信にはパラメータサーバ方式と P2P 方式がある.

パラメータサーバ方式 パラメータサーバのパラメータを,各 GPU がそれぞれ更新していく.
P2P 方式 ある GPU での更新を他の GPU に伝播させる.

 

モデル並列

一つのモデルを複数の GPU に置く.一つの GPU にはモデルの一部が乗っている状態.各レイヤを GPU に割り当てたり,一つのレイヤを複数の GPU に割り当てたり,いろんな切り方がある.どのような切り方がいいかはモデル依存.

各方式の弱点

データ並列:大規模化に伴う精度低下

一回の重みの更新の時に関わるサンプル数が [バッチサイズ] × [並列数] になるため,並列化しすぎると精度が低下する.

どこまで並列化できるかや,たくさん並列化しても精度を落とさないようにする研究が行われている.

  • 「8k 並列までなら精度落ちない」by 顔本
  • 「32k まではいける」by PFN

ちなみに SGD 的な最適化を行う場合,学習率を下げることとバッチサイズを大きくすることは等価 であるため,学習が進むにつれて学習率を下げる代わりに並列数を大きくするのもアリかもしれない.簡単には実装できなさそうだけれど.

同期更新:GPU の性能差で無駄が発生

パラメータの更新時に全ての GPU での勾配計算が完了するのを待つため,GPU に大きな性能差がある場合に無駄な時間が発生する.

非同期更新:Staleness 問題

非同期更新では,勾配の計算中に他の GPU がパラメータを更新するので,勾配計算に使っていたパラメータが相対的に古くなってしまう.これを Staleness 問題という.Staleness 問題は収束性の悪化の原因となるらしい.

モデル並列:通信コスト

フォワードプロセスでも GPU 間で通信が必要なので,データ並列に比べ通信コストが高い.

私たちがやったこと

弊研究室 からは K 先輩と私の 2 人で参加した.私たちは Chainer を使った seq2seq 機械翻訳モデルのコードに対して ChainerMN でデータ並列の分散化を施した.

資料 の通りに秒速 MN 化を行ったところ,悲しいことにバグが大量発生したので Chainer の中の人に助けられながらその解消を行っていった.なんとか時間ギリギリでエラーの出ない状態になり,並列化でどれくらい速くなったか測ろうとしたところ時間切れとなってしまった.ログを見る限り並列化しないほうが速かったので,多分まだどこかにバグがあるんだと思う.悲しい.

バグ取りを通して得られた知見

重複するエラーメッセージ数

並列数とエラーメッセージの重複数が同じ場合は GPU ID に関係のないところで出ているエラー,異なる場合は GPU ID によってエラーが出る場合と出ない場合があるエラー.私たちの場合は GPU に ID を割り振る操作をコードの中で複数回呼んでしまっていたことで起きていた.

単一 GPU でも同じエラーが出るかどうか

同じコードでも単一 GPU に設定した場合は動く場合,GPU 間の通信時に起きているエラーの可能性が高い.単一 GPU だと通信が行われないのでエラーが発生しない.

GPU に載せるテンソルは to_gpu とかの後に作る

ChainerMN ではデバイスをセットする操作の前後の行列を混ぜると死ぬ.

 

参加しての感想

ChainerMN 開発者をメンターに据えて ChainerMN を使ってみるという贅沢な時間でした.開発者ならではのお話が聞けて楽しかったです.

2 日間とも Nvidia さまがお弁当を提供してくれたり,1 ヶ月間 Reedbush を利用できるという特典も付いているのに参加費は無料という超絶お得なイベントでした.参加してよかったです.

分散深層学習を行うのは初めてだったのですが,難しかったです.私の研究では画像もテキストも扱うので,モデルの大きさによってはバッチサイズを小さくしないと動かないということが起こります.そんな時にデータ並列は [バッチサイズ] × [並列数] が実質のバッチサイズになるので魅力だと思いました.頑張ろうかな.頑張れるかな.

修論で忙しいにも関わらず本記事の最終確認をしてくれた T 氏に感謝いたします. 

Latex で画像位置がずれる問題へ対処した話

経緯

lab メンが某会議への論文投稿でハマっていたのをみんなで解決した.ググってもなかなかドンピシャの解決にたどり着けなかったので記事に残す.

 

想定する読者

  • 論文の投稿を dvi + eps 形式で行うように指定されている人
  • Overleaf のプレビューでは正しいのに,dvi を出力してコンパイルすると画像位置がどうしてもずれてしまう人
  • matplotlib で eps 形式の図を出力して latex に includegraphics しようとしている人

 

発生した問題

ことの経緯を以下にまとめる.

  1. モデル図はパワポで作って eps 形式で保存
  2. グラフは python の matplotlib.pyplot で描画して eps 形式で保存
  3. Overleaf でこれらの eps ファイルを includegraphics 
  4. コンパイラlatex に設定してコンパイル
  5. Overleaf のプレビューで正しくコンパイルできていることを確認
  6. Overleaf のドキュメントに従って dvi 形式でダウンロード
  7. eps ファイルたちと dvi ファイルを一つのフォルダにまとめて zip
  8. 某会議に zip ファイルを提出
  9. 某会議のシステムで pdf にコンパイルされ,その結果がこちらに届く
  10. 届いたものを確認するとグラフの表示位置がずれている

 

似たような状況として以下がある.ただしこちらの解決策は今回通用しなかった.

tex.stackexchange.com

 

私たちが dvi 形式に疎く,また某会議がわのコンパイル環境がわからなかったこともあり,対処が難航した.Overleaf で出ているエラーを解決したり,includegraphics のオプションで重複のある部分を取り除いたり,利用 OS の種類を某会議への提出時に選択するのだが,それを変えてみたり....

 

対処

elehoody.blog.fc2.com

調査の結果,上記と同じことが起きていたっぽいことがわかった.matplotlib でグラフを保存する際 pdf 形式を選択し,ImageMagic で eps に変換することで解決した.

eps にはいろんな情報が含まれているっぽい.今回は一部の余分な情報が悪さをしてて,pdf にすることでそいつを落としたら解決したのかな,と理解した.知らんけど.

 

あとがき

Overleaf の問題なのか,某会議の方の問題なのか,ビューワーの問題なのかがわからなくて苦労した.Overleaf で直接 pdf をダウンロードできるので,私含めみんなが dvi を意識したことがなかったのも足を引っ張った.

私含め 5 人でこの問題に対処したのだが,結果的に解決に繋がらなかった方法も含めて,それぞれが鋭い着想に基づいた方法で lab メンつおいってなった.eps 全てではなく,グラフだけがずれていることに着目した lab メンがこの方法を提案し,それを聞いた私が上の記事を見つけた.ちゃんとした位置に図が配置されている pdf を見たときは歓声が上がった.みんなで課題解決するの楽しい.

ちなみに今回は eps 形式という指定があったからそうしたが,選べるのなら eps 形式ではなく pdf 形式で図を入れたほうが安定だと思う.こことかにそう書いてある.

 

何はともあれ無事投稿できたようで安心.通っているといいな.

 

Amazon Mechanical Turk (MTurk) を使ってみたメモ

経緯

研究の一環で Amazon Mechanical Turk (MTurk) を使う機会があった.日本語のドキュメントや記事が少なく,ところどころ苦戦したので,使用感などをメモっておく.

私が参考にした大変よくまとまった資料を以下に紹介する.MTurk を使うための資料としては本記事よりもこちらを読むことを推奨する.

www.slideshare.net

 

想定する読者

  • MTurk を使う予定の弊 lab 学生
  • クラウドソーシングでデータを集めようと思う人
  • MTurk についてなんでもいいから情報が欲しい人

 

MTurk の概要

MTurk は Amazon が提供する,クラウドソーシングを円滑に行うためのサービスである.MTruk ユーザはワーカかリクエスタどちらかの形態をとる.ワーカは仕事を行う人,リクエスタは仕事を発行する人である.

 

MTurk の利用:ワーカ編

ワーカは仕事(MTurk では1個の仕事を HIT と呼ぶ)を行う.

HIT 選び

サービス上で現在開かれている HIT 一覧を確認することができる.HIT には仕事内容の簡単な説明,報酬,ワーカ条件,制限時間などが定められている.だいたいどれくらいの時間でできる仕事なのかを説明のところに明記しているものが多いので,それで時給換算できる.ワーカ条件とはその HIT に取り組めるワーカの条件で,『US 在住』『今までで最低 50 件の HITs をこなした』などの項目がある.HIT をクリックすることでより詳細な仕事内容を確認することができる.

HIT への取り組み

詳細な HIT 内容を確認した上で,仕事に取り組むボタン(ボタンの名前は忘れた)を押して,実際に仕事を行う.仕事は選択肢から正解をどんどん選んでいくものもあれば,画像の物体位置に矩形とオブジェクトラベルを付与するようなものもある.このような仕事を制限時間内に行い,最後に submit を押すと仕事を行なったことになる.制限時間をすぎると submit できないので,集中して取り組む必要がある.

報酬の受け取り

ワーカが submit した成果は HIT 発行者であるリクエスタによって確認される.リクエスタが承認するとワーカは報酬を得る.否認すると報酬はもらえない.また,HIT 承認率はワーカ条件として指定可能なため,否認が増えると取り組める HIT が減ることになる.仕事には誠実に取り組みましょう.

 

MTurk の利用:リクエスタ編

リクエスタは HIT の発行と提出された成果の承認を行う.

HIT の発行

HIT の発行にあたり定義するべき項目はざっと以下の通りである.

  • HIT のタイトル
  • 仕事内容の簡単な説明
  • キーワード(ワーカがHITを検索する上で利用される)
  • 報酬
  • ワーカ人数
  • 制限時間(緩めに設定しておくことが推奨されている)
  • ワーカ募集期間(もちろん人数に達した時点で募集をやめることにはなる)
  • ワーカの submit から自動承認を行うまでの期間(この期間をすぎると否認できなくなる)
  • ワーカ条件

特に気をつけるべきは『報酬』と『制限時間』と『ワーカ条件』である.以下ではそれぞれについて注意点を述べる.

気をつけるべきポイント:報酬編

報酬は適切に定められることが望ましい.だいたい 5$/1h と風の噂で聞いたため,1 時間程度の HIT だった私は 5$ と設定した.ただ,あくまで時給換算は目安であることに注意すべきである.仕事内容や仕事画面の UX 設計によっては,たとえ同じ拘束時間であってもワーカの感じる仕事量に差が出ることがあり,必ずしも時給換算した報酬が適切とは限らない.ワーカが仕事内容の説明を読んで簡単そうだと思うのなら報酬は安めに設定すべきだし,難しそう/めんどそうだと思うのなら報酬は高めに設定すべきである.

特に,報酬が安すぎると全然ワーカが集まらないといったことが起こる.大変...

(20181116追記)クラウドソーシングにおける賃金設定のガイドラインがあるらしい.Guidelines for Academic Requesters - WeAreDynamo Wiki

気をつけるべきポイント:制限時間編

制限時間は厳守される.そのため,制限時間は『普通にやっていれば絶対に超えない時間』くらいには緩めに設定しておくべきである.私の場合は 1 時間の想定に対し制限時間を 2 時間と設定したにも関わらず,1 名のワーカが制限時間をオーバーしてしまった.3 時間くらいにしておけばよかったかなぁ...

気をつけるべきポイント:ワーカ条件編

ワーカ条件には様々なものが選べる.その中で設定するときに特に注意すべきが『HIT 承認率』である.これはそのワーカが今まで submit した仕事のうちどれくらい承認されたかを表すものである.私は最初これを『greater than 99%』としていた.さて,これを和訳するとどういう意味になるだろうか.答えは『99% より上』である.サービスの実装上,この条件だと,承認率 99.3% のワーカも条件外になってしまう.正しくは『greater than or equal 99%(99%以上)』であるべきだ.こんなところで英語力のなさが露呈した...

提出された成果の承認

リクエスタは成果提出者のワーカIDと実際の成果物を確認し,成果物の質によって承認/否認を決定する.何もしなければ自動的に承認される.成果物の質の定義は様々で,私の場合はダミー問題を用意しそれへの正解率を基準に決定した.

否認することはリクエスタにとってもワーカにとってもリスクとなるため,基本的には行わないことが望ましい.よっぽど成果物の質が悪い場合にのみ否認を選択する.否認するときには否認理由を対象のワーカに通知することができる.ワーカはリクエスタのメールアドレスを見ることができるので,説明不足な否認を行うと抗議文が届いたりして面倒なことになりそう.否認理由はしっかりと書くことが望ましい.

 

その他 MTurk を利用した上で気になったこと

ワーカ-リクエスタ間のやり取りについて

ワーカからリクエスタにはメールを送ることができる.リクエスタからワーカには直接の連絡を取ることができない.リクエスタからワーカに連絡をとる唯一の方法は,成果物を否認するときのメッセージのみである.なんか不公平だよね.

仕事画面の作り方について

仕事画面は MTurk 上で作ることができる.結構様々な機能があるっぽい.ただしアップロードできるデータ量に制限があり,それを超えるような仕事の場合は自前でサイトを作成し,そこへのリンクを飛ばすという方法を取る.この場合 MTurk 上ではサイトから発行する仕事完了コードを受け取るだけになる.完了コードはワーカによって別々のものを発行することが望ましい.

ワーカは MTurk とサイトを行き来することになるので,途中で間違えてページを閉じてしまったりしても大丈夫なように自前サイトにはログイン機能を実装することをおすすめする.また,MTurk 上で受け取る情報はワーカ ID と終了コードのみになるため,成果物の確認をするならば自前サイト側でもワーカ ID をもらう必要があると思う.多分.ワーカ ID は大事なものなので,ちゃんと『もらった情報は研究にしか使いませんよ』的なことを説明書きに書いたり,最低限 https なサイトにしたりする方がいい.

 

あとがき

なかなか執筆時間が取れず,MTurk を使ってから結構時間が経っての投稿となってしまった.そのせいでところどころうろ覚えで,あまり意味のある文章にはならなかったように思われる.悲しい.弊 lab では今回,共同の MTurk リクエスタアカウントを作成し(てもらっ)た.今後この記事が弊 lab 学生の役に立つことを祈る.

 

参考にさせていただいたサイト

Amazon Mechanical Turk - Wikipedia

Amazon Mechanical Turk

実践 Amazon Mechanical Turk