Pytroch入坑 4. Centerloss+Mnist+可视化

0.前言

对于分类问题,常见的损失函数是Softmax,许多研究人员在损失函数的调整上下功夫,详见    

      https://blog.csdn.net/sinat_37787331/article/details/80156308    

本次实现pytroch +centlerloss+mnist

参考:https://github.com/UpCoder/centerloss

https://github.com/CharlesNord/centerloss

1.代码

# coding: utf8
import torch
from torch.autograd import Variable




class CenterLoss(torch.nn.Module):
    def __init__(self, num_classes, feat_dim, loss_weight=1.0):
        super(CenterLoss, self).__init__()
        self.num_classes = num_classes
        self.feat_dim = feat_dim
        self.loss_weight = loss_weight
        self.centers = torch.nn.Parameter(torch.randn(num_classes, feat_dim))
        self.use_cuda = False


    def forward(self, y, feat):
        if self.use_cuda:
            hist = Variable(
                torch.histc(y.cpu().data.float(), bins=self.num_classes, min=0, max=self.num_classes) + 1).cuda()
        else:
            hist = Variable(torch.histc(y.data.float(), bins=self.num_classes, min=0, max=self.num_classes) + 1)


        centers_count = hist.index_select(0, y.long())  # 计算每个类别对应的数目


        batch_size = feat.size()[0]
        feat = feat.view(batch_size, 1, 1, -1).squeeze()
        if feat.size()[1] != self.feat_dim:
            raise ValueError("Center's dim: {0} should be equal to input feature's dim: {1}".format(self.feat_dim,
                                                                                                    feat.size()[1]))
        centers_pred = self.centers.index_select(0, y.long())
        diff = feat-centers_pred
        loss = self.loss_weight * 1/2.0 * (diff.pow(2).sum(1) / centers_count).sum()
        return loss


    def cuda(self, device_id=None):
        self.use_cuda = True
        return self._apply(lambda t: t.cuda(device_id))

import torch
from torch.autograd import Variable
import torch.utils.data as Data
import torchvision
from torchvision import transforms
import torch.nn.functional as F
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import matplotlib.patheffects as PathEffects
from centerLoss import CenterLoss
import torch.optim.lr_scheduler as lr_scheduler
import matplotlib.cm as cm

trainset = torchvision.datasets.MNIST(root='../data', train=True, transform=transforms.Compose(
    [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
))

testset = torchvision.datasets.MNIST(root='../data', train=False, transform=transforms.Compose(
    [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]
))

train_loader = Data.DataLoader(dataset=trainset, batch_size=128, shuffle=True, num_workers=4)
test_loader = Data.DataLoader(dataset=testset, batch_size=128, shuffle=True, num_workers=4)


class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.extract = torch.nn.Sequential(
            torch.nn.Linear(784, 512),
            torch.nn.PReLU(),
            torch.nn.Linear(512, 256),
            torch.nn.PReLU(),
            torch.nn.Linear(256, 128),
            torch.nn.PReLU(),
            torch.nn.Linear(128, 64),
            torch.nn.PReLU(),
            torch.nn.Linear(64, 32),
            torch.nn.PReLU(),
            torch.nn.Linear(32, 2),
        )
        self.predict = torch.nn.Sequential(
            torch.nn.PReLU(),
            torch.nn.Linear(2, 10),
        )

    def forward(self, x):
        feature = self.extract(x.view(-1, 784))
        pred = F.log_softmax(self.predict(feature))
        return feature, pred


class ConvNet(torch.nn.Module):
    def __init__(self):
        super(ConvNet, self).__init__()
        self.extract = torch.nn.Sequential(
            torch.nn.Conv2d(1, 32, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.Conv2d(32, 32, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.MaxPool2d(2, 2),
            torch.nn.Conv2d(32, 64, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.Conv2d(64, 64, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.MaxPool2d(2, 2),
            torch.nn.Conv2d(64, 128, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.Conv2d(128, 128, kernel_size=5, padding=2),
            torch.nn.PReLU(),
            torch.nn.MaxPool2d(2, 2),
        )
        self.feat = torch.nn.Linear(128*3*3, 2)
        self.pred = torch.nn.Sequential(
            torch.nn.Linear(2, 10)
        )

    def forward(self, x):
        x = self.extract(x)
        x = x.view(-1, 128*3*3)
        feat = self.feat(x)
        pred = F.log_softmax(self.pred(feat))
        return feat, pred


model = Net().cuda()
# model = ConvNet().cuda()
optimizer4nn = torch.optim.SGD(model.parameters(), lr=1e-3, momentum=0.9, weight_decay=0.0005)
scheduler = lr_scheduler.StepLR(optimizer4nn, 20, gamma=0.8)

centerloss = CenterLoss(10, 2, 0.1).cuda()
nllloss = torch.nn.NLLLoss().cuda()
#crossentropy = torch.nn.CrossEntropyLoss().cuda()
optimizer4center = torch.optim.SGD(centerloss.parameters(), lr=0.5)


def train(train_loader, model, epoch):
    print("Training Epoch: {}".format(epoch))
    model.train()
    for step, (data, target) in enumerate(train_loader):
        data = Variable(data).cuda()
        target = Variable(target).cuda()
        feat, pred = model(data)
        loss = nllloss(pred, target) + centerloss(target, feat)
        optimizer4nn.zero_grad()
        optimizer4center.zero_grad()
        loss.backward()
        optimizer4nn.step()
        optimizer4center.step()
        if step % 100 == 0:
            print("Epoch: {} step: {}".format(epoch, step))


def test(test_loader, model, epoch):
    print("Predicting Epoch: {}".format(epoch))
    model.eval()
    total_pred_label = []
    total_target = []
    total_feature = []
    for step, (data, target) in enumerate(test_loader):
        data = Variable(data).cuda()
        target = Variable(target).cuda()
        feature, pred = model(data)
        _, pred_label = pred.max(dim=1)
        total_pred_label.append(pred_label.data.cpu())
        total_target.append(target.data.cpu())
        total_feature.append(feature.data.cpu())

    total_pred_label = torch.cat(total_pred_label, dim=0)
    total_target = torch.cat(total_target, dim=0)
    total_feature = torch.cat(total_feature, dim=0)

    precision = torch.sum(total_pred_label == total_target) / float(total_target.shape[0])
    print("Validation accuracy: {}%".format(precision * 100))
    scatter(total_feature.numpy(), total_target.numpy(), epoch)


def scatter(feat, label, epoch):
    plt.ion()
    plt.clf()
    palette = np.array(sns.color_palette('hls', 10))
    ax = plt.subplot(aspect='equal')
    # sc = ax.scatter(feat[:, 0], feat[:, 1], lw=0, s=40, c=palette[label.astype(np.int)])
    for i in range(10):
        plt.plot(feat[label == i, 0], feat[label == i, 1], '.', c=palette[i])
    plt.legend(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], loc='upper right')
    ax.axis('tight')
    for i in range(10):
        xtext, ytext = np.median(feat[label == i, :], axis=0)
        txt = ax.text(xtext, ytext, str(i), fontsize=18)
        txt.set_path_effects([PathEffects.Stroke(linewidth=5, foreground="w"), PathEffects.Normal()])

    plt.draw()
    plt.savefig('./benchmark/centerloss_{}.png'.format(epoch))
    plt.pause(0.001)


for epoch in range(50):
    scheduler.step()
    train(train_loader, model, epoch)
    test(test_loader, model, epoch)

2.效果

第一个epoch ,acc 9%.  第14个epoch 91%。  第50个epoch acc 96.79%。 网络用的是很简单的网络。

效果图如下              

epoch 0



epoch  8


epoch 10


epoch 12


epoch 14,acc90%


epoch 25

epoch  40

epoch 49,9  acc96%左右



2.继续实验

改变 维度,2->10   变为  3->10,权重0.1    acc 97.6%


改变权重,  3->10    0.5    acc 97.5%


说明改变最后第二层维度可以提升ACC,且权重越大,不同类之间的距离越大


改网络结构,net-》convnet,3->10,权重为0.1

第二个epoch acc就到50%+了,到15个epoch  ACC达到99%+

第5epoch


第15个epoch,ACC 99%+


效果更佳


  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: 附件中的脚本和训练数据提供了一个基于PyTorch的手写数字识别模型的实现。该模型使用一个卷积神经网络(Convolutional Neural Network,CNN)来进行训练和预测。 首先,pytorch_mnist.py是一个Python脚本,包含了模型的网络结构、损失函数、优化器以及训练、验证和测试的流程。它通过加载mnist.npz中的数据集,对模型进行训练,并评估其在测试集上的性能。 mnist.npz是一个Numpy数组文件,其中包含了手写数字MNIST数据集MNIST数据集是一个常用的机器学习数据集,包含了60000个用于训练的手写数字图像和10000个用于测试的手写数字图像。每个图像都是28x28像素大小的灰度图像,表示了0到9之间的一个数字。mnist.npz文件将数据集分为了训练集、验证集和测试集,并存储为Numpy数组的形式。 脚本pytorch_mnist.py使用了PyTorch框架来定义了一个具有两个卷积层和三个全连接层的CNN模型。训练过程中,脚本使用了随机梯度下降(Stochastic Gradient Descent,SGD)算法来优化模型的权重参数,并使用交叉熵损失函数来度量模型的性能。脚本还实现了训练集上的批次循环、验证集上的性能评估和在测试集上的预测。 下载并运行这些脚本和数据,你将能够训练一个基于CNN的手写数字识别模型,并使用该模型对新的手写数字图像进行识别。这个模型可以作为一个简单但有效的数字识别工具,有助于学习和理解深度学习和计算机视觉领域的相关概念和技术。 ### 回答2: 附件提供了两个文件,分别是脚本文件pytorch_mnist.py和训练数据文件mnist.npz。 脚本文件pytorch_mnist.py是使用PyTorch框架编写的一个用于识别手写数字的神经网络模型。它通过卷积神经网络的方法对输入的手写数字图像进行分析和识别。脚本首先加载训练数据,然后定义了一个包含卷积层、池化层和全连接层的神经网络模型。接着使用随机梯度下降算法对模型进行训练,并实现了损失函数和优化器。最后,在一定的迭代次数下,保存了训练好的模型,在测试集上进行准确率的评估。 训练数据文件mnist.npz包含了用于训练和测试的手写数字图像数据集,其中包括了60,000个训练样本和10,000个测试样本。这些图像数据已经被处理成灰度图像,并存储在一个numpy数组中。可以通过读取这些数据,并分为训练集和测试集,用于模型的训练和评估。 总结起来,这个附件提供了一个使用PyTorch框架编写的手写数字识别模型的实现脚本以及相应的训练数据。通过使用这些资源,我们可以训练一个卷积神经网络模型来对手写数字图像进行识别,并通过测试数据评估该模型的准确率。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值