在Android Studio里撰寫Python程序
by 高煥堂
1. 首先建立一個Android項目
首先建立一個新的Android程序開發項目。
例如,檔案名稱是—myHello.py。
並且開始撰寫Python程序:
其完整程序如下:
# myHello.py
import numpy as np
from java import jclass
def sigmoid(x):
return 1/(1+np.exp(-x))
def softmax(x):
orig_shape=x.shape
if len(x.shape)>1:
#Matrix
tmp=np.max(x,axis=1)
x-=tmp.reshape((x.shape[0],1))
x=np.exp(x)
tmp=np.sum(x,axis=1)
x/=tmp.reshape((x.shape[0],1))
else:
#Vector
tmp=np.max(x)
x-=tmp
x=np.exp(x)
tmp=np.sum(x)
x/=tmp
return x
hidden_nodes = 3
output_labels = 2
dx = np. array([[7.5, 5.5], [3, 12.5], [6.6, 3.5], [1.2, 7.5]],
dtype=np.float32)
test_x = np. array( [[2.8, 5.9], [4.8, 3.3]], dtype=np.float32)
dt = np. array([[1,0], [0,1], [1,0], [0,1]],dtype=np.float32)
wh = np. array([[0.1, 0.5, 0.1],
[0.1, 0.5, 0.1]], dtype=np.float32)
bh = np.array([0.5, 0.5, 0.5], dtype=np.float32)
wo = np. array([[0.1, 0.5], [0.5, 0.5], [0.5, 0.1]], dtype=np.float32)
bo = np.array([0.5, 0.5], dtype=np.float32)
lr = 0.05
yv = 0
def one_round(x, t):
global wh, bh, wo, bo, lr, yv
#----- 開始訓練 -----------------------
#feedforward
yh = np.dot(x, wh) + bh
zh = sigmoid(yh)
yo = np.dot(zh, wo) + bo
zo = softmax(yo)
# BP for Output ---------------------
error = t - zo
delta = lr * error
error_h = np.dot(delta , wo.T)
dw_o = np.zeros((3, 2), np.float32)
for i in range(3):
for j in range(2):
dw_o[i, j] = zh[i] * delta[j]
db_o = delta
# BP for Hidden
delta_h = zh * (1-zh) * error_h
dw_h = np.zeros((2, 3), np.float32)
for i in range(2):
for j in range(3):
dw_h[i, j] = x[i] * delta_h[j]
db_h = delta_h
# Update Weights
wh += dw_h
bh += db_h
wo += dw_o
bo += db_o
yv += 1
#------------------------------------
def train(ep):
global wh, bh, wo, bo, lr, yv
for k in range(100):
for i in range(4):
one_round(dx[i], dt[i])
return yv
#----- Predict ------------------------
def predict(x):
global wh, bh, wo, bo, lr, yv, test_x
yh = np.dot(test_x, wh) + bh
zh = sigmoid(yh)
yo = np.dot(zh, wo) + bo
zo = softmax(yo)
pv = np.round(zo, 5)
return pv
# END
2. 上述Python程式碼的說明
這是一個二元分類的范例。其中有2只<玩具兔>和2只<玩具貓>。其中,主要的特征在於兔子是:耳朵長、尾巴短;而貓則是:尾巴長、耳朵短。其資料如下:
※ 正向推演(Feed-Forward)階段
上述Python程式,建立了一個兩層的NN模型(含有一個隱藏層):
其中,權重(W)則代表訊息傳遞的強弱。然后,需要使用到不同的數學式來計算各個y值(包括y0、y1、y2、y3),這些數學式,就如下圖所示:
所謂正向推演部分,就是將x0和x1訓練資料喂給(Feed)這NN模型的輸入層,然后透過上圖的數學式的計算,推演出下一層(即隱藏層)的y0、y1和y2。,基於這些y[]值、計算出z[]值,再透過數學式的計算,推演到下一層(即輸出層)的 z3值。
※ 反向傳播(Back-Propagation)階段
經由剛才的正向推演計算,得到了輸出層的z3值之后,就可以展開反向傳播的運算了。首先計算落差值(t-z3),再從這落差值計算出<反向修正值(Delta)>,如下圖:
然后,拿這反向修正(Delta)值來與w03相乘,就反向推演出隱藏層第#0神經元(即y0)的誤差值了。如下圖:
同樣地,拿這delta值來與w13相乘,就反向推演出隱藏層y1神經元的誤差值了。如下圖:
同樣地,拿這delta值來與w13相乘,就反向推演出隱藏層y2神經元的誤差值了。如下圖:
到此已經反向推演出隱藏層的各神經元的落差值:loss_y0、loss_y1和loss_y2值了。接下來,就依據落差值來計算出修正值:delta_y0、delta_y1和delta_y2值。以便修正各相關的權重(Weight)值了。例如,從loss_y0計算出delta_y0,繼續藉由delta_y0來修正w00和w10值,來提升這NN模型的智慧,如下圖:
同樣地,也從loss_y1計算出delta_y1,繼續藉由delta_y1來修正w01和w11的值。一樣地,也從loss_y2計算出delta_y2,繼續藉由delta_y2來修正w02和w12的值,來記錄NN模型的智慧,如下圖:
最后,依據輸出層的delta值來修正輸出層的權重(Weight)如下圖:
於是,完成了這個2層AI模型的訓練了。
3. 開發Java程式:定義UI
開始以Java設計UI部分,茲修改myActivity.java如下:
其完整程序如下:
#myActivity.java
package com.example.chaquo01;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import java.util.List;
import com.chaquo.python.android.AndroidPlatform;
import com.chaquo.python.*;
public class myActivity extends AppCompatActivity {
TextView tv1, tv2, tv3, tv4, tv5, tv6;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = (TextView) findViewById(R.id.tv_device);
tv2 = (TextView) findViewById(R.id.tv_device2);
tv3 = (TextView) findViewById(R.id.tv_device3);
tv4 = (TextView) findViewById(R.id.tv_device4);
tv5 = (TextView) findViewById(R.id.tv_device5);
tv6 = (TextView) findViewById(R.id.tv_device6);
tv2.setText(" ....... Prediction .......");
//-------------------------------------------------------------------------
if (!Python.isStarted()) {
Python.start(new AndroidPlatform(this));
}
//------- 呼叫 Python(myHello)程式里的函數:mul_add()
Python py = Python.getInstance();
PyObject obj1 = py.getModule("myHello").callAttr("train", 1000);
PyObject obj2 =
py.getModule("myHello").callAttr("predict", 1000);
List<PyObject> pyList = obj2.asList();
String ss1 = pyList.get(0).toString();
String ss2 = pyList.get(1).toString();
tv3.setText(" ["+ss1);
tv4.setText(" "+ss2 + "]");
}}
4. 執行這個Android App程序
執行這個Android App程序,它首先啟動myActivity.java。執行到指令:
PyObject obj1 = py.getModule("myHello").callAttr("train", 1000);
就呼叫myHello.py的train()函數。進行AI模型的訓練。訓練好了,就執行到指令:
PyObject obj2 = py.getModule("myHello").callAttr("predict", 1000);
就呼叫myHello.py的predicyt()函數,進行預測的任務。然后,輸出預測的結果,如下圖所示:
◆