基于感知器的手写数字识别

1原理介绍

本次实验要求使用线性分类器实现手写数字识别,线性分类器选择的是感知器模型。基于感知器的实验数据必须是线性可分的,感知器不仅可以使用在二分类还可以使用在多分类。不过,在二分类与多分类的算法实现过程略有不同。这些不同主要体现在权重更新与判别超平面的实现两个方面。

1.1二分类

将数据分为两类。首先,要求数据是线性可分的;然后,选择初始权重,通过训练集实现对权重的更新;接着,使用更新后的权重实现对测试集的识别;最后,将识别结果与测试数据的标签进行比较,得出正确率。在这里插入图片描述
上面是感知器的损失函数,该损失函数表示误分类点到判别超平面的距离,感知器算法通过更新权重实现损失函数的最小化。权重的更新规则:
在这里插入图片描述
本次实验初始权重取0向量,b的取1向量。首先,判断某点到判别面的距离,计算yi*(wixi+b)是否大于0,该点被正确分类时,其wixi+b与yi是同号的,此时前面的计算式大于0;误分类时它们异号,前面的计算式小于0,此时需要对权重和b进行更新,已使yi*(wixi+b)大于0(注意:在初始权重下每个yi(wixi+b)都为0,此时认为每个点都是误分类点,然后一次更新权重);接着,再次计算yi(wixi+b)是否大于0,如果大于零就去判断下一个点,否则就再次更新权重与b,直到对所有的点都有yi(wi*xi+b)。
感知器得到的判别超平面并不是唯一的,它与初值的选择以及迭代过程中误分类点的选择顺序都有很大关系,所以为了得到唯一的超平面,需要对分离超平面增加约束条件,这就形成了支持向量机。

1.2多类情况

本次实验使用感知器实现手写数字识别属于多分类的问题。首先对手写数字图片进行处理,将图片转化为88的01矩阵;然后,将该矩阵转化为一维数组的形式,X={x1,x2,…x64},此时为了简化计算,将b并入权重向量W={b,w1,w2,…,w64},因此需要在X前面加上1,计算wixi+b就简化为计算W.TX;然后,设置10组初始权重(因为数字为0-9,有10个类别),并对某个点一次用10组权重计算W.TX,得到10个目标函数值,使用argmax函数得到最大函数值对应的索引号,此索引号的值就是该决策识别的数字类别;接着,将识别到的值与该测试数据所对应的类别进行比较,如果两者相等说明识别正确,否则就需要对权重进行更新,并再次判断识别结果的正确性。
多类问题的权重更新与二分类有所不同,以下是多类问题权重的更新规则:
在这里插入图片描述
如,对于第j类的数据Xi,计算Wj.T
Xi,然后将其值与{W0.TXi,W1.TXi,W2.TXi,…,Wj-1.TXi,Wj+1.TXi,…,W9.TXi}逐个进行比较,如果Wj.TXi较大则与下一个进行比较,否则就需要对权重进行修正,C为学习率。直到Wj.TXi为10组权重向量中的最大值。这是多类问题与二分类问题再权重更新的不同,同时多类问题的判别超平面的实现也有差别,一般通过Wi.TXi-Wj.TXj=0得到第i个类别与第j个类别的超平面函数。

2代码

2.1代码介绍

下面给出了基于感知器的多分类问题的代码。整个代码分为数据预处理、确定初始权重、训练数据及更新权重以及识别数据几个部分。数据处理的代码就不列出来了,最后转化为1*65(在由64个特征构成的向量前面加1)的一维数组就行。

wk=[None for i in range(0,10)]
for i in range(0,10):#确定初始权重,这里将初始权重都设置为0向量
    wk[i]=np.zeros((65,1)).reshape((1,-1))
    # wk[i]=np.full(65,i).reshape(1,-1)
a=0.02#学习率
def circle(x,w1,w2):#更新权重,实现权重更新过程中的迭代
    distinguish_fun1=np.dot(x,w1)
    distinguish_fun2=np.dot(x,w2)
    count=0
    while(distinguish_fun1<=distinguish_fun2):#当Wj.T*Xi不大于其他组权重与Xi的内积时,进行循环
        w1=w1+np.dot(a,x)#更新Wj
        w2=w2-np.dot(a,x)#更新Wt
        count+=1#记录迭代次数
        distinguish_fun1=np.dot(x,w1)#计算更新后的Wj.T*Xi与Wt.T*Xi
        distinguish_fun2=np.dot(x,w2)
    return distinguish_fun1,count,w1,w2   #函数返回值
count_test = 0
for j in range(0,10):#测试集类别
    for i in range(j*37,j*37+37):#每个类别的样本
        wx=[]#存放Wt.T*Xi的值
        # wx1=[]
        for t in range(0,10):
            wx.append(np.dot(x0[i][0],wk[t][0]))
            # wx.append(np.dot(y0[i][0],wk[t][0]))
        label=np.argmax(wx)#返回识别的类别
        if label!=j:#不一致,需要进行权重修正
            for t1 in range(0,10):#遍历每组权重
                x,y,z,k=circle(x0[i][0],wk[j][0],wk[t1][0])
                wk[j][0]=z #将修改后的权重更新到Wj
    # print(f"权重向量为:{wk[j][0]}")
    for p in range(j*10,j*10+10):#将修正后的Wj作为识别第j类测试数据集的权重
        wx1=[]
        for t2 in range(0,10):#遍历每组权重
            wx1.append(np.dot(y0[p],wk[t2][0]))
        label1=np.argmax(wx1)
        if label1==j:
            count_test+=1
            print(f"待识别数字为{j};识别结果为{label1};识别正确")
        else:
            print(f"待识别数字为{j};识别结果为{label1};识别错误")
rate=count_test/100
print(f"正确率:{rate*100}%")
print(f"更新后的10组权重向量为:")

2.2结果分析

下图是得到的识别结果
在这里插入图片描述
最后结果的正确率为99%,符合实验的准确率要求。可以看出,感知器在多类问题的表现较为可观。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,下面是基于 Python 和 PyTorch 的多层感知机实现手写数字识别的代码示例。 首先,我们需要导入必要的库和数据集。这里我们使用 PyTorch 自带的 MNIST 数据集。 ```python import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from torchvision import datasets, transforms # 定义数据集路径 data_path = './data' # 定义数据预处理方式 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=(0.5,), std=(0.5,)) ]) # 加载数据集 train_dataset = datasets.MNIST(root=data_path, train=True, download=True, transform=transform) test_dataset = datasets.MNIST(root=data_path, train=False, download=True, transform=transform) # 定义批次大小 batch_size = 128 # 创建数据加载器 train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=True) ``` 接着,我们定义多层感知机模型,这里使用两层全连接层。 ```python class MLP(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super(MLP, self).__init__() self.fc1 = nn.Linear(input_dim, hidden_dim) self.fc2 = nn.Linear(hidden_dim, output_dim) self.relu = nn.ReLU() def forward(self, x): x = x.view(x.size(0), -1) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return x ``` 然后,我们定义模型的超参数,并实例化模型和优化器。 ```python # 定义模型的超参数 input_dim = 784 hidden_dim = 128 output_dim = 10 learning_rate = 0.001 num_epochs = 10 # 实例化模型和优化器 model = MLP(input_dim, hidden_dim, output_dim) optimizer = optim.Adam(model.parameters(), lr=learning_rate) ``` 接下来,我们定义训练和测试的函数。 ```python def train(model, train_loader, optimizer, criterion): model.train() train_loss = 0 train_correct = 0 for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) train_loss += loss.item() pred = output.argmax(dim=1, keepdim=True) train_correct += pred.eq(target.view_as(pred)).sum().item() loss.backward() optimizer.step() train_loss /= len(train_loader.dataset) train_acc = train_correct / len(train_loader.dataset) return train_loss, train_acc def test(model, test_loader, criterion): model.eval() test_loss = 0 test_correct = 0 with torch.no_grad(): for data, target in test_loader: output = model(data) test_loss += criterion(output, target).item() pred = output.argmax(dim=1, keepdim=True) test_correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) test_acc = test_correct / len(test_loader.dataset) return test_loss, test_acc ``` 最后,我们进行训练并测试模型。 ```python criterion = nn.CrossEntropyLoss() for epoch in range(1, num_epochs+1): train_loss, train_acc = train(model, train_loader, optimizer, criterion) test_loss, test_acc = test(model, test_loader, criterion) print('Epoch [{}/{}], Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}' .format(epoch, num_epochs, train_loss, train_acc, test_loss, test_acc)) ``` 训练完成后,我们可以使用模型进行预测。 ```python import matplotlib.pyplot as plt import numpy as np # 随机选择一张测试图片 index = np.random.randint(0, len(test_dataset)) image, target = test_dataset[index] image = image.unsqueeze(0) # 使用模型进行预测 output = model(image) pred = output.argmax(dim=1, keepdim=True) # 显示图片和预测结果 plt.imshow(image.squeeze(), cmap='gray') plt.title('Ground Truth: {}, Prediction: {}'.format(target, pred.item())) plt.axis('off') plt.show() ``` 以上就是基于 Python 和 PyTorch 的多层感知机实现手写数字识别的代码示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值