【Deep Learning with Python】C5 Activation,Filter可视化

Activation

总的来说,拿到中间层次输出,用一张图片输入,可视化。如何获得中间层次。这一节的程序很有用。

  • 多输出模型

 

from keras import models

layer_outputs = [layer.output for layer in model.layers[:8]]

activation_model = models.Model(inputs=model.input, outputs=layer_outputs)

 

上述代码使用了8个中间层作为输出层。结果将返回一个8维的列表。

 

  • CNN特征抽取的理解更正

第一层

最后一层

观察到一个问题:前面的层次输出非常具体,后面的层次反而看不懂。这和我的直觉是相反的。

我理解的有问题

  • 前面的卷积核提取线段边缘特征之后,合并仍然会比较接近原图,但是后期的一个值可能就代表一整只猫
  • 后期的特征高度融合,会变得越来越复杂,越来越抽象。也可以这么理解,它会保持住越来越少的整体原图信息,却会获得越来越多关于本类别的信息。
  • 后期的卷积核所具备的捕获特征的能力会变得越来越强。
  • 越往后的activation激活的越少,这意味着,该卷积无法捕获相应信息。
  • 知识蒸馏

从这个角度来理解特征高度抽象过程。文中给出了人类的一种类比,比如单车,尽管我们看过无数单车,但是我们没有办法回忆起大部分细节。只能记住分把单车和其他东西区分开来的信息,换句话说,我们并不是只能记得个大概,我们的记忆只保留了关键信息,将无用的信息筛除掉。

Filter

卷积核可视化还是比较难理解的。每一个卷积核代表着一种特征。如果图像中某块区域与某个卷积核的结果越大,那么该区域就越“像”该卷积核。

这里使用了“梯度上升”的方式,随机输入,利用梯度,使得卷积核的输出最大,方便可视化。实现不是很好理解,因为涉及了很多底层的api。

上图为一部分卷积核的可视结果,不要和activation的可视化混淆。

可以看到,卷积核的可视化,很类似某些纹理,和傅里叶变换类似,卷积核就像一个个的三角函数,复合成复杂的图像。

 

def generate_pattern(layer_namefilter_indexsize=150):

    得到某层的输出activation

    layer_output = model.get_layer(layer_name).output

    定义损失,定义为输出均值

    loss = K.mean(layer_output[:, :, :, filter_index])

    梯度,计算损失关于输入的梯度,要注意,我们会让输入梯度上升

    grads = K.gradients(loss, model.input)[0]

    这一步是标准化

    grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)

    这是个有意思的函数,tf中定义好图,如何打包遍历,用到就是function

    iterate = K.function([model.input], [loss, grads])

    随机输入,利用梯度最大化,使其最终和filter非常像

    input_img_data = np.random.random((1, size, size, 3)) * 20 + 128.

    step = 1.

    for i in range(40):

        loss_value, grads_value = iterate([input_img_data])

        反梯度下降

        input_img_data += grads_value * step

    

    img = input_img_data[0]

    return deprocess_image(img)

 

可视化技巧

  • 大量展示

原理是新建一个大的数组,一个一个排上去,所以coding有些技巧。

 

size = 64

margin = 5

results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3))

for i in range(8):

for j in range(8):

filter_img = generate_pattern(layer_name, i + (j * 8), size=size)

i和j从0开始,刚好使得完美控制margin

horizontal_start = i * size + i * margin

horizontal_end = horizontal_start + size

vertical_start = j * size + j * margin

vertical_end = vertical_start + size

results[horizontal_start: horizontal_end,vertical_start: vertical_end, :] = filter_img

plt.figure(figsize=(20, 20))

plt.imshow(results)

 

 

  • 让数据可视化更加好看

 

def deprocess_image(x):

这两步是标准化

x -= x.mean()

x /= (x.std() + 1e-5)

这应该是一个放大因子

x *= 0.1

这一步是标准化中减去mean的逆操作

x += 0.5

防止超过范围

x = np.clip(x, 0, 1)

x *= 255

x = np.clip(x, 0, 255).astype('uint8')

return x

 

 

 

 

Reference

Main3.py

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值