第83回情報処理学会全国大会の情報保障

気になった情報保障(字幕)について

今回も情報処理学会全国大会に参加したんですが,
情報処理学会 第83回全国大会 - なぜか数学者にはワイン好きが多い
最終日,いつものようにIPSJ-oneに参加しました.
情報処理学会第83回全国大会

IPSJ-ONE
日時:3月20日(土)15:30-18:00
会場:特別会場

【セッション概要】情報処理学会には多数の研究会がある一方,それぞれの研究者が異分野で現在注目されている研究を知る機会は少ない.専門家ではない学生や他分野からの参加者にとってはなおさらである.そこで本企画では,多様な研究分野を垣根なく俯瞰するため,若手を中心とする優れた研究者が次々と登壇し,各自の研究を端的に紹介する.専門家のみならず,高校生,学部生,他分野の参加者にも理解しやすい講演を提供する.優れた研究と高いプレゼン力のある研究者を各研究会に推薦頂き,研究の内容などを考慮して登壇者を厳選した.分かりやすいプレゼンと完成度の高い演出を通じて優れた研究者をハイライトしつつ,異分野も含めた交流が研究を更に発展させるような場を目指す.また,マスメディア・ネットメディア等を通じた多数のアウトリーチも予定している.

IPSJ-oneでは毎年字幕生成がやられていて,試みはいいなあと思いつつ精度は悪いなーと思ってました.
リアルタイムに音声認識して文字で提示されていたのですが,ミスが多くてひどい.ところが今年は,IPSJ-one以外の情報保障セッションは参加できなかったので分からないのですが,IPSJ-oneでは,事前に収録したビデオに対し字幕作成したんですかね?講演者が話す前に字幕が出てました.
とてもプレゼンが盛り上がっていた,NTTの石畠さんの講演だとこんな感じ.
f:id:tullio:20210321033927p:plain

どうやって字幕作ったんですかね.メカニズムを公開して欲しい.
まあ,たぶん近く説明してもらえると思うので,楽しみにしています.

Jupyter上で,Scalaで画像データを表示する

ScalaをJupyter上で使うノウハウを蓄積したい

Scalaコンパイル型の言語ですが,REPLが使えるのでインタプリタ的に開発ができて便利です.
なのでサーバコンソール上でも十分な開発ができるのですが,Jupyterを導入することでさらに便利になります.
Scala/SparkのJupterカーネル「Almond」の導入 - なぜか数学者にはワイン好きが多い
ノートブックとして作業履歴や実行結果を記録できることも便利なのですが,画像データなんかを扱う場合,コンソールだと表示できない画像を表示できるのが便利です.
ところがScalaあるあるで,ドキュメントが少ないのでJupyter-Almond-Scalaで画像データを表示したりする方法がよく分からないです.そこでブログを書いてみるって感じです.

almond上でscalaノートブックを開く

まず,こちらの通りに,ノートブックを開いて頂きたい.

Jupyter labをインストールしてScalaをSparkで使う
情報処理学会 第83回全国大会 - なぜか数学者にはワイン好きが多い

ノートブック上でファイル保存されている画像データを読み込む

画像ファイルを表示するapiは準備されていて,

Image.fromFile("ここに画像ファイルのパスを書く")

これで表示できます.Imageはalmondの内蔵クラスなので,importしたりライブラリを持ってくる必要は無いです.
こんな感じ
f:id:tullio:20210321030208p:plain
もうちょいカッコよく表示するためには,例えばこんなメソッドを定義するのが良いかと思います.

def getImageText(imageFile: String) = 
s"data:image/png;base64,${Image.fromFile(imageFile).data.get("image/png").get}"

こいつを使うと,画像を並べたり色々できると思います.例えばこんな感じ.

Html(s"<table><tr><td><img src=${getImageText("/tmp/image-2-0-219-80.png")}></td><td><img src=${getImageText("/tmp/image-3-3-226-80.png")}></td></tr></table>")

f:id:tullio:20210321031055p:plain
Pythonも良いけど,データ分析はScalaだね!
...と言えそうな記事を書いていきたい笑

情報処理学会 第83回全国大会

2021年情報処理学会全国大会

今年も参加しました
情報処理学会第83回全国大会
オンライン開催のため,以前のように現地の写真をレポートすることができないのが残念です.
2017年情報処理学会全国大会。 - なぜか数学者にはワイン好きが多い
情報処理学会第76回全国大会に行ってきた - なぜか数学者にはワイン好きが多い
第75回情報処理学会全国大会 - なぜか数学者にはワイン好きが多い
2012年第74回情報処理学会全国大会出席まとめ - なぜか数学者にはワイン好きが多い
情報処理学会全国大会2011 - なぜか数学者にはワイン好きが多い
第70回情報処理学会全国大会 - なぜか数学者にはワイン好きが多い

初のオンライン開催では,バタバタと決まったこともあり,学生さんの参加者が激減した記憶があります.
情報処理学会第82回全国大会

が,今回は参加者は多かったように思います.
印象的だったのは,オンラインに慣れている何人かの学生さんが,ビデオ映像を入れて上手にプレゼンテーションをアピールした発表をしていることです.Zoom操作・パソコントラブル等もずいぶん減ったような印象でした.

ちょっとだけ負担が増えたことは,情報処理学会ではオンライン開催のトラブルを防ぐため,セッションの座長の他に「座長補佐」というものを置くようになりました.だいたいの人は座長と座長補佐の両方を引き受けることになるため,準備の手間が2倍になった感じです.まあ,仕方がないかなーと思います.
また,オンラインの方が質疑応答参加のハードルが高いのか,質問等が圧倒的に減ったように思います.座長も現場の雰囲気が見えないために時間により質疑応答を打ち切りやすく,時間は比較的守られる反面,全国大会のコミュニケーションを促進するという目的に対してはイマイチのイベントになっているなあという気がしました.

ああ,本当に字ばっかりの記事になった笑

自分の発表の時に,前の職場の同僚が聴講参加しているのを見つけてしまい,超緊張した&もっと面白いネタで発表すれば良かったと後悔したのは秘密です.
# t2sy氏,君だw

Jupyter labをインストールしてScalaをSparkで使う

この間,

注:Jupyter自体は予めインストールされているとします.

と書いたところを,一応丁寧に.
自分の備忘録として.
AWS EC2にインストールする必要が出たので.

EC2にデフォルトではpython2しか入っていなかったので,python3を入れてjupyterをインストールします.

sudo yum install python3-devel
pip-3 install --user jupyterlab

jupyterを立ち上げた時にブラウザが立ち上がらないようにするとかパスワードやトークンを不必要にしてセキュリティレベルを落とす(アクセス元制限とか他の方法でセキュリティ設定がされていることとする)とか,設定を変更します.

jupyter lab --generate-config
emacs .jupyter/jupyter_lab_config.py

c.ExtensionApp.open_browser = False  
c.ServerApp.token = ''  

ここまででjupyter-labを立ち上げると,ランチャーにはデフォルトで登録されているpythonなどが出ます.
f:id:tullio:20210320013752p:plain

ここで,紹介した方法でalmondをインストールします.
Scala/SparkのJupterカーネル「Almond」の導入 - なぜか数学者にはワイン好きが多い

その後,jupyter-labを立ち上げると,ランチャーにscalaが出ます.

f:id:tullio:20210320014055p:plain

Scala(almond)を選んでノートブックを立ち上げたあと,sparkを使うにはライブラリをインポートします.
あと,ドキュメントにあるようにログレベルも変更します.
Spark · almond

import $ivy.`org.apache.spark::spark-sql:3.1.1`
import $ivy.`sh.almond::almond-spark:0.11.0`
import org.apache.log4j.{Level, Logger}
Logger.getLogger("org").setLevel(Level.OFF)

ライブラリのインポートが成功したあとに,sparkセッションのインスタンスを作成します.

import org.apache.spark.sql._

val spark = {
  NotebookSparkSession.builder()
    .master("local[*]")
    .getOrCreate()
}

あとは,sparkを使う感じで実行ができます.

import spark.implicits._
val a = Seq(1,2,3).toDF
a.show
+-----+
|value|
+-----+
|    1|
|    2|
|    3|
+-----+

簡単で,素敵ですね(colla風)

Scala/SparkのJupterカーネル「Almond」の導入

Jupyter Almondカーネルをインストールする

Spark/Scalaを使うことができるJupyterのカーネルとして,Apache Toreeのメンテナンスをしています.

Home

Apache Toreeは,Spark3対応の開発が進んでいる状況ですが,なにぶん開発がアクティブとは言い難いです.
GitHub - apache/incubator-toree: Mirror of Apache Toree (Incubating)
最後のコミットは昨年8月のようです.
Prepare for next development interaction 0.6.0.dev1 · apache/incubator-toree@fb61d80 · GitHub

f:id:tullio:20210303223421j:plain
Apache Toree Commit Activity
f:id:tullio:20210303223524j:plain
Almond Commit Activity

Commit Activityを見ると開発の活発度は一目瞭然です.
そこで,Almondを試しにインストールしてみました.

インストール方法

オフィシャルサイトでは,色々なインストール方法が紹介されています.
Installation · almond
私はこれで行きました.

$ curl -Lo coursier https://git.io/coursier-cli
$ chmod +x coursier
$ ./coursier -J-Dhttps.proxyHost=[Proxyのアドレス] -J-Dhttps.proxyPort=[Proxyのポート] bootstrap almond:0.11.0 --scala 2.12.9 -o almond
$ ./almond --install --name 'Scale(almond)' --id scala_almond 

注:Jupyter自体は予めインストールされているとします.

Proxy設定について

proxyが必要な環境だったので,結構ハマりました.
インストールの際は,上記の用にcoursierコマンドに,Java用のProxy設定オプションを加えます.また,Jupyterを立ち上げてカーネルとしてscala_almondを選んでからも,ライブラリインストールのために以下のコマンドをノートブック上で実行します.

System.setProperty("https.proxyHost","Proxyのアドレス")
System.setProperty("https.proxyPort", "Proxyのポート")

Sparkを使うためには,以下のようにSparkのライブラリを導入します.

import $ivy.`org.apache.spark::spark-sql:3.1.1`

そういや,ちょうどSpark-3.1.1がリリースされました.
Spark 3.1.1 released | Apache Spark

AWS EMRでSpark RAPIDSを使う

AWSでSpark RAPIDSを使うには

クラウドじゃなくて,自前のサーバでSpark RAPIDSを使うには,Spark RAPIDS一式を準備する必要があります.
マシンがX86ならビルド済みのライブラリがありますが,Power PCだと自前で用意する必要があります.

Spark RAPIDSを試したら凄かった - なぜか数学者にはワイン好きが多い
とてつもなく苦労して,作業時間は2週間かかりました.

しかし,クラウドだと,苦労しません...

AWS-EMR - spark-rapids

The current EMR 6.2.0 release supports Spark version 3.0.1 and RAPIDS Accelerator version 0.2.0. For more details of supported applications, please see the EMR release notes.

EMR6.2ではSpark3.0.1及びRAPIDS Accelarator0.2.0をサポートしています.

Using the Nvidia Spark-RAPIDS Accelerator for Spark - Amazon EMR

With Amazon EMR release version 6.2.0 and later, you can use Nvidia’s RAPIDS Accelerator for Apache Spark plugin to accelerate Spark using EC2 graphics processing unit (GPU) instance types.

EMR6.2以上では,Sparkを高速化するためにEC2 GPUインスタンスを使うNVIDIAのRAPIDS Accelarator Sparkプラグインを使うことができます.

AWSのEMR 6.2(2021/02/09時点の最新バージョン)では,追加のライブラリ等は無しに,設定するだけでSpark RAPIDSを使うことができます.基本的には,設定はこれだけ.

{
	"Classification":"spark",
	"Properties":{
		"enableSparkRapids":"true"
	}
}

実際にはまだ設定はありますが,依存するjarなどの書き並べるような設定は必要なく,EMR側で準備されているところがポイントです.

当然,コアインスタンスにはGPUを積んでいるインスタンスが必要で,現時点の東京リージョンでは,こちらが一番安いインスタンスです.

  インスタンスサイズ vCPU メモリ (GB) GPU ストレージ (GB) オンデマンド料金/時間*
単一の GPU VM g4dn.xlarge 4 16 1 125 0.526 USD

AWSのページによって料金に違いがあるのですが,$0.5--$0.7のようです.EMRのデフォルトのm5.xlargeが$0.124程度のため5倍くらい値段が高いです.

EMR6.2で利用できるSparkはSpark3であり,Spark3はScala2.12を使う必要があります.Scala 2.11ベースのSparkを使っている場合は,バージョンアップを考えると良いと思います.
Spark3からはHadoop 3対応やAccelerator-aware Scheduler,Adaptive Query Execution,Dynamic Partition Pruning など大量の改良点があるので,効率化・高速化が期待できるということで,ぜひバージョンアップを試みると良いのではないでしょうか.

ScalaでSparkのプログラムを作る作業を高速化する.

SparkのScalaプロジェクトのビルドを爆速にする

Scalaを気に入っています.Javaはとにかくコードが冗長になり,気持ち悪かったです.Cはシンプルだし大好きです.なのでObjective-CC++はそれなりに好きだったのですが,Cのコードがそのまま書けてしまうのは流石に今どきだとどうかと思ったり,型についてアバウト過ぎるのでデバグが大変だったりしました.Rubyは大好きでラピッドプロトタイピングしたりしてアルゴリズムを検証するには最高なのですが,ライブラリ化なんかを考えると使いにくかったり.その辺り,Scalaなら便利だし楽しいし好きです.

ただしScalaは難しくて学習コストが高い.が,これは頑張ればいい話なのでScalaのせいじゃないです.しかし,Scalaで作っているプログラムがデカくなってくると,ビルドに時間がかかる.これは努力じゃどうにもならなくて,生産性や効率を考えるととても問題です.しかし解決策はたくさんあります.

ScalaでSparkのプログラムを書くことを考えます.Scalaは各種のライブラリを色々使って便利にコーディングできるので,大量のライブラリをリンクすることになります.そして,Sparkを使う時は,sbt-assemblyなどでuber-jar/fat-jarを作るのが普通で,全てのライブラリをリンクするので時間がかかるしjarのサイズがデカくなる.

私のdeeplearning4jを使ったプログラムは,jarのサイズはこんな感じです.

-rw-r--r-- 1 tullio docker 799M Feb  6 15:37 DeepZip-assembly-0.1.0-SNAPSHOT.jar

799Mバイト.デカイよ.1Gバイトにもなろうとするファイルを作らないとならないとは.sbt-assemblyでビルドしてuber-jarを作ると,これくらい時間がかかります.

sbt:DeepZipTest> assembly
[info] Strategy 'deduplicate' was applied to 3 files (Run the task at debug level to see details)
[info] Strategy 'discard' was applied to 11 files (Run the task at debug level to see details)
[info] Strategy 'filterDistinctLines' was applied to 14 files (Run the task at debug level to see details)
[info] Strategy 'first' was applied to 2672 files (Run the task at debug level to see details)
[info] Strategy 'last' was applied to 14 files (Run the task at debug level to see details)
[success] Total time: 169 s (02:49), completed Feb 6, 2021 3:37:58 PM

cleanしてassemblyすると,こんな感じ.

sbt:DeepZipTest> clean
[success] Total time: 11 s, completed Feb 6, 2021 3:59:37 PM
sbt:DeepZipTest> assembly
[info] Updating
[info] Strategy 'deduplicate' was applied to 3 files (Run the task at debug level to see details)
[info] Strategy 'discard' was applied to 11 files (Run the task at debug level to see details)
[info] Strategy 'filterDistinctLines' was applied to 14 files (Run the task at debug level to see details)
[info] Strategy 'first' was applied to 2672 files (Run the task at debug level to see details)
[info] Strategy 'last' was applied to 14 files (Run the task at debug level to see details)
[info] Strategy 'rename' was applied to 102 files (Run the task at debug level to see details)
[success] Total time: 263 s (04:23), completed Feb 6, 2021 4:04:04 PM

3分から5分かかるんですが,長いです.タイプミスして一文字間違えただけでビルドし直し3分.イラつくだけじゃなく,本当に効率が落ちます.作業が遅くなる.

これを高速化する方法はたくさんあるのですが,単純に全てのリンクを止めるというのが簡単で効果的です.
そのマジックは,sbt-assemblyに仕込まれています.

GitHub - sbt/sbt-assembly: Deploy fat JARs. Restart processes. (port of codahale/assembly-sbt)

Splitting your project and deps JARs

To make a JAR file containing only the external dependencies, type

> assemblyPackageDependency

This is intended to be used with a JAR that only contains your project

assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false, includeDependency = false)

自分のプロジェクトと依存ライブラリのjarを分離する

外部の依存ライブラリだけのJARファイルを作るには,このようにタイプして下さい:

> assemblyPackageDependency

自分のプロジェクトのファイルだけのJARファイルを作るには,このように出来ます:

assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false, includeDependency = false)

使い方は簡単で,自分が作っているプロジェクト以外の依存ライブラリのjarを作っておく.

sbt:DeepZipTest> assemblyPackageDependency
[info] Strategy 'deduplicate' was applied to 3 files (Run the task at debug level to see details)
[info] Strategy 'discard' was applied to 11 files (Run the task at debug level to see details)
[info] Strategy 'filterDistinctLines' was applied to 14 files (Run the task at debug level to see details)
[info] Strategy 'first' was applied to 2672 files (Run the task at debug level to see details)
[info] Strategy 'last' was applied to 14 files (Run the task at debug level to see details)
[success] Total time: 178 s (02:58), completed Feb 6, 2021 4:14:04 PM

ls -lh
-rw-r--r-- 1 tullio docker 799M Feb  6 16:14 DeepZip-assembly-0.1.0-SNAPSHOT-deps.jar

依存ライブラリ一式のjarを作るのに3分かかってますが,これは一度作っておけばOKなので,問題ありません.jarのサイズは799Mバイトで,作りたいfat-jarの大部分を占めていることが分かります.

さて,依存ライブラリjarを作っておくと,自分で作っているコードのビルドは,ほとんど一瞬で終わります.
ビルドコマンドは,assemblyじゃなくてpackageでOK.

sbt:DeepZipTest> package
[success] Total time: 0 s, completed Feb 6, 2021 4:18:25 PM

ls -lh
-rw-r--r-- 1 tullio docker  92K Feb  6 16:18 deepziptest_2.12-0.1.0-SNAPSHOT.jar

ビルド時間は0秒(笑),jarのファイルサイズは92Kバイト

ビルド時間が5分だったのが0秒になります.これは効率化,向上でしょう.

Sparkで実行するには,完全なubar-jarだったら

spark-submit --class DeepZip DeepZip-assembly-0.1.0-SNAPSHOT.jar

となるところを,

spark-submit --class DeepZip --jars DeepZip-assembly-0.1.0-SNAPSHOT-deps.jar deepziptest_2.12-0.1.0-SNAPSHOT.jar

と--jarsで依存ライブラリのjarをアップロードするだけです.

ビルドが一瞬になって,Scalaの快適ライフをどうぞ!
全てのScalaプログラマーは,eed3si9n | works by eugene yokotaさんに感謝しつつsbt-assemblyを使うのが良いと思います.

Spark RAPIDSを試したら凄かった

NVIDIA Spark RAPIDSを試してみた

Apache Sparkファンとしては,Sparkの色々な活用方法を探しています.特に私はIBM PowerでSparkを使っているので,機械学習のためのライブラリを使おうとすると,色々と苦労しています.幸い,IBM Powerは,ギリギリでNVIDIAのサポートを受けています.例えば,CUDAが使えます.
ならばSparkでCUDAを使ってGPUを活用したい!
と思いますよね.

そこでSpark RAPIDS.

GitHub - NVIDIA/spark-rapids: Spark RAPIDS plugin - accelerate Apache Spark with GPUs

RAPIDSは様々なプロジェクトのトップです.
Open GPU Data Science | RAPIDS

今回は,RAPIDSの中のSpark RAPIDSだけ取り上げます.

ローカルモードで試してみる

私はIBM Power8とIBM Power9から構成されるHadoop YARNクラスタでSparkを使っています.ただ,GPUが付いているPower9は一台しか無いので,SparkをYARNモードじゃなくてlocalモードで試してみます.

細かいことはあとで説明するとして,結果を貼り付けてみます.

f:id:tullio:20210206005645p:plain
Spark RAPIDS test 1

普通に,Hadoopのログファイルを読んで,limitで適当にレコード数を決めて,時間情報でsortして,あるカラムでgroupByするというSpark SQLを実行して,実行時間を計測してみました.
赤はRAPIDSを使わなかった時で,レコード数に比例して処理時間が増えています.緑はRAPIDSを使った時で,レコード数が増えても処理時間が変わりません(!).色々試した結果,GPUのメモリが溢れるまでは定数時間でイケました.

レコード数が20480000,約2000万レコードの時,sparkを--master localでCPUで実行した時は,処理時間が16秒でした.同じjarファイルをspark-submitした場合,1秒でした.16倍の高速化です.

CPUで実行する時と,GPUを使う時は,Sparkのconfigureで切り替えています.GPUを使う場合のConfはこんな感じ.

spark.rapids.shuffle.transport.enabled  true
spark.rapids.sql.enabled                true
spark.rapids.sql.explain                ALL
spark.rapids.sql.concurrentGpuTasks     1
spark.plugins                           com.nvidia.spark.SQLPlugin
spark.rapids.sql.castStringToTimestamp.enabled  true


詳細は,順次,報告します!