AMD系インスタンスでJuliaを始めよう①【CPU編】
Contents
はじめに
先週は本年度から始まった大学入学共通テストでしたね!受験生の皆さんはおつかれさまでした!
筆者が大学受験時代の頃はセンター試験という名称でしたが、これもそのうちおじさんしか知らないような名称になるんですね~。さて、共通テストの数学の問題を覗いてみたのですが、センター試験と比べ数1Aは問題の質が良いんじゃないかな?と感じました。特に2人の人物のディスカッションにあわせて問題を解くやつは、議論ベースの問題解決志向養成の意図が感じられ、大変好感が持てました。
一方、数2Bはあまりセンター試験と変わってない気がしました。ここで、共通テスト数学2Bの問題を眺めていた時の筆者の気持ちとして最適なものを次の中から一つ選べ。
正解は①です!他の選択肢も悪くはないんですが本記事では①が正解です!
これから2回の記事に渡ってインスタンスでJuliaを解説したいと思います。1回目にあたる本記事ではJuliaの導入と動作確認について、2回目の記事ではAMD系インスタンスにおいて、GPUでJuliaを動かす方法を解説します。2021年の必答問題Juliaを学びましょう!
前提
この記事は下記の条件を満たした方を対象としております。
- HGAでインスタンスを作成済であること(推奨インスタスタイプはamd系、筆者はamd1dl使用)
- インスタンスにログイン可能であること(方法, VSCodeでの接続も推奨します)
- 動作確認はJupyter Labを使って行いました(参考記事)
- 何らかのプログラミング言語、またはMatlabの使用経験があること
Juliaとは
JuliaはMITの研究者達によって開発された、プログラミング言語で、数値計算を得意とします。文法はPythonに極めて近いです。インタプリタ型言語の使用経験がある方ならすんなり理解できると思います。ただし、配列のインデックスがFortran同様1始まりである点に注意しましょう。この点もあり、数学や物理専攻の方なら、書きやすいと言われているPythonよりも更に書きやすく思うことでしょう。また実行速度もPythonに比べて極めて速く、静的な型付けでコンパイルが必要なCとおおむね同等の速さとなる場面も多いようです。
Juliaの導入
Juliaのダウンロードインストール
次のコマンドを順に実行してJulia(v1.5.2)のダウンロードとインストールを行います。またjuliaコマンドがどのディレクトリからも呼び出せるようシンボリックリンクを貼っています。
wget https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-1.5.2-linux-x86_64.tar.gz
tar xvf julia-1.5.2-linux-x86_64.tar.gz
sudo mv julia-1.5.2 /opt/
sudo ln -s /opt/julia-1.5.2/bin/julia /usr/local/bin/julia
Juliaの動作確認
Juliaが正常にインストールされたかチェックします:
julia -v
と入力したときバージョンが表示されたらokです。REPL(Read Eval Print Loop, 対話モード)で早速コードを実行してみましょう。
julia
と入力したら下図のようなモードに切り替わるので
println("HGA使ってみましょう!")
と入力してみましょう。下図のように実行されれば動作確認はばっちりです(宣伝もしておきました。公式ブログの記事としても申し分ないですね!)。

Jupyter LabでJuliaを実行する
Jupyter LabでJuliaを実行する方法について解説します。なお、インスタンスでJupyter Labを使用する方法については前回の記事を参考にしてください。実は筆者はJupyter Labが好きになりつつあります。コードの実行環境とマークダウンが書けるセルが揃って表示されるのは便利ですね!コード補完もJupyter Notebookに比べて極めてよくなってます!
JupyterのカーネルでJuliaを動作させるために、Julia用に専用のパッケージというものを導入する必要があります。Pythonでいえばcondaとかpipでインストールするアレです。ターミナルで
julia
と入力しREPLに切り替えて]と入力します:
]
すると下図のようなpkg>という、パッケージマネージメント用のモードに切り替わるのでそこで
add IJulia
と入力し、JupyterのカーネルでJuliaを実行するためのパッケージが導入できます。

パッケージが導入できたら実際にnotebookサーバを立ち上げてJuliaを動かしてみましょう。
まず、ローカルPCのブラウザからJupyterLabのnotebookにアクセスするため、以下のコマンドでnotebookサーバを立ち上げます:
jupyter lab

サーバを立ち上げたローカルPC(インスタンスに接続かけているPC)のブラウザからhttp://localhost:8888にアクセスします。

Notebook用のカーネル選択画面にJuliaが表示されていたらOKです!クリックしてNotebookを開きましょう。下図のようにセル内にprintln("HGA使ってみましょう!")と入力し、Ctrl+Enterキー押下で実行するとHGAに会員登録したくなるでしょう(ならない???)。

Juliaを使ってみる
Juliaの書き方はPythonそっくりです。配列においてインデックスが1スタートである点に気を付ければひとまず十分だと思います。特筆すべきはPython同様、リスト内包表記で配列が定義できることです(具体例は後ほど)。本記事ではJuliaの文法の解説はしませんが、いくつかの例を基に、手を動かしてJuliaに慣れることを目指します。
例1:logの計算と補完について
logの計算をやってみましょう!log()でネイピア数を底とする対数、log2()で2を底とする対数の値が出力されます(下図)。

ここら辺の計算ができないと共通テスト数2Bの大問1[2]で早速失点するので気を付けてくださいね。できればなんのためにlogという概念が出てきたのか考えたり調べたりしてみましょう。今時手計算なんてしないから関係ない?お、おう・・・。
ここで一つ絶対に覚えてもらいたい便利な技があります。ネイピア数(Euler's number)やθ(シータ, theta)など数学でよく使う記号を用いる時、
\euler
と入力しTabキーを押せば、ネイピア数を表す記号(e)に変換されます。同様に\theta + Tabキーでθ, \pi + Tabキーで円周率πが出てきます。これだけ紹介できればもうこの記事終わりで良いんじゃないかと思うくらい便利な方法なので日頃から意識して使うようにし、必ずマスターされることをおすすめします!この方法忘れるくらいならlog計算の方忘れてください!
例2:オイラーの公式と(数学)関数の定義
Julia最大の魅力の一つは、数式の表記がPythonやMatlab以上に直観的に表記できることです。下図を見ればその素晴らしさがよくわかると思います。なお、imは虚数を表す予約語です。また、掛け算の*は不要だったりします。

上から3つ目のセルではファイマンも言及しているあの等式について計算しています。虚部が0に限りなく近いが0となっていないところにコンピュータ演算の難しさと魅力があらわれていますね。これはテイラー級数の打ち切りに起因する部分が大きいのか、デジマルバイナリの変換や演算過程に起因する部分が大きいのか、筆者にはわかりません。
例3:グラフのプロットとパッケージの導入
Notebook上でグラフをプロットしてみましょう。今回はPlotsとPyPlotというパッケージをそれぞれ導入し、グラフを描画します。それから後の例で使いたいので、もう一個Optimという最適化問題を解くためのパッケージもついてでに導入します。
まず、インスタンスに接続しているターミナルに戻り、notebookサーバをシャットダウンしてください(Ctrl+c, jupyter上のターミナルからもできます)。次にターミナル上で
julia
と入力しREPLに切り替え、そこで
]
を入力しパッケージのマネジメントモードに切り替えます。そこで
add Plots
add PyPlot
add Optim
をそれぞれ入力し、パッケージを導入します(下図)。

以上でパッケージの追加導入完了です。再びnotebookサーバを立ち上げますが、このとき既に開いているJupyter画面を念のためリロードするようにしましょう。下図のように最初に
using [パッケージ名]
で使用したいパッケージを導入するのがポイントです。オイラーの等式を満たす点をガウス平面上にプロットしてみましょう(実軸上の-1の箇所にプロットされるはずです)!実行例のようにラベルや表示範囲を指定することもできます。PythonやMatlabでグラフ描画した経験がある方はほとんど戸惑わないと思います。そして相変わらず数式表現の素晴らしさが光りますね。ここで、パッケージのimport時(つまり、初めてパッケージを使う時)、セルの実行に時間が結構かかるので注意してください。一度カーネル内で導入してしまえば後は早いです。

次に2変数関数のグラフを描画してみましょう!(下図)

セルの(初回)実行時はかなり時間がかかると思います。Plots自体がサイズの大きいパッケージだからです。しかし、一度導入してしまえば、後は早いです。また、Pythonで言うリスト内包表記が使える点も特筆に値します。
ここで、注意していただきたいのは、2次元配列の構造上、転置(’)が必要である点です。順番に説明しますと、2変数関数をプロットする際には、あらかじめ二つの定義域を初期値:刻み値:終端値の形で宣言します(配列の形で保持します)。その後、2つの定義域の値毎に、2変数関数に値がセットされ、それを計算した結果がやはり配列(z)にセットされます。これをあらためて、各定義域の値ごとにプロットしていくことで、2変数関数のプロットが完成する流れになるのですが、問題は関数fから配列zを作る際に、Juliaの配列の構造から、転置が必要である点です。実は、Julia(に限らずほぼ全てのプログラミング言語の2次元配列・そのカウンターパート)では、2次元配列では要素にy→xという形でアクセスします。今、2次元行列を例に説明します。2次元行列において、各要素の値を得るには、x番列のy行目という(x, y)の形でアクセスするのが普通です。一方、Julia(に限らずプログラミング言語ほぼ全般)でもこのように行列を表現する2次元配列というものが用意されているのですが、行列で言うx番列のy行目には(y, x)の形でアクセスします。
この添え字と要素の対応を(x, y)の形式にするために転置が必要です。なお、今回のケースの場合、x1とx2からなる2次元配列がいわゆる対称行列に相当するために、転置は必ずしも必要ありません。
例4:最適化問題を解いてみよう
前節で導入したOptimパッケージを導入して最適化問題を解いてみましょう。 最適化問題とは、ある関数の値を最小(または最大)にするような変数の値はいくつ?的なことを問う問題のことです。多くの場合、2変数関数以上の多変数関数に対して、極値を求める問題と換言することもできるでしょう。
ディープラーニングであれば損失関数の極小値を取るような重みの値を求めます。これは最適化問題の好例です。また、最小作用の原理に基づいて何らかの基礎式を用いる場合(解析力学、量子力学、etc...)にもこの考えは使われます(ただし、最小作用の原理からある基礎式を導出する場合、ある作用積分値が変化しないような条件--端点間の変分が時刻によらず0となる条件--拘束条件がその基礎式だよね、的な考えをとり、最適化問題の主要な関心とはずれます。)
ここではネルダ・ミード法を使って前節で描画した関数の最小値を求めることを考えます。この手法は偏微導関数を求める必要がないので、適用可能な問題(関数)の範囲はかなり広いですが、「これなら微分しちゃった方が早くない?」とあなたが感じる関数に対しては大抵その通りよろしくないパフォーマンスとなる手法でもあります。ネガティブな予測は大体その通りになるという、世の中の不条理さがそのまま出る可能性が常にある手法といっても良いと思います。その上、以下の例の関数だとばっちり微分しちゃった方が早いパターンなのです(x_solved = [0,0]でmin(f)= 1と暗算で求めるのはやめてください。筆者のライフポイントがマイナスに転じます。)
この手法の場合、初期値(どの地点から適用していくか)の決定がパフォーマンスに影響を与えたりするので重要ですが、今回は何も考えず両方3にしてみました。

10^-5とオーダがやや大きめな気がしなくもないですが、これはおおむね原点と言い張れそうですね!
今回は、あくまでCPUベースでJuliaを実行させました。次回はAMD GPUを使ったインスタンスにおいてJuliaをGPUベースで動作させることを考えます。次回もお楽しみに!!
[HGAoffcial]
[dot]
[/dot]