一份可視化特征圖的代碼
點(diǎn)擊下方“AI算法與圖像處理”,一起進(jìn)步!
重磅干貨,第一時(shí)間送達(dá)
前言?本文給大家分享一份我用的特征圖可視化代碼。
寫在前面的話
特征圖可視化是很多論文所需要做的一份工作,其作用可以是用于證明方法的有效性,也可以是用來增加工作量,給論文湊字?jǐn)?shù)。
具體來說就是可視化兩個(gè)圖,使用了新方法的和使用之前的,對(duì)比有什么區(qū)別,然后看圖寫論文說明新方法體現(xiàn)的作用。
吐槽一句,有時(shí)候這個(gè)圖 論文作者自己都不一定能看不懂,雖然確實(shí)可視化的圖有些改變,但并不懂這個(gè)改變說明了什么,反正就吹牛,強(qiáng)行往自己新方法編的故事上扯,就像小學(xué)一年級(jí)的作文題--看圖寫作文。
之前知乎上有一個(gè)很熱門的話題,如果我在baseline上做了一點(diǎn)小小的改進(jìn),卻有很大的效果,這能寫論文嗎?
這種情況最大的問題就在于要如何寫七頁以上,那一點(diǎn)點(diǎn)的改進(jìn)可能寫完思路,公式推理,畫圖等內(nèi)容才花了不到一頁,剩下的內(nèi)容如何搞?可視化特征圖!!!
這一點(diǎn)可以在我看過的甚多論文上有所體現(xiàn),反正我是沒看明白論文給的可視化圖,作者卻能扯那么多道道。這應(yīng)該就是用來增加論文字?jǐn)?shù)和增加工作量的。
總之一句話,可視化特征圖是很重要的工作,最好要會(huì)。
初始化配置
這部分先完成加載數(shù)據(jù),修改網(wǎng)絡(luò),定義網(wǎng)絡(luò),加載預(yù)訓(xùn)練模型。
加載數(shù)據(jù)并預(yù)處理
這里只加載一張圖片,就不用通過classdataset了,因?yàn)閏lassdataset是針對(duì)大量數(shù)據(jù)的,生成一個(gè)迭代器一批一批地將圖片送給網(wǎng)絡(luò)。但我們?nèi)匀灰瓿蒫lassdataset中數(shù)據(jù)預(yù)處理的部分。
數(shù)據(jù)預(yù)處理所必須要有的操作是調(diào)整大小,轉(zhuǎn)化為Tensor格式,歸一化。至于其它數(shù)據(jù)增強(qiáng)或預(yù)處理的操作,自己按需添加。
def?image_proprecess(img_path):
????img?=?Image.open(img_path)
????data_transforms?=?transforms.Compose([
????????transforms.Resize((384,?384),?interpolation=3),
????????transforms.ToTensor(),
????????transforms.Normalize([0.485,?0.456,?0.406],?[0.229,?0.224,?0.225])
????????])
????data?=?data_transforms(img)
????data?=?torch.unsqueeze(data,0)
????return?data
修改網(wǎng)絡(luò)
假如你要可視化某一層的特征圖,則需要將該層的特征圖返回出來,因此需要先修改網(wǎng)絡(luò)中的forward函數(shù)。具體修改方式如下所示。
def?forward(self,?x):
????x?=?self.model.conv1(x)
????x?=?self.model.bn1(x)
????x?=?self.model.relu(x)
????x?=?self.model.maxpool(x)
????feature?=?self.model.layer1(x)
????x?=?self.model.layer2(feature)
????x?=?self.model.layer3(x)
????x?=?self.model.layer4(x)
????return feature,x
定義網(wǎng)絡(luò)并加載預(yù)訓(xùn)練模型
def?Init_Setting(epoch):
????dirname?=?'/mnt/share/VideoReID/share/models/Methods5_trial1'
????model?=?siamese_resnet50(701,?stride=1,?pool='avg')
????trained_path?=?os.path.join(dirname,?'net_%03d.pth'?%?epoch)
????print("load?%03d.pth"?%?epoch)
????model.load_state_dict(torch.load(trained_path))
????model?=?model.cuda().eval()
????return?model
可視化特征圖
這部分主要是將特征圖的某一通道轉(zhuǎn)化為一張圖來可視化。
def?visualize_feature_map(img_batch,out_path,type,BI):
????feature_map?=?torch.squeeze(img_batch)
????feature_map?=?feature_map.detach().cpu().numpy()
????feature_map_sum?=?feature_map[0,?:,?:]
????feature_map_sum?=?np.expand_dims(feature_map_sum,?axis=2)
????for?i?in?range(0,?2048):
????????feature_map_split?=?feature_map[i,:,?:]
????????feature_map_split?=?np.expand_dims(feature_map_split,axis=2)
????????if?i?>?0:
????????????feature_map_sum?+=feature_map_split
????????feature_map_split?=?BI.transform(feature_map_split)
????????plt.imshow(feature_map_split)
????????plt.savefig(out_path?+?str(i)?+?"_{}.jpg".format(type)?)
????????plt.xticks()
????????plt.yticks()
????????plt.axis('off')
????feature_map_sum?=?BI.transform(feature_map_sum)
????plt.imshow(feature_map_sum)
????plt.savefig(out_path?+?"sum_{}.jpg".format(type))
????print("save?sum_{}.jpg".format(type))
這里一行一行來解釋。
1. 參數(shù)img_batch是從網(wǎng)絡(luò)中的某一層傳回來的特征圖,BI是雙線性插值的函數(shù),自定義的,下面會(huì)講。
2. 由于只可視化了一張圖片,因此img_batch是四維的,且batchsize維為1。第三行將它從GPU上弄到CPU上,并變成numpy格式。
3. 剩下部分主要完成將每個(gè)通道變成一張圖,以及將所有通道每個(gè)元素對(duì)應(yīng)位置相加,并保存。
雙線性插值
由于經(jīng)過多次網(wǎng)絡(luò)降采樣,后面層的特征圖往往變得只有7x7,16x16大小。可視化后特別小,因此需要將它上采樣,這里采樣的方式是雙線性插值。因此,這里給一份雙線性插值的代碼。
class?BilinearInterpolation(object):
????def?__init__(self,?w_rate:?float,?h_rate:?float,?*,?align='center'):
????????if?align?not?in?['center',?'left']:
????????????logging.exception(f'{align}?is?not?a?valid?align?parameter')
????????????align?=?'center'
????????self.align?=?align
????????self.w_rate?=?w_rate
????????self.h_rate?=?h_rate
????def?set_rate(self,w_rate:?float,?h_rate:?float):
????????self.w_rate?=?w_rate????#?w?的縮放率
????????self.h_rate?=?h_rate????#?h?的縮放率
????#?由變換后的像素坐標(biāo)得到原圖像的坐標(biāo)????針對(duì)高
????def?get_src_h(self,?dst_i,source_h,goal_h)?->?float:
????????if?self.align?==?'left':
????????????#?左上角對(duì)齊
????????????src_i?=?float(dst_i?*?(source_h/goal_h))
????????elif?self.align?==?'center':
????????????#?將兩個(gè)圖像的幾何中心重合。
????????????src_i?=?float((dst_i?+?0.5)?*?(source_h/goal_h)?-?0.5)
????????src_i?+=?0.001
????????src_i?=?max(0.0,?src_i)
????????src_i?=?min(float(source_h?-?1),?src_i)
????????return?src_i
????#?由變換后的像素坐標(biāo)得到原圖像的坐標(biāo)????針對(duì)寬
????def?get_src_w(self,?dst_j,source_w,goal_w)?->?float:
????????if?self.align?==?'left':
????????????#?左上角對(duì)齊
????????????src_j?=?float(dst_j?*?(source_w/goal_w))
????????elif?self.align?==?'center':
????????????#?將兩個(gè)圖像的幾何中心重合。
????????????src_j?=?float((dst_j?+?0.5)?*?(source_w/goal_w)?-?0.5)
????????src_j?+=?0.001
????????src_j?=?max(0.0,?src_j)
????????src_j?=?min((source_w?-?1),?src_j)
????????return?src_j
????def?transform(self,?img):
????????source_h,?source_w,?source_c?=?img.shape??#?(235,?234,?3)
????????goal_h,?goal_w?=?round(
????????????source_h?*?self.h_rate),?round(source_w?*?self.w_rate)
????????new_img?=?np.zeros((goal_h,?goal_w,?source_c),?dtype=np.uint8)
????????for?i?in?range(new_img.shape[0]):???????#?h
????????????src_i?=?self.get_src_h(i,source_h,goal_h)
????????????for?j?in?range(new_img.shape[1]):
????????????????src_j?=?self.get_src_w(j,source_w,goal_w)
????????????????i2?=?ceil(src_i)
????????????????i1?=?int(src_i)
????????????????j2?=?ceil(src_j)
????????????????j1?=?int(src_j)
????????????????x2_x?=?j2?-?src_j
????????????????x_x1?=?src_j?-?j1
????????????????y2_y?=?i2?-?src_i
????????????????y_y1?=?src_i?-?i1
????????????????new_img[i,?j]?=?img[i1,?j1]*x2_x*y2_y?+?img[i1,?j2]?*?\
????????????????????x_x1*y2_y?+?img[i2,?j1]*x2_x*y_y1?+?img[i2,?j2]*x_x1*y_y1
????????return?new_img
#使用方法
BI?=?BilinearInterpolation(8,?8)
feature_map?=?BI.transform(feature_map)
main函數(shù)流程
上面介紹了各個(gè)部分的代碼,下面就是整體流程。比較簡(jiǎn)單。
imgs_path?=?"/path/to/imgs/"
save_path?=?"/save/path/to/output/"
model?=?Init_Setting(120)
BI?=?BilinearInterpolation(8,?8)
data?=?image_proprecess(out_path?+?"0836.jpg")
data?=?data.cuda()
output,?_?=?model(data)
visualize_feature_map(output,?save_path,?"drone",?BI)
可視化效果圖

交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有美顏、三維視覺、計(jì)算攝影、檢測(cè)、分割、識(shí)別、NeRF、GAN、算法競(jìng)賽等微信群
個(gè)人微信(如果沒有備注不拉群!) 請(qǐng)注明:地區(qū)+學(xué)校/企業(yè)+研究方向+昵稱
下載1:何愷明頂會(huì)分享
在「AI算法與圖像處理」公眾號(hào)后臺(tái)回復(fù):何愷明,即可下載。總共有6份PDF,涉及 ResNet、Mask RCNN等經(jīng)典工作的總結(jié)分析
下載2:終身受益的編程指南:Google編程風(fēng)格指南
在「AI算法與圖像處理」公眾號(hào)后臺(tái)回復(fù):c++,即可下載。歷經(jīng)十年考驗(yàn),最權(quán)威的編程規(guī)范!
下載3 CVPR2021 在「AI算法與圖像處理」公眾號(hào)后臺(tái)回復(fù):CVPR,即可下載1467篇CVPR?2020論文 和 CVPR 2021 最新論文

