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