此內容主要說明如何實現 MATLAB 與 Python 協作的應用
- 目錄:
- 在 MATLAB 中呼叫 Python 函式 (Calling Python from MATLAB)
- 在 Python 環境下呼叫 MATLAB 函式 (Calling MATLAB from Python)
- 將 MATLAB 函式封裝成 Python package (Packaging MATLAB program to Python package)
對於以上三種情境會有一些對應的條件需求:
使用情境 | MATLAB Installed | Python Installed | MATLAB Runtime Installed | Compiler SDK Toolbox |
---|---|---|---|---|
在 MATLAB 中呼叫 Python 函式 |
✔️ | ✔️ | ||
在 Python 環境下呼叫 MATLAB 函式 |
✔️ | ✔️ | ||
將 MATLAB 函式封裝成 Python package |
✔️ | ✔️ |
建議直接使用 Anaconda1 安裝並設定路徑,且方便之後根據不同狀況建立獨立環境安裝模組。
MATLAB 從 R2014b 開始支援 Python 2.7,建議至少使用 MATLAB R2020b 以上版本。
MATLAB Interface Engine 有支援對應 Python 版本的限制,詳細請見 MATLAB 官網支援版本列表
以下列出幾版:
MATLAB 版本 | Python 2.7 | Python 3.6 | Python 3.7 | Python 3.8 | Python 3.9 | Python 3.10 | Python 3.11 |
---|---|---|---|---|---|---|---|
R2023b |
✔️ | ✔️ | ✔️ | ||||
R2023a |
✔️ | ✔️ | ✔️ | ||||
R2022b |
✔️ | ✔️ | ✔️ | ✔️ | |||
R2022a |
✔️ | ✔️ | ✔️ | ✔️ | |||
R2021b |
✔️ | ✔️ | ✔️ | ✔️ | |||
R2021a |
✔️ | ✔️ | ✔️ | ||||
R2020b |
✔️ | ✔️ | ✔️ | ✔️ |
在 MATLAB 環境底下使用 Python 前可以透過 MATLAB 語法 pyenv
2 來確認當前 MATLAB 有讀取到想要使用的 Python 版本。
除此之外 pyenv
具有以下參數可以讓使用者切換 Python 環境以及更改啟動模式
Version
:
Version 參數可以用來指定想要使用的 Python 版本
% Example: Set Python execution version for MATLAB interface engine
% MATLAB Version: R2022b
% 使用 Windows registry (Windows Only)
>> pyenv(Version = "3.10")
% 使用完整路徑
>> pyenv(Version = "/usr/bin/python")
ExecutionMode
:
ExecutionMode 參數設定是否要在和 MATLAB 同一個 process 底下執行 Python 程式碼
'InProcess'
: 在 MATLAB process 中運行腳本。在對性能至關重要的使用情況下,請使用此模式。(Default)
'OutOfProcess'
: 啟動一個獨立的 process,用於安全執行Python腳本和模組並避免函式庫衝突。
- Python 模組需要使用與 MATLAB 相同的第三方庫的時
- 想要使用 Python 偵錯流程時
% Example: Set Python execution mode for MATLAB interface engine
% MATLAB Version: R2022b
% 設定執行模式
>> pyenv(ExecutionMode = 'OutOfProcess')
在 MATLAB 裡面可以直接使用 py
的前綴詞來使 MATLAB 調用 Python 裡面的既有函式,包含轉換變數型態等動作:
% Example: Create python list in MATLAB
% MATLAB Version: R2022b
>> pyList = py.list([1,2,3])
pyList =
Python list with values:
[1.0, 2.0, 3.0]
Use string, double or cell function to convert to a MATLAB array.
除此之外, py
的後綴也可以直接使用已安裝的 Python 模組, py
接上對應已安裝模組, MATLAB 即會自動 import:
% Example: Create scikit-learn regression model in MATLAB
% MATLAB Version: R2022b
>> reg_Model = py.sklearn.linear_model.LinearRegression
reg_model =
Python LinearRegression with properties:
n_jobs: [1×1 py.NoneType]
copy_X: 1
positive: 0
fit_intercept: 1
LinearRegression()
使用 py
調用模組時,也可以使用 Tab
鍵來提示模組所含的物件與函式。
🚩 調用使用者自訂義函式 Calling User-defined Function
一般來說除了直接調用 python 函式庫裡面的函示之外,使用者可能會根據自身的需求去撰寫自訂義的函式或是函式庫。
在 MATLAB 中一樣可以透過 py
的前綴去調用這些自訂義的函式來使用。
若是要直接使用 py
前綴來調用使用者自訂義函式,需先確保該程式碼在 Python 的搜尋路徑底下:
在 MATLAB 底下將當下目錄加入 Python 搜尋路徑:
% Example: Add current directory to Python serach path
% MATLAB Version: R2022b
>> if count(py.sys.path,'') == 0
insert(py.sys.path,int32(0),'');
end
Python User-defined Function:
# myModule.py
# Sample script for calling user-defined function in MATLAB
import numpy as np
def Addup_randiMat(A_max,B_max):
matA = np.random.randint(0,A_max,(2,2))
matB = np.random.randint(0,B_max,(2,2))
return matA+matB
在 MATLAB 中呼叫自訂義 Python 函式
% Example: Call Python user-defined function in matlab
% MATLAB Version: R2022b
>> py.myModule.Addup_randiMat(10,5)
ans =
Python ndarray:
4 7
11 3
Use details function to view the properties of the Python object.
Use int64 function to convert to a MATLAB array.
🚩 載入使用者自訂義函式 Import User-defined Function as Module
除了前面提到的使用 py
前綴,MATLAB 也可以將 Python User-defined function script 以 module 的方式載入並儲存成物件變數
% Example: Load python module
% MATLAB Version: R2022b
>> module = py.importlib.import_module('myModule')
module =
Python module with properties:
np: [1×1 py.module]
Addup_randiMat: [1×1 py.function]
<module 'myModule' from 'C:\\Users\\Tim\\Desktop\\myModule.py'>
如果 module 有所更動,在 MATLAB 中也可以透過 reload 來更新物件而不用再呼叫一次import
>> py.importlib.reload(module)
在 MATLAB 中可以使用字串的方式來表達 Python 程式碼,並透過 pyrun
3 的函式來執行
% Example: Directly run python code
% MATLAB Version: R2022b
>> pyCode = [
"Grocery = {'Apple':100, 'Orange':30}";
"Items = Grocery.keys()";
"Prices = Grocery.values()"];
>> [Items, Prices] = pyrun(pyCode, ["Items", "Prices"])
Items =
Python dict_keys with no properties.
dict_keys(['Apple', 'Orange'])
Prices =
Python dict_values with no properties.
dict_values([100, 30])
除了先前提到的 pyrun
使用字串表達 Python 程式碼之外,也可以執行既有的 Python 腳本並把想要的變數傳回 MATLAB workspace 中。
MATLAB 中的 pyrunfile
4 讓使用者可以執行既有的程式碼腳本。
Python sample code:
# pyrunfile_demo.py
# Demo script for MATLAB 'pyrunfile'
import numpy as np
randomMat = np.random.rand(100,100) # Create 100x100 of random matrix
MATLAB sample code
% Example: Run python script and get variable
% MATLAB Version: R2022b
>> result = pyrunfile('pyrunfile_demo','randomMat')
result =
Python ndarray:
Columns 1 through 8
0.3091 0.9741 0.6238 0.0295 0.4298 0.4562 0.3216 0.6516
0.2124 0.7749 0.3696 0.2310 0.1058 0.0205 0.7097 0.5682
0.9184 0.3028 0.5064 0.5527 0.4872 0.5226 0.1789 0.3618
...
Use details function to view the properties of the Python object.
Use double function to convert to a MATLAB array.
在 MATLAB 中調用 Python 的情境下最常遇到的問題就是 Python 端發生錯誤但卻沒辦法像 MATLAB 腳本一樣進入偵錯模式去查看變數變化。
但今天透過 VScode 的介面可以連結 MATLAB 程序來觸發 VScode 的中斷點。
- 在終端機輸入以下指令安裝
debugpy
套件:
python -m pip install debugpy
- 在想要偵錯的 Python 腳本中引入
debugpy
套件並加入debugpy.debug_this_thread()
程式碼,範例程式碼可以參考:
# Debug in User-defined Python Script with MATLAB
import debugpy
debugpy.debug_this_thread() # Enable Debugging
def Addup(x1,x2):
x1 += 1
x2 *= 10
output = x1+x2
return output
- 建立 VScode 偵錯調用腳本
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to MATLAB",
"type": "python",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
NOTE: Ubuntu users may need to change the value of the ptrace variable using the command below.
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
-
確認 MATLAB 中所使用得 Python 環境以及程序ID,如果執行結果的
ExecutionMode
顯示NotLoaded
可以隨意執行一行 Python 程式碼
例如:py.list([1,2,3])
>> pyenv
ans =
PythonEnvironment with properties:
Version: "3.9"
Executable: "C:\Users\Tim\anaconda3\envs\python39\python.exe"
Library: "C:\Users\Tim\anaconda3\envs\python39\python39.dll"
Home: "C:\Users\Tim\anaconda3\envs\python39"
Status: Loaded
ExecutionMode: OutOfProcess
ProcessID: "19460"
ProcessName: "MATLABPyHost"
- 在 VScode 裡面點選 "Run and Debug" 並選擇 "Attach using Process ID" 連結到剛剛顯示的 MATLAB Process ID
在 MATLAB 中執行程式碼即可成功觸發 VScode 中斷點偵錯模式
MATLAB 在近幾年的版本中推出了許多將特定功能包裝起來的 APP,程式撰寫人員或是跨越不同領域的人能夠快速上手並節省開發時間。
對於習慣在 Python 環境開發的使用者或是想要在 Python 中開發但又希望沿用 MATLAB 特有功能的使用者可以參考本章節內容。
MATLAB 的目前釋出了與 Python 結合的 API 套件 matlabengine
一般可以在你的 MATLAB 安裝路徑底下找到:
>> matlabroot\extern\engines\python
目前在 PyPI 上也有釋出該套件,所以使用者也可以直接透過 pip
指令安裝:
pip install matlabengine
在 Python 透過以下指令可以啟動 MATLAB 程序:
# Example: Start MATLAB API engine in Python
# MATLAB Version: R2022b
# Python Version: 3.9
import matlab.engine as eng
session = eng.start_matlab('-desktop') # '-desktop' 參數會將 MATLAB 桌面顯示出來
除此之外,如果有已經開啟的 MATLAB 程序也可以透過以下指令去連結:
# Example: Using current running MATLAB session
# MATLAB Version: R2022b
# Python Version: 3.9
import matlab.engine as eng
matlab_ID = eng.find_matlab() # 選擇對應的 Process ID
session = eng.connect_matlab(matlab_ID[0])
在 Python 中調用 MATLAB 和直接在 MATLAB 中使用的主要差異在於需要物件前綴和部分需要定義輸出數量。
以單純的產生亂數來看的話,在 Python 中調用 MATLAB 函式如下範例:
# Example: Call MATLAB function in Python
# MATLAB Version: R2022b
# Python Version: 3.9
import matlab.engine as eng
sess = eng.start_matlab()
matlab_rand = sess.rand(2)
print(type(matlab_rand))
print(matlab_rand)
輸出:
<class 'matlab.double'>
[[0.421761282626275,0.7922073295595544],[0.9157355251890671,0.959492426392903]]
預設的輸出會是 MATLAB 物件的變數型態,可以透過 Numpy
套件轉換成 numpy.array
# Example: Convert MATLAB array to Numpy array
# MATLAB Version: R2022b
# Python Version: 3.9
import numpy as np
np_array = np.array(matlab_rand
print(type(np_array))
print(np_array)
輸出:
<class 'numpy.ndarray'>
[[0.421761282626275,0.7922073295595544]
[0.9157355251890671,0.959492426392903]]
對於有多個輸出的函式需要特別去定義輸出的數量:
# Example: Call MATLAB function with multiple outputs
# MATLAB Version: R2022b
# Python Version: 3.9
matlab_array = matlab.double([1,5,2,8,4,3]) # Convert list to MATLAB array
sorted_array, sort_idx = session.sort(matlab_array, nargout=2)
print(sorted_array, sort_idx)
輸出:
[[1.0,2.0,3.0,4.0,5.0,8.0]] [[1.0,3.0,6.0,5.0,2.0,4.0]]
文章前面提到的兩種方式主要是在同時裝有 MATLAB 和 Python 的開發環境下進行協作,
但有另外一種使用情境是開發者想將既有的 MATLAB 演算法套件轉移到 Python 的框架下去使用。
要滿足這個需求除了重新用 Python 撰寫一次以外,比較省時且安全的辦法是將既有演算法轉換成 Python 的套件直接調用。
要將 MATLAB 程式碼編譯成 Python package 主要透過 MATLAB Compiler SDK® 來達成。(MATLAB Compiler Required)*
MATLAB Compiler SDK 除了 Python package 之外也支援多種其他程式語言的函式庫編譯5,如: .NET、C、C++、JAVA 等...
編譯的流程可以分為使用圖形化介面以及程式碼來達成,先以圖形化介面為例:
-
選取想要轉換的 MATLAB 程式碼,建議這裡的專案名稱可以使用後面要用來引入 Python 環境的 Package name
% addup.m % Sample funciton script for Python package compile function y = addup(a,b) y = a+b;
-
編譯完成以後會產生三個資料夾,分別為:
- for_redistribution
- for_redistribution_files_only
- for_testing
在 for_redistribution_files_only 的資料夾中可以找到 `setup.py` ,透過以下的指令安裝在想要使用的 Python 環境中:
python setup.py install
-
在 Python 環境中僅需先匯入 compiled 後的 package,並使用
initialize()
去啟動MATLAB Runtime
:# Example: Call compiled MATLAB function # MATLAB Version: R2022b # Python Version: 3.9 import pyPackage myLib = pyPackage.initialize() Result = myLib.addup(10,2) print(Result)
輸出:
12
Footnotes
-
Anaconda Official Website [https://www.anaconda.com/download] ↩
-
MATLAB
pyenv
Function Documentation [https://www.mathworks.com/help/matlab/ref/pyenv.html] ↩ -
MATLAB
pyrun
Function Documentation [https://www.mathworks.com/help/matlab/ref/pyrun.html] ↩ -
MATLAB
pyrunfile
Function Documentation [https://www.mathworks.com/help/matlab/ref/pyrunfile.html] ↩ -
MATLAB Compiler SDK [https://www.mathworks.com/products/matlab-compiler-sdk.html] ↩