5年ぶりにPCを購入
プライベートでは殆どのことをスマホでやってしまうのでハイスペックなPCを持っていなかったのだが、わけあってPCを購入した。しかも、Ryzen 9のデスクトップ型。
もともと、プライベートでは軽い技術の検証や簡単なアプリの作成でしかPCを使用していなくて、重い処理はGCEインスタンスを建ててやっていた。 2017年頃から12inch Macbookを使用しているが軽くて気に入っている。次買うときも12inch Macbookが欲しいと思って待ち続けたが一向に出る気配がない。というか、多分もう出ないと思っている。 そんな中、最近OSSの開発などで重めの処理が増えてきて、GCEでのリモート開発が効率悪いというかやり辛いと感じ始めていた。 というわけで、プライベート開発用にスペック高めのPCを購入した。 購入したのは、Minisforum EliteMini HX90というRyzen 9 5900HXを搭載したベアボーンキットで、これに別途購入したメモリ 32GB、SSD 1TBを積んだ。 12inch MacbookがCore m5のメモリ8GBなのでかなりのスペックアップ。それでも今回の購入金額の方が安かった。OSはUbuntu 21.10を入れた。
インストールで色々ハマったので別記事で書く。
Deeplearning Framework in Ruby
※ 本記事は自分の個人サイトに2021-03-05に投稿したブログから引っ越してきたものです。
書籍ゼロから作る Deep Learning ❸で題材となっているDeep Learningフレームワーク DeZeroをRubyとNumo::NArrayを使って実装してみたので、現状できることの紹介と実装時のポイントをいくつか説明します。
DeZeroとは
オライリーから出ている書籍ゼロから作る Deep Learning ❸は、Step-by-StepでDeep Learningフレームワークを作るという内容となっており、そこで最終的に作られるフレームワークがDeZeroです。 DeZeroは、MLP(多層パーセプトロン)だけでなくCNNやRNNのモデルまで作ることができる本格的なフレームワークとなっています。
実装自体はPythonで書かれており、内部の重要なデータ構造である多次元配列はnumpyを使っています。 そして、このnumpyの機能があるからこそ多次元配列に対する面倒な計算処理を簡単に記述することができます。 また、numpyの計算処理自体はPythonではなくCによるネイティブコードで実行されるので非常に高速です。
以上のような特徴を持ったDeZeroをRubyで実装する場合、重要になるのがnumpyで実装されている多次元配列とその計算の部分になります。 RubyではPythonのライブラリを呼ぶことができるPyCallを使ってnumpyを使う方法があり、既にその方法でDeZeroを実装されているものがあります。 一方、Rubyにもnumpyの代替となるライブラリとしてNumo::NArrayがあります。
今回、そもそもDeZeroをRubyで実装しようと思ったのは、このNumo::NArrayがどれだけnumpyの代わりとして使えるのか試してみたかったというところにあります。
そこで、numpyの代わりにNumo::NArrayを使ってDeZeroの実装を始めました。
Deep Learning Framework for Ruby
DeZeroのRuby実装ということでDezerbという名前にしました。
現段階では、簡単なMLPのモデルを作れるところまで実装が完了しているので、そのデモを紹介します。
線型回帰の実行例
線形関数 y = wx + b
の平均二乗誤差に対して勾配降下法を使って100エポック訓練した結果を表示します。
緑色の'x'マークで左下から右上にランダムに分布しているポイントが訓練データとなります。
紫色の直線が訓練後の線形関数で、訓練データに概ね適合しているのがわかります。
ニューラルネットワークの実行例
活性化関数としてシグモイド関数を適用する2層のニューラルネットワークを10000エポック訓練した結果です。 こちらも概ね適合しています。
実装のポイント
numpyとNumo::NArrayのメソッドの対応
Numo vs numpyというドキュメントに各々のメソッドの対応表があります。この表を見るとわかるのですが主要なメソッドはほとんどカバーされていることがわかります。
この対応表を見ながらnumpyのメソッドの部分を単純にNumo::NArrayのものに書き換えていけばほぼ完成です。
Numo::NArrayに足りないメソッドをRubyで実装
配列の全要素の和を求めるsum
のような関数では、バックプロパゲーション時に配列のブロードキャストを行います。実装上、numpyではbroadcast_to関数で明示的にブロードキャストしますが、Numo::NArrayにはbroadcast_to
のような明示的なブロードキャストメソッドがありません。
そこで、処理速度は犠牲になりますがbroadcast_to
メソッドをRubyで実装しました。
ブロードキャストのルール通りに、先にブロードキャスト前後の配列の次元数を揃えて(reshape)、各次元のサイズの大きい方に値を反復しながら引き伸ばす(tile)、というように実装しています。
尚、このブロードキャスト自体のバックプロパゲーションの処理にnumpyのsqueeze
を使っているのですが、こちらもNumo::NArrayには用意されていないのでRubyで実装しました。
演算子のオーバーロード
細かいことですが、PythonとRubyで演算子をオーバーロードしたときの挙動が異なるため、その実装の違いを取り挙げておきます。
計算式の変数を表すクラスとしてVariable
クラスを実装しています。このVariable
オブジェクト同士の計算だけでなくVariable
オブジェクトとNumo::NArrayオブジェクトの計算をシームレスに記述できるように演算子をオーバーロードしています。
Pythonの場合、演算子のオーバーロードは__演算子名__
(ex. __mul__
)メソッドと__r演算子名__
メソッドを定義することで、Pythonのビルトイン数値オブジェクトとVariable
オブジェクトの演算をシームレスに記述できます。また、ndarrayとVariable
オブジェクトの演算も記述できるようにVariable
クラスのインスタンス属性__array_priority__
(演算子の優先度)の値をndarrayより高い値に設定しています。
Rubyでも同じことを実現するために、Variable
クラスにcoerce
メソッドを定義し、その中で非Variable
オブジェクトの項をVariable
オブジェクトに変換(キャスト)しています。
最後に
DeZeroをRubyで再実装することで、ニューラルネットワークの計算手法について改めて学び直すことができました。また、具体的な実装をすることで理解があやふやであったところが明確になったと感じています。更には、実装の過程で、今まで使ったことのなかったRubyの言語機能を知ることができるなど副次的な学びもありました。
そして主目的であるNumo::NArrayがnumpyの代わりとしてどれだけ使えるのかという点については、今回の利用の範囲ではほぼ完璧に代替として使えることがわかりました。(broadcast_toやsqueezeもそのうち実装されることを願っています)
今後は引き続き、CNNやRNNのモデルが作れるところまで実装を進めていこうと思います。また、GPU対応としてCumoを取り入れてみたり、GBDT(勾配ブースティング決定木)などニューラルネットワーク以外のモデルも作れるようにすると面白そうです。
Deep Learning始めた
ここ数年の盛り上がり方から、流石にある程度知っておかないとまずいかなと漠然と思い始め、Deep Learningの勉強を始めてみた。
今年の4月頃からCourseraのDeep Learning Specialization 5コースを受講したり、ゼロから作る Deep Learningを読んで、とりあえず初めの一歩を踏み出した。途中、微分と線形代数を思い出したり、数式の意味を理解するのに苦労した。
そして、7月頃にTensorFlowではじめるDeepLearning実装入門でTensorFlowに入門し、この本に載っているNeural Image Captioningを実装してみた。更に、これ自体単純なAIの例として面白いのでWebアプリ化してみたのが以下。
手持ちの画像をアップロードするとそれにキャプションを付けてくれるというもの。キャプション生成には10数秒ほど時間がかかります。
中身を簡単に説明すると、CNN(GoogLeNet Inception-v3)とRNN(ブロックにLSTMを使用)を繋げたモデルを、TensorFlowを使って実装している。そしてこのモデルをSTAIR Captionというデータセットを使って、AWSのp2.xlargeというGPUインスタンスで15時間ほど学習させた。
Webアプリとしては、Djangoを使って作成しておりニューラルネットワークでの推論処理は非同期実行にする為celeryというライブラリを使用した。
今回、TensorFlowを使ってWebアプリを作成するにあたり、あらゆることが初めての経験であった為、製作期間1ヶ月間はとても有意義な時間だった。
TensorFlowはもちろんのこと、そもそもPython自体書いたことがなかった為、パーフェクトPythonを参照しながらコーディングを進めた。また、Djangoも公式チュートリアルとBuilding Django 2.0 Web Applicationsを読んで使い方を覚え、PostgreSQLやNginxについても一から始めた。更に、AWSも初めて使ったり、元々契約していたVPSが不具合でyumのアップデートができなくて別のVPSを契約し直して一から構築し直したりと色々と大変だった。(ここが一番ハマった)
今後は、引き続きDeep Learningの知識を深めながら、TensorFlowだけでなくKerasも試してみようと考えている。あと、Kaggleにもチャレンジしてみたい。
hello
ブログをはじめる
fn main() { println!("ブログをはじめる"); }