我们为最终的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)])
下面我们将展示此类的相关代码。代码非常简单,为了更清楚地说明,这里解释了重要的部分。
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)])
可以看到使用集成学习有较大提升。