In this notebook, we are going to use PySINGA to train a MLP model for classifying 2-d points into two categories (i.e., positive and negative). We use this example to illustrate the usage of PySINGA's modules. Please refer to the documentation page for the functions of each module.
In [1]:
from __future__ import print_function
from builtins import range
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
To import PySINGA modules
In [2]:
from singa import tensor
from singa import optimizer
from singa import loss
from singa import layer
#from singa.proto import model_pb2
Task is to train a MLP model to classify 2-d points into the positive and negative categories.
The following steps would be conducted to generate the training data.
We draw the boundary line as $y=5x+1$
In [3]:
# generate the boundary
f = lambda x: (5 * x + 1)
bd_x = np.linspace(-1., 1, 200)
bd_y = f(bd_x)
We generate the datapoints by adding a random noise to the data points on the boundary line
In [4]:
# generate the training data
x = np.random.uniform(-1, 1, 400)
y = f(x) + 2 * np.random.randn(len(x))
We label the data points above the boundary line as positive points with label 1 and other data points with label 0 (negative).
In [5]:
# convert training data to 2d space
label = np.asarray([5 * a + 1 > b for (a, b) in zip(x, y)])
data = np.array([[a,b] for (a, b) in zip(x, y)], dtype=np.float32)
plt.plot(bd_x, bd_y, 'k', label = 'boundary')
plt.plot(x[label], y[label], 'ro', ms=7)
plt.plot(x[~label], y[~label], 'bo', ms=7)
plt.legend(loc='best')
plt.show()
2 and 3 are combined by the SoftmaxCrossEntropy.
In [6]:
# create layers
layer.engine = 'singacpp'
dense = layer.Dense('dense', 2, input_sample_shape=(2,))
p = dense.param_values()
print(p[0].shape, p[1].shape)
# init parameters
p[0].gaussian(0, 0.1) # weight matrix
p[1].set_value(0) # bias
# setup optimizer and loss func
opt = optimizer.SGD(lr=0.05)
lossfunc = loss.SoftmaxCrossEntropy()
In [7]:
tr_data = tensor.from_numpy(data)
tr_label = tensor.from_numpy(label.astype(int))
# plot the classification results using the current model parameters
def plot_status(w, b, title='origin'):
global bd_x, bd_y, data
pr = np.add(np.dot(data, w), b)
lbl = pr[:, 0] < pr[:, 1]
plt.figure(figsize=(6,3));
plt.plot(bd_x, bd_y, 'k', label='truth line')
plt.plot(data[lbl, 0], data[lbl, 1], 'ro', ms=7)
plt.plot(data[~lbl, 0], data[~lbl, 1], 'bo', ms=7)
plt.legend(loc='best')
plt.title(title)
plt.xlim(-1, 1);
plt.ylim(data[:, 1].min()-1, data[:, 1].max()+1)
# sgd
for i in range(1000):
act = dense.forward(True, tr_data)
lvalue = lossfunc.forward(True, act, tr_label)
dact = lossfunc.backward()
dact /= tr_data.shape[0]
_, dp = dense.backward(True, dact)
# update the parameters
opt.apply(i, dp[0], p[0], 'w')
opt.apply(i, dp[1], p[1], 'b')
if (i%100 == 0):
print('training loss = %f' % lvalue.l1())
plot_status(tensor.to_numpy(p[0]), tensor.to_numpy(p[1]),title='epoch %d' % i)
#train(dat, label)
The layer class has forward and backward functions for back-propagation.
The optimzier class apply function updates the parameter values using the gradients. The first argument is the iteration ID, followed by the gradient tensor and the value tensor. Each parameter tensor has a name associated with it, which is used by Optimizer to keep some internal data (e.g., history gradients) for each parameter.
The loss class computes the loss value given the predictions and the ground truth in forward() function. It computes the gradients of the predictions w.r.t the loss function and outputs the gradient tensor(s) by backward() function.