[论文笔记]The Unreasonable Effectiveness of Deep Features as a Perceptual Metric

Title

The Unreasonable Effectiveness of Deep Features as a Perceptual Metric


Information

论文地址:https://arxiv.org/abs/1801.03924?context=cs

github地址:

Summary

作者发现传统的计算图像差距的评价标准不符合人的感知,针对这一情况,他通过传统方法和深度学习的比较,发现能用于视觉任务的深度网络在感知上更加准确。因此基于深度网络提出了Learned Perceptual Image Patch Similarity(LPIPS)的评价标准。

Research Objective

提出一种能准确评价图像间差距的评价标准

Problem Statement

常用的图像相似度评价标准如L2/PSNR/SSIM/FSIM等和人类感知并不相符


image

Method(s)

作者根据深度学习网络计算感知距离


image
image

参考图x, 变形图片x0,通过深度网络F获取距离的方法:

  1. 从深度学习的L层中提取特征,在通道维度上单位归一化,记作y,y0。其中第l层记作\hat{y}^l, \hat{y}_0^l,维度是H_l×W_l×C_l
  2. 将第l层的激活层结果利用向量w_l缩放,w_l维度是C_l
  3. 计算l2距离
  4. 将所有通道的结果和在空间的所有层上求平均

其中利用w缩放和计算余弦距离是等价的
image

Evaluation

分别和传统方法和CNN-based方法做比较。实验结果如下图。 其中CNN-based又有三种获得权重的方式

  • lin:获得预训练网络,top训练,其它层固定
  • tune: 获得预训练网络,全部训练
  • scratch:初始化为高斯分布的权重重新训练
image

Conclusion

  1. 解决视觉任务的模型经过训练都能获得对图像感知评价的能力。模型特征越能用于分类和检测,模型的感知能力越强
  2. 提供了一个数据集,包括484K个人类的感知判断

Code

一个简单易理解的pytorch实践,代码来源:https://github.com/S-aiueo32/lpips-pytorch
使用LPIPS loss的外层接口如下。

from lpips_pytorch import LPIPS

# define as a criterion module
criterion = LPIPS(
    net_type='alex',  # choose a network type from ['alex', 'squeeze', 'vgg']
    version='0.1'  # Currently, v0.1 is supported
)
loss = criterion(x, y)

构建LPIPS层如下。

class LPIPS(nn.Module):
    r"""Creates a criterion that measures
    Learned Perceptual Image Patch Similarity (LPIPS).

    Arguments:
        net_type (str): the network type to compare the features: 
                        'alex' | 'squeeze' | 'vgg'. Default: 'alex'.
        version (str): the version of LPIPS. Default: 0.1.
    """
    def __init__(self, net_type: str = 'alex', version: str = '0.1'):

        assert version in ['0.1'], 'v0.1 is only supported now'

        super(LPIPS, self).__init__()

        # pretrained network
        self.net = get_network(net_type) # 获取预训练网络,如AlexNet
        '''
        AlexNet(
          (layers): Sequential(
            (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
            (1): ReLU(inplace)
            (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
            (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
            (4): ReLU(inplace)
            (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
            (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
            (7): ReLU(inplace)
            (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
            (9): ReLU(inplace)
            (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
            (11): ReLU(inplace)
            (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
          )
        )
        '''

        # linear layers
        self.lin = LinLayers(self.net.n_channels_list) # 根据alexnet的通道数建立一个5层网络,不参与训练,获得每一层的特征距离后对应输入lin网络,之后就是基于这五层计算lpips loss。下文有代码
        self.lin.load_state_dict(get_state_dict(net_type, version)) # 从论文作者的github仓库中获取预训练网络的权重并加载

    def forward(self, x: torch.Tensor, y: torch.Tensor):
        feat_x, feat_y = self.net(x), self.net(y) # 获取特征, 输入(Bs,C,H,W),输出(5,channel, H, W),后三维不统一

        diff = [(fx - fy) ** 2 for fx, fy in zip(feat_x, feat_y)] # 基于每层网络计算特征间的l2距离(共5层)
        res = [l(d).mean((2, 3), True) for d, l in zip(diff, self.lin)] # 算每层网络基于通道的l2距离平均值

        return torch.sum(torch.cat(res, 0), 0, True) # 计算所有层的距离和

其中LinLayers的实现如下:

class LinLayers(nn.ModuleList):
    def __init__(self, n_channels_list: Sequence[int]):
        super(LinLayers, self).__init__([
            nn.Sequential(
                nn.Identity(), # 一个什么都不做的层,用来保存数据,通常用在保存输入、残差学习中
                nn.Conv2d(nc, 1, 1, 1, 0, bias=False)
            ) for nc in n_channels_list
        ])

        for param in self.parameters():
            param.requires_grad = False # 固定住权重,不参与训练

get_state_dict的实现如下:

def get_state_dict(net_type: str = 'alex', version: str = '0.1'):
    # build url
    url = 'https://github.com/richzhang/PerceptualSimilarity/' \
        + f'tree/master/models/weights/v{version}/{net_type}.pth'

    # download
    old_state_dict = torch.hub.load_state_dict_from_url(
        url, progress=True,
        map_location=None if torch.cuda.is_available() else torch.device('cpu')
    ) # 从作者的github开源仓库中获取权重


    # rename keys
    new_state_dict = OrderedDict()
    for key, val in old_state_dict.items():
        new_key = key
        new_key = new_key.replace('lin', '')
        new_key = new_key.replace('model.', '')
        new_state_dict[new_key] = val

    return new_state_dict
    
'''
LinLayers(
  (0): Sequential(
    (0): Identity()
    (1): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1), bias=False)
  )
  (1): Sequential(
    (0): Identity()
    (1): Conv2d(192, 1, kernel_size=(1, 1), stride=(1, 1), bias=False)
  )
  (2): Sequential(
    (0): Identity()
    (1): Conv2d(384, 1, kernel_size=(1, 1), stride=(1, 1), bias=False)
  )
  (3): Sequential(
    (0): Identity()
    (1): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1), bias=False)
  )
  (4): Sequential(
    (0): Identity()
    (1): Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1), bias=False)
  )
)
'''
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352