【TensorFlow-windows】keras接口——卷积核可视化
前言
在機器之心上看到了關(guān)于卷積核可視化相關(guān)理論,但是作者的源代碼是基于fastai寫的,而fastai的底層是pytorch,本來準(zhǔn)備自己用Keras復(fù)現(xiàn)一遍的,但是尷尬地發(fā)現(xiàn)Keras還沒玩熟練,隨后發(fā)現(xiàn)了一個keras-vis包可以用于做卷積核可視化。以下理論是在不熟悉fastai的運行機制的基礎(chǔ)上做的簡單理解,可能有誤,歡迎指正。
國際慣例,參考博客:
40行Python代碼,實現(xiàn)卷積特征可視化
github:visualizing-cnn-feature-maps
Keras Visualization Toolkit
Keras官方可視化卷積核
理論
簡單概率為一句話就是:優(yōu)化輸入以最大化指定層特征圖的平均激活。
先貼一下GitHub上的可視化部分代碼:
class FilterVisualizer():def __init__(self, size=56, upscaling_steps=12, upscaling_factor=1.2):self.size, self.upscaling_steps, self.upscaling_factor = size, upscaling_steps, upscaling_factorself.model = vgg16(pre=True).cuda().eval()set_trainable(self.model, False)def visualize(self, layer, filter, lr=0.1, opt_steps=20, blur=None):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_grad=True) # convert image to Variable that requires gradoptimizer = torch.optim.Adam([img_var], lr=lr, weight_decay=1e-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))很容易發(fā)現(xiàn),可視化流程為:
- 載入訓(xùn)練好的模型,設(shè)置權(quán)重為不可訓(xùn)練
- 隨機初始化一個噪聲,預(yù)處理一下,并將其轉(zhuǎn)換為可訓(xùn)練張量,也就是可以對這個輸入求梯度,我們以前的神經(jīng)網(wǎng)絡(luò)是對權(quán)重求梯度去優(yōu)化權(quán)重,這里剛好反過來,是對輸入求梯度去優(yōu)化梯度
- 目標(biāo)損失就是想要可視化的卷積核對應(yīng)的特征圖的平均激活值。額外多一句嘴,都知道卷積核的大小是(m,n,s1,s2)(m,n,s1,s2)(m,n,s1,s2)大小,其中mmm是上一層特征圖數(shù)目,nnn是卷積核個數(shù)也是下一層特征圖的個數(shù),所以每一個卷積核對應(yīng)下一層特征圖其中的一個,也就說每個特征圖都是獨立的,只和與它相關(guān)的那一個卷積核有關(guān),我們想可視化第幾個卷積核,平均激活就這個卷積核對應(yīng)的特征圖的平均值。
- 接下來就是在一定迭代次數(shù)內(nèi)不斷更新對輸入求梯度并更新輸入值,這就是輸入從噪聲到特征響應(yīng)圖的可視化過程。
如果用公式表示就是:
input=input?learn_rate×?loss?inputinput=input - learn\_rate\times\frac{\partial loss}{\partial input} input=input?learn_rate×?input?loss?
區(qū)分于傳統(tǒng)的訓(xùn)練神經(jīng)網(wǎng)絡(luò)時候的:
w=w?learn_rata×?loss?ww=w-learn\_rata\times \frac{\partial loss}{\partial w} w=w?learn_rata×?w?loss?
至于外層還有一個循環(huán)是,迭代完opt_steps后,將當(dāng)前更新完的輸入resize成一個大點的尺寸,再迭代,如此反復(fù)折騰,至于原因,在機器之心的文章上有寫:
Keras-vis工具包的使用
預(yù)備工作
-
導(dǎo)入模型與載入權(quán)重
from keras.applications import VGG16 model=VGG16(weights='imagenet',include_top=True)查看模型每層的名字,以便后續(xù)可視化
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激活,本質(zhì)是將最后一層歸一化得到屬于每一類的概率,所以他的每個節(jié)點與其它節(jié)點相關(guān),這就是softmax的特殊性。反觀其它層,每個特征圖或者全連接的節(jié)點都是互相獨立的。所以為了消除最后一層受到softmax導(dǎo)致各節(jié)點不獨立的影響,在優(yōu)化的時候使用線性激活替代softmax激活,方法如下:
引入相關(guān)包:
from vis.utils import utils from keras import activations用名字找到最后一層的索引,并更改它的激活函數(shù)
layer_idx=utils.find_layer_idx(model=model,layer_name='predictions') model.layers[layer_idx].activation=activations.linear model=utils.apply_modifications(model)接下來就可以可視化了
引入相關(guān)包
from vis.visualization import visualize_activation import matplotlib.pyplot as plt不迭代可視化,結(jié)果不太整潔
img=visualize_activation(model,layer_idx=layer_idx,filter_indices=20) plt.imshow(img)迭代可視化,結(jié)果會整潔一點
img=visualize_activation(model,layer_idx=layer_idx,filter_indices=20,max_iter=500,verbose=False) plt.imshow(img)加入Jitter,獲得更好的可視化結(jié)果:
#得到更加干凈的可視化結(jié)果圖 from vis.input_modifiers import Jitter img=visualize_activation(model=model,layer_idx=layer_idx,filter_indices=20,max_iter=500,verbose=False,input_modifiers=[Jitter(16)]) plt.imshow(img)可視化任意層卷積核
以block3_conv3的第56個卷積核為例
layer_idx=utils.find_layer_idx(model=model,layer_name='block3_conv3') img=visualize_activation(model=model,layer_idx=layer_idx,filter_indices=56,verbose=False,input_modifiers=[Jitter(16)]) plt.imshow(img)
看著像餅干。
可視化響應(yīng)熱度圖
通過最后一層全連接層可視化可以發(fā)現(xiàn),第20個權(quán)重會響應(yīng)鳥嘴和上半身的羽毛,試試將一只鳥丟進去,看看最終響應(yīng)的部位。
先引入對應(yīng)包:
import numpy as np import matplotlib.cm as cm from vis.visualization import visualize_cam,overlay讀取圖像,以及三種顯示方案(區(qū)別我也不清楚,沒看):
img=utils.load_img('ouzel1.jpg',target_size=(224,224)) modifier=[None,'guided','relu']可視化
i=0 for m in modifier: plt.subplot(str(13)+str(i))layer_idx=utils.find_layer_idx(model=model,layer_name='predictions')grads=visualize_cam(model,layer_idx,filter_indices=20,seed_input=img,backprop_modifier=modifier[0])jet_heatmap=np.uint8(cm.jet(grads)[...,:3]*255)plt.imshow(overlay(jet_heatmap,img))i=i+1不太放心,再試試第379個節(jié)點響應(yīng)的什么,從類別標(biāo)簽上看,第379個標(biāo)簽是howler_monkey,應(yīng)該是一種猴子,可視化響應(yīng)內(nèi)容看看:
img=visualize_activation(model=model,layer_idx=layer_idx,filter_indices=379,max_iter=300,verbose=False,input_modifiers=[Jitter(16)]) plt.imshow(img)看著像猴子,應(yīng)該有猴臉和尾巴。
找一張猴子
看看響應(yīng)情況:
Bingo~~!!響應(yīng)了猴子臉
后記
此博客只介紹了Keras_vis包中的部分功能,其余功能以后有機會再探索,博客介紹的卷積核可視化與響應(yīng)熱度圖還是比較有用的。
博客代碼:
百度網(wǎng)盤鏈接:https://pan.baidu.com/s/1SpcSoPkQE6aWx2HfoXX-Aw
提取碼:xuox
好久沒寫博客, 逃~~
總結(jié)
以上是生活随笔為你收集整理的【TensorFlow-windows】keras接口——卷积核可视化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阴阳师樱花妖御魂搭配 樱花妖技能解析
- 下一篇: 轩辕剑之天之痕盘古技能介绍 天赋详解及阵