プログラムとは
プログラムとはコンピュータに対する命令を記述したものです。
コンピュータはあくまで所定の手続きを行うハードウェアであって、適宜所定の手続きを呼び出すことで望む処理を実現することができます。
コンピュータが解釈できること
コンピュータが解釈できるのは「0」と「1」の羅列だけです。そして「0」と「1」というのはそれぞれ電圧が「ない」か「ある」かに対応します。この膨大なバイナリの組み合わせによってコンピュータは何かしらのものを表現します。
ここでいう何かしらとは、「処理」であったり「データ」であったり様々ですが、いずれにしてもコンピュータにとってはバイナリであるということです。コンピュータが解釈できるバイナリを機械語と言います。これ以外にコンピュータが解釈できるものはありません。
人間が解釈できること
人間が解釈できることの範囲は膨大です。頑張れば「0」と「1」の羅列を理解することもできるかもしれません。しかしそれは多大なる努力が必要となります。従って、バイナリで表現されている処理を直接指し示すことのできる別の表現を使うほうが便利です。
こうしてアセンブリ言語というものが作られることになりました。
アセンブリ言語
アセンブリ言語は比較的コンピュータが理解できる機械語に近い言語です。
このように機械語に近い言語ほど「低水準」と表現されます。あるいは低レベルとも言います。言語に対して低レベルとか低水準と表現したとしても、それは決して「悪い」という意味ではないです。
アセンブリ言語と機械語の仲介を行うのがアセンブラと呼ばれるものです。アセンブラは人間が記述したアセンブリ言語を機械語へと翻訳してくれます。しっかり対応をつけておくことで、人間は一切機械語を意識することなく、コンピュータに命令を与えることができるというわけです。
プログラムは最終的には機械語である
人間が意識するか否かに関わらず、コンピュータがプログラムを実行する段階においては必ず機械語になっています。機械語以外コンピュータは解釈し得ないというのを認識しなければなりません。
なぜならば(プログラミングにおいて機械語に触れることがなくとも)内部では翻訳作業が行われ機械語としてコンピュータに渡されており、それには有限の時間を必要とするからです。
高水準言語
普段利用しているのは高水準言語
普段私達が利用しているのは高水準言語です。
つまり機械語からは遠い言語というわけです。PythonやRuby、JAVAやPHPはもちろんのこと、Cですら高水準言語です。C言語はポインタを使ってハード的な面を意識しながらプログラミングをするため、「低水準まで記述できる」と表現しますが、それでも高水準言語に該当します。
高水準言語は、簡単に言えばアセンブリ言語の処理をひとまとめにして更に高度な処理を簡単に記述できるようにしたものだと考えればいいでしょう。
翻訳は二段構え
従って、多くの高水準言語は、一旦アセンブリ言語に翻訳されたから、更にアセンブラによって機械語に翻訳されます。
機械語と高水準言語はかなり離れていますから、翻訳も難しくなります。また、高水準言語からアセンブリ言語へ翻訳する場合も、必ずしも最適な状態で翻訳されるとは限りません。高水準言語で書いたプログラムをアセンブリ言語に変換してから、更に人間の手で翻訳結果を最適化して、最終的に機械語に変換するということが行われる場合もあります。
ただし、組み込みソフトのようなハードに密接に関わる場合以外は滅多に行われません。
ともかく翻訳作業が2回待っている、あるいは難しい翻訳作業が必要であるということを認識しましょう。
コンパイラ
コンパイラとは高水準の言語を、機械語、あるいはより低水準の言語に翻訳する機能を持っています。コンパイラによって翻訳の具合はまちまちであるため、人がアセンブリ言語をいじって最適化する場合もあります。
機械語に翻訳されたファイルを実際に起動することで、コンピュータはもともとはC言語で記述されていた命令に従って動作することができるというわけです。
このとき注意して欲しいのは、やはりこの時点では完全に機械語であるということです。コンピュータにとってはもはやC言語で書かれたコード(ソースファイル)などあってもなくてもよく、削除してしまっても当然動作します。
インタプリタ
インタプリタはコンパイラのように機械語に翻訳するにとどまりません。実際に実行するところまでを管理してくれます。
インタプリタのメリットは、実行が上手くいかなかった時点で、すぐにデバッグに取り掛かれるということです。コンパイラを使う場合は、ソースコードを書いてコンパイル(翻訳)し、実行してみるということをしなければ振る舞いを実際に見ることはできません。
インタプリタを使えば、コードを書きながら逐次テストをすることができ、コードを書きなおして翻訳をするという作業そのものを利用者から切り離してくれるというわけです。
しかし注意しなければならないのは、インタプリタは高水準言語で書かれたコードを1行ずつ実行していくということです。
この機能によって、プログラムを書きながらテストをするということができるのですが、これは完成されたコードにとっては不要な機能になります。なぜなら、「1行だけコードを読む→翻訳する→実行する→次の行を読む」という具合にコンピュータが動作するからです。
もしもこれがコンパイルされ、機械語になっているのであればコンピュータの作業は「実行する」だけになります。従って通常インタプリタを使ったタイプの場合は、実効速度が比較的低速になるという欠点があります。
実際の利用のされ方
コンパイラとインタプリタは、「全部翻訳してから実行する」か「一行ずつ翻訳と実行をする」と対比され、この対比によって、デバッグのしやすさや、実効速度について理解ができます。しかし本質的には「コンパイラはより低水準な言語に翻訳をする」というものであり、「インタプリタは一行ずつ翻訳して実行まで行う」というものです。
従ってコンパイラでより低水準な言語に落としてから、インタプリタによって実行をするという使われ方もあるということです。
TensorFlow と Chainer
TensorFlowはコンパイルを挟む
TensorFlowはPythonによって記述した計算グラフをコンパイルします。
つまり、Pythonではない何らかの別の表現に翻訳しているのです。そうしてから学習を実行します。計算グラフは一度コンパイルされたら変更が効きません。基本的にChainerに比べTensorFlowは高速です。ただし、決定した計算グラフを一度展開する必要があるため、メモリをバカバカ食います)。
Chainerはインタプリタで動く
Chainerは純粋にPythonでの実装です。Pythonはインタプリタで動作するため、Chainerで記述したニューラルネットワークもインタプリタで動作します。プログラムは確実に一行ずつ実行されるため、Pythonによって分岐処理を施しておけば、そのとおりいつでも計算グラフを変更できます。
ただし、一般に低速です(それでも健闘しています)。メモリはインタプリタがその行を実行する毎に使うわけですから、基本的に計算グラフ全体を保持する必要はありません。計算された過程をパラメータの方が保持しておく仕組みとなっています。
関連記事