感知机算法实现二分类和多分类(手写数字Minist)

感知机

感知机是一种线性二分类模型,输入实例 的特征向量,输出实例的类别,取值为+1和-1

感知机算法实现二分类和多分类(手写数字Minist)_第1张图片

 

感知机算法实现手写数字二分类,具体步骤如下,数据集在第一节已经给出。

1、从Minist测试集中抽取1000张训练图片(前5000),200张测试图片(后5000),对应的数字是[8,4],同时将label转化为[1,-1]

2、训练权值w和偏值b

  2.1、设置学习率lr=0.001 (每更新一次权值,学习率减少原来的0.01)

     迭代次数epoch=1000

  2.2、更新权值w(这里是一张一张图片进行计算,并不是每次计算都会更新权值,只有当yi*(w*x+b)<=0时)

     将数据向量进行增广变换,将b加到x与w的内积运算中

3、预测

import numpy as np
import scipy.io as sio
'''
数组转化为向量 .ravel()
'''

mate_data = sio.loadmat('./mat格式的MNIST数据/test_images.mat')
# print(mate_data.keys())
key_name =list(mate_data.keys())[-1]
data = mate_data[key_name]
mate_label = sio.loadmat('./mat格式的MNIST数据/test_labels.mat')
# print(mate_label.keys())
key_name1 = list(mate_label.keys())[-1]
label = mate_label[key_name1]


#设定数据量
train_num = 1000
test_num  = 200
#设定参数
j = 0
q = 0
number = [8,4] #取出的数据
#取出训练数据和对应标签,同时将标签[9,4]转化为[1,-1]
train_data = np.zeros((28,28,1000),dtype=np.uint8)
train_label= np.zeros((1,1000),dtype=int)
while True:
    for i in range(5000):
        if label[:,i]==number[0] or label[:,i]==number[1]:
            train_data[:,:,j]  = data[:,:,i]
            train_label[:,j] = label[:,i]
            if train_label[:,j] == number[0]:
                train_label[:,j] = 1
            elif train_label[:,j] ==number[1]:
                train_label[:,j] = -1
            j = j + 1
            if j >=1000:
                break
    if j >=1000:
        break
#取出测试数据和对应标签
test_data = np.zeros((28,28,200),dtype=np.uint8)
test_label = np.zeros((1,200),dtype=int)
while True:
    for i in range(5000,10000):
        if label[:,i]==number[0] or label[:,i]==number[1]:
            test_data[:,:,q] = data[:,:,i]
            test_label[:,q] = label[:,i]
            if test_label[:,q] ==number[0]:
                test_label[:,q] = 1
            elif test_label[:,q] ==number[1]:
                test_label[:,q] = -1
            q = q + 1
            if q >=200:
                break
    if q>=200:
        break

def train(train_data,train_label):
    #获得数据的长度
    train_size = len(train_label.ravel())
    #初始化w,b
    w = np.zeros((1,785),dtype=np.float32).ravel()
    #在数据集中选取数据和标签
    study_count = 0
    no_change_count = 0
    lr = 0.01  # 学习率
    epoch = 1000 # 迭代次数
    while True:
        no_change_count +=1
        if no_change_count >epoch:
            break
        #随机抽取数据
        index = np.random.randint(0,train_size-1)
        img1 = train_data[:,:,index].reshape(1,-1)
        img2 = np.append(img1,[[1]],axis=1)
        img = img2.ravel()
        label = train_label[:,index]
        result = label*np.sum(np.dot(w,img))

        if result <=0:
            #更新权值
            w = w + lr*label*img
            study_count +=1
            lr = lr-lr*0.01
    return w,study_count

w,study_count = train(train_data,train_label)

#预测
result = np.zeros((1,200))
for i in range(200):
    test_img1 = test_data[:,:,i].reshape(1,-1)
    #对测试数据进行增广
    test_img2 = np.append(test_img1,[[1]],axis=1)
    test_img = test_img2.ravel()
    if np.sum(test_img*w) > 0:
        result[:,i] = 1
    else:
        result[:,i] = -1

#计算准确率
acc = 0
for j in range(200):
    if result[:,j] == test_label[:,j]:
        acc += 1
print('训练中更新了权值{}次'.format(study_count))
print('测试集的准确率为:{}'.format(acc/len(test_label.ravel())))

感知机算法实现手写数字多分类

与二分类不同的是,设置k(10)组权值向量,学习率lr

迭代:

如果第i类样本j存在wi*xj <= wt*xj (其中t为非i类),则进行如下权值修正

wi = wi + lr*xj

wt = wt + lr*xj

直到所有的wi*xj > wt*xj 退出迭代

得到k组权值向量

预测:

待测数字与k组权值向量求内积,求得最大值的索引即为该数字的预测值

上述算法参考李航老师的《统计学习》

import numpy as np
import scipy.io as sio
'''
矩阵转化为向量 .ravel()
'''

mate_data = sio.loadmat('./mat格式的MNIST数据/test_images.mat')
# print(mate_data.keys())
key_name =list(mate_data.keys())[-1]
data = mate_data[key_name]
mate_label = sio.loadmat('./mat格式的MNIST数据/test_labels.mat')
# print(mate_label.keys())
key_name1 = list(mate_label.keys())[-1]
label = mate_label[key_name1]

'''
data里有10000张0-9的图片
label中有对应的数字标签

将前8000张作为训练集,后2000张作为测试集

'''

#确定初始权向量

w = [None for i in range(0,10)]
for i in range(0,10):
    w[i] = np.zeros((1,785),dtype=np.float32).ravel()
a = 0.01


def circle(x,w1,w2):
    fun1 = np.dot(x,w1)
    fun2 = np.dot(x,w2)
    count = 0
    while(fun1<=fun2):
        w1 = w1 + np.dot(a,x)
        w2 = w2 - np.dot(a,x)
        fun1 = np.dot(x,w1)
        fun2 = np.dot(x,w2)
        count += 1
    return w1,count


for i in range(8000):
    #获得数据和标签
    img = data[:,:,i].reshape(1,-1)
    img = np.append(img,[[1]],axis=1)
    x   = img.ravel()
    y = int(label[:,i])

    wx = []  #存储wt*xi的值

    for t in range(10):
        wx.append(np.dot(x,w[t]))
    #返回识别的类别
    label_1 = np.argmax(wx)
    if label_1 != y:  #需要修正权值
        for t1 in range(10):
            z,count = circle(x,w[y],w[t1])
            w[y] = z

# print(w[1])
acc = 0
for i in range(8000,10000):
    w1 = []
    img = data[:,:,i].reshape(1,-1)
    img = np.append(img,[[1]],axis=1)
    x   = img.ravel()
    y   = int(label[:,i])
    for j in range(10):
        w1.append(np.dot(x,w[j]))
    label_2 = np.argmax(w1)
    if y ==label_2:
        acc += 1
        print('待识别的数字为:{},识别的结果为:{},识别正确'.format(str(y),str(label_2)))
    else:
        print('待识别的数字为:{},识别的结果为:{},识别错误'.format(str(y),str(label_2)))

print('正确率为:{}'.format(acc/2000))

你可能感兴趣的:(模式识别与机器学习,算法,分类,机器学习)