Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

HalideでつくるDomain Specific Architectureの世界

1.422 visualizaciones

Publicado el

2017/12/17に開催されたFPGAエクストリーム・コンピューティング 第10回( https://fpgax.connpass.com/event/77616/ )にて発表した資料です。

詳細はFixstars Tech Blogをご覧ください →
http://proc-cpuinfo.fixstars.com/2018/02/fpgax-halide-dsa/

Publicado en: Software
  • Sé el primero en comentar

HalideでつくるDomain Specific Architectureの世界

  1. 1. Halideでつくる Domain Specific Architectureの世界 Takuro Iizuka Fixstars Solutions Inc.
  2. 2. 名前: 飯塚 拓郎 所属: Fixstars Solutions Inc.(カリフォルニア州アーバイン) 普段はこの辺にいます
  3. 3. ベイエリア、 いわゆるシリコンバレーはここ 名前: 飯塚 拓郎 所属: Fixstars Solutions Inc.(カリフォルニア州アーバイン)
  4. 4. 直線距離で600km弱 東京↔大阪くらいある
  5. 5. 実際、大体まっすぐに行ける
  6. 6. 日本 北米 Fixstars Solutions Inc. 金融 Option pricing General Batch Processing Inspection Machine Predictive Maintenance Imaging Device Genomics ADAS Autopilot System Imaging Device Genomics ADAS Autopilot System 基盤技術R&D I/O Acceleration • 最適化ファームウェア • NAND Flash, SSD CPU Acceleration • 並列コンピューティング • x86, POWER, ARM, GPU, FPGA 共同開発 フィードバック マーケティングリサーチ
  7. 7. システム最適化の原則: いかに優れた部分最適も 全体最適には勝てない
  8. 8. ハードウェア オペレーティング・システム ドライバ ライブラリ アプリケーション
  9. 9. ハードウェア オペレーティング・システム ドライバ ライブラリ アプリケーション最適化! 最適化! 最適化! 最適化! 最適化!
  10. 10. ハードウェア オペレーティング・システム ドライバ ライブラリ アプリケーション最適化! 最適化! 最適化! 最適化! 最適化! 全体として最適か?
  11. 11. ハードウェア ソフトウェア モジュール A 最適化! ソフトウェア モジュール B ソフトウェア モジュール X 最適化! 最適化!
  12. 12. ハードウェア ソフトウェア モジュール A 最適化! ソフトウェア モジュール B ソフトウェア モジュール X 最適化! 最適化! 全体として最適か?
  13. 13. Q: では、レイヤを超えて システムを再構築すれば良いのか?
  14. 14. A: Yes でもあり No でもある
  15. 15. 問題は, 今時の情報システムが複雑すぎること
  16. 16. 境界を超えるための技術
  17. 17. 設計 ハードウェア オペレーティング・システム ドライバ ライブラリ アプリケーション 職人プログラマによって再構築、最適化 ドメイン特化言語による 高次アルゴリズム記述 ハードウェア オペレーティング・システム ドライバ ライブラリ アプリケーション ドメインに特化したシステムアーキテクチャをコンパイラによって自動生成する これまで これから
  18. 18. Domain Specific Architecture
  19. 19. Halide to FPGA
  20. 20. Halideとは è 画像処理の高性能計算に特化した オープンソースのDSL – http://halide-lang.org/ è 特徴 – 簡潔なアルゴリズム記述 – C++の内部DSLとして実装 – マルチプラットフォーム対応 – アルゴリズムとスケジューリングの分離
  21. 21. アルゴリズムとスケジューリングの分離 è アルゴリズム – 計算部の本質的な処理のみを記述 – ハードウェアによらず単一の記述でよい è スケジューリング – 計算順序やデータの保持の仕方を記述 – 並列化やループ変形などの最適化もここで記述 – ハードウェアごとに異なるスケジュールを指定可能 これにより、最適化にまつわる Try&Errorの時間を劇的に削減できる
  22. 22. void box_filter_3x3(const Image in, Image &blury) { Image blurx(in.width(), in.height()); for (int y = 0; y < in.height(); y++) for (int x = 0; x < in.width(); x++) blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3; for (int y = 0; y < in.height(); y++) for (int x = 0; x < in.width(); x++) blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3; } C++によるナイーブなコード
  23. 23. C++によるx86向け最適化コード void box_filter_3x3(const Image &in, Image &blury) { __m128i one_third = _mm_set1_epi16(21846); #pragma omp parallel for for (int yTile = 0; yTile < in.height(); yTile += 32) { __m128i a, b, c, sum, avg; __m128i blurx[(256/8)*(32+2)]; // allocate tile blurx array for (int xTile = 0; xTile < in.width(); xTile += 256) { __m128i *blurxPtr = blurx; for (int y = -1; y < 32+1; y++) { const uint16_t *inPtr = &(in[yTile+y][xTile]); for (int x = 0; x < 256; x += 8) { a = _mm_loadu_si128((__m128i*)(inPtr-1)); b = _mm_loadu_si128((__m128i*)(inPtr+1)); c = _mm_load_si128((__m128i*)(inPtr)); sum = _mm_add_epi16(_mm_add_epi16(a, b), c); avg = _mm_mulhi_epi16(sum, one_third); _mm_store_si128(blurxPtr++, avg); inPtr += 8; } } blurxPtr = blurx; for (int y = 0; y < 32; y++) { __m128i *outPtr = (__m128i *)(&(blury[yTile+y][xTile])); for (int x = 0; x < 256; x += 8) { a = _mm_load_si128(blurxPtr+(2*256)/8); b = _mm_load_si128(blurxPtr+256/8); c = _mm_load_si128(blurxPtr++); sum = _mm_add_epi16(_mm_add_epi16(a, b), c); avg = _mm_mulhi_epi16(sum, one_third); _mm_store_si128(outPtr++, avg); } } } } }
  24. 24. C++によるx86向け最適化コード void box_filter_3x3(const Image &in, Image &blury) { __m128i one_third = _mm_set1_epi16(21846); #pragma omp parallel for for (int yTile = 0; yTile < in.height(); yTile += 32) { __m128i a, b, c, sum, avg; __m128i blurx[(256/8)*(32+2)]; // allocate tile blurx array for (int xTile = 0; xTile < in.width(); xTile += 256) { __m128i *blurxPtr = blurx; for (int y = -1; y < 32+1; y++) { const uint16_t *inPtr = &(in[yTile+y][xTile]); for (int x = 0; x < 256; x += 8) { a = _mm_loadu_si128((__m128i*)(inPtr-1)); b = _mm_loadu_si128((__m128i*)(inPtr+1)); c = _mm_load_si128((__m128i*)(inPtr)); sum = _mm_add_epi16(_mm_add_epi16(a, b), c); avg = _mm_mulhi_epi16(sum, one_third); _mm_store_si128(blurxPtr++, avg); inPtr += 8; } } blurxPtr = blurx; for (int y = 0; y < 32; y++) { __m128i *outPtr = (__m128i *)(&(blury[yTile+y][xTile])); for (int x = 0; x < 256; x += 8) { a = _mm_load_si128(blurxPtr+(2*256)/8); b = _mm_load_si128(blurxPtr+256/8); c = _mm_load_si128(blurxPtr++); sum = _mm_add_epi16(_mm_add_epi16(a, b), c); avg = _mm_mulhi_epi16(sum, one_third); _mm_store_si128(outPtr++, avg); } } } } } 長くて色々つらい ハードウェア変わると書き直し アルゴリズム変わると書き直し
  25. 25. Halideによるアルゴリズム記述 Func box_filter_3x3(Func in) { Func blurx, blury; Var x, y; blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3; blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3; return blury; }
  26. 26. Func box_filter_3x3(Func in) { Func blurx, blury; Var x, y; blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3; blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3; return blury; } Halideによるアルゴリズム記述 アルゴリズム記述部
  27. 27. Func box_filter_3x3(Func in) { Func blurx, blury; Var x, y; blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3; blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3; blury.tile(x, y, xi, yi, 256, 32).vectorize(xi, 8).parallel(y); blurx.compute_at(blury, x).store_at(blury, x).vectorize(x, 8); return blury; } HalideによるCPU向け最適化コード アルゴリズム記述部 スケジューリング記述部
  28. 28. Halideのコンパイルフロー Halide Compiler ) . E B - / - ) A . (C +
  29. 29. Halide FPGA Backendのコンパイルフロー Halide Compiler + B B A B BH IJ . F B .. / .. / A B + C B B BH(G - A B BH +. E +. E B 新規拡張 )
  30. 30. + F C E +/ C E + E Halide FPGA Backendの内部 Func filter_A(Func in) { <...> return f; } F + A A D
  31. 31. アルゴリズム記述方法
  32. 32. 関数の定義 è アルゴリズムは関数として定義される – 関数: Halide::Func – 誘導変数: Halide::Var Halideソースコード 等価なC++ソースコード 意味: 関数 f は定義域 x, y に対して x+y を値域に持つ 名前空間Halide::は以下省略 Func f; Var x, y; f(x, y) = x + y; for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { f[y][x] = x + y; } }
  33. 33. 関数の次元数 è 最大4次元までの関数を定義可能 f は3次元の関数(e.g. 3D空間、カラー画像) Func f; Var c, x, y; f(c, x, y) = c + x + y;
  34. 34. 関数の次元数 è 最大4次元までの関数を定義可能 f は3次元の関数(e.g. 3D空間、カラー画像) f は4次元の関数 Func f; Var c, x, y; f(c, x, y) = c + x + y; Func f; Var c, x, y, z; f(c, x, y, z) = c + x + y + z;
  35. 35. 関数の参照 è 関数の右辺に定義された関数への参照 – 関数合成が可能 意味: 関数 f2 は定義域 x, y に対して f1(x+y) を値域に持つ Var x, y; Func f1; f1(x, y) = x + y; Func f2; f2(x, y) = f1(x, y); Var x, y; Func f2; f2(x, y) = x + y;
  36. 36. 式 è 式はExpr型の変数として表される – 関数: Func – 誘導変数: Var – 式: Expr 組み立てた計算式を、式としてとっておくことが出来る Var x, y; Expr e = x + y; Func f; f(x, y) = e; Var x, y; Func f; f(x, y) = x + y;
  37. 37. RDomと畳み込み関数 è 畳み込みを表すためのプリミティブ – リダクションドメイン: RDom – RDom(min, extent) • 指定された次元で[min, min+extent-1]の領域を畳み込み 等価なC++ソースコード rxは[-1, 1]を動く誘導変数 Var x; Func f; f(x) = x; RDom rx(-1, 3); Func g; g(x) = sum(f(x + rx)); for (int x=0; x<width; x++) { T sum = 0; for (int rx=-1; rx<2; rx++) { sum += x + rx; } g[x] = sum; } +
  38. 38. FPGA Backend が生成する ハードウェアアーキテクチャ
  39. 39. FPGAバックエンドのアーキテクチャ生成戦略 è 基本はデータフローアーキテクチャを生成 – モジュール間は可能なかぎりストリーム化 – モジュール内のループは完全にパイプライン化 f × g + h + pipeline DMA DMA in p Halide FPGA Backend Stream Stream Stream Stream Func pipeline(ImageParam in, Param p) { Func f, g, h; f(x, y) = in(x, y) * 2; g(x, y) = in(x, y) + p; h(x, y) = f(x, y) + g(x, y); f.compute_root(); g.compute_root(); h.compute_root(); return h; }
  40. 40. FPGAバックエンドのアーキテクチャ生成戦略 è 3x3の畳み込みの場合 + in_buffer f_buffer in_port f_port ■ Shift Regs ■ Block RAM 等価なC++プログラム = Halide FPGA Backend Func conv3x3(ImageParam in) { Var x, y; RDom r{-1, 3, -1, 3}; Func f; f(x, y) = sum(in(x+r.x, y+r.y)); f.compute_root(); return f; } for(y=0; y<height; y++) for(x=0; x<width; x++) { f[y][x]=0; for(ry=-kh/2; ry<kh/2+1; ry++) for(rx=-kw/2; rx<kw/2+1; rx++) f[y][x]+=in[y+ry][x+rx]; }
  41. 41. FPGAバックエンドのアーキテクチャ生成戦略 + in_buffer f_buffer in_port f_port 等価なC++プログラム = ■ Shift Regs ■ Block RAM Halide FPGA Backend Func conv3x3(ImageParam in) { Var x, y; RDom r{-1, 3, -1, 3}; Func f; f(x, y) = sum(in(x+r.x, y+r.y)); f.compute_root(); return f; } for(y=0; y<height; y++) for(x=0; x<width; x++) { f[y][x]=0; for(ry=-kh/2; ry<kh/2+1; ry++) for(rx=-kw/2; rx<kw/2+1; rx++) f[y][x]+=in[y+ry][x+rx]; }
  42. 42. FPGAバックエンドのアーキテクチャ生成戦略 + in_buffer f_buffer in_port f_port ■ Shift Regs ■ Block RAM 等価なC++プログラム = Halide FPGA Backend Func conv3x3(ImageParam in) { Var x, y; RDom r{-1, 3, -1, 3}; Func f; f(x, y) = sum(in(x+r.x, y+r.y)); f.compute_root(); return f; } for(y=0; y<height; y++) for(x=0; x<width; x++) { f[y][x]=0; for(ry=-kh/2; ry<kh/2+1; ry++) for(rx=-kw/2; rx<kw/2+1; rx++) f[y][x]+=in[y+ry][x+rx]; }
  43. 43. FPGAバックエンドのアーキテクチャ生成戦略 + in_buffer f_buffer in_port f_port ■ Shift Regs ■ Block RAM 等価なC++プログラム = Halide FPGA Backend Func conv3x3(ImageParam in) { Var x, y; RDom r{-1, 3, -1, 3}; Func f; f(x, y) = sum(in(x+r.x, y+r.y)); f.compute_root(); return f; } for(y=0; y<height; y++) for(x=0; x<width; x++) { f[y][x]=0; for(ry=-kh/2; ry<kh/2+1; ry++) for(rx=-kw/2; rx<kw/2+1; rx++) f[y][x]+=in[y+ry][x+rx]; }
  44. 44. 疑問
  45. 45. FPGA規模にあわせて スループットを変えたいんだけど? ストリームが必ずしも最適なアーキ じゃない場合もあるけど? 特定のパラメータをレジスタに マッピングしたいんだけど? データをAXI4で入れたいんだけど? レイテンシ削減のために モジュールを統合したいんだけど? 疑問
  46. 46. スケジューリングによるカスタムアーキテクチャ è HalideスケジューリングAPIを使用して、計算の意 味を変えずにコードを変形することができる – 計算タイミングの指定 – ループ変形 – etc… 重要:スケジューリングによる効果はターゲットハードによって異なる è FPGAバックエンドの場合 – ハードウェアアーキテクチャを 要求に応じてチューニングできる • 演算器の数 • I/Oバス幅 • I/Oインタフェースの種類
  47. 47. 計算タイミングの指定 è Func::compute_inline – Funcをインライン展開する • スケジューリング無指定の場合のデフォルトの挙動 C++ Var x, y; Func blur_x; blur_x(x, y) = in(x, y) + in(x+1, y); Func blur_y; blur_y(x, y) = (blur_x(x, y) + blur_x(x, y+1)) / 4; Var x, y; Func blur_y; blur_y(x, y) = (in(x, y) + in(x+1, y) + in(x, y+1) + in(x+1, y+1)) / 4; for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { blur_y[y][x] = (blur_x[y][x] + blur_x[y][x] + blur_x[y+1][x] + blur_x[y+1][x]) / 4; } }
  48. 48. 計算タイミングの指定 è Func::compute_inline – モジュールの統合 h × + + pipeline DMA DMA in p Halide FPGA Backend Func pipeline(ImageParam in, Param p) { Func f, g, h; f(x, y) = in(x, y) * 2; g(x, y) = in(x, y) + p; h(x, y) = f(x, y) + g(x, y); f.compute_inline(); g.compute_inline(); h.compute_root(); return h; }
  49. 49. 計算タイミングの指定 è Func::compute_root – ルートレベル(最外レベル)で当該Funcの計算を行う C++ Var x, y; Func blur_x; blur_x(x, y) = in(x, y) + in(x+1, y); Func blur_y; blur_y(x, y) = (blur_x(x, y) + blur_x(x, y+1)) / 4; blur_x.compute_root(); for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { blur_x[y][x] = in[y][x] + in[y][x+1]; } } for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { blur_y[y][x] = (blur_x[y][x] + blur_x[y+1][x]) / 4; } }
  50. 50. 計算タイミングの指定 è Func::compute_root – モジュールの分割 f × g + h + pipeline DMA DMA in p Halide FPGA Backend Func pipeline(ImageParam in, Param p) { Func f, g, h; f(x, y) = in(x, y) * 2; g(x, y) = in(x, y) + p; h(x, y) = f(x, y) + g(x, y); f.compute_root(); g.compute_root(); h.compute_root(); return h; }
  51. 51. ループアンロール è Func::unroll – 指定した次元に対してループ展開を行う unroll C++ Var x, y; Func f; f(x, y) = x + y; for (int y=0; y<height; y++) for (int x=0; x<width; x++) f[y][x] = x + y;
  52. 52. ループアンロール è Func::unroll – 指定した次元に対してループ展開を行う Unroll Var x, y; Func f; f(x, y) = x + y; f.unroll(x, 2); for (int y=0; y<height; y++) for (int x=0; x<width; x+=2) { f[y][x] = x + y; f[x+1][y] = x+1 + y; } Unroll C++ unroll C++ for (int y=0; y<height; y++) for (int x=0; x<width; x++) f[y][x] = x + y;
  53. 53. ループアンロール è Func::unroll – 演算スループットの向上 h × + + pipeline DMA DMA in p × + + Halide FPGA BackendFunc pipeline(ImageParam in, Param p) { Func f, g, h; f(x, y) = in(x, y) * 2; g(x, y) = in(x, y) + p; h(x, y) = f(x, y) + g(x, y); h.compute_root() .unroll(x, 2); return h; }
  54. 54. ループアンロール+バースト長の指定 è Func::hls_burst – I/Oのバースト長を調整する h × + + pipeline DMA DMA in p × + + Halide FPGA Backend Func pipeline(ImageParam in, Param p) { Func f, g, h; f(x, y) = in(x, y) * 2; g(x, y) = in(x, y) + p; h(x, y) = f(x, y) + g(x, y); in.hls_burst(x, 2); h.compute_root() .unroll(x, 2) .hls_burst(x, 2); return h; } ! /
  55. 55. CNNに適用してみよう
  56. 56. Convolutional Neural Network è 画像認識に頻繁に使用されるニューラルネットワーク – 前段にConvolution層/Pooling層を重ねるのが特徴 – 後段で全結合層による分類や回帰を行う è 推論時のボトルネック – Convoluton層: 演算数が膨大 – FC層: 重みの容量が膨大 Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner. Gradient-based learning applied to document recognition. Proceedings of the IEEE, november 1998.
  57. 57. FPGA向けアルゴリズム最適化: XNOR-Net[1] è Conv層の入力 Iと重み W を二値化 – ラインバッファ・重みの容量を1/32に削減 – 積和がXNORとpopcountで演算可能 ! ∗ # ≈ ( sign(!) ⊛ sign(# ) ○ -. ∗ : Convolution operator ⊛ : XNOR and popcount operator ○ : Element-wise product operator -.: Scaling factor + - - - + - + - + - + - + + - - + + 0 1 0 1 1 0 0 1 1 1 0 0 0 1 0 1 0 1 × 4.∗ ⊛ ! # sign(!) sign(#) binarize [1] Rastegari, M. et al., “XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks”, https://arxiv.org/abs/1603.05279
  58. 58. FPGA向けアルゴリズム最適化: Log-based Quantization[2] è初段・最終段のConv/FC層 – 二値化すると精度の低下が激しい è初段・最終段のConv/FC層の入力と重みを 対数量子化 – ラインバッファ・重みの容量を削減 – 積算がシフト演算で計算可能 • 今回はlog2-baseで量子化 Dataset Network Accuracy fixed-32 2-base log2-base MNIST LeNet-5 98% 95% 98% CIFAR-10 NIN 89% 66% 82% [2] Miyashita, D. et al., “Convolutional Neural Networks using Logarithmic Data Representation”, https://arxiv.org/abs/1603.01025
  59. 59. Halide DSLによる量子化MNIST実装 è 各層は適当に融合してモジュール化 – 低レイテンシ化 – 省リソース化 – パフォーマンスとモジュラリティの両立 è モジュール間はコンパイラの最適化によりストリーム化 – シーケンシャルアクセスになるよう 各モジュール内部でウィンドウレジスタ+ラインバッファでバッファリング Norm&Quant Conv BN ReLU Pooling BN Conv ReLU Pooling Scale Active BN Scale Active FC ReLU FC M0 M1 M2 M3 M4 M5 M6
  60. 60. Halide DSLによる量子化MNIST実装 è パイプライン全体のスループットは? – モジュールの演算スループット、モジュール間のI/Oス ループットのもっとも低い部分に引っ張られる M0 CU CU CU M1 CU CU CU M2 CU CU CU M3 CU CU CU M4 CU CU CU M5 CU CU CU M6 CU CU CU CU=Computing Unit
  61. 61. Halide DSLによる量子化MNIST実装 è 量子化MNISTの場合(バッチサイズ=1) – デフォルト(スループット未調整)の状態では、 第2層目のConvolutionの演算(M3)がボトルネック M0 CU M1 CU M2 CU M3 CU M4 CU M5 CU M6 CU 28x28 =784 5x5x20x28x28 =392000 2x2x20x24x24 =46080 20x5x5x50x12x12 =3600000 2x2x50x8x8 =12800 50x4x4x500 =400000 500x10 =5000 3600000cycle=40FPS(150MHz) (単位:iteration)
  62. 62. Halide DSLによる量子化MNIST実装 è 量子化MNISTの場合(バッチサイズ=1) – 畳み込みの入力チャネル層を2unrollすると 全体性能も倍になる M0 CU M1 CU M2 CU M3 M4 CU M5 CU M6 CU 28x28 =784 5x5x20x28x28 =392000 2x2x20x24x24 =46080 10x5x5x50x12x12 =1800000 2x2x50x8x8 =12800 50x4x4x500 =400000 500x10 =5000 CU CU conv2_sum.update().unroll(rc, 2); 1800000cycle=80FPS(150MHz) (単位:iteration)
  63. 63. Halide DSLによる量子化MNIST実装 unroll数 リソース 性能 conv1 conv2 fc3 pool1 pool2 LUT BRAM DSP FPS #1 0 0 0 0 0 27830 60 100 40 #2 0 10 0 0 0 27491 60 101 400 #3 5 100 5 0 0 28731 70 95 1875 #4 25 500 800 4 2 35403 64 86 9421 スケジューリングにより推論性能を200倍以上に向上 必要に応じて FC層やPooling層もアンロール リソース消費も変化 スループット向上
  64. 64. まとめ
  65. 65. HalideのFPGAバックエンドを構築することで… 最小限の努力でハードウェアの構築と動作が可能に • 簡潔なアルゴリズムの記述により、実装工数を大幅削減 • スケジューリングによりアーキテクチャを一瞬でカスタム ポータビリティを担保できる • CPUでアルゴリズム開発・テストののちに FPGAへ実装、などの柔軟な開発ワークフローが可能 • 今はGPUだが将来的にはハード化したいなどの要求にも対応 ますます加速するヘテロジニアス化への対応 • CPU+GPU+FPGAといったヘテロ構成のシステムを 同一の言語内でデザインできる
  66. 66. 適応領域 è 自動運転システム – Nexty Electronics との合弁会社、 Fixstars Autonomous Technologiesにおける基盤技術 – 低レイテンシ/低消費電力でのセンシング、認識処理、異常検知 è メディカルイメージング – 北米における産学共同研究プロジェクト – CT/MRI, ブレインマッピング等 – 超大規模ボリュームデータのストリーミング処理
  67. 67. https://www.halide2fpga.com Halideで実装されたFPGAアプリケーションのショウケースを公開しています
  68. 68. https://github.com/fixstars/Halide-elements Halideで実装された様々なアルゴリズムをMIT Licenseの下GitHub上で公開しています
  69. 69. http://www.fixstars.com/recruit/ Fixstarsでは優秀なエンジニアを募集しています(インターンシップも随時募集中)

×