#RubyKaigi 2025 で「Improvement of REXML and speed up using StringScanner 」というタイトルで発表しました
2025/04/16〜2025/04/18にかけて松山で開催されたRubyKaigi 2025に参加し、今回は RubyKaigi 本編に登壇するという実績を解除することができました🎉
昨年の RubyKaigi 2024 のLT でお話した話
の続きで、今回、発表した資料は下記になります。
REXML 3.2.6 (Ruby 3.3.0 添付のもの) から最新の REXML 3.4.1 の間で、StringScanner を使った実装に置き換える事で、XMLパース処理が最大6割速くなったので、 StringScanner を使うと何故パース処理が速くなるのか、どのような点に気をつけてパース処理を書けば速くなるのか などを、REXML の実装を踏まえながら高速化のポイントを紹介させて頂きました。
高速化のポイント
- XMLのパース処理にRegexpクラスの代わりにStringScanner を使うと速い
- 単純な性能比較で StringScanner の方が5割程度速い
- StringScanner を効果的に使うことで StringScanner (C拡張部分) の処理を最適化する
- StringScanner のRegexpマッチの代わりにStringマッチを使うとより高速
- 正規表現は便利だが処理が重いので、文字列でのマッチで代替可能な場合はStringマッチ(内部処理は
memcmp()
やrb_memsearch()
での文字列比較)を使う事で速く処理できる
- 正規表現は便利だが処理が重いので、文字列でのマッチで代替可能な場合はStringマッチ(内部処理は
- Stringマッチならマッチ対象文字列が長くなっても、性能劣化を最小限に抑えられる
- 正規表現の場合、マッチ対象文字列が長くなるとパフォーマンス低下に繋がりやすい
- String Object の生成を避けると速い
- マッチ結果を返すために Object 生成するのにコストがかかるので、マッチ結果を Integer で返すと Object 生成しないので速くなる
- StringScanner のRegexpマッチの代わりにStringマッチを使うとより高速
- Ruby 実装部分で遅い処理には定数やメモ化を使うことでボトルネックを解消する
という感じで、細かな改善の積み重ねで最大6割の高速化を実現した内容をベンチマークコードとその結果を用いて説明させて頂きました。
また、上記の高速化の取り組みを実施後、YJITを有効化すると、Ruby 実装部分が JIT コンパイルされるので、さらに高速化されます。
StringScanner の 新機能(#scan_until(String)
)追加による Stringマッチ、新メソッド(#peek_byte
)追加による String Object 生成回避 といった高速化手法が増えた事も、今回の高速化に繋がっているので、StringScanner を使ってパース処理を実装してみたいという方は、ぜひトライしてみてください。
最後に
今回、RubyKaigi 本編初登壇で、当日朝まで資料を修正してたりしていたので、やり切った感が半端ない感じでした。
自分の発表が終わった後に、質問に来てくれた方が 5人ぐらいおられました。 その中で、内藤の発表を受けて、「モチベーションが非常に上がったので、とりあえずその感動を伝えたい」とその事だけを伝えに来てくれた方もおられたので、RubyKaigi で「何かを持ち帰る」だけでなく「何かを持ち帰って頂ける」ようになれたんだなと思いました。
来年も登壇できるように頑張ります!
ruby/rexml のメンテナーになりました
ruby/rexml のメンテナーになりました。
— NAITOH Jun (@naitoh) 2024年12月16日
rexml をもっと良い感じにしていくぞ💪https://t.co/Ve7bRd564m
というわけで、ruby/rexml のメンテナーになりましたので、この1年間の REXML (と StringScanner) への取り組みをまとめてみます。
- 1. rexml 高速化
- 2. 不正XMLチェックの強化
- 3. 各パーサー間でのパース処理結果の統一
- 4. REXML の SAX2 & Pull パーサ使用時のDoS脆弱性を報告 & 修正
- 5. StringScanner の改善
- 6. まとめ
1. rexml 高速化
Ruby 3.3.0 添付の rexml 3.2.6 gem から、Ruby 3.4.0 添付の rexml 3.4.0 gem の間で最大4割の高速化を実現しました。🎉
Add 3.4.0 entry · ruby/rexml@19d8ebf · GitHub
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [x86_64-linux] Calculating ------------------------------------- rexml 3.2.6 master 3.2.6(YJIT) master(YJIT) dom 8.073 9.400 13.512 16.667 i/s - 100.000 times in 12.386407s 10.638806s 7.400877s 5.999736s sax 13.416 15.955 19.910 25.617 i/s - 100.000 times in 7.453542s 6.267482s 5.022630s 3.903620s pull 15.971 19.289 23.253 30.003 i/s - 100.000 times in 6.261289s 5.184190s 4.300510s 3.332993s stream 14.660 18.499 20.502 28.797 i/s - 100.000 times in 6.821191s 5.405752s 4.877656s 3.472597s
rexml 3.2.6 → 3.4.0 の比較
YJIT=OFF | YJIT=ON | |
---|---|---|
dom | +16.4% | +23.3% |
sax | +18.9% | +28.6% |
pull | +20.7% | +29.0% |
stream | +26.1% | +40.4% |
- YJIT=OFF 状態で 16.4%〜26.1% の高速化
- YJIT=ON 状態で 23.3%〜40.4% の高速化
という感じで、最大4割の高速化を実現しましたので、やった事を説明しようと思います。
パース処理の内部実装を Regexp クラスから StringScanner に変更
Ruby の Regexp クラスを用いた正規表現でのパース処理を StringScanner を用いたパース処理に置き換えました。 この辺りは RubyKaigi 2024 LT で発表しましたので詳細は下記を参照ください。
なお、上記blog でStringScanner#check と Regexp#match とのマイクロベンチマークで 単純なケースでは StringScanner は Regexp より 1.67 倍速い
と言いました。
この点、LT 発表では詳細には触れなかったのですが、Regexp クラスでは Onigmo という正規表現エンジンが使用されており、StringScanner の正規表現もOnigmoを使用しています。 つまり同じ正規表現エンジンを使って処理しているのですが、Regexp クラスの場合、マッチ時に MatchData Object を生成して返すのでその分遅くなっているようです。 (StringScanner はマッチした文字列だけを返すので速い。)
似たような StringScanner#match? と Regexp#match? の下記マイクロベンチマークでは、両方ともマッチデータは応答しないため、ほぼ同じ性能です。
prelude: |- require "strscan" str = "test string" s = StringScanner.new(str) re = /\A\w+/ benchmark: s.match?(/\w+/): | s.match?(/\w+/) re.match(str): | re.match?(str)
$ benchmark-driver benchmark/test.yaml Warming up -------------------------------------- s.match?(/\w+/) 12.391M i/s - 12.828M times in 1.035236s (80.70ns/i) re.match(str) 12.888M i/s - 12.964M times in 1.005849s (77.59ns/i) Calculating ------------------------------------- s.match?(/\w+/) 14.362M i/s - 37.174M times in 2.588407s (69.63ns/i) re.match(str) 14.672M i/s - 38.665M times in 2.635401s (68.16ns/i) Comparison: re.match(str): 14671575.6 i/s s.match?(/\w+/): 14361690.4 i/s - 1.02x slower
※ StringScanner#match?
はパターンマッチの値 self[nth] は変更され、Regexp#match?
は $~
などパターンマッチに関する組み込み変数の値は変更されないため、Regexp#match?
が若干速いようです。
同じ正規表現エンジンを用いているのでどこまで高速化できるのか? が疑問点だったのですが、下記の観点で最適化した結果、 最終的な REXML の高速化に繋がったと考えています。
正規表現をなるべく使わないようにする (文字列のみのマッチで代替する)
正規表現を使うと処理に時間がかかるため、XMLパース処理を見直し、このタイミングではこの文字列かこの文字列が来る、違う文字列が来たらエラー
といった感じで文字列比較でパース可能な処理は正規表現を使わないように変更しました。
StringScanner は文字列の先頭から順番にパースしていくので StringScanner らしい処理に書き換えることで高速化できました。
不要な文字列 Object の生成を抑える形で最適化する
StringScanner#scan
はマッチした文字列を返すのですが、返された文字列を使用しないケースでは文字列 Object 生成処理が無駄なため、マッチした文字列長を返す StringScanner#skip
を使うように変更しました。
繰り返し使う正規表現オブジェクトやエンコード処理をキャッシュして生成コストを抑える
- Optimize Source#read_until method by naitoh · Pull Request #135 · ruby/rexml · GitHub
- Optimize `IOSource#read_until` method by naitoh · Pull Request #210 · ruby/rexml · GitHub
頻繁に呼ばれる double quotation
や single quotation
の正規表現オブジェクト生成やエンコード処理に時間がかかっていたためキャッシュしました。
2. 不正XMLチェックの強化
下記のようなXMLは不正で、処理を続行するとパース処理で不要な考慮が必要になるためエラーするように変更しています。
- 複数のルートタグ
<root1></root1><root2></root2>
- 開始ルートタグ前の文字列
foo<root></root>
- 終了ルートタグ後の文字列
<root></root>bar
- ルートタグ無し文字列
404 error
アプリケーション側も不正なXMLはエラーになってくれると嬉しいと思います。
3. 各パーサー間でのパース処理結果の統一
REXML はパース処理方法の違いから DOM/SAX2/Pull/Stream の各パーサーがあり、それぞれ使い勝手が異なり用途に合わせて使って頂く事を想定しているのですが、パース処理結果に差異があったので揃えました。
- SAX2 パーサーで 定義済み実態参照が展開されない
- Stream パーサーでユーザー定義実態参照が展開されない
4. REXML の SAX2 & Pull パーサ使用時のDoS脆弱性を報告 & 修正
CVE-2024-41946: REXML内のDoS脆弱性 で報告したのですが、内容的には DOM の REXML におけるエンティティ展開に伴うサービス不能攻撃について (CVE-2013-1821)、 CVE-2014-8080: REXML におけるXML展開に伴うサービス不能攻撃について と同じになります。
上記 3 の各パーサー間でのパース処理結果の統一の一環で、各パーサー間の実装差を減らしたいなと処理を見てると、DOM だけ対処されて、なんで SAX2 & Pull パーサの場合、この処理無いんだろう?と気づいてDOMの再現用テストコードを流用して SAX2 & Pull パーサで試したら問題があったので横展開する形で治しました。 テストコード大事。
セキュリティ報告ってやった事が無かったので新鮮で勉強になりました。(久々に patch コマンド使った。)
5. StringScanner の改善
REXMLを高速化するために StringScanner を使い出したのですが、StringScanner もいい感じにする必要があったので改善しています。
StringScanner#captures
の挙動がMatchData#captures
の振る舞いと異なっていたので修正- JRuby ではあまり使われていなかったのか
StringScanner#<<
でjava.lang.OutOfMemoryError
が発生する問題を見つけたので報告して修正してもらいました。 StringScanner#scan_until(pattern)
の文字列比較対応 (今までは正規表現のみ対応)
上記の 2〜4 は RubyKaigi 2024 follow up で話させて頂きましたので、下記の資料が参考になると思います。
6. まとめ
という感じで REXML をいい感じに改善していたら ruby/rexml のメンテナーに推薦頂き、REXMLが大分わかってきたのでメンテナーになりました。
REXML をもっと良い感じにしていくぞ💪
#RubyKaigi 2024 LTで「Improved REXML XML parsing performance using StringScanner 」というタイトルで発表しました。
RubyKaigi 2024 LT で 6年振り にLT発表させて頂きました。
今回の内容は、おおよそ naitoh.hatenablog.com を5分に縮めた内容になります。
具体的には、下記になります。
- 自分が作成している RBPDF gem で SVG 画像(XMLで記述されています。)を処理したいので、XML処理ライブラリの中でインストールの容易な REXML を使いたい。
- REXML は C拡張の gem の libxml-ruby と比較して dom で65倍、sax でも 21倍遅いので、速くしたい。
- Ruby 3.3 で YJIT を有効にするだけで dom で65倍→44倍、sax で 21倍→14倍の性能差まで改善されるが、まだ遅いのでさらに改善したい。
- RubyKaigi 2019 の Better CSV processing with Ruby 2.6 で、StringScanner を用いって CSV gem を速くした話で REXML も速くしたいという話があった。
- REXML は Regexp クラスを用いて実装されているので、StringScanner で書き換えを実施すれば良いか検討。
- StringScanner への書き換えは下記の手順で実施。
- 結果、下記まで性能改善することができた。
- YJIT無効状態で、dom: 65倍→60倍に短縮、sax: 21倍→17倍に短縮。
- YJIT有効状態で、dom: 44倍→25倍に短縮、sax: 14倍→8.6倍に短縮。🎉
※ 資料で計測したコードは https://gist.github.com/naitoh/abc5134fdf37bb3952e36f1fb77163b0 になります。 (YJIT 無効時は、RubyVM::YJIT.enable
の行をコメントアウトして計測。)
Ruby 1.8.7 の頃の絶望的(300倍くらい?)なREXMLの遅さ から比較すると、同じオーダの性能差まで短縮できたので、用途によっては本番環境でも使えるのではないでしょうか。
今回のLTは無事、時間内に終わりましたが、緊張して声が震えてしまいました。いろんな場でLTして緊張しないようになりたいですね。 今年のRubyKaigi も楽しかったです。感謝!
RubyKaigi 2024 に出したCFP
久々にCFP出したけど通らなかったので公開します。
REXMLは Ruby 1.8.7 の頃に比べると本当に速くなってるし、YJITは Pure Ruby のライブラリにとってゲームチェンジャーだと思うんですよ。
※ 実際に出したCFP は英語で記述しています。
Title
REXMLのXML解析処理の改善
Abstract
REXML は Ruby で標準で使える XMLライブラリ(Bundled Gem)で、Ruby で実装されています。
Pure Ruby のためインストールし易い特徴があるのですが、逆に処理性能が遅いです。 今回、この REXML のパース処理を高速化したので、どのような手法を用いて実施したのかをお話しします。
Details
intended audience(対象読者)
このトークは下記の方を対象に考えています。
outcomes(成果)
REXML の XMLパース処理が正規表現(Regexp)で実装されているのを StringScanner (1) を用いたXMLパース処理に書き直し(2)、XML パース処理を最大 32%高速化(3)しました。
REXML と StringScanner の解説をまじえながら、私がどのような手法を用いてREXMLのXMLパース処理を高速化したのかを説明する事で、XMLの処理方法や StringScanner のパース処理方法を理解して欲しいと考えています。
- https://docs.ruby-lang.org/ja/latest/class/StringScanner.html
- PR
- https://github.com/ruby/rexml/actions/runs/7723085598/job/21052458823
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux] Calculating ------------------------------------- rexml 3.2.6 master 3.2.6(YJIT) master(YJIT) dom 4.902 5.224 7.664 8.755 i/s - 100.000 times in 20.400673s 19.140694s 13.047998s 11.422036s sax 13.011 15.593 18.846 23.533 i/s - 100.000 times in 7.685622s 6.413001s 5.306133s 4.249434s pull 15.512 19.271 22.121 29.095 i/s - 100.000 times in 6.446480s 5.189123s 4.520615s 3.436964s stream 14.188 17.217 19.395 24.327 i/s - 100.000 times in 7.048419s 5.808095s 5.155877s 4.110616s Comparison: dom master(YJIT): 8.8 i/s 3.2.6(YJIT): 7.7 i/s - 1.14x slower master: 5.2 i/s - 1.68x slower rexml 3.2.6: 4.9 i/s - 1.79x slower sax master(YJIT): 23.5 i/s 3.2.6(YJIT): 18.8 i/s - 1.25x slower master: 15.6 i/s - 1.51x slower rexml 3.2.6: 13.0 i/s - 1.81x slower pull master(YJIT): 29.1 i/s 3.2.6(YJIT): 22.1 i/s - 1.32x slower master: 19.3 i/s - 1.51x slower rexml 3.2.6: 15.5 i/s - 1.88x slower stream master(YJIT): 24.3 i/s 3.2.6(YJIT): 19.4 i/s - 1.25x slower master: 17.2 i/s - 1.41x slower rexml 3.2.6: 14.2 i/s - 1.71x slower
outlines(概要)
- 最初にXMLの概要とXMLの処理方式(DOM, SAX)の違いを説明します。
- REXML の処理性能を他のRuby C拡張 gem と比較しながら現状の処理速度を説明します。
- 文字列スキャナである StringScanner の使い方の説明をします。
- 処理速度を改善するために行った事(ベンチマークの整備、プロファイラを用いたボトルネックの確認、StringScannerのバグ修正等、StringScannerを用いた処理の書き換え)を説明します。
- まとめ
Pitch
Explain why this talk should be considered (この講演を考慮すべき理由)
Python や PHP などと比較して、Ruby の標準 XML パーサーが遅いのが気になっていました。
Ruby 1.8.7 の記事ですが、1万行程度のXMLの(DOM)パース処理 で C拡張gem の libxml-ruby と比較して数桁遅く、本番環境では使い物にならない状況でした。
https://suer.hatenablog.com/entry/20110126/xml_parse
この当時と比較して、Ruby の高速化、YJIT による高速化、REXML 自身の高速化などにより状況が改善されつつあるため、Pure Ruby 実装である REXML を再評価できればと考えています。
what makes you qualified to speak on the topic. (このテーマを話す資格がある理由)
仕事(SMI-S XML, PubMed XML)やプライベート(SVG)でXMLを処理する事が多く、複数の種類のXMLファイルを処理した経験があります。 また、nokogiri, ox, REXML と複数の XMLパーサーを使用した経験があり、今回 REXML のパース処理をStringScannerを用い高速化できた事で、REXML や StringScanner について解説できると考えています。
- Storage Management Initiative Specification (SMI-S)
- https://www.nlm.nih.gov/bsd/licensee/data_elements_doc.html
- https://developer.mozilla.org/en-US/docs/Web/SVG
Spoken language in your talk
日本語
Ruby 2.6 の新機能の endless range と Range#% を Numo::NArray と Cumo で対応しました。
自分が参加している Red Data Tools の Element で @mrkn さんから、
ArithmeticSequence と Range から begin, end, step, exclude_end を取り出す C API を trunk に追加しました。 ruby/ruby@914a290 だれか、これを使って NArray などの slicing に対応するプルリクエストを作ってみませんか?
という提案を頂いたので、 Numo::NArray と Cumo (※ Numo::NArray のGPU 版)で 上記 C API を使用して Ruby 2.6 の新機能の endless range と Range#% に対応を実施しました。
endless range とは、下記のように 末端の "-1" 指摘を省略できる書き方です。
また、step の alias として % を使用できると、より直感的に書く事ができます。
- Ruby 2.5
> a = [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4] > a[1..-1] => [1, 2, 3, 4] > a[1...-1] => [1, 2, 3] > (1..4).to_a => [1, 2, 3, 4] > (1..4).step(2).to_a => [1, 3]
- Ruby 2.6 (endless range, Range#%)
> a = [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4] > a[1..] => [1, 2, 3, 4] > a[1...] => [1, 2, 3, 4] > (1..4).to_a => [1, 2, 3, 4] > ((1..4) % 2).to_a => [1, 3]
このように便利な記法が Numo::NArray や Cumo でも使えると嬉しいので、Ruby 2.6 の環境で同様に書けるように対応しました。
- Numo::NArray
> require 'numo/narray' > a = Numo::Int32.new(5).seq => Numo::Int32#shape=[5] [0, 1, 2, 3, 4] > a[1..] => Numo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[1...] => Numo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[(1..) % 2] => Numo::Int32(view)#shape=[2] [1, 3]
- Cumo
> require 'cumo' > a = Cumo::Int32.new(5).seq => Cumo::Int32#shape=[5] [0, 1, 2, 3, 4] > a[1..] => Cumo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[1...] => Cumo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[(1..) % 2] => Cumo::Int32(view)#shape=[2] [1, 3]
numo-narray の endless range、Range#%の PR は master に 取り込まれている ので次のリリース(0.9.1.5以降?)で使用可能になると思われます。
cumo は リリース版ですでに 取り込まれている ので 0.2.5 以降で使用可能です。
Ruby 本体側でデータサイエンス向けの機能が取り込まれていくと、データサイエンス用ライブラリ側も便利になっていきますので嬉しいですよね。
Redmineのpdf出力機能で使われているRBPDF gem ライブラリについて
(この記事は Redmine Advent Calendar 2018 - Adventar の13日目の記事です。)
Redmine の PDF 出力機能で使われている 私が作成した RBPDF gem ライブラリについてのお話です。
RBPDF は下記のような特徴があります。
- Pure Ruby
- HTMLからのPDF変換対応 (CSS 一部サポート)
- PNG/JPEG/GIF形式画像のPDF出力対応 (8bit PNG画像以外は RMagick が必要です。)
- CJKV(中国語・日本語・朝鮮語・ベトナム語) 対応
- 組み込みサブセットFont対応
- アラビア語などのRTL (Right-To-Left) 言語サポート
- 目次・しおり ※PDFへのリンクです。
- 図形 ※PDFへのリンクです。
- 円グラフ ※PDFへのリンクです。
実際にどのような事ができるかは Examples をご覧下さい。
なお、RBPDFは一から作成したものではなくPHPのPDF出力ライブラリTCPDFを、Redmineで使用するために Ruby に移植したものになります。
Redmine の PDF出力機能の歴史
RBPDFを作成することになった経緯を Redmine の PDF出力機能の歴史と合わせてお話しします。
Redmine の PDF出力機能は 1.0 の頃は FPDF という PHPのライブラリを Ruby に移植した RFPDF が使われていました。 このころは日本語が文字化けするなど多くの問題を抱えていましたが、Defect #61: Broken character encoding in pdf export - Redmine のチケットで edwinmoss さんが開発された 同じくPHP由来のTCPDFベースの RFPDF に置き換え & 修正作業を行うことで無事、Redmine 1.2 で CJK(日本・韓国・中国語)と多くの言語の文字化けが解決しました。
なお、これが私のRedmine での初の採用パッチになります。 詳細は、第2回勉強会 - redmine.tokyo (当時は shinagawa.redmine)で LTをさせて頂きました。
RFPDF(TCPDFベース)の機能で画像出力や(Textileから変換された)HTMLの変換などにも対応可能な事がわかったので、Redmine 1.3 で Textileによる書式設定 Feature #69: Textilized description in PDF - Redmine や画像出力 Feature #3261: support attachment images in PDF export - Redmine の対応を実施しました。
ただ、この対応時に多くの課題が見えてきたので、抜本的に解決を図るため edwinmoss さんから RFPDF の開発を引き継ぎ、ベースのTCPDFのバージョンを5.2まで上げる形でPHPからRubyへ移植を実施、RBPDF 1.18 として gem を作成しました。 これは Redmine 2.6 の PDFエクスポートの改善として取り込まれました。
TCPDFをベースとしてgem パッケージを開発した理由は下記になります。
- Redmine コミッターの @marutosijp さんから、PDF出力機能は複雑なので Redmine 本体から分離したいと伺っていた。
- Redmine にパッチが採用されるためにはWindows/Linux OS環境で動作しなければならない。
- Redmine のライセンス(GPL2)と互換のあるLGPL 2.1ライセンスのTCPDF 5.2(PHP)をRubyに移植できれば、RTL言語対応や埋め込みフォント対応、HTMLサポートの改善などが見込める。
詳細は、LTthon | RubyHiroba 2014で発表させて頂きました。
www.slideshare.net
その後、RBPDF 1.19 で埋め込みサブセットフォントをサポートし、Defect #19017: Wiki PDF Export: <pre> not rendered with monospaced font - Redmine で Redmine 3.2 で取り込まれCJK 以外の言語の PDFファイルで発生していた(対象言語の全フォント埋め込みによる)肥大化問題が解決されました。 これで自分の当初のゴールとしていた内容の対応は完了しました。
Redmine の PDF出力機能で改善されるといいなと思っている点
PDF出力機能の基盤部分の改善は実施しましたが、使い勝手の部分では時間が取れず手が回っていないのですが、今後、下記が改善されるといいなと思いっています。
- Feature #6851: Change PDF page size - Redmine
- Feature #13576: Setup page orientation for PDF export - Redmine
- PDF出力は、現状A4サイズ固定ですが、A3とかになればチケット一覧が見やすくなります。
- Defect #19133: PDF Export loses {{toc}} - Redmine
- しおりつけたいですね。
- Feature #11998: PDF export svg support - Redmine
以上です。
#RubyData_tokyo Meetupで「Usability of Numo::NArray in Numerical Computing of Ruby.」というタイトルで発表してきました
上記のRubyData Tokyo Meetup で「Usability of Numo::NArray in Numerical Computing of Ruby.」というタイトルで発表してきました 発表資料は下記になります。
www.slideshare.net
Red Chainer の開発中に気づいた Numo::NArray のわかりにくかった所や、Numo::NArray に対して自分が取り組んだ、Inplace/Broadcast性能改善、SIMD演算対応、dot(transpose)性能改善 などを踏まえ、現在の計算速度の改善状況などをお話しました。
自分でも驚きだったのが、ベンチマークの結果、 加算と減算 (Inplace計算は除く)は Numo::Narrayの方が numpy より計算が速い という事ですね。 資料中のベンチマークのコードと結果は下記にあります。
※ Deep Learning From Scratch 部分の測定内容(p26,p27)は資料中のURLを参照ください。
Numo::NArray の使い方で自分が理解できていなかったところが、今回の発表で整理できてスッキリしたので Red Chainer の開発に生かしていきたいと思います。