我为5种情感识别制作了一个CNN模型。我想用单张图片来测试它,以获取每种情感的个别类别预测结果。
评估模型是可行的,但我似乎找不到如何用单张图片进行预测的方法。我该怎么做呢?
模型
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
调用fit_one_cycle
函数来训练模型
@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 decayoptimizer = opt_func(model.parameters(), max_lr, weight_decay=weight_decay)# Set up one-cycle learning rate schedulersched = 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
这会返回准确率和损失,我希望将其更改为返回每个类别的预测百分比。
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']))
回答:
评估模型是可行的,但我似乎找不到如何用单张图片进行预测的方法。我该怎么做呢?
简单来说,如果你有一张图片,请确保:
- 在开头使用额外的
1
维度 - 确保使用
CHW
格式而不是HWC
(或者在PyTorch中指定,查看如何操作请点击这里)
例如:
my_model = CNN(...)random_image = torch.randn(1, 3, 100, 100) # 3个通道,100x100的图像
顺便提一下,你的准确率计算可以简化如下:
def accuracy(outputs, labels): preds = torch.argmax(outputs, dim=1) return torch.sum(preds == labels) / len(preds)
获取类别概率
类似于argmax,你可以使用softmax,它将网络输出的logits(未归一化的概率)转换为概率:
def probability(outputs): return torch.nn.functional.softmax(outputs, dim=1)