Introduction
Motivation
- Matlab + Psychtoolbox[ref. 1]で心理実験を構築する
- 実験パラダイムの中で、pythonによる処理を呼び出したい
e.g., 音声認識(Google cloud platform Speech-to_Text API [ref.2])
Background
- Matlabから外部言語処理を呼び出す方法は色々とある[ref. 3]。
- C/C++ (or Fortran)で記述される処理をMatlab Executable (MEX) 関数[ref. 4]としてビルドすることでmatlabとシームレスに統合することが可能となる
- 最新のC/C++の機能やオブジェクト指向の設計の組み込み
- 高速化
- スレッドセーフなマルチスレッド処理
- アウトプロセスでC++アプリケーションの実行
- Pythonで記述されたアプリケーションも呼び出すことが可能である[ref. 5]。
- Pythonでは、豊富なtoolboxから機械学習や音声認識などのアプリケーションが作成しやすい
- 計算などの高速化を図りたい場合は、Cythonを使ってC/C++に変換してからMEX関数化可能?(現在検討中)
- C/C++ (or Fortran)で記述される処理をMatlab Executable (MEX) 関数[ref. 4]としてビルドすることでmatlabとシームレスに統合することが可能となる
- 筆者が実装しようとしている音声認識は、Pythonで実装した
- 心理実験のタイムラインの都合からストリーミング音声のリアルタイム文字起こしが必要だった
- C/C++では、音声ファイルのストリーミング文字起こしはできても、ストリーミング音声入力に対応させられなかった(力不足)
- Sample codes: googleapis/python-speech - GitHub [ref. 6]
Goal
Matlabからpythonで作成したアプリケーションを呼び出す
環境
- Machines
- macOS Monterey (apple silicon)
- Windows10
- Python
- python3.9.13
- Mac: Python for x86_64 installed via rosetta
- python3.9.13
- Editor for Python
- VScode
- Matlab
- 2021b
Pythonの互換性
Matlab
MatlabでPythonを使用するためのシステム構成は公式リファレンスを参照のこと[ref. 7]。以下に一部抜粋して記す。
MATLAB® で Python® モジュールを呼び出すには、サポートされているバージョンの参照実装 (CPython) がシステムにインストールされていなければなりません。https://www.python.org/download などにある配布版をインストールしてください。MATLAB では、Microsoft® ストアからインストールした CPython はサポートしていません。MATLAB は Version 2.7、3.7、3.8、および 3.9 をサポートしています。詳細については、Versions of Python Supported by MATLAB Products by Release を参照してください。Linux® または Mac プラットフォームを使用している場合は、既に Python がインストールされています。Windows® を使用している場合は、Python がインストールされていなければ、配布版をインストールする必要があります。詳細は、サポートされている Python 実装のインストールを参照してください。
Python2はpython2.7のみ、python3はpython3.7以降をサポートしていることに注意されたし。各自の環境によっては、venv
による仮想環境を用意して環境分けしておいた方がよい。例えば、音声処理のためにPyAudio
ライブラリを使いたい場合、Python3.7以降が正式サポートされていないため、1)非公式ながら公開してくれているパッケージをインストール(win環境のみ)、2)python2.7環境を作る、3)Python3.7以降でなんとかPyAudioをインストールする、といった方法を検討する必要がある。
Mac
Apple siliconプロセッサ搭載のMacでは、MATLABはRosetta2環境で実行される(R2020b Update3およびそれ以降のリリース)[ref. 8]。Matlab2022aではnative platformのベータ版が公開されているっぽいが、詳細は不明。MatlabがRosetta2環境で実行されるということは、Pythonもintel cpu用のものを用意する必要がある。Arm版とIntel版でpythonを切り替える方法については、別途referenceを参照のこと[ref. 9 10]。
Matlabの設定
Python environmentの公式ドキュメントを確認しておくと良い[ref. 11]。
処理系の指定
Pythonインタープリタの規定の実行モードをpyenv
関数によって変更することができる。この変更は複数のmatlabセッション間で維持される。
pe = pyenv('Version', 'python処理系(実行可能ファイル)への絶対path')
仮想環境/hoge/piyo/.venv/pyIntel3x/bin/python
の処理系をpyenv
に引き渡して指定した場合、PythonEnvironment のプロパティは以下のように表示される。
Version: "3.9"
Executable: "/hoge/piyo/.venv/pyIntel3x/bin/python"
Library: "************************************************"
Home: "************************************************"
Status: NotLoaded
ExecutionMode: InProcess
Executableが適切に読み込めれば、LibraryやHomeは自動的に読み取って設定してくれるはずである。Python処理系が適切に設定されていれば、基本的には仮想環境下のライブラリを見に行ってくれるので問題なくpythonプログラムを実行できるはずである。他に認証キーのpath設定が必要だったりする場合は、terminalでpath設定や仮想環境のactivateしてからmatlabをterminalで呼び出すとより安心である。上手くいかない場合は、terminal上で当該pythonプログラムが実行できるのを確認した上で、そのterminalからmatlab
コマンドでMatlaを立ち上げてテストすると良い。
各環境のpath
.venvディレクトリ下に仮想環境を構築した場合、matlabに引き渡すpython処理系のpathは以下になる。
OS | path |
---|---|
mac | \hoge.venv\環境名\bin\python |
windows10 | \hoge.venv\環境名\Scripts\python.exe |
はまった点
Mac環境で、arm版とintel版の環境を作っていたので、pathはどれを指定すれば良いのか混乱してしまっていた。arm版pythonをデフォにしていたので、python
またはpython3
で実行できる一方、intel版を実行したい場合はコマンドをpython3x
に設定していた。しかしながら仮想環境をactivateした場合、その環境での処理はpython
コマンドで行うことになる。それを失念しており、matlabの環境設定時に引き渡すpathを、which python3x
の出力結果(インストール先)にしてしまっていた。正くは、仮想環境をactivateしている状況下でのwhich python
コマンドの出力結果を引き渡す必要がある。なお、windows環境ならばwhich
コマンドの代わりに、powershellならばwhere.exe
、cmdならばwhere
を使えばよい。
ExecutionMode
Python スクリプトを MATLAB と同じプロセスで実行するか(InProcess)、または別プロセスとして実行するか(OutOfProcess)のモード選択が可能である。一般的には、OutOfProcess
であればライブラリの競合なども生じないため、安定して動作する。パフォーマンスを重要視する場合にはInProcess
が使われる一方で、安全に実行するならばOutOfProcess
を使うという住み分けで良い。Matlabでも必要なサードパーティライブラリの異なるバージョンを必要とするpythonライブラリの使用、ワークフローのデバッグなどの場合にはOutOgProcess
を選択する。アウトプロセスだと呼び出しにオーバーヘッドが伴い、これによりパフォーマンスに影響を及ぼす場合がある。このことから、pythonの処理内容を踏まえて検討すべき点である。
モードの切り替え、例えばOutOfProcess
への切り替えは以下のコマンドで実行できる。
pyenv('ExecutionMode','OutOfProcess')
Pythonのコンパイル
Pythonを実行するまでの時間を少しでも早くできると嬉しい。Python単体ならばcompileall
[ref. 12]によってライブラリのバイトコンパイルができるとのこと。試してみる価値はあるが、まだ検証はしていない。Matlab側が勝手にコンパイルしてくれているようで、hoge.py
をコンパイルした./__pycache__/hoge.pyc
が自動的にできていますね。
Versionの切り替え
versionを変更する際には、PythonがInProcessで読み込まれている場合は、MATLABを再起動し、新しいバージョン情報を指定してpyenvを実行する。一方で、OutOfProcessモードで読み込まれている場合は、terminate(pyenv)
コマンドによってpythonインタープリターに関連づけられているプロセスを修了してから、新しいバージョン情報を指定してpyenvを実行すれば良い。
pythonの呼び出し
Pythonの関数/モジュール/パッケージを呼び出す方法は3つある[ref. 5]。
-
py.
接頭辞をモジュールの名前に追加して実行 [ref. 13]- Pythoモジュールに直接アクセス
- pyrun関数の利用 [ref. 14]
- Pythonスクリプトの実行
- pyrunfile関数の利用 [ref. 15]
- Pythonスクリプトファイルの実行
呼び出し方法の詳細については、各自正式リファレンスページに譲る。下記では、自分のための覚書と所感を記す程度に止める。
py.接頭辞
pythonライブラリにアクセスするために利用される方法である。Pythonで利用されるlist関数などを呼び出したいときには、py.list({'This','is a','list'})
のようにして実行が可能となる。モジュール内で定義される関数を呼び出す場合は階層的にpy.module.func
のようにすれば良い。例えばtextwrapモジュールのwrap関数を使いたいのであれば、py.textwrap.wrap('This is a string')
のようにして実行する。これは自作モジュールでも同様で[ref. 16]、自作hoge.py
モジュールの中でdef piyo():
のように定義される関数を呼び出すにはpy.hoge.piyo
となる。シンプルにpythonのモジュールないし関数にアクセスしたいときに使うため、matlabの構文に強い縛りを受ける形にはなる。
pyrun
PythonインタープリターのPythonステートメントをMATLABコマンドプロンプトから実行したいときに利用する。例えば、Pythonワークスペースに変数aとbを用意して値の和を表示するには、pyrun(["a = 3", "b = 4", "print(a + b)"])
とすれば良い。MATLABからデータをコマンドに渡して、結果を MATLABデータとして返すこともできます。例えばmatlabのワークスペースにd1 = 5
, d2 = 10
として変数を作成していた場合、res = pyrun("x = y*z","x",y=d1,z=d2)
のようにmatlab変数を引き渡すことでres=50
がmatlabのワークスペースに格納される。Python likeなステートメントを組み込んでで開発できます、という感じである。
pyrunfile
関数pyrunfileを使用してPythonワークスペースに作成された変数は永続的ではないため、再利用ができない。Matlabで関数を呼び出すときの感覚に一番近い利用方法である。WorkSpaceを汚したくなければ基本的にpyrunfile
で良い。Python的にはモジュール実行という印象である。py.接頭辞をつけてモジュール内のmain関数にアクセスしても同様である。
入力引数
Matlabで呼び出すときはバックグラウンド処理させるので余計な描画は省きたいときや、デバッグモードをオプションとして組み込みたいときなど、python関数にコマンドライン引数を渡したい状況が出てくる場合がある。Pythonでは、argparse
[ref. 17]モジュールをimportすれば実装は簡単にできる。ではMatlabで呼び出すときはどのように入力引数を渡せば良いだろうか?その場合はpyrunfile
を使うこととなる。
動作確認
上手くいかない場合は、こちらの正式リファレンスを見て1つずつ確認していくと良い[ref. 18]。
大体の原因はpath設定が環境に合っていなかったり、モジュール名が競合していたり、タイポだったりするように思える。
DOSコマンド[ref. 19]でpythonを実行してみるのも良い手ではある。
dos('python hoge.py')
とdos('python処理系の絶対path hoge.py')
をmatlab上で実行してみて、問題なく実行されるか確認するとよい。これはOSを呼び出して指定されたコマンドを実行してくれるので、matlabとは独立した環境でpythonモジュールが動作するのかを確認することができる。
シンプルにpyrunfile('hoge.py --foo bar');
としてあげればよい。この方法ならば、hoge.py
からの戻り値も取得できる。