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()函数,进行预测的任务。然后,输出预测的结果,如下图所示: