用单层感知器对手写数字进行分类

Classifying handwritten digits with single layer perceptron

我想用简单的 Python 代码对手写数字 (MNIST) 进行分类。我的方法是一个简单的单层感知器,我用批处理方法来完成。

我的问题是,例如,如果我训练数字“1”,然后训练其他数字,网络总是显示“1”的结果。事实上,训练发生在第一个数字上。不知道是什么问题

我认为这与批量训练有关,在一次训练后,第二个数字不能因为网络收敛。但是我不知道怎么解决。

我用多层感知器进行了测试,我得到了相同的行为。

注意:每次我选择一个数字并加载很多数字并开始训练,对于其他数字我会重新启动除权重矩阵(w0)之外的所有东西

这是我的代码:

1-导入库:

import os, struct
from array import array as pyarray
from numpy import append, array, int8, uint8, zeros
import numpy as np
from IPython.display import Image
import matplotlib.pyplot as plt
from IPython import display
from scipy.special import expit
from scipy.misc import imresize
from IPython.core.page import page
from IPython.core.formatters import format_display_data

np.set_printoptions(threshold=np.nan)
np.set_printoptions(suppress=True)

2- Sigmoid 函数:

def sigmoid(x, deriv=False):
    if(deriv==True):
        return x*(1-x)
    return expit(x)

3- 初始化权重

np.random.seed(1)
w0 = 2*np.random.random((784,10))-1

4-读取 MNIST 数据集

dataset="training"
path="."

if dataset == "training":
    fname_img = os.path.join(path, 'train-images-idx3-ubyte')
    fname_lbl = os.path.join(path, 'train-labels-idx1-ubyte')
elif dataset == "testing":
    fname_img = os.path.join(path, 't10k-images-idx3-ubyte')
    fname_lbl = os.path.join(path, 't10k-labels-idx1-ubyte')
else:
    raise ValueError("dataset must be 'testing' or 'training'")

flbl = open(fname_lbl, 'rb')
magic_nr, size = struct.unpack(">II", flbl.read(8))
lbl = pyarray("b", flbl.read())
flbl.close()

fimg = open(fname_img, 'rb')
magic_nr, size, rows, cols = struct.unpack(">IIII", fimg.read(16))
img = pyarray("B", fimg.read())
fimg.close()

5- 选择号码

number = 4
digits=[number]
ind = [ k for k in range(size) if lbl[k] in digits ]
N = len(ind)

images = zeros((N, rows, cols), dtype=uint8)
labels = zeros((N, 1), dtype=int8)

for i in range(len(ind)):
    images[i] = array(img[ ind[i]*rows*cols : (ind[i]+1)*rows*cols ]).reshape((rows, cols))
    labels[i] = lbl[ind[i]]

6- 将每个数字转换为向量并将矩阵单元格转换为二进制:

p = np.reshape(images,(len(images),784))
p[p > 0] = 1

7-目标矩阵(每列一个数字)

t = np.zeros((len(images), 10),dtype=float)
t[:,number] = 1

8-训练(梯度下降)

for iter in xrange(600):
    predict = sigmoid(np.dot(p,w0))
    e0 = predict - t
    delta0 = e0 * sigmoid(predict,True)
    w0 -= 0.01*np.dot(p.T,delta0)

9- 测试

test_predict = sigmoid(np.dot(p[102],w0))
print test_predict

用来自单个 class(数字)的数据训练网络直到它收敛,然后添加另一个 class 等等是没有意义的。

如果您只训练一个 class,所需的输出将始终相同,网络可能会很快收敛。它可能会为所有类型的输入模式生成此输出,而不仅仅是您用于训练的输入模式。

您需要做的是在训练期间呈现来自所有 classes 的输入,例如以随机顺序。这样网络将能够找到不同 classes.

之间的边界

如果你的目标是制作一个可以对某个数字进行分类的感知器,那么权重的初始化(步骤 3)应该在训练(步骤 8)之前完成,这样每次你训练模型(不同数字)。

总而言之,我会将#3 移到#8 之前。