简体   繁体   English

如何对 pytorch 情绪检测 model 进行预测

[英]How to make prediction on pytorch emotion detection model

I made a CNN model for emotion recognition on 5 emotions.我制作了一个 CNN model 用于对 5 种情绪进行情绪识别。 I wanted to test it on an single image to get the individual class predictions for each emotion.我想在单个图像上对其进行测试,以获得每种情绪的单独 class 预测。

Evaluating the model works, but I can't seem to find how to make a prediction with a single image.评估 model 有效,但我似乎无法找到如何使用单个图像进行预测。 How can I do that?我怎样才能做到这一点?

The Model Model

def conv_block(in_channels, out_channels, pool=False):
layers = [nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), 
          nn.BatchNorm2d(out_channels), 
          nn.ELU(inplace=True)]
if pool: layers.append(nn.MaxPool2d(2))
return nn.Sequential(*layers)

class ResNet(ImageClassificationBase):
    def __init__(self, in_channels, num_classes):
        super().__init__()
        
        self.conv1 = conv_block(in_channels, 128)
        self.conv2 = conv_block(128, 128, pool=True)
        self.res1 = nn.Sequential(conv_block(128, 128), conv_block(128, 128))
        self.drop1 = nn.Dropout(0.5)
        
        self.conv3 = conv_block(128, 256)
        self.conv4 = conv_block(256, 256, pool=True)
        self.res2 = nn.Sequential(conv_block(256, 256), conv_block(256, 256))
        self.drop2 = nn.Dropout(0.5)
        
        self.conv5 = conv_block(256, 512)
        self.conv6 = conv_block(512, 512, pool=True)
        self.res3 = nn.Sequential(conv_block(512, 512), conv_block(512, 512))
        self.drop3 = nn.Dropout(0.5)


        self.classifier = nn.Sequential(nn.MaxPool2d(6), 
                                        nn.Flatten(),
                                        nn.Linear(512, num_classes))
        
    def forward(self, xb):
        out = self.conv1(xb)
        out = self.conv2(out)
        out = self.res1(out) + out
        out = self.drop1(out)

        out = self.conv3(out)
        out = self.conv4(out)
        out = self.res2(out) + out
        out = self.drop2(out)

        out = self.conv5(out)
        out = self.conv6(out)
        out = self.res3(out) + out
        out = self.drop3(out)

        out = self.classifier(out)
        return out

The fit_one_cycle function is called to train the model调用fit_one_cycle function 来训练 model

@torch.no_grad()
def evaluate(model, val_loader):
model.eval()
outputs = [model.validation_step(batch) for batch in val_loader]
return model.validation_epoch_end(outputs)

def get_lr(optimizer):
    for param_group in optimizer.param_groups:
       return param_group['lr']

def fit_one_cycle(epochs, max_lr, model, train_loader, val_loader, 
              weight_decay=0, grad_clip=None, opt_func=torch.optim.SGD):
    torch.cuda.empty_cache()
    history = []

# Set up custom optimizer with weight decay
optimizer = opt_func(model.parameters(), max_lr, weight_decay=weight_decay)
# Set up one-cycle learning rate scheduler
sched = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, epochs=epochs, 
                                            steps_per_epoch=len(train_loader))

    for epoch in range(epochs):
        # Training Phase 
        model.train()
        train_losses = []
        lrs = []
        for batch in train_loader:
            loss = model.training_step(batch)
            train_losses.append(loss)
            loss.backward()
        
            # Gradient clipping
            if grad_clip: 
                nn.utils.clip_grad_value_(model.parameters(), grad_clip)
        
            optimizer.step()
            optimizer.zero_grad()
        
            # Record & update learning rate
            lrs.append(get_lr(optimizer))
            sched.step()
    
        # Validation phase
        result = evaluate(model, val_loader)
        result['train_loss'] = torch.stack(train_losses).mean().item()
        result['lrs'] = lrs
        model.epoch_end(epoch, result)
        history.append(result)
    return history

This returns the accuracy and loss, i want to change this so it returns prediction percentages for each class.这将返回准确性和损失,我想更改它以便返回每个 class 的预测百分比。

    def accuracy(outputs, labels):
    _, preds = torch.max(outputs, dim=1)
    return torch.tensor(torch.sum(preds == labels).item() / len(preds))

class ImageClassificationBase(nn.Module):
    def training_step(self, batch):
        images, labels = batch 
        out = self(images)
        loss = F.cross_entropy(out, labels)
        return loss
    
    def validation_step(self, batch):
        images, labels = batch
        out = self(images)
        loss = F.cross_entropy(out, labels)
        acc = accuracy(out, labels)
        return {'val_loss': loss, 'val_acc': acc}
        
    def validation_epoch_end(self, outputs):
        batch_losses = [x['val_loss'] for x in outputs]
        epoch_loss = torch.stack(batch_losses).mean()
        batch_accs = [x['val_acc'] for x in outputs]
        epoch_acc = torch.stack(batch_accs).mean()
        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}
    
    def epoch_end(self, epoch, result):
        print("Epoch [{}], last_lr: {:.5f}, train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}".format(
            epoch, result['lrs'][-1], result['train_loss'], result['val_loss'], result['val_acc']))

Evaluating the model works, but I can't seem to find how to make a prediction with a single image.评估 model 有效,但我似乎无法找到如何使用单个图像进行预测。 How can I do that?我怎样才能做到这一点?

Simply, if you have a single image make sure to:简单地说,如果您只有一张图片,请确保:

  • use additional 1 dimension at the beginning在开始时使用额外的1维度
  • make sure to use CHW format instead of HWC (or specify that within pytorch, check out how to do that here )确保使用CHW格式而不是HWC (或在 pytorch 中指定,在此处查看如何操作)

For example:例如:

my_model = CNN(...)
random_image = torch.randn(1, 3, 100, 100) # 3 channels, 100x100 img

BTW.顺便提一句。 Your accuracy could be written a little simpler like this:你的准确性可以写得更简单一点:

def accuracy(outputs, labels):
    preds = torch.argmax(outputs, dim=1)
    return torch.sum(preds == labels) / len(preds)

Getting class probability获取 class 概率

Similar to argmax you can use softmax which transforms logits (unnormalized probability outputted by your network) into probabilities:与 argmax 类似,您可以使用 softmax 将 logits(网络输出的非标准化概率)转换为概率:

def probability(outputs):
    return torch.nn.functional.softmax(outputs, dim=1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM