Измерение погрешности с использованием MC Dropout на pytorch

Я пытаюсь реализовать байесовский CNN с использованием Mc Dropout на Pytorch, основная идея заключается в том, что, применяя отсев во время тестирования и выполняя множество прямых проходов, вы получаете прогнозы из множества различных моделей. Я нашел применение Mc Dropout и действительно не понял, как они применили этот метод и как именно они выбрали правильный прогноз из списка прогнозов.

вот код


 def mcdropout_test(model):
    model.train()
    test_loss = 0
    correct = 0
    T = 100
    for data, target in test_loader:
        if args.cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, volatile=True), Variable(target)
        output_list = []
        for i in xrange(T):
            output_list.append(torch.unsqueeze(model(data), 0))
        output_mean = torch.cat(output_list, 0).mean(0)
        test_loss += F.nll_loss(F.log_softmax(output_mean), target, size_average=False).data[0]  # sum up batch loss
        pred = output_mean.data.max(1, keepdim=True)[1]  # get the index of the max log-probability
        correct += pred.eq(target.data.view_as(pred)).cpu().sum()

    test_loss /= len(test_loader.dataset)
    print('\nMC Dropout Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))


    train()
    mcdropout_test()

Я заменил

data, target = Variable(data, volatile=True), Variable(target)

добавляя

with torch.no_grad(): в начале

И вот как я определил свой CNN

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 192, 5, padding=2)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(192, 192, 5, padding=2)
        self.fc1 = nn.Linear(192 * 8 * 8, 1024)
        self.fc2 = nn.Linear(1024, 256)
        self.fc3 = nn.Linear(256, 10)
        self.dropout = nn.Dropout(p=0.3)
        
        nn.init.xavier_uniform_(self.conv1.weight)
        nn.init.constant_(self.conv1.bias, 0.0)
        nn.init.xavier_uniform_(self.conv2.weight)
        nn.init.constant_(self.conv2.bias, 0.0)
        nn.init.xavier_uniform_(self.fc1.weight)
        nn.init.constant_(self.fc1.bias, 0.0)
        nn.init.xavier_uniform_(self.fc2.weight)
        nn.init.constant_(self.fc2.bias, 0.0)
        nn.init.xavier_uniform_(self.fc3.weight)
        nn.init.constant_(self.fc3.bias, 0.0)


    def forward(self, x):
        x = self.pool(F.relu(self.dropout(self.conv1(x))))  # recommended to add the relu
        x = self.pool(F.relu(self.dropout(self.conv2(x))))  # recommended to add the relu
        x = x.view(-1, 192 * 8 * 8)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(self.dropout(x)))
        x = self.fc3(self.dropout(x))  # no activation function needed for the last layer
        return x

Может ли кто-нибудь помочь мне получить правильную реализацию метода исключения Монте-Карло на CNN?


person Ka_    schedule 06.08.2020    source источник


Ответы (1)


Реализовать MC Dropout в Pytorch очень просто. Все, что нужно сделать, это установить для выпадающих слоев вашей модели режим обучения. Это позволяет использовать разные маски отключения во время различных прямых проходов. Ниже представлена ​​реализация MC Dropout в Pytorch, иллюстрирующая, как несколько прогнозов из различных прямых проходов складываются вместе и используются для вычисления различных показателей неопределенности.

import sys

import numpy as np

import torch
import torch.nn as nn


def enable_dropout(model):
    """ Function to enable the dropout layers during test-time """
    for m in model.modules():
        if m.__class__.__name__.startswith('Dropout'):
            m.train()

def get_monte_carlo_predictions(data_loader,
                                forward_passes,
                                model,
                                n_classes,
                                n_samples):
    """ Function to get the monte-carlo samples and uncertainty estimates
    through multiple forward passes

    Parameters
    ----------
    data_loader : object
        data loader object from the data loader module
    forward_passes : int
        number of monte-carlo samples/forward passes
    model : object
        keras model
    n_classes : int
        number of classes in the dataset
    n_samples : int
        number of samples in the test set
    """

    dropout_predictions = np.empty((0, n_samples, n_classes))
    softmax = nn.Softmax(dim=1)
    for i in range(forward_passes):
        predictions = np.empty((0, n_classes))
        model.eval()
        enable_dropout(model)
        for i, (image, label) in enumerate(data_loader):

            image = image.to(torch.device('cuda'))
            with torch.no_grad():
                output = model(image)
                output = softmax(output) # shape (n_samples, n_classes)
            predictions = np.vstack((predictions, output.cpu().numpy()))

        dropout_predictions = np.vstack((dropout_predictions,
                                         predictions[np.newaxis, :, :]))
        # dropout predictions - shape (forward_passes, n_samples, n_classes)
    
    # Calculating mean across multiple MCD forward passes 
    mean = np.mean(dropout_predictions, axis=0) # shape (n_samples, n_classes)

    # Calculating variance across multiple MCD forward passes 
    variance = np.var(dropout_predictions, axis=0) # shape (n_samples, n_classes)

    epsilon = sys.float_info.min
    # Calculating entropy across multiple MCD forward passes 
    entropy = -np.sum(mean*np.log(mean + epsilon), axis=-1) # shape (n_samples,)

    # Calculating mutual information across multiple MCD forward passes 
    mutual_info = entropy - np.mean(np.sum(-dropout_predictions*np.log(dropout_predictions + epsilon),
                                            axis=-1), axis=0) # shape (n_samples,)

Переходя к реализации, опубликованной в вопросе выше, можно получить несколько прогнозов из T различных прямых проходов, сначала установив модель в режим обучения (model.train()). Обратите внимание, что это нежелательно, потому что нежелательная стохастичность будет введена в прогнозы, если в модели есть слои, отличные от выпадающих, такие как норма партии. Следовательно, лучший способ - просто установить отсеиваемые слои в режим обучения, как показано в приведенном выше фрагменте.

person Iswariya Manivannan    schedule 13.08.2020
comment
Могу ли я узнать, почему именно вы использовали model.eval () непосредственно перед enable_dropout (model)? - person Ka_; 13.08.2020
comment
Чтобы использовать отсев во время тестирования для MCD, только слои отсева должны быть настроены для обучения, в то время как другие слои должны находиться в режиме оценки. Следовательно, я сначала переключаю модель в режим оценки, а затем устанавливаю только слои исключения для обучения в enable_dropout (модель). - person Iswariya Manivannan; 14.08.2020
comment
Большое спасибо за ваши ясные объяснения. Не могли бы вы высказать свое мнение о CNN, который я использовал, и о том, что я могу изменить в нем. - person Ka_; 14.08.2020
comment
Замените model.train () в mcdropout_test (model) на model.eval () и после этого вызовите enable_dropout (model). Конечно, вам нужно добавить в свой код определение функции enable_dropout (модель). - person Iswariya Manivannan; 14.08.2020
comment
Хорошо, спасибо! - person Ka_; 14.08.2020
comment
Не могли бы вы рассказать мне, как получить общую энтропию, я пытался вычислить энтропию для каждого прямого прохода, но мне нужно найти общую энтропию, чтобы получить неопределенность модели, как именно я ее вычисляю? - person Ka_; 03.09.2020
comment
Просто возьмите среднее значение (np.mean (энтропия)) энтропии, вычисленной ранее. - person Iswariya Manivannan; 08.09.2020
comment
Я попытался сделать то же самое для расчета неопределенности классов в этом сообщении stackoverflow.com/questions/63755687/ есть ли у вас какие-либо заметки об этой реализации ? - person Ka_; 10.09.2020