神经网络与深度学习(基于动手学深度学习pytorch)(三)

本文详细解释了混淆矩阵在机器学习中的作用,探讨了精确率、召回率等评价指标,并介绍了目标检测技术如YOLO和语义分割,以及风格迁移中的损失函数,包括内容损失、样式损失和总变差损失的计算方法。
摘要由CSDN通过智能技术生成

【深度学习视觉应用】

1.数据集与评价指标

1.1算法评估

1.1.1 混淆矩阵

在机器学习领域,混淆矩阵(Confusion Matrix),又称为可能性矩阵或错误矩阵。混淆矩阵是可视化工具,特别用于监督学习,在无监督学习一般叫做匹配矩阵。在图像精度评价中,主要用于比较分类结果和实际测得值,可以把分类结果的精度显示在一个混淆矩阵里面。

混淆矩阵的结构一般如下图表示的方法。

TP: 被正确地划分为正例的个数,即实际为正例且被分类器划分为正例的实例数
FP: 被错误地划分为正例的个数,即实际为负例但被分类器划分为正例的实例数
FN:被错误地划分为负例的个数,即实际为正例但被分类器划分为负例的实例数
TN: 被正确地划分为负例的个数,即实际为负例且被分类器划分为负例的实例数

混淆矩阵的每一列代表了预测类别,每一列的总数表示预测为该类别的数据的数目;

每一行代表了数据的真实归属类别,每一行的数据总数表示该类别的数据实例的数目;每一列中的数值表示真实数据被预测为该类的数目。

从混淆矩阵当中,可以得到更高级的分类指标:Accuracy(精确率),Precision(正确率或者准确率),Recall(召回率),Specificity(特异性),Sensitivity(灵敏度)。

(1)精确率(Accuracy)
精确率是最常用的分类性能指标。可以用来表示模型的精度,即模型识别正确的个数/样本的总个数。一般情况下,模型的精度越高,说明模型的效果越好。

Accuracy = (TP+TN)/(TP+FN+FP+TN)

(2) 正确率或者准确率(Precision)
又称为查准率,表示在模型识别为正类的样本中,真正为正类的样本所占的比例。一般情况下,查准率越高,说明模型的效果越好。

Precision = TP/(TP+FP)

(3) 召回率(Recall)
又称为查全率,召回率表现出在实际正样本中,分类器能预测出多少。

Recall(召回率) = Sensitivity(敏感指标,True Positive Rate,TPR)= 查全率

表示的是,模型正确识别出为正类的样本的数量占总的正类样本数量的比值。一般情况下,Recall越高,说明有更多的正类样本被模型预测正确,模型的效果越好。

Recall = TP/(TP+FN)

查准率和查全率是一对矛盾的指标。一般来说,查准率高时,查全率旺旺偏低;二查全率高时,查准率往往偏低。

(4 )精确率(Accuracy)和正确率(Precision)的区别
Accuracy,不管是哪个类别,只要预测正确,其数量都放在分子上,而分母是全部数据量,说明这个精确率是对全部数据的判断。

而正确率在分类中对应的是某个类别,分子是预测该类别正确的数量,分母是预测为该类别的全部的数量。

或者说,Accuracy是对分类器整体上的精确率的评价,而Precision是分类器预测为某一个类别的精确的评价。

(5)Specificity(特异性)
特异性指标,表示的是模型识别为负类的样本的数量,占总的负类样本数量的比值。

负正类率(False Positive Rate, FPR),计算公式为:FPR=FP/(TN+FP),计算的是模型错识别为正类的负类样本占所有负类样本的比例,一般越低越好。

Specificity = 1 - FPR

1.1.2 P-R曲线

P-R的关系曲线图表示了召回率和准确率之间的关系,精度(准确率)越高,召回率越低

1.1.3 AP计算

mAP :均值平均准确率
AP=\sum_{k=1}^NP(k)\Delta r(k)
其中 𝑁 代表测试集中所有图片的个数, 𝑃(𝑘) 表示在能识别出 𝑘 个图片的时候
Precision的值,而 Δ𝑟(𝑘) 则表示识别图片个数从 𝑘 − 1 变化到 𝑘 时(通过调整阈
值)Recall值的变化情况

2.目标检测与YOLO

目标检测是在给定的图片中精确找到物体所在位置,并标注出物体的类别。
物体的尺寸变化范围很大,摆放物体的角度,姿态不定,而且可以出现在图
片的任何地方,并且物体还可以是多个类别。

2.1语义分割

语义分割可以看做一个分类模型,唯一复杂的地方在于需要给图像中的每个像素进行分类。

分类模型一般都是接受相同大小的输入图像,摒弃空间坐标。其使用的全连接层可以被看成一个核能够覆盖全部元素的卷积层。

所以,是否能使用全卷积网络来替代全连接网络呢?

答案是可以的,使用全卷积网络还避免了必须使用“相同大小的输入”的需求,两个网络的转换如图 2 所示。

FCN 方法是第一个基于深度学习的分割方法,只包含卷积层,可以输入任意大小的图然后生成其分割结果图。

贡献:该方法是图像分割的一个重要的转折点,证明了深度学习网络可以端到端的实现对不同大小图像的语义分割。

缺点:FCN 模型速度较慢,无法支持实时的语义分割;没有考虑全局上下文信息;无法方便的扩展到 3D 图像。

3.1风格迁移

首先,我们初始化合成图像,例如将其初始化成内容图像。该合成图 像是样式迁移过程中唯一需要更新的变量,即样式迁移所需迭代的模 型参数。
然后,我们选择一个预训练的卷积神经网络来抽取图像的特征,其中 的模型参数在训练中无须更新。深度卷积神经网络凭借多个层逐级抽 取图像的特征。我们可以选择其中某些层的输出作为内容特征或样式 特征。

样式迁移常用的损失函数由3部分组成:
内容损失(content loss)使合成图像与内容图像在内容特征上接近
样式损失(style loss)令合成图像与样式图像在样式特征上接近
总变差损失(total variation loss)则有助于减少合成图像中的噪点。
最后,当模型训练结束时,我们输出样式迁移的模型参数,即得到最终 的合成图像。

3.1.1内容代价函数

选定隐藏层 l ,用 𝑎 𝑙 [𝐶] 表示图片C在第l层的激活项输出, 𝑎 𝑙 [G] 表 示图片G在第l 层的激活项输出,则定义内容代价函数如下:
J_{content}(C,G)=||a^{[l](C)}-a^{[l](G)}||_2^2

3.1.2 风格代价函数

$G_{k_1k_2}^{[l](X)}=\sum_{i=1}^{n_H^{[l]}}\sum_{j=1}^{n_W^{[l]}}(a_{i,j,k_1}^{[l](X)}\cdot a_{i,j,k_2}^{[l](X)})\\G^{[l](X)}=\begin{bmatrix}G_{11}^{[l](X)}&\cdots&G_{1n_c^{[l]}}^{[l](X)}\\\vdots&\ddots&\vdots\\G_{n_c^{[l]}1}^{[l](X)}&\cdots&G_{n_c^{[l]}n_c^{[l]}}^{[l](X)}\end{bmatrix}$
J_{style}^{[l]}(S,G)=\frac{1}{\left(2n_{H}^{[l]}n_{W}^{[l]}n_{C}^{[l]}\right)^{2}}\sum_{k}\sum_{k'}(G_{kk'}^{[l](S)}-G_{kk'}^{[l](G)})
$J_{style}(S,G)=\sum_l\lambda^{[l]}J_{style}^{[l]}(S,G)$

3.1.3 总体代价函数

J(G)=\alpha J_{content}(G)+\beta J_{style}(G)
代码
import time
import torch
import torchvision
from torch import nn
from d2l import torch as d2l
d2l.set_figsize()
content_img = d2l.Image.open('C:/Users/Lenovo/Desktop/d2l-zh/pytorch/img/rainier.jpg')
d2l.plt.imshow(content_img);
style_img = d2l.Image.open('C:/Users/Lenovo/Desktop/d2l-zh/pytorch/img/autumn-oak.jpg')
d2l.plt.imshow(style_img);
rgb_mean = torch.tensor([0.485, 0.456, 0.406])
rgb_std = torch.tensor([0.229, 0.224, 0.225])
def preprocess(img, image_shape):
    transforms = torchvision.transforms.Compose([
        torchvision.transforms.Resize(image_shape),
        torchvision.transforms.ToTensor(),
        torchvision.transforms.Normalize(mean=rgb_mean, std=rgb_std)])
    return transforms(img).unsqueeze(0)
def postprocess(img):
    img = img[0].to(rgb_std.device)
    img = torch.clamp(img.permute(1, 2, 0) * rgb_std + rgb_mean, 0, 1)
    return torchvision.transforms.ToPILImage()(img.permute(2, 0, 1))
pretrained_net = torchvision.models.vgg19(pretrained=True)
style_layers, content_layers = [0, 5, 10, 19, 28], [25]
net = nn.Sequential(*[pretrained_net.features[i] for i in
                     range(max(content_layers + style_layers) + 1)])
def extract_features(X, content_layers, style_layers):
    contents = []
    styles = []
    for i in range(len(net)):
        X = net[i](X)
        if i in style_layers:
             styles.append(X)
        if i in content_layers:
            contents.append(X)
    return contents, styles
def get_contents(image_shape, device):
    content_X = preprocess(content_img, image_shape).to(device)
    contents_Y, _ = extract_features(content_X, content_layers, style_layers)
    return content_X, contents_Y
def get_styles(image_shape, device):
    style_X = preprocess(style_img, image_shape).to(device)
    _, styles_Y = extract_features(style_X, content_layers, style_layers)
    return style_X, styles_Y
def content_loss(Y_hat, Y):
    # 我们从动态计算梯度的树中分离目标:
    # 这是一个规定的值,而不是一个变量。
    return torch.square(Y_hat - Y.detach()).mean()
def gram(X):
    num_channels, n = X.shape[1], X.numel() // X.shape[1]
    X = X.reshape((num_channels, n))
    return torch.matmul(X, X.T) / (num_channels * n)
def style_loss(Y_hat, gram_Y):
    return torch.square(gram(Y_hat) - gram_Y.detach()).mean()
def tv_loss(Y_hat):
    return 0.5 * (torch.abs(Y_hat[:, :, 1:, :] - Y_hat[:, :, :-1, :]).mean() +
                  torch.abs(Y_hat[:, :, :, 1:] - Y_hat[:, :, :, :-1]).mean())
content_weight, style_weight, tv_weight = 1, 1e3, 10
def compute_loss(X, contents_Y_hat, styles_Y_hat, contents_Y, styles_Y_gram):
    # 分别计算内容损失、风格损失和全变分损失
    contents_l = [content_loss(Y_hat, Y) * content_weight for Y_hat, Y in zip(
        contents_Y_hat, contents_Y)]
    styles_l = [style_loss(Y_hat, Y) * style_weight for Y_hat, Y in zip(
        styles_Y_hat, styles_Y_gram)]
    tv_l = tv_loss(X) * tv_weight
    # 对所有损失求和
    l = sum(10 * styles_l + contents_l + [tv_l])
    return contents_l, styles_l, tv_l, l
class SynthesizedImage(nn.Module):
    def __init__(self, img_shape, **kwargs):
        super(SynthesizedImage, self).__init__(**kwargs)
        self.weight = nn.Parameter(torch.rand(*img_shape))
    def forward(self):
        return self.weight
def get_inits(X, device, lr, styles_Y):
    gen_img = SynthesizedImage(X.shape).to(device)
    gen_img.weight.data.copy_(X.data)
    trainer = torch.optim.Adam(gen_img.parameters(), lr=lr)
    styles_Y_gram = [gram(Y) for Y in styles_Y]
    return gen_img(), styles_Y_gram, trainer
def train(X, contents_Y, styles_Y, device, lr, num_epochs, lr_decay_epoch):
    X, styles_Y_gram, trainer = get_inits(X, device, lr, styles_Y)
    scheduler = torch.optim.lr_scheduler.StepLR(trainer, lr_decay_epoch, 0.8)
    animator = d2l.Animator(xlabel='epoch', ylabel='loss',
                            xlim=[10, num_epochs],
                            legend=['content', 'style', 'TV'],
                            ncols=2, figsize=(7, 2.5))
    for epoch in range(num_epochs):
        trainer.zero_grad()
        contents_Y_hat, styles_Y_hat = extract_features(
            X, content_layers, style_layers)
        contents_l, styles_l, tv_l, l = compute_loss(
            X, contents_Y_hat, styles_Y_hat, contents_Y, styles_Y_gram)
        l.backward()
        trainer.step()
        scheduler.step()
        if (epoch + 1) % 10 == 0:
           animator.axes[1].imshow(postprocess(X))
           animator.add(epoch + 1, [float(sum(contents_l)),
                                    float(sum(styles_l)), float(tv_l)])
    return X
device, image_shape = d2l.try_gpu(), (300, 450)
net = net.to(device)
content_X, contents_Y = get_contents(image_shape, device)
_, styles_Y = get_styles(image_shape, device)
output = train(content_X, contents_Y, styles_Y, device, 0.3, 500, 50)

样式迁移常用的损失函数由3部分组成:内容损失使合成图像与内容图 像在内容特征上接近,样式损失令合成图像与样式图像在样式特征上 接近,而总变差损失则有助于减少合成图像中的噪点。
可以通过预训练的卷积神经网络来抽取图像的特征,并通过最小化损 失函数来不断更新合成图像。
用格拉姆矩阵表达样式层输出的样式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值