SlideShare a Scribd company logo

TVM の紹介

コンパイラ勉強会 (2018/11/10, @Fixstars) 用の発表資料

1 of 68
Download to read offline
Deep Learning 向けコンパイラ
TVM の紹介
11/10 コンパイラ勉強会
増田正博
自己紹介
• 名前: 増田正博
• コンピュータビジョン・グラフィックスや, 周辺の技術に興味
• Fixstars でインターン経験あり
• AMDGPU バックエンドの開発から, TVM にコントリビュートするように
• TVM 関係の記事もいくつか書きました https://qiita.com/masahi
オレが始めた
2017 ~
Deep Learning コンパイラ?
Deep Learning コンパイラ
2015 ~ 現在
前置き
• Deep Learning における, 学習済みモデルの推論のみを扱います
• 入力として有向グラフと多次元配列 (画像など) が与えられる
• ノード: なんらかの演算を表す (畳み込み, 行列積, シンプルな要素ごとの演算 etc)
• エッジ: 演算間のデータフローを表す. 多次元配列 (Tensor) が流れていくイメージ
GoogleNet, from Going Deeper with Convolutions
計算グラフ ( Computational Graph)
本日のテーマ
Root から各ノードの演算を実行し, 出力を得る. これをとにかく速くやりたい
DL 用途に特化した (広い意味での) 最適化コンパイラ
→
• 内部でどのような処理をしているかをざっくり紹介
• TVM をどのように使うか, などの説明は最小限
高速化のポイント
・各ノードに対応する演算 (オペレータ) の最適化
・不必要なノードを刈る, 隣接するノードを一つにまとめる,
などのグラフ構造の最適化
TVM: An Automated End-to-End Optimizing Compiler for Deep Learning
Contents
• TVM の概要
• オペレータレベルの最適化
• グラフレベルの最適化
• パフォーマンス
• デプロイ用のツールとしての側面
• オープンソースプロジェクトとしての側面

Recommended

TVMの次期グラフIR Relayの紹介
TVMの次期グラフIR Relayの紹介TVMの次期グラフIR Relayの紹介
TVMの次期グラフIR Relayの紹介Takeo Imai
 
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)
Deep Learningのための専用プロセッサ「MN-Core」の開発と活用(2022/10/19東大大学院「 融合情報学特別講義Ⅲ」)Preferred Networks
 
Hopper アーキテクチャで、変わること、変わらないこと
Hopper アーキテクチャで、変わること、変わらないことHopper アーキテクチャで、変わること、変わらないこと
Hopper アーキテクチャで、変わること、変わらないことNVIDIA Japan
 
機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編機械学習 / Deep Learning 大全 (4) GPU編
機械学習 / Deep Learning 大全 (4) GPU編Daiyu Hatakeyama
 
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat ModelsDeep Learning JP
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門Fixstars Corporation
 
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2
Kaggle Happywhaleコンペ優勝解法でのOptuna使用事例 - 2022/12/10 Optuna Meetup #2Preferred Networks
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
 

More Related Content

What's hot

Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Fixstars Corporation
 
モデルアーキテクチャ観点からの高速化2019
モデルアーキテクチャ観点からの高速化2019モデルアーキテクチャ観点からの高速化2019
モデルアーキテクチャ観点からの高速化2019Yusuke Uchida
 
モデル高速化百選
モデル高速化百選モデル高速化百選
モデル高速化百選Yusuke Uchida
 
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...Deep Learning JP
 
[DL輪読会]MetaFormer is Actually What You Need for Vision
[DL輪読会]MetaFormer is Actually What You Need for Vision[DL輪読会]MetaFormer is Actually What You Need for Vision
[DL輪読会]MetaFormer is Actually What You Need for VisionDeep Learning JP
 
第9回ACRiウェビナー_セック/岩渕様ご講演資料
第9回ACRiウェビナー_セック/岩渕様ご講演資料第9回ACRiウェビナー_セック/岩渕様ご講演資料
第9回ACRiウェビナー_セック/岩渕様ご講演資料直久 住川
 
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料Yusuke Uchida
 
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介Preferred Networks
 
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2Preferred Networks
 
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic DatasetsDeep Learning JP
 
近年のHierarchical Vision Transformer
近年のHierarchical Vision Transformer近年のHierarchical Vision Transformer
近年のHierarchical Vision TransformerYusuke Uchida
 
[DL輪読会]Neural Ordinary Differential Equations
[DL輪読会]Neural Ordinary Differential Equations[DL輪読会]Neural Ordinary Differential Equations
[DL輪読会]Neural Ordinary Differential EquationsDeep Learning JP
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2Preferred Networks
 
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)Preferred Networks
 
ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門Fixstars Corporation
 
ChatGPT 人間のフィードバックから強化学習した対話AI
ChatGPT 人間のフィードバックから強化学習した対話AIChatGPT 人間のフィードバックから強化学習した対話AI
ChatGPT 人間のフィードバックから強化学習した対話AIShota Imai
 
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-SupervisionDeep Learning JP
 
【DL輪読会】Perceiver io a general architecture for structured inputs & outputs
【DL輪読会】Perceiver io  a general architecture for structured inputs & outputs 【DL輪読会】Perceiver io  a general architecture for structured inputs & outputs
【DL輪読会】Perceiver io a general architecture for structured inputs & outputs Deep Learning JP
 
【DL輪読会】"Language Instructed Reinforcement Learning for Human-AI Coordination "
【DL輪読会】"Language Instructed Reinforcement Learning  for Human-AI Coordination "【DL輪読会】"Language Instructed Reinforcement Learning  for Human-AI Coordination "
【DL輪読会】"Language Instructed Reinforcement Learning for Human-AI Coordination "Deep Learning JP
 

What's hot (20)

Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門
 
モデルアーキテクチャ観点からの高速化2019
モデルアーキテクチャ観点からの高速化2019モデルアーキテクチャ観点からの高速化2019
モデルアーキテクチャ観点からの高速化2019
 
モデル高速化百選
モデル高速化百選モデル高速化百選
モデル高速化百選
 
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...
【DL輪読会】Towards Understanding Ensemble, Knowledge Distillation and Self-Distil...
 
[DL輪読会]MetaFormer is Actually What You Need for Vision
[DL輪読会]MetaFormer is Actually What You Need for Vision[DL輪読会]MetaFormer is Actually What You Need for Vision
[DL輪読会]MetaFormer is Actually What You Need for Vision
 
AutoTVM紹介
AutoTVM紹介AutoTVM紹介
AutoTVM紹介
 
第9回ACRiウェビナー_セック/岩渕様ご講演資料
第9回ACRiウェビナー_セック/岩渕様ご講演資料第9回ACRiウェビナー_セック/岩渕様ご講演資料
第9回ACRiウェビナー_セック/岩渕様ご講演資料
 
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料
Swin Transformer (ICCV'21 Best Paper) を完璧に理解する資料
 
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
 
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
最新リリース:Optuna V3の全て - 2022/12/10 Optuna Meetup #2
 
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets
[DL輪読会]Grokking: Generalization Beyond Overfitting on Small Algorithmic Datasets
 
近年のHierarchical Vision Transformer
近年のHierarchical Vision Transformer近年のHierarchical Vision Transformer
近年のHierarchical Vision Transformer
 
[DL輪読会]Neural Ordinary Differential Equations
[DL輪読会]Neural Ordinary Differential Equations[DL輪読会]Neural Ordinary Differential Equations
[DL輪読会]Neural Ordinary Differential Equations
 
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
 
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)
不老におけるOptunaを利用した分散ハイパーパラメータ最適化 - 今村秀明(名古屋大学 Optuna講習会)
 
ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門ARM CPUにおけるSIMDを用いた高速計算入門
ARM CPUにおけるSIMDを用いた高速計算入門
 
ChatGPT 人間のフィードバックから強化学習した対話AI
ChatGPT 人間のフィードバックから強化学習した対話AIChatGPT 人間のフィードバックから強化学習した対話AI
ChatGPT 人間のフィードバックから強化学習した対話AI
 
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision
【DL輪読会】Unpaired Image Super-Resolution Using Pseudo-Supervision
 
【DL輪読会】Perceiver io a general architecture for structured inputs & outputs
【DL輪読会】Perceiver io  a general architecture for structured inputs & outputs 【DL輪読会】Perceiver io  a general architecture for structured inputs & outputs
【DL輪読会】Perceiver io a general architecture for structured inputs & outputs
 
【DL輪読会】"Language Instructed Reinforcement Learning for Human-AI Coordination "
【DL輪読会】"Language Instructed Reinforcement Learning  for Human-AI Coordination "【DL輪読会】"Language Instructed Reinforcement Learning  for Human-AI Coordination "
【DL輪読会】"Language Instructed Reinforcement Learning for Human-AI Coordination "
 

Similar to TVM の紹介

文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting
文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting
文献紹介:Learnable Gated Temporal Shift Module for Free-form Video InpaintingToru Tamaki
 
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...Masahiro Sakai
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml ssuser3a4b8c
 
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編Yosuke Onoue
 
1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリNVIDIA Japan
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望Kohei KaiGai
 
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングCMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングComputational Materials Science Initiative
 
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能MITSUNARI Shigeo
 
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4Takeshi Yamamuro
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013Ryo Sakamoto
 
並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.jsYoshiiro Ueno
 
ディープラーニングフレームワーク とChainerの実装
ディープラーニングフレームワーク とChainerの実装ディープラーニングフレームワーク とChainerの実装
ディープラーニングフレームワーク とChainerの実装Ryosuke Okuta
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsKohei KaiGai
 
第11回 配信講義 計算科学技術特論B(2022)
第11回 配信講義 計算科学技術特論B(2022)第11回 配信講義 計算科学技術特論B(2022)
第11回 配信講義 計算科学技術特論B(2022)RCCSRENKEI
 
ICCV 2019 論文紹介 (26 papers)
ICCV 2019 論文紹介 (26 papers)ICCV 2019 論文紹介 (26 papers)
ICCV 2019 論文紹介 (26 papers)Hideki Okada
 
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at ScaleToru Tamaki
 
20180109 titech lecture_ishizaki_public
20180109 titech lecture_ishizaki_public20180109 titech lecture_ishizaki_public
20180109 titech lecture_ishizaki_publicKazuaki Ishizaki
 

Similar to TVM の紹介 (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting
文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting
文献紹介:Learnable Gated Temporal Shift Module for Free-form Video Inpainting
 
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...
“Symbolic bounds analysis of pointers, array indices, and accessed memory reg...
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml
 
Slide
SlideSlide
Slide
 
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
PyOpenCLによるGPGPU入門 Tokyo.SciPy#4 編
 
1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ1072: アプリケーション開発を加速するCUDAライブラリ
1072: アプリケーション開発を加速するCUDAライブラリ
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
 
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティングCMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
 
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
浮動小数点(IEEE754)を圧縮したい@dsirnlp#4
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
 
並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js並列対決 Elixir × Go × C# x Scala , Node.js
並列対決 Elixir × Go × C# x Scala , Node.js
 
ディープラーニングフレームワーク とChainerの実装
ディープラーニングフレームワーク とChainerの実装ディープラーニングフレームワーク とChainerの実装
ディープラーニングフレームワーク とChainerの実装
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
 
第11回 配信講義 計算科学技術特論B(2022)
第11回 配信講義 計算科学技術特論B(2022)第11回 配信講義 計算科学技術特論B(2022)
第11回 配信講義 計算科学技術特論B(2022)
 
ICCV 2019 論文紹介 (26 papers)
ICCV 2019 論文紹介 (26 papers)ICCV 2019 論文紹介 (26 papers)
ICCV 2019 論文紹介 (26 papers)
 
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
文献紹介:An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale
 
20180109 titech lecture_ishizaki_public
20180109 titech lecture_ishizaki_public20180109 titech lecture_ishizaki_public
20180109 titech lecture_ishizaki_public
 

Recently uploaded

20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishinMakoto Mori
 
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfHarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfMatsushita Laboratory
 
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
00001_test_automation_portfolio_20240227
00001_test_automation_portfolio_2024022700001_test_automation_portfolio_20240227
00001_test_automation_portfolio_20240227ssuserf8ea02
 
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんscikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんtoshinori622
 
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdfAyachika Kitazaki
 
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)Kanta Sasaki
 
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHubK Kinzal
 

Recently uploaded (8)

20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin20240227 完全に理解した LT 「mise いいよ mise」 / morishin
20240227 完全に理解した LT 「mise いいよ mise」 / morishin
 
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdfHarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
HarukiShinkawa_果樹農家が期待する行動への変容を促す仕掛け設計のための収穫作業体験者の行動観察とモデル化_仕掛学2024.pdf
 
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
COPY FROMで異常データをスキップできるようになった話(第45回 PostgreSQLアンカンファレンス@オンライン 発表資料)
 
00001_test_automation_portfolio_20240227
00001_test_automation_portfolio_2024022700001_test_automation_portfolio_20240227
00001_test_automation_portfolio_20240227
 
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみんscikit-learn以外の分類器でpipelineを作ってみた! いずみん
scikit-learn以外の分類器でpipelineを作ってみた! いずみん
 
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
20240222_Neko_IoTLT_vol9_kitazaki_v1.pdf
 
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
オリジナルNFTを発行するブロックチェーン開発ハンズオン(NFTの発行に必要なツールから実装まで)
 
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub解説: Token Extensions - Solana Developer Hub Online #SolDevHub
解説: Token Extensions - Solana Developer Hub Online #SolDevHub
 

TVM の紹介

  • 1. Deep Learning 向けコンパイラ TVM の紹介 11/10 コンパイラ勉強会 増田正博
  • 2. 自己紹介 • 名前: 増田正博 • コンピュータビジョン・グラフィックスや, 周辺の技術に興味 • Fixstars でインターン経験あり • AMDGPU バックエンドの開発から, TVM にコントリビュートするように • TVM 関係の記事もいくつか書きました https://qiita.com/masahi オレが始めた
  • 3. 2017 ~ Deep Learning コンパイラ? Deep Learning コンパイラ 2015 ~ 現在
  • 4. 前置き • Deep Learning における, 学習済みモデルの推論のみを扱います • 入力として有向グラフと多次元配列 (画像など) が与えられる • ノード: なんらかの演算を表す (畳み込み, 行列積, シンプルな要素ごとの演算 etc) • エッジ: 演算間のデータフローを表す. 多次元配列 (Tensor) が流れていくイメージ GoogleNet, from Going Deeper with Convolutions 計算グラフ ( Computational Graph)
  • 5. 本日のテーマ Root から各ノードの演算を実行し, 出力を得る. これをとにかく速くやりたい DL 用途に特化した (広い意味での) 最適化コンパイラ → • 内部でどのような処理をしているかをざっくり紹介 • TVM をどのように使うか, などの説明は最小限 高速化のポイント ・各ノードに対応する演算 (オペレータ) の最適化 ・不必要なノードを刈る, 隣接するノードを一つにまとめる, などのグラフ構造の最適化 TVM: An Automated End-to-End Optimizing Compiler for Deep Learning
  • 6. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 7. TVM とは? • DL フレームワークで学習したモデルをデプロイしたい • 各ハードウェアバックエンド上で高速に推論実行したい そのための • 類似するプロジェクト • TensorFlow XLA • WebDNN ドメイン特化言語 コンパイラ ランタイムライブラリ https://tvm.ai/about
  • 8. TVM と NNVM CUDA ONNX MXNet Tensorflow Keras グラフレベル + オペレータレベル 最適化 LLVM OpenCL x86 ARM AMDGPU NNVM グラフ全体を扱う TVM オペレータ(各ノード)を扱う
  • 9. LLVM とのアナロジー • フロントエンド → IRの最適化 → バックエンドコード生成 の流れは同じ From “The Architecture of Open Source Applications: LLVM” by Chris Lattner
  • 10. Halide の影響 • “アルゴリズムとスケジュールの分離” を踏襲 • Halide と同じ IR を使用している. メモリ上の表現はほぼ同じ Func sample(Func A, Func B){ Func f; Var x, y; f(x, y) = A(x, y) + B(x, y); // schedule f.parallel(y).vectorize(x, 8); return f; } def sample(A, B): f = tvm.compute(A.shape, lambda y, x: A[y, x] + B[y, x]) # schedule sch = tvm.create_schedule(f.op) y, x = sch[f].op.axis sch[f].parallel(y) xo, xi = sch[f].split(x, factor=8) sch[f].vectorize(xi) return f TVM による記述 Halide による記述 詳しくは Halide による画像処理プログラミング入門 Prelude to Halide
  • 11. 核となるアイデア • cuDNN などの “手で最適化された” コードは使わない. 自分でコード生成する • 出力されるコードのひな形を登録 • 登録されたひな形から, 各バックエンド向けに Auto Tuning + コード生成 def matmul(A, B): M, K = A.shape K, N = B.shape k = tvm.reduce_axis((0, K), name='k’) C = tvm.compute((M, N), lambda i, j: tvm.sum(A[i, k] * B[k, j], axis=k), name="C") return C def schedule_matmul(C, s): y, x = C.op.axis k, = s[C].op.reduce_axis yo, xo, yi, xi = s[C].tile(y, x, 16, 16) ko, ki = s[C].split(k, factor=8) s[C].reorder(yo, xo, ko, yi, ki, xi) fused = s[C].fuse(yo, xo) s[C].parallel(fused) s[C].vectorize(xi) 計算の定義 (バックエンド非依存) CPU 向けスケジュール
  • 12. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 13. オペレータレベルの最適化 • オペレータ = 1つのレイヤー, 計算グラフのノードに相当 • Convolution, Pooling, Batch normalization など スケジューリング計算の定義 Lowering コード生成 TVM IR → LLVM IR LLVM による最適化 CUDA Kernel 生成 より抽象度の低い IR に変換 ループ範囲・バッ ファサイズの推論 ループ構造など を指定 各ターゲットごと に記述 Auto Tuning 純粋関数 限られた記述力 ターゲット非依存
  • 14. 計算の定義 def matmul(A, B): M, K = A.shape K, N = B.shape k = tvm.reduce_axis((0, K), name='k’) C = tvm.compute((M, N), lambda i, j: tvm.sum(A[i, k] * B[k, j], axis=k), name="C") return C • 行列積の TVM による定義 • CPU, GPU バックエンドともに同じ定義を使用 • 記述できるものは, 行列の演算や畳み込みなどに限られる • DL 用途としてはこれで十分
  • 15. TVM IR を見てみる M = N = K = 512 A = tvm.placeholder((M, K), name='A') B = tvm.placeholder((K, N) , name='B') C = matmul(A, B) s = tvm.create_schedule(C.op) print(tvm.lower(s, [A, B, C], simple_mode=True)) produce C { for (i, 0, 512) { for (j, 0, 512) { C[((i*512) + j)] = 0.000000f for (k, 0, 512) { C[((i*512) + j)] = (C[((i*512) + j)] + (A[((i*512) + k)]*B[(j + (k*512))])) } } } } デフォルトのスケジュール 計算の定義からループのネスト 構造を自動生成
  • 16. スケジューリング • 定義した計算の意味を変えずに, ループ構造・種類を変更 tile_size = 16 y, x = C.op.axis k, = s[C].op.reduce_axis yo, xo, yi, xi = s[C].tile(y, x, tile_size, tile_size) ko, ki = s[C].split(k, factor=8) s[C].reorder(yo, xo, ko, yi, ki, xi) fused = s[C].fuse(yo, xo) s[C].parallel(fused) s[C].vectorize(xi) tile, split, reorder, fuse, vectorize, parallel は Halide 由来 16 x 16 のブロックに分割 内積をとる軸を分割し, ループの順序を変更 外側ブロック数についてのループを並列化 最内ループをベクトル化
  • 17. スケジューリング適用後 produce C { parallel (i.outer.j.outer.fused, 0, 1024) { for (i.inner.init, 0, 16) { C[ramp(((((i.outer.j.outer.fused/32)*512) + ((i.inner.init*32) + (i.outer.j.outer.fused % 32)))*16), 1, 16)] = x16(0.000000f) } for (k.outer, 0, 64) { for (i.inner, 0, 16) { for (k.inner, 0, 8) { C[ramp(((((i.outer.j.outer.fused/32)*512) + ((i.inner*32) + (i.outer.j.outer.fused % 32)))*16), 1, 16)] = (C[ramp(((((i.outer.j.outer.fused/32)*512) + ((i.inner*32) + (i.outer.j.outer.fused % 32)))*16), 1, 16)] + (x16(A[((((((i.outer.j.outer.fused/32)*1024) + k.outer) + (i.inner*64))*8) + k.inner)])*B[ramp(((((k.inner*32) + (i.outer.j.outer.fused % 32)) + (k.outer*256))*16), 1, 16)])) } } } } }
  • 18. GPU へのマッピング tile_size = 16 yo, xo, yi, xi = s[C].tile(y, x, tile_size, tile_size) s[C].bind(yo, tvm.thread_axis("blockIdx.y")) s[C].bind(xo, tvm.thread_axis("blockIdx.x")) s[C].bind(yi, tvm.thread_axis("threadIdx.y")) s[C].bind(xi, tvm.thread_axis("threadIdx.x")) produce C { // attr [iter_var(blockIdx.y, , blockIdx.y)] thread_extent = 32 // attr [iter_var(blockIdx.x, , blockIdx.x)] thread_extent = 32 // attr [iter_var(threadIdx.y, , threadIdx.y)] thread_extent = 16 // attr [iter_var(threadIdx.x, , threadIdx.x)] thread_extent = 16 C[(((((blockIdx.y*512) + blockIdx.x) + (threadIdx.y*32))*16) + threadIdx.x)] = 0.000000f for (k, 0, 512) { C[(((((blockIdx.y*512) + blockIdx.x) + (threadIdx.y*32))*16) + threadIdx.x)] = (C[(((((blockIdx.y*512) + blockIdx.x) + (threadIdx.y*32))*16) + threadIdx.x)] + (A[((((blockIdx.y*16) + threadIdx.y)*512) + k)]*B[(((blockIdx.x*16) + threadIdx.x) + (k*512))])) } }
  • 19. 共有メモリの利用 num_thread = 16 k, = s[C].op.reduce_axis ko, ki = s[C].split(k, factor=num_thread) A, B = s[C].op.input_tensors AA = s.cache_read(A, "shared", [C]) BB = s.cache_read(B, "shared", [C]) s[AA].compute_at(s[C], ko) s[BB].compute_at(s[C], ko) # load one value into shared mem per thread y, x = s[AA].op.axis _, _, ty, tx = s[AA].tile(y, x, num_thread, num_thread) s[AA].bind(ty, tvm.thread_axis("threadIdx.y")) s[AA].bind(tx, tvm.thread_axis("threadIdx.x")) y, x = s[BB].op.axis _, _, ty, tx = s[BB].tile(y, x, num_thread, num_thread) s[BB].bind(ty, tvm.thread_axis("threadIdx.y")) s[BB].bind(tx, tvm.thread_axis("threadIdx.x")) http://www.es.ele.tue.nl/~mwijtvliet/5KK73/?page=mmcuda)
  • 20. 共有メモリの利用 produce C { // attr [iter_var(blockIdx.y, , blockIdx.y)] thread_extent = 64 // attr [A.shared] storage_scope = "shared" allocate A.shared[float32 * 16 * 16] // attr [B.shared] storage_scope = “shared” allocate B.shared[float32 * 16 * 16] // attr [iter_var(blockIdx.x, , blockIdx.x)] thread_extent = 64 // attr [iter_var(threadIdx.y, , threadIdx.y)] thread_extent = 16 // attr [iter_var(threadIdx.x, , threadIdx.x)] thread_extent = 16 C[(((((blockIdx.y*1024) + blockIdx.x) + (threadIdx.y*64))*16) + threadIdx.x)] = 0.000000f for (k.outer, 0, 64) { produce A.shared { // attr [iter_var(threadIdx.y, , threadIdx.y)] thread_extent = 16 // attr [iter_var(threadIdx.x, , threadIdx.x)] thread_extent = 16 A.shared[((threadIdx.y*16) + threadIdx.x)] = A[(((((blockIdx.y*1024) + k.outer) + (threadIdx.y*64))*16) + threadIdx.x)] } produce B.shared { // attr [iter_var(threadIdx.y, , threadIdx.y)] thread_extent = 16 // attr [iter_var(threadIdx.x, , threadIdx.x)] thread_extent = 16 B.shared[((threadIdx.y*16) + threadIdx.x)] = B[((((blockIdx.x + (k.outer*1024)) + (threadIdx.y*64))*16) + threadIdx.x)] } for (k.inner, 0, 16) { C[(((((blockIdx.y*1024) + blockIdx.x) + (threadIdx.y*64))*16) + threadIdx.x)] = (C[(((((blockIdx.y*1024) + blockIdx.x) + (threadIdx.y*64))*16) + threadIdx.x)] + (A.shared[((threadIdx.y*16) + k.inner)]*B.shared[(threadIdx.x + (k.inner*16))])) } } }
  • 21. Lowering からコード生成へ ループ範囲・バッファサイズの推論 ループのベクトル化, アンローリング 再利用できるバッファの検出 共有メモリ, ローカルメモリの割り当て ダブルバッファリング スレッド同期命令の挿入 Lowering コード生成 NVRTC LLVM TVM IR TVM IR から LLVM IR へ変換 または, 直接 CUDA カーネル生成
  • 22. コード生成: AVX 2 M = N = K = 1024 A = tvm.placeholder((M, K), name='A') B = tvm.placeholder((K, N) , name='B') C = matmul(A, B) s = schedule(C) target = "llvm -mcpu=core-avx2" func = tvm.build(s, [A, B, C], target=target) print(func.get_source("asm")) .LBB2_4: leal (%rdx,%rsi), %edi movslq %edi, %rdi vbroadcastss -28(%rbx), %ymm4 vmovaps 32(%rcx,%rdi,4), %ymm5 vfmadd231ps 64(%rsp), %ymm4, %ymm5 vmovups 32(%rsp), %ymm6 vfmadd213ps (%rcx,%rdi,4), %ymm6, %ymm4 vbroadcastss -24(%rbx), %ymm6 vfmadd231ps %ymm7, %ymm6, %ymm4 vfmadd132ps (%rsp), %ymm5, %ymm6 vbroadcastss -20(%rbx), %ymm5 vfmadd231ps %ymm8, %ymm5, %ymm6 vfmadd213ps %ymm4, %ymm9, %ymm5 vbroadcastss -16(%rbx), %ymm4 vfmadd231ps %ymm11, %ymm4, %ymm5 vfmadd213ps %ymm6, %ymm10, %ymm4 vbroadcastss -12(%rbx), %ymm6 vfmadd231ps %ymm12, %ymm6, %ymm4 vfmadd213ps %ymm5, %ymm13, %ymm6 vbroadcastss -8(%rbx), %ymm5 vfmadd231ps %ymm15, %ymm5, %ymm6 vfmadd213ps %ymm4, %ymm14, %ymm5 vbroadcastss -4(%rbx), %ymm4 vfmadd231ps %ymm1, %ymm4, %ymm5 vfmadd213ps %ymm6, %ymm2, %ymm4 vbroadcastss (%rbx), %ymm6 vfmadd231ps %ymm3, %ymm6, %ymm4 vfmadd213ps %ymm5, %ymm0, %ymm6 vmovaps %ymm6, 32(%rcx,%rdi,4) vmovaps %ymm4, (%rcx,%rdi,4) addq $1024, %rsi addq $4096, %rbx cmpq $16384, %rsi jne .LBB2_4
  • 23. コード生成: NEON target = tvm.target.arm_cpu(model="rasp3b") func = tvm.build(s, [A, B, C], target=target) print(func.get_source("asm")) vld1.32 {d18, d19}, [r3:128]! vld1.32 {d26[], d27[]}, [r2:32]! vld1.64 {d22, d23}, [r0:128] vld1.64 {d24, d25}, [r6:128] vmla.f32 q9, q13, q15 vldmia r4, {d30, d31} vld1.64 {d20, d21}, [r3:128] vld1.32 {d28[], d29[]}, [r2:32] vmla.f32 q11, q13, q7 vmla.f32 q12, q13, q8 add r2, r1, #8 add r4, sp, #32 vmla.f32 q10, q13, q15 vld1.32 {d26[], d27[]}, [r2:32] vmla.f32 q12, q14, q4 vmla.f32 q9, q14, q6 vmla.f32 q11, q14, q3 add r2, r1, #12 vmla.f32 q12, q13, q0 vmla.f32 q10, q14, q5 vldmia r4, {d28, d29} add r4, sp, #96 vmla.f32 q9, q13, q2 vmla.f32 q10, q13, q1 vmla.f32 q11, q13, q14 vld1.32 {d28[], d29[]}, [r2:32] vldmia r4, {d26, d27} add r4, sp, #80 add r2, r1, #16 vmla.f32 q11, q14, q13 vldmia r4, {d26, d27} ..... ターゲットを変えるだけで, 全く違った アーキテクチャ用のコード生成が可能
  • 24. コード生成: CUDA s = schedule_shared_mem(C) target = "cuda" func = tvm.build(s, [A, B, C], target=target) print(func.imported_modules[0].get_source()) extern "C" __global__ void default_function_kernel0( float* __restrict__ C, float* __restrict__ A, float* __restrict__ B) { __shared__ float A_shared[256]; __shared__ float B_shared[256]; C[((((((int)blockIdx.y) * 16384) + (((int)blockIdx.x) * 16)) + (((int)threadIdx.y) * 1024)) + ((int)threadIdx.x))] = 0.000000e+00f; for (int k_outer = 0; k_outer < 64; ++k_outer) { __syncthreads(); A_shared[((((int)threadIdx.y) * 16) + ((int)threadIdx.x))] = A[((((((int)blockIdx.y) * 16384) + (k_outer * 16)) + (((int)threadIdx.y) * 1024)) + ((int)threadIdx.x))]; B_shared[((((int)threadIdx.y) * 16) + ((int)threadIdx.x))] = B[((((((int)blockIdx.x) * 16) + (k_outer * 16384)) + (((int)threadIdx.y) * 1024)) + ((int)threadIdx.x))]; __syncthreads(); for (int k_inner = 0; k_inner < 16; ++k_inner) { C[((((((int)blockIdx.y) * 16384) + (((int)blockIdx.x) * 16)) + (((int)threadIdx.y) * 1024)) + ((int)threadIdx.x))] = (C[((((((int)blockIdx.y) * 16384) + (((int)blockIdx.x) * 16)) + (((int)threadIdx.y) * 1024)) + ((int)threadIdx.x))] + (A_shared[((((int)threadIdx.y) * 16) + k_inner)] * B_shared[(((int)threadIdx.x) + (k_inner * 16))])); } } }
  • 25. コード生成: AMDGPU for_body: ; preds = %for_body, %entry %.promoted = phi float [ 0.000000e+00, %entry ], [ %147, %for_body ] %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for_body ] tail call void @llvm.amdgcn.s.barrier() %84 = trunc i64 %indvars.iv to i32 %85 = add i32 %9, %84 %86 = shl i32 %85, 4 %87 = add nsw i32 %86, %6 %88 = sext i32 %87 to i64 %89 = getelementptr inbounds float, float addrspace(1)* %1, i64 %88 %90 = bitcast float addrspace(1)* %89 to i32 addrspace(1)* %91 = load i32, i32 addrspace(1)* %90, align 4, !tbaa !8 store i32 %91, i32 addrspace(3)* %18, align 4, !tbaa !11 %indvars.iv.tr = trunc i64 %indvars.iv to i32 %92 = shl i32 %indvars.iv.tr, 10 %93 = add i32 %19, %92 %94 = shl i32 %93, 4 %95 = add nsw i32 %94, %6 %96 = sext i32 %95 to i64 %97 = getelementptr inbounds float, float addrspace(1)* %2, i64 %96 %98 = bitcast float addrspace(1)* %97 to i32 addrspace(1)* %99 = load i32, i32 addrspace(1)* %98, align 4, !tbaa !14 store i32 %99, i32 addrspace(3)* %21, align 4, !tbaa !17 tail call void @llvm.amdgcn.s.barrier() %100 = load float, float addrspace(3)* %22, align 16, !tbaa !11 %101 = load float, float addrspace(3)* %23, align 4, !tbaa !17 %102 = tail call float @llvm.fmuladd.f32(float %100, float %101, float %.promoted) %103 = load float, float addrspace(3)* %25, align 4, !tbaa !11 %104 = load float, float addrspace(3)* %27, align 4, !tbaa !17 %105 = tail call float @llvm.fmuladd.f32(float %103, float %104, float %102) %106 = load float, float addrspace(3)* %29, align 8, !tbaa !11 %107 = load float, float addrspace(3)* %31, align 4, !tbaa !17 %108 = tail call float @llvm.fmuladd.f32(float %106, float %107, float %105) ..... BB0_1: v_add_u32_e32 v11, vcc, s6, v0 v_ashrrev_i32_e32 v12, 31, v11 v_ashrrev_i32_e32 v10, 31, v9 v_lshlrev_b64 v[11:12], 2, v[11:12] v_lshlrev_b64 v[13:14], 2, v[9:10] v_mov_b32_e32 v1, s1 v_add_u32_e32 v10, vcc, s0, v11 v_addc_u32_e32 v11, vcc, v1, v12, vcc v_mov_b32_e32 v15, s3 v_add_u32_e32 v12, vcc, s2, v13 v_addc_u32_e32 v13, vcc, v15, v14, vcc flat_load_dword v1, v[10:11] flat_load_dword v10, v[12:13] s_waitcnt vmcnt(0) lgkmcnt(0) s_barrier s_add_u32 s6, s6, 16 s_addc_u32 s7, s7, 0 v_add_u32_e32 v9, vcc, 0x4000, v9 s_cmp_lg_u64 s[6:7], s[4:5] ds_write_b32 v6, v1 ds_write_b32 v5, v10 s_waitcnt lgkmcnt(0) s_barrier ds_read2_b32 v[18:19], v8 offset1:16 ds_read2_b64 v[10:13], v7 offset1:1 ds_read2_b64 v[14:17], v7 offset0:2 offset1:3 s_waitcnt lgkmcnt(1) v_mac_f32_e32 v4, v10, v18 v_mac_f32_e32 v4, v11, v19 ds_read2_b32 v[10:11], v8 offset0:32 offset1:48 s_waitcnt lgkmcnt(0) v_mac_f32_e32 v4, v12, v10 v_mac_f32_e32 v4, v13, v11 ds_read2_b32 v[10:11], v8 offset0:64 offset1:80 ds_read2_b32 v[12:13], v8 offset0:96 offset1:112 ds_read2_b32 v[18:19], v8 offset0:128 offset1:144 s_waitcnt lgkmcnt(2) v_mac_f32_e32 v4, v14, v10 v_mac_f32_e32 v4, v15, v11 s_waitcnt lgkmcnt(1) .....
  • 26. AutoTVM – 学習ベースの Auto Tuning フレームワーク • 以前の TVM • 特定のネットワーク向けに手でパラメータチューニング • チューニング対象外のネットワークでは遅かった • AutoTVM によって, 高速なスケジュールを自動で生成できるようになった ブロック行列積のタイルの大きさをチューニング可能にする例 from tvm import autotvm cfg = autotvm.get_config() cfg.define_knob("tile_size", [4, 8, 16, 32]) yo, xo, yi, xi = s[C].tile(y, x, cfg['tile_size'].val, cfg['tile_size'].val) tile_size = 16 yo, xo, yi, xi = s[C].tile(y, x, tile_size, tile_size)
  • 27. def schedule_direct_cuda(cfg, s, conv): n, f, y, x = s[conv].op.axis rc, ry, rx = s[conv].op.reduce_axis cfg.define_split("tile_f", f, num_outputs=4) cfg.define_split("tile_y", y, num_outputs=4) cfg.define_split("tile_x", x, num_outputs=4) cfg.define_split("tile_rc", rc, num_outputs=2) cfg.define_split("tile_ry", ry, num_outputs=2) cfg.define_split("tile_rx", rx, num_outputs=2) cfg.define_knob("auto_unroll_max_step", [0, 512, 1500]) cfg.define_knob("unroll_explicit", [0, 1]) pad_data, kernel = s[conv].op.input_tensors s[pad_data].compute_inline() output = conv OL = s.cache_write(conv, 'local’) AA = s.cache_read(pad_data, 'shared', [OL]) WW = s.cache_read(kernel, 'shared', [OL]) n, f, y, x = s[output].op.axis kernel_scope, n = s[output].split(n, nparts=1) bf, vf, tf, fi = cfg["tile_f"].apply(s, output, f) by, vy, ty, yi = cfg["tile_y"].apply(s, output, y) bx, vx, tx, xi = cfg["tile_x"].apply(s, output, x) bf = s[output].fuse(n, bf) s[output].bind(bf, tvm.thread_axis("blockIdx.z")) s[output].bind(by, tvm.thread_axis("blockIdx.y")) s[output].bind(bx, tvm.thread_axis("blockIdx.x")) s[output].bind(vf, tvm.thread_axis("vthread")) s[output].bind(vy, tvm.thread_axis("vthread")) s[output].bind(vx, tvm.thread_axis("vthread")) s[output].bind(tf, tvm.thread_axis("threadIdx.z")) s[output].bind(ty, tvm.thread_axis("threadIdx.y")) s[output].bind(tx, tvm.thread_axis("threadIdx.x")) s[output].reorder(bf, by, bx, vf, vy, vx, tf, ty, tx, fi, yi, xi) s[OL].compute_at(s[output], tx) n, f, y, x = s[OL].op.axis rc, ry, rx = s[OL].op.reduce_axis rco, rci = cfg['tile_rc'].apply(s, OL, rc) ryo, ryi = cfg['tile_rx'].apply(s, OL, ry) rxo, rxi = cfg['tile_ry'].apply(s, OL, rx) s[OL].reorder(rco, ryo, rxo, rci, ryi, rxi, n, f, y, x) s[AA].compute_at(s[OL], rxo) s[WW].compute_at(s[OL], rxo) for load in [AA, WW]: n, f, y, x = s[load].op.axis fused = s[load].fuse(n, f, y, x) tz, fused = s[load].split(fused, nparts=cfg["tile_f"].size[2]) ty, fused = s[load].split(fused, nparts=cfg["tile_y"].size[2]) tx, fused = s[load].split(fused, nparts=cfg["tile_x"].size[2]) s[load].bind(tz, tvm.thread_axis("threadIdx.z")) s[load].bind(ty, tvm.thread_axis("threadIdx.y")) s[load].bind(tx, tvm.thread_axis("threadIdx.x")) s[output].pragma(kernel_scope, 'auto_unroll_max_step', cfg['auto_unroll_max_step'].val) s[output].pragma(kernel_scope, 'unroll_explicit', cfg['unroll_explicit'].val) AutoTVM 使用例 • CUDA バックエンドの Direct Convolution スケジュール • Thread block, 共有メモリの大きさなどが チューニングされる tvm/topi/python/topi/cuda/conv2d_direct.py より抜粋 AutoTVM についての詳細は, チュートリアル 及び 論文を参照
  • 28. TVM による高速化 ケーススタディ • CPU 行列積 • CUDA Direct Convolution • CUDA Winograd Convolution
  • 29. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 30. グラフレベルの最適化 • TVM の上位レイヤーにあたる, NNVM が担当 • WebDNN の発表資料もおすすめ • グラフ最適化がとても詳しく説明されている Graph Transformation モデルインポート 各オペレータを TVM でコンパイル ここまでの話ここからの話
  • 31. グラフコンパイル ワークフロー • DL フレームワークから直接, または ONNX 経由でモデルをインポート • ターゲット, 入力のサイズを指定して, グラフをコンパイル import mxnet as mx sym_mx, params_mx = mx.load_checkpoint(...) # load a trained model import nnvm net, params = nnvm.frontend.from_mxnet(sym_mx, params_mx) target = "cuda" x = np.zeros((1, 3, 224, 224)).astype(np.float32) shape_dict = {'data': x.shape} graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params)
  • 32. 推論実行 ctx = tvm.context(target, 0) module = runtime.create(graph, lib, ctx) module.set_input(**params) module.set_input("data", x) module.run() out = module.get_output(0) • 生成されたカーネルとデバイスごとのランタイムを繋ぎ合わせて実行
  • 33. NNVM によるネットワーク構造の定義 • 通常は, 直接 NNVM API でモデルを定義することはない • TensorFlow などと同様の, データフロー記述 import nnvm.symbol as sym def get_net(filters=8): data = sym.Variable(name="data") data = sym.conv2d(data, kernel_size=(3,3), channels=filters) data = sym.batch_norm(data) data = sym.relu(data) data = sym.max_pool2d(data, pool_size=(2, 2), strides=(2, 2)) data = sym.flatten(data) data = sym.dense(data, units=1000) data = sym.softmax(data, axis=1) return data nnvm.sym.conv2d に対して, TVM による ・計算の定義 ・各バックエンド用のスケジュール が紐づけられている 他のシンボルについても同様
  • 34. Graph(%data, %conv2d0_weight, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, %dense0_weight, %dense0_bias) { %5 = tvm_op(%data, %conv2d0_weight, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, flatten_data='0', func_name='fuse_conv2d_broadcast_mul_broadcast_add_relu', num_inputs='5', num_outputs='1’) %6 = tvm_op(%5, flatten_data='0', func_name='fuse_max_pool2d', num_inputs='1', num_outputs='1’) %7 = tvm_op(%6, flatten_data='0', func_name='fuse_flatten', num_inputs='1', num_outputs='1’) %10 = tvm_op(%7, %dense0_weight, %dense0_bias, flatten_data='0', func_name='fuse_dense', num_inputs='3', num_outputs='1’) %11 = tvm_op(%10, flatten_data='0', func_name='fuse_softmax', num_inputs='1', num_outputs='1’) ret %11 } Graph IR • コンパイルしたグラフの IR をダンプ • Convolution, Batch norm, ReLU が フューズされている net = get_net() net, params = utils.create_workload(net, 1, (3, 224, 224)) graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params) print(graph.ir())
  • 35. 最適化レベルを上げる • opt_level を 3 に (デフォルトは2) • Batch norm のスケーリングが消え, Convolution のパラメータが代わりに スケールされる Graph(%data, %conv2d0_weight_sc, %conv2d0_bias_sc, %batch_norm0_add_beta_expand, %dense0_weight, %dense0_bias) { %4 = tvm_op(%data, %conv2d0_weight_sc, %conv2d0_bias_sc, %batch_norm0_add_beta_expand, num_outputs='1', num_inputs='4', flatten_data='0', func_name='fuse_conv2d_broadcast_add_relu’) %5 = tvm_op(%4, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_max_pool2d’) %6 = tvm_op(%5, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_flatten’) %9 = tvm_op(%6, %dense0_weight, %dense0_bias, num_outputs='1', num_inputs='3', flatten_data='0', func_name='fuse_dense’) %10 = tvm_op(%9, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_softmax’) ret %10 } with nnvm.compiler.build_config(opt_level=3): graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params)
  • 36. Winograd アルゴリズム を使う • 入力サイズとフィルター数を, Winograd Convolution に適したものに変更 • Direct Convolution が Winograd Convolution に置き換わる Graph(%data, %transpose0, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, %dense0_weight,%dense0_bias) { %5 = tvm_op(%data, %transpose0, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, num_outputs='1', num_inputs='5', flatten_data='0', func_name='fuse__contrib_conv2d_winograd_without_weight_transform_broadcast_mul_broadcast_add_relu’) %6 = tvm_op(%5, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_max_pool2d’) %7 = tvm_op(%6, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_flatten’) %10 = tvm_op(%7, %dense0_weight, %dense0_bias, num_outputs='1', num_inputs='3', flatten_data='0', func_name='fuse_dense’) %11 = tvm_op(%10, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_softmax’) ret %11 } net = get_net(filters=64) in_shape = (1, 64, 56, 56) net, params = utils.create_workload(net, 1, in_shape[1:]) with nnvm.compiler.build_config(opt_level=3): graph, lib, params = nnvm.compiler.build(net, target, {"data": in_shape}, params=params)
  • 37. Winograd アルゴリズム を使う • Winograd F(4x4, 3x3) の例 6 x 6 のフィルター変換がコンパイル時に計算される print("Before precompute prune pass") for (k, v) in params.items(): print("%s:" % k, v.shape) with nnvm.compiler.build_config(opt_level=3): graph, lib, params = nnvm.compiler.build(net, target, {"data": in_shape}, params=params) print("After precompute prune pass") for (k, v) in params.items(): print("%s:" % k, v.shape) Before precompute prune pass conv2d0_weight: (64, 64, 3, 3) conv2d0_bias: (64,) ... After precompute prune pass transpose0: (6, 6, 64, 64) conv2d0_bias: (64,) ... フィルター変換の最後に transpose が起こるため、パラメータ名が変 わっている
  • 38. NCHWc レイアウトで Convolution • NCHW レイアウトが標準 (N: バッチ数, C, チャネル数, H, W: 縦, 横) • CPU では, NCHWc レイアウトによる Convolution が高速 • NCHW8c, NCHW16c など, ベクトル幅の倍数でチャネルを分割 Understanding Memory Formats, MKL-DNN Documatation
  • 39. レイアウト変換を有効にする • x86 バックエンドでは, opt_level = 3 の場合に NCHWc レイアウトを使う • レイアウト変換ノードを挿入, NCHWc Convolution に置き換え Graph(%data, %conv2d0_weight_OIHW8i8o, %conv2d0_bias_C8c, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, %dense0_weight, %dense0_bias) { %1 = tvm_op(%data, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse___layout_transform___2’) %6 = tvm_op(%1, %conv2d0_weight_OIHW8i8o, %conv2d0_bias_C8c, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, num_outputs='1', num_inputs='5', flatten_data='0', func_name='fuse__contrib_conv2d_NCHWc_broadcast_mul_broadcast_add_relu’) %7 = tvm_op(%6, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_max_pool2d’) %8 = tvm_op(%7, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse___layout_transform___flatten’) %11 = tvm_op(%8, %dense0_weight, %dense0_bias, num_outputs='1', num_inputs='3', flatten_data='0', func_name='fuse_dense’) %12 = tvm_op(%11, num_outputs='1', num_inputs='1', flatten_data='0', func_name='fuse_softmax’) ret %12 } target = "llvm -mcpu=core-avx2" with nnvm.compiler.build_config(opt_level=3): graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params) print(graph.ir())
  • 40. 外部ライブラリの使用 • cuDNN などの, 各ベンダーが提供するライブラリを使うこともできる • 例: 全ての conv2d オペレータを cuDNN のカーネルに置き換える • Fully connected layer を cuBLAS の SGEMM に置き換えることも可能 • AMD のライブラリもサポート target = "cuda –libs=cudnn" graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params)
  • 41. Graph Transformation: まとめ • レイアウト変換 • スケーリング演算のパラメータへの埋め込み • コンパイル時実行可能なノードの削除 • オペレータの置き換え (Winograd, NCHWc Convolution, cuDNN) • Operator Fusion
  • 42. Operator Fusion: 概要 • 複数のオペレータ(カーネル) を一つにまとめる • 余分なメモリへのロード・ストア, GPU カーネル起動オーバーヘッドの削減 Conv2d Bias Add Batch norm ReLU Fused op
  • 43. Operator Fusion: NNVM の実装 • オペレータは主に4つのグループに分かれている • グループ間でフューズ可能か決められている NN op convolution conv transpose pooling fully connected Injective reshape layout transform transpose concatenate Elementwise math op relu elemwise sum sigmoid Broadcast broadcast_add broadcast_mul … expand_dims NN op には Elementwise か Broadcast op をフューズできる NN op 以外は同じグループの op 同士で フューズできる, など
  • 44. Operator Fusion: 例 • Convolution + Bias Add + Batch norm + ReLU data = sym.Variable(name="data") data = sym.conv2d(data, kernel_size=(3,3), channels=8, use_bias=True) data = sym.batch_norm(data) data = sym.relu(data) Graph(%data, %conv2d0_weight, %conv2d0_bias,%batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand) { %5 = tvm_op(%data, %conv2d0_weight, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, flatten_data='0', func_name='fuse_conv2d_broadcast_mul_broadcast_add_relu', num_inputs='5', num_outputs='1’) ret %5 }
  • 45. Operator Fusion: CUDA カーネル for (int rc_inner = 0; rc_inner < 4; ++rc_inner) { for (int ry_inner = 0; ry_inner < 3; ++ry_inner) { for (int rx_inner = 0; rx_inner < 3; ++rx_inner) { for (int ff = 0; ff < 2; ++ff) { for (int xx = 0; xx < 2; ++xx) { compute[((ff * 2) + xx)] = (compute[((ff * 2) + xx)] + (pad_temp_shared[((((((((int)threadIdx.y) * 8) + (((int)threadIdx.x) * 2)) + (rc_inner * 32)) + (ry_inner * 8)) + rx_inner) + xx)] * input1_shared[(((((((int)threadIdx.z) * 72) + (rc_inner * 9)) + (ry_inner * 3)) + rx_inner) + (ff * 36))])); } } } } } for (int ax1_inner_inner_inner = 0; ax1_inner_inner_inner < 2; ++ax1_inner_inner_inner) { for (int ax3_inner_inner_inner = 0; ax3_inner_inner_inner < 2; ++ax3_inner_inner_inner) { tensor[(((((((((int)blockIdx.y) * 108) + (((int)blockIdx.x) * 6)) + (((int)threadIdx.z) * 5832)) + (((int)threadIdx.y) * 54)) + (((int)threadIdx.x) * 2)) + (ax1_inner_inner_inner * 2916)) + ax3_inner_inner_inner)] = max((((compute[(((ax1_inner_inner_inner * 2) + ax3_inner_inner_inner) - (((int)blockIdx.z) * 4))] + input2[((((int)threadIdx.z) * 2) + ax1_inner_inner_inner)]) * input3[((((int)threadIdx.z) * 2) + ax1_inner_inner_inner)]) + input4[((((int)threadIdx.z) * 2) + ax1_inner_inner_inner)]), 0.000000e+00f); } } • 生成された CUDA カーネルより一部を抜粋
  • 46. Operator Fusion: 極端な例 def get_net(): def weird_activation(data): act1 = sym.relu(1 - sym.log(data)) act2 = sym.relu(sym.exp(2 * data + 1)) act3 = sym.leaky_relu(data) return -0.5 * act1 + 1.5 * act2 + act3 data = sym.Variable(name="data") data = sym.conv2d(data, kernel_size=(3,3), channels=8) data = sym.batch_norm(data) data = weird_activation(data) return data Graph(%data, %conv2d0_weight, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand) { %5 = tvm_op(%data, %conv2d0_weight, %conv2d0_bias, %batch_norm0_gamma_mul_div_expand, %batch_norm0_add_beta_expand, flatten_data='0', func_name='fuse_conv2d_broadcast_mul_broadcast_add_log___rsub_scalar___relu___mul_scalar_____mul_scalar_____add_scalar ___exp_relu___mul_scalar___broadcast_add_leaky_relu_broadcast_add', num_inputs='5', num_outputs='1’) ret %5 } Conv Batch norm Elemwise sum
  • 47. Operator Fusion: 効果 TVM: An Automated End-to-End Optimizing Compiler for Deep Learning より
  • 48. [WIP] Graph level Auto Tuning • AutoTVM によって, オペレータ (ノード) 単位のチューニングが可能になった • だが, 入力のレイアウトは固定 (NCHW, NCHW[8, 16, 32…]c) • 最適なレイアウトは入力によって変わりうる → レイアウト変換のコストを考慮したグラフ全体のチューニングが必要 離散最適化問題を解くことになる 同様の問題を扱った論文 Optimal DNN Primitive Selection with Partitioned Boolean Quadratic Programming, CGO 2018 Node A Node B NCHW8c NCHW16c NCHW32c NCHW8c 0 0.1 0.25 NCHW16c 0.12 0 0.2 NCHW32c 0.3 0.18 0 レイアウト変換コスト NCHW8c 3.2 NCHW16c 2.8 NCHW32c 3.0 NCHW8c 2.6 NCHW16c 2.75 NCHW32c 2.5 ノードコスト ノードコスト
  • 49. [WIP] Relay – NNVM IR v2 • 詳細は LT にて, または論文を参照 • NNVM IR の言語としての記述力は限られている → 正真正銘のプログラミング言語を組み込んでしまえ! • 純粋関数型言語 + Tensor の各次元数を埋め込んだ型システム • 各グラフ変換パスの, Relay IR 変換パスへの再実装が進行中 • Operator fusion, 自動微分など
  • 50. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 51. NVIDIA GPU 公式ブログより引用 入力サイズ: (1, 3, 224, 224) 単位: ミリ秒 cuDNN には勝ち, TensorRT と互角
  • 52. AMDGPU AMD 版の cuDNN, MIOpen と比較
  • 54. Intel Xeon 18 コア + AVX 512 Optimizing CNN Model Inference on CPUs より引用 MXNet + MKLDNN を 1 として、スピードアップを比較 Graph level Auto Tuning を適用した結果
  • 55. 自分で測ってみた: GPU VGG16 Resnet50 Densenet121 AutoTVM 6.68 4.03 4.64 TVM + cuDNN 7.10 5.14 7.14 MXNet + cuDNN 8.07 5.89 8.39 PyTorch + cuDNN 7.79 6.55 12.3 VGG16 Resnet50 Densenet121 AutoTVM 7.44 6.45 9.2 TVM + MIOpen 7.18 6.13 10.3 Qiita 記事より引用 Radeon R9 Nano GTX 1070 ti 入力サイズ: (1, 3, 224, 224) 単位: ミリ秒
  • 56. 自分で測ってみた: x86 VGG16 Resnet50 Resnet101 Densenet121 AutoTVM 69.26 16.49 30.87 14.53 MXNet + MKLDNN 62.96 21.15 38.85 24.06 Core i7-8700K (6C 6T) + AVX 2 VGG16 Resnet50 Resnet101 AutoTVM 25.35 9.54 16.68 MXNet + MKLDNN 24.88 12.64 22.96 Core i9-7940X (14C 14T) + AVX 512
  • 57. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 58. デプロイ用ツールとして使う • コンパイルしたモデルをデプロイするのも簡単 • 最小限のランタイムライブラリとアプリケーションをリンクするだけ • Python 不要, ONNX もいらない • 場合によっては cuDNN などのライブラリを使うことも可能 • C++ Runtime 以外にも、Java, Rust をサポート • Go Runtime の PR も進行中 libtvm.so libtvm_runtime.so Thread pool Codegen LLVM interface Model loading NDArray Device API HalideIR Lowering pass
  • 59. ハードウェアバックエンド デスクトップ GPU CUDA, OpenCL, ROCm (AMDGPU) モバイル GPU OpenCL, Metal, Vulkan (SPIR-V) CPU x86, ARM (Android, Rasp) (WIP) FPGA VTA, SDAccel, AOCL VTA については、以前の勉強会で発表あり VTA 試してみた 開発中? • Huawei AI チップ バックエンド (RFC) • Qualcomm Hexagon DSP オフロード (RFC) AMD の公式スライドに TVM のロゴが !!
  • 60. モデルをファイルにシリアライズ • コンパイルされたコードを含む共有ライブラリ • JSON 形式のグラフ構造の定義 • 各オペレータのパラメータ を出力 graph, lib, params = nnvm.compiler.build(net, target, shape_dict, params=params) output_prefix = “model" lib.export_library("{}_deploy.so".format(output_prefix)) with open("{}_deploy.json".format(output_prefix), "w") as fo: fo.write(graph.json()) with open("{}_deploy.params".format(output_prefix), "wb") as fo: fo.write(nnvm.compiler.save_param_dict(params))
  • 61. C++ からモデルをロード const std::string json_file(“model_deploy.json"); const std::string param_file(“model_deploy.params"); tvm::runtime::Module mod_syslib = tvm::runtime::Module::LoadFromFile(“model_deploy.so"); std::string json_data; std::string params_data; // Read json and parameter files and fill in json_data, params_data ... const int device_type = kDLGPU; const int device_id = 0; auto runtime_create_func = tvm::runtime::Registry::Get("tvm.graph_runtime.create"); tvm::runtime::Module mod = (*runtime_create_func)(json_data, mod_syslib, device_type, device_id);
  • 62. 推論の実行 tvm::runtime::PackedFunc load_params = mod.GetFunction("load_params"); tvm::runtime::PackedFunc set_input = mod.GetFunction("set_input"); tvm::runtime::PackedFunc run = mod.GetFunction("run"); tvm::runtime::PackedFunc get_output = mod.GetFunction("get_output"); DLTensor* x = nullptr; DLTensor* y = nullptr; // Allocate x and y, fill in x … TVMByteArray params_arr; params_arr.data = params_data.data(); params_arr.size = params_data.length(); load_params(params_arr); set_input("data" x); run(); get_output(0, y);
  • 63. Contents • TVM の概要 • オペレータレベルの最適化 • グラフレベルの最適化 • パフォーマンス • デプロイ用のツールとしての側面 • オープンソースプロジェクトとしての側面
  • 64. TVM とコミュニティ • コントリビュータやユーザーを主体としたコミュニティづくりを重視 より詳しくは, TVM Community Structure, [RFC] Community Guideline Improvements しばらくコントリビュートしていると, レビューアになってくれと頼まれる
  • 66. • 企業からの興味 • Amazon, Huawei: 頻繁に PR が来る. 製品に使っている • Facebook, Alibaba: x86, ARM 向けの最適化をやっているらしい • Microsoft: Github の Issue によく現れる. ONNX がらみ? • Qualcomm: Hexagon DSP バックエンドを開発中 • 国内では, NTT からコミットする人が複数. FPGA? • 他のオープンソースプロジェクトからの利用 • MXNet: NNVM の一部を使用. TVM でコンパイルした関数を呼ぶこともできる • miya: Theano を開発したグループが現在開発中の DL 用プログラミング言語. バックエンドとして NNVM を使用するらしい
  • 67. まとめ • プログラミング言語やコンパイラ技術の, DL への導入が流行っている • 先進的な最適化・チューニング技術 • 多様なハードウェアバックエンドのサポート • ハイパフォーマンス これらを兼ね備えた TVM に今後も期待. ニューラルネットワーク = プログラム DL フレームワーク = 言語処理系
  • 68. Links • TVM: An Automated End-to-End Optimizing Compiler for Deep Learning, OSDI 2018 • https://arxiv.org/abs/1802.04799 • Learning to Optimize Tensor Programs, NIPS 2019 • AutoTVM 論文 • https://arxiv.org/abs/1805.08166 • Relay: A New IR for Machine Learning Frameworks • https://arxiv.org/abs/1810.00952 • VTA: An Open Hardware-Software Stack for Deep Learning • https://arxiv.org/abs/1807.04188 • Optimizing CNN Model Inference on CPUs • Amazon のエンジニアによる、Xeon 向けの TVM 最適化に関する論文 • https://arxiv.org/abs/1809.02697 • Discussion forum • https://discuss.tvm.ai/ • 公式ドキュメント. チュートリアルなども充実. • https://docs.tvm.ai/ • Automatic Kernel Optimization for Deep Learning on All Hardware Platforms • https://tvm.ai/2018/10/03/auto-opt-all.html