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をRubyNumo::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'マークで左下から右上にランダムに分布しているポイントが訓練データとなります。 紫色の直線が訓練後の線形関数で、訓練データに概ね適合しているのがわかります。

f:id:koji-m:20220122222632p:plain

ニューラルネットワークの実行例

活性化関数としてシグモイド関数を適用する2層のニューラルネットワークを10000エポック訓練した結果です。 こちらも概ね適合しています。

f:id:koji-m:20220122222757p:plain

実装のポイント

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実装しました。

演算子オーバーロード

細かいことですが、PythonRuby演算子オーバーロードしたときの挙動が異なるため、その実装の違いを取り挙げておきます。

計算式の変数を表すクラスとして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アプリ化してみたのが以下。

Neural Image Captioning

手持ちの画像をアップロードするとそれにキャプションを付けてくれるというもの。キャプション生成には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にもチャレンジしてみたい。