8. Pytorch入门教程——使用单个模型和集成模型在数据集上进行验证,预测

我们为最终的Densenet和Resnet模型加载两个文件,并在测试集上进行评估

transfer_densenet = load_chkpoint('densenet_cifar10_chkpoint_file')

load_chkpoint: best accuracy = 93.190
set_transfer_model: self.Model set to DenseNet
setting optim Ada Delta
DenseNet: setting head: inputs: 1024 hidden:[] outputs: 10
Transfer: best accuracy = 93.190
setting optim Ada Delta

transfer_densenet.evaluate(testloader)

(92.75,
[(‘airplane’, 92.80000000000001),
(‘automobile’, 97.39999999999999),
(‘bird’, 89.0),
(‘cat’, 88.3),
(‘deer’, 93.7),
(‘dog’, 84.5),
(‘frog’, 96.6),
(‘horse’, 94.39999999999999),
(‘ship’, 95.0),
(‘truck’, 95.8)])

transfer_resnet = load_chkpoint('resnet34_cifar10_chkpoint_file')

load_chkpoint: best accuracy = 92.780
set_transfer_model: self.Model set to ResNet34
setting optim Ada Delta
ResNet34: setting head: inputs: 512 hidden:[] outputs: 10
Transfer: best accuracy = 92.780
setting optim Ada Delta

transfer_resnet.evaluate(testloader)

(92.45,
[(‘airplane’, 91.5),
(‘automobile’, 97.1),
(‘bird’, 90.10000000000001),
(‘cat’, 83.89999999999999),
(‘deer’, 94.0),
(‘dog’, 86.7),
(‘frog’, 94.5),
(‘horse’, 94.8),
(‘ship’, 96.39999999999999),
(‘truck’, 95.5)])

一、集成多个模型来提高准确率

  • 我们已经测试和评估了两种不同的“迁移”模型。这两种模型在这个数据集上的表现似乎几乎一样好。我们可能想知道,如果我们以某种方式把两个模型的结果结合起来,做出最终的预测,会发生什么。将两个或多个模型组合在一起称为集成学习;
  • 你可能听说过这个术语,在传统的ML中,随机森林(RF)和梯度增强决策树(GBDT)作为集成模型。这里我们讨论的是使用两个或更多的深度学习模型来达到更好的准确性。有关更多信息,请参见Elements of Statistical Learning;
  • 集成背后的概念是,一个模型在预测时可能错误地分类了一个特定的例子,但是其他模型中的一个或多个可能是正确的。如果我们以某种方式结合预测,我们最终的预测准确性可能会提高;
  • 一种简单的方法是根据一些启发给每个模型的预测赋予权重,例如:
  1. 不同集成的预测值(如概率)的简单平均;
  2. 根据集成在验证集上的性能,为集成中的每个成员分配不同的权重;
  3. 根据我们在多个数据集上使用模型的经验分配权重。如果一个模型在大多数情况下表现得更好,我们应该给予它的预测更多的权重。
  • 创建集成的一种通用方法是创建一个从基类中派生的集成模型类,就像创建Transfer-Learning和FC一样;
  • 我们不需要拟合和训练方法,因为集成中的成员需要在集成前预先训练。然而,在集成类中实现预测和评估方法是有意义的;
  • 我们可以在构建集模型成时将模型对象及其权重传递给集成模型。在一个非常理想的场景中,我们希望使用某种类型的ML模型来学习这些权重本身,但是为了使事情更简单(至少在本教程中),我们将使用一些启发式方法传递权重;
  • 然后,我们可以编写评估和预测方法,这样它们就可以调用每个成员的相应方法,并将它们乘以模型的给定权重,然后再加上权重预测,从而得到最终的结果。

下面我们将展示此类的相关代码。代码非常简单,为了更清楚地说明,这里解释了重要的部分。

class EnsembleModel(Network):
    '''
    构造函数期望模型列表中的每个成员都是一个元组。
    元组的第一个元素必须是预先训练的模型对象,第二个元素必须是
    模型的权重。
    '''
    def __init__(self,models):
        self.criterion = None
        super().__init__()
        self.models = models
        '''
        这些权重和必须为1,这样我们的预测就是每一类所有模型预测的权重和
        '''
        if sum(model[1] for model in models) != 1.0:
            raise ValueError('Weights of Ensemble must sum to 1')
            
        
    def evaluate(self,testloader,metric='accuracy'):
        from collections import defaultdict
        #evaluations = defaultdict(float)
        #num_classes = self.models[0][0].num_outputs
        class_correct = defaultdict(int)
        class_totals = defaultdict(int)

        class_names = self.models[0][0].class_names  
        with torch.no_grad():
            
            for inputs, labels in testloader:
                ps_list = []  
                '''
                我们在一个循环中调用每个模型的前向方法,并将预测值乘以模型的权重。
                '''
                for model in self.models:
                    model[0].eval()
                    model[0].to(model[0].device)
                    inputs, labels = inputs.to(model[0].device), labels.to(model[0].device)
                    outputs = model[0].forward(inputs)
                    ps = torch.exp(outputs)
                    ps = ps * model[1] # multiply by model's weight
                    
                    '''
                    我们构建一个预测概率的列表,然后遍历这个列表,求这些值的和。
                    由于预测已经在前一个循环中乘以了权重,我们现在只需要求和就可以得到最终的加权和。
                    加权和向量包含每个类集成的预测值。我们可以得到它的最大值,就像我们对常规模型所做的那样,从而得到这幅图像的最终预测。
                    '''
                    ps_list.append(ps)
                    
                final_ps = ps_list[0]
                for i in range(1,len(ps_list)):
                    final_ps = final_ps + ps_list[i]
                _, final_preds = torch.max(final_ps, 1)
                #print(final_preds)
                update_classwise_accuracies(final_preds,labels,class_correct,class_totals)
        
       
        
        return get_accuracies(class_names,class_correct,class_totals)
                   
    '''
    Predict与常规Predict非常相似。唯一的区别是我们有两个循环,最后的预测是所有预测的总体加权和的topk。
    '''
    def predict(self,inputs,topk=1):
        ps_list = []  
        for model in self.models:
            model[0].eval()
            model[0].to(model[0].device)
            with torch.no_grad():
                inputs = inputs.to(model[0].device)
                outputs = model[0].forward(inputs)
                ps_list.append(torch.exp(outputs)*model[1])
       
        final_ps = ps_list[0]
        for i in range(1,len(ps_list)):
            final_ps = final_ps + ps_list[i]
        
        _,top = final_ps.topk(topk, dim=1)
            
        return top
    
    def forward(self,x):
        outputs = []
        for model in self.models:
             outputs.append(model[0].forward(x))
        return outputs

二、评估集成模型

创建一个集成对象,将0.5权值分配给两个模型,因为它们没有太大的差异,并观察性能的改进。

ensemble = EnsembleModel([(transfer_densenet,0.5),(transfer_resnet,0.5)])
ensemble.evaluate(testloader)

(93.95,
[(‘airplane’, 93.7),
(‘automobile’, 97.5),
(‘bird’, 91.10000000000001),
(‘cat’, 88.9),
(‘deer’, 95.39999999999999),
(‘dog’, 87.2),
(‘frog’, 96.5),
(‘horse’, 96.2),
(‘ship’, 96.89999999999999),
(‘truck’, 96.1)])

可以看到使用集成学习有较大提升。

你可能感兴趣的:(Pytorch入门教程,pytorch,深度学习,神经网络,机器学习)