宁波哪家做网站好,福州网站的优化,视频营销成功的案例,汽配公司的网站要怎么做前言
在机器之心上看到了关于卷积核可视化相关理论#xff0c;但是作者的源代码是基于fastai写的#xff0c;而fastai的底层是pytorch#xff0c;本来准备自己用Keras复现一遍的#xff0c;但是尴尬地发现Keras还没玩熟练#xff0c;随后发现了一个keras-vis包可以用于做…前言
在机器之心上看到了关于卷积核可视化相关理论但是作者的源代码是基于fastai写的而fastai的底层是pytorch本来准备自己用Keras复现一遍的但是尴尬地发现Keras还没玩熟练随后发现了一个keras-vis包可以用于做卷积核可视化。以下理论是在不熟悉fastai的运行机制的基础上做的简单理解可能有误欢迎指正。
国际惯例参考博客
40行Python代码实现卷积特征可视化
github:visualizing-cnn-feature-maps
Keras Visualization Toolkit
Keras官方可视化卷积核
理论
简单概率为一句话就是:优化输入以最大化指定层特征图的平均激活。
先贴一下GitHub上的可视化部分代码
class FilterVisualizer():def __init__(self, size56, upscaling_steps12, upscaling_factor1.2):self.size, self.upscaling_steps, self.upscaling_factor size, upscaling_steps, upscaling_factorself.model vgg16(preTrue).cuda().eval()set_trainable(self.model, False)def visualize(self, layer, filter, lr0.1, opt_steps20, blurNone):sz self.sizeimg np.uint8(np.random.uniform(150, 180, (sz, sz, 3)))/255 # generate random imageactivations SaveFeatures(list(self.model.children())[layer]) # register hookfor _ in range(self.upscaling_steps): # scale the image up upscaling_steps timestrain_tfms, val_tfms tfms_from_model(vgg16, sz)img_var V(val_tfms(img)[None], requires_gradTrue) # convert image to Variable that requires gradoptimizer torch.optim.Adam([img_var], lrlr, weight_decay1e-6)for n in range(opt_steps): # optimize pixel values for opt_steps timesoptimizer.zero_grad()self.model(img_var)loss -activations.features[0, filter].mean()loss.backward()optimizer.step()img val_tfms.denorm(img_var.data.cpu().numpy()[0].transpose(1,2,0))self.output imgsz int(self.upscaling_factor * sz) # calculate new image sizeimg cv2.resize(img, (sz, sz), interpolation cv2.INTER_CUBIC) # scale image upif blur is not None: img cv2.blur(img,(blur,blur)) # blur image to reduce high frequency patternsself.save(layer, filter)activations.close()def save(self, layer, filter):plt.imsave(layer_str(layer)_filter_str(filter).jpg, np.clip(self.output, 0, 1))很容易发现可视化流程为
载入训练好的模型设置权重为不可训练随机初始化一个噪声预处理一下并将其转换为可训练张量也就是可以对这个输入求梯度我们以前的神经网络是对权重求梯度去优化权重这里刚好反过来是对输入求梯度去优化梯度目标损失就是想要可视化的卷积核对应的特征图的平均激活值。额外多一句嘴都知道卷积核的大小是(m,n,s1,s2)(m,n,s1,s2)(m,n,s1,s2)大小其中mmm是上一层特征图数目nnn是卷积核个数也是下一层特征图的个数所以每一个卷积核对应下一层特征图其中的一个也就说每个特征图都是独立的只和与它相关的那一个卷积核有关我们想可视化第几个卷积核平均激活就这个卷积核对应的特征图的平均值。接下来就是在一定迭代次数内不断更新对输入求梯度并更新输入值这就是输入从噪声到特征响应图的可视化过程。
如果用公式表示就是 inputinput−learn_rate×∂loss∂inputinputinput - learn\_rate\times\frac{\partial loss}{\partial input} inputinput−learn_rate×∂input∂loss 区分于传统的训练神经网络时候的 ww−learn_rata×∂loss∂www-learn\_rata\times \frac{\partial loss}{\partial w} ww−learn_rata×∂w∂loss 至于外层还有一个循环是迭代完opt_steps后将当前更新完的输入resize成一个大点的尺寸再迭代如此反复折腾至于原因在机器之心的文章上有写
我们现在有了一个分辨率好得多的低频模式并且没有太多的噪音。为什么这样做会有用呢我的想法是当我们从低分辨率开始时我们会得到低频模式。放大后放大后的模式图相比直接用大尺度图像优化生成的模式图有较低的频率。因此在下一次迭代中优化像素值时我们处于一个更好的起点看起来避免了局部最小值。这有意义吗为了进一步减少高频模式我在放大后稍微模糊了图像。
我发现以 1.2 的倍数放大 12 次之后得到的结果不错。Keras-vis工具包的使用
预备工作 导入模型与载入权重 from keras.applications import VGG16
modelVGG16(weightsimagenet,include_topTrue)查看模型每层的名字以便后续可视化 model.summary()输出 Layer (type) Output Shape Param # input_1 (InputLayer) (None, 224, 224, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, 28, 28, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, 14, 14, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 7, 7, 512) 0
_________________________________________________________________
flatten (Flatten) (None, 25088) 0
_________________________________________________________________
fc1 (Dense) (None, 4096) 102764544
_________________________________________________________________
fc2 (Dense) (None, 4096) 16781312
_________________________________________________________________
predictions (Dense) (None, 1000) 4097000 Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0可视化最后一层全连接层
因为最后一层是全连接层使用softmax激活本质是将最后一层归一化得到属于每一类的概率所以他的每个节点与其它节点相关这就是softmax的特殊性。反观其它层每个特征图或者全连接的节点都是互相独立的。所以为了消除最后一层受到softmax导致各节点不独立的影响在优化的时候使用线性激活替代softmax激活方法如下:
引入相关包
from vis.utils import utils
from keras import activations用名字找到最后一层的索引并更改它的激活函数
layer_idxutils.find_layer_idx(modelmodel,layer_namepredictions)
model.layers[layer_idx].activationactivations.linear
modelutils.apply_modifications(model)接下来就可以可视化了
引入相关包
from vis.visualization import visualize_activation
import matplotlib.pyplot as plt不迭代可视化结果不太整洁
imgvisualize_activation(model,layer_idxlayer_idx,filter_indices20)
plt.imshow(img)迭代可视化结果会整洁一点
imgvisualize_activation(model,layer_idxlayer_idx,filter_indices20,max_iter500,verboseFalse)
plt.imshow(img)加入Jitter获得更好的可视化结果
#得到更加干净的可视化结果图
from vis.input_modifiers import Jitter
imgvisualize_activation(modelmodel,layer_idxlayer_idx,filter_indices20,max_iter500,verboseFalse,input_modifiers[Jitter(16)])
plt.imshow(img)可视化任意层卷积核
以block3_conv3的第56个卷积核为例
layer_idxutils.find_layer_idx(modelmodel,layer_nameblock3_conv3)
imgvisualize_activation(modelmodel,layer_idxlayer_idx,filter_indices56,verboseFalse,input_modifiers[Jitter(16)])
plt.imshow(img)看着像饼干。
可视化响应热度图
通过最后一层全连接层可视化可以发现第20个权重会响应鸟嘴和上半身的羽毛试试将一只鸟丢进去看看最终响应的部位。
先引入对应包
import numpy as np
import matplotlib.cm as cm
from vis.visualization import visualize_cam,overlay读取图像以及三种显示方案(区别我也不清楚没看)
imgutils.load_img(ouzel1.jpg,target_size(224,224))
modifier[None,guided,relu]可视化
i0
for m in modifier: plt.subplot(str(13)str(i))layer_idxutils.find_layer_idx(modelmodel,layer_namepredictions)gradsvisualize_cam(model,layer_idx,filter_indices20,seed_inputimg,backprop_modifiermodifier[0])jet_heatmapnp.uint8(cm.jet(grads)[...,:3]*255)plt.imshow(overlay(jet_heatmap,img))ii1不太放心再试试第379个节点响应的什么从类别标签上看第379个标签是howler_monkey应该是一种猴子可视化响应内容看看
imgvisualize_activation(modelmodel,layer_idxlayer_idx,filter_indices379,max_iter300,verboseFalse,input_modifiers[Jitter(16)])
plt.imshow(img)看着像猴子应该有猴脸和尾巴。 找一张猴子 看看响应情况
imgutils.load_img(monkey.jpg,target_size(224,224))
i0
for m in modifier: plt.subplot(str(13)str(i))layer_idxutils.find_layer_idx(modelmodel,layer_namepredictions)gradsvisualize_cam(model,layer_idx,filter_indices379,seed_inputimg,backprop_modifiermodifier[0])jet_heatmapnp.uint8(cm.jet(grads)[...,:3]*255)plt.imshow(overlay(jet_heatmap,img))ii1Bingo~~响应了猴子脸
后记
此博客只介绍了Keras_vis包中的部分功能其余功能以后有机会再探索博客介绍的卷积核可视化与响应热度图还是比较有用的。
博客代码
百度网盘链接https://pan.baidu.com/s/1SpcSoPkQE6aWx2HfoXX-Aw 提取码xuox
好久没写博客 逃~~