利用Pytorch實(shí)現(xiàn)獲取特征圖的方法詳解
簡單加載官方預(yù)訓(xùn)練模型
torchvision.models預(yù)定義了很多公開的模型結(jié)構(gòu)
如果pretrained參數(shù)設(shè)置為False,那么僅僅設(shè)定模型結(jié)構(gòu);如果設(shè)置為True,那么會啟動一個(gè)下載流程,下載預(yù)訓(xùn)練參數(shù)
如果只想調(diào)用模型,不想訓(xùn)練,那么設(shè)置model.eval()和model.requires_grad_(False)
想查看模型參數(shù)可以使用modules和named_modules,其中named_modules是一個(gè)長度為2的tuple,第一個(gè)變量是name,第二個(gè)變量是module本身。
# -*- coding: utf-8 -*-
from torch import nn
from torchvision import models
# load model. If pretrained is True, there will be a downloading process
model = models.vgg19(pretrained=True)
model.eval()
model.requires_grad_(False)
# get model component
features = model.features
modules = features.modules()
named_modules = features.named_modules()
# print modules
for module in modules:
if isinstance(module, nn.Conv2d):
weight = module.weight
bias = module.bias
print(module, weight.shape, bias.shape,
weight.requires_grad, bias.requires_grad)
elif isinstance(module, nn.ReLU):
print(module)
print()
for named_module in named_modules:
name = named_module[0]
module = named_module[1]
if isinstance(module, nn.Conv2d):
weight = module.weight
bias = module.bias
print(name, module, weight.shape, bias.shape,
weight.requires_grad, bias.requires_grad)
elif isinstance(module, nn.ReLU):
print(name, module)
圖片預(yù)處理
使用opencv和pil讀圖都可以使用transforms.ToTensor()把原本[H, W, 3]的數(shù)據(jù)轉(zhuǎn)成[3, H, W]的tensor。但opencv要注意把數(shù)據(jù)改成RGB順序。
vgg系列模型需要做normalization,建議配合torchvision.transforms來實(shí)現(xiàn)。
mini-batches of 3-channel RGB images of shape (3 x H x W), where H and W are expected to be at least 224. The images have to be loaded in to a range of [0, 1] and then normalized using mean = [0.485, 0.456, 0.406] and std = [0.229, 0.224, 0.225].
參考:https://pytorch.org/hub/pytorch_vision_vgg/
# -*- coding: utf-8 -*-
from PIL import Image
import cv2
import torch
from torchvision import transforms
# transforms for preprocess
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# load image using cv2
image_cv2 = cv2.imread('lena_std.bmp')
image_cv2 = cv2.cvtColor(image_cv2, cv2.COLOR_BGR2RGB)
image_cv2 = preprocess(image_cv2)
# load image using pil
image_pil = Image.open('lena_std.bmp')
image_pil = preprocess(image_pil)
# check whether image_cv2 and image_pil are same
print(torch.all(image_cv2 == image_pil))
print(image_cv2.shape, image_pil.shape)提取單個(gè)特征圖
如果只提取單層特征圖,可以把模型截?cái)啵怨?jié)省算力和顯存消耗。
下面索引之所以有+1是因?yàn)閜ytorch預(yù)訓(xùn)練模型里面第一個(gè)索引的module總是完整模塊結(jié)構(gòu),第二個(gè)才開始子模塊。
# -*- coding: utf-8 -*-
from PIL import Image
from torchvision import models
from torchvision import transforms
# load model. If pretrained is True, there will be a downloading process
model = models.vgg19(pretrained=True)
model = model.features[:16 + 1] # 16 = conv3_4
model.eval()
model.requires_grad_(False)
model.to('cuda')
print(model)
# load and preprocess image
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
transforms.Resize(size=(224, 224))
])
image = Image.open('lena_std.bmp')
image = preprocess(image)
inputs = image.unsqueeze(0) # add batch dimension
inputs = inputs.cuda()
# forward
output = model(inputs)
print(output.shape)提取多個(gè)特征圖
第一種方式:逐層運(yùn)行model,如果碰到了需要保存的feature map就存下來。
第二種方式:使用register_forward_hook,使用這種方式需要用一個(gè)類把feature map以成員變量的形式緩存下來。
兩種方式的運(yùn)行效率差不多
第一種方式簡單直觀,但是只能處理類似VGG這種沒有跨層連接的網(wǎng)絡(luò);第二種方式更加通用。
# -*- coding: utf-8 -*-
from PIL import Image
import torch
from torchvision import models
from torchvision import transforms
# load model. If pretrained is True, there will be a downloading process
model = models.vgg19(pretrained=True)
model = model.features[:16 + 1] # 16 = conv3_4
model.eval()
model.requires_grad_(False)
model.to('cuda')
# check module name
for named_module in model.named_modules():
name = named_module[0]
module = named_module[1]
print('-------- %s --------' % name)
print(module)
print()
# load and preprocess image
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
transforms.Resize(size=(224, 224))
])
image = Image.open('lena_std.bmp')
image = preprocess(image)
inputs = image.unsqueeze(0) # add batch dimension
inputs = inputs.cuda()
# forward - 1
layers = [2, 7, 8, 9, 16]
layers = sorted(set(layers))
feature_maps = {}
feature = inputs
for i in range(max(layers) + 1):
feature = model[i](feature)
if i in layers:
feature_maps[i] = feature
for key in feature_maps:
print(key, feature_maps.get(key).shape)
# forward - 2
class FeatureHook:
def __init__(self, module):
self.inputs = None
self.output = None
self.hook = module.register_forward_hook(self.get_features)
def get_features(self, module, inputs, output):
self.inputs = inputs
self.output = output
layer_names = ['2', '7', '8', '9', '16']
hook_modules = []
for named_module in model.named_modules():
name = named_module[0]
module = named_module[1]
if name in layer_names:
hook_modules.append(module)
hooks = [FeatureHook(module) for module in hook_modules]
output = model(inputs)
features = [hook.output for hook in hooks]
for feature in features:
print(feature.shape)
# check correctness
for i, layer in enumerate(layers):
feature1 = feature_maps.get(layer)
feature2 = features[i]
print(torch.all(feature1 == feature2))使用第二種方式(register_forward_hook),resnet特征圖也可以順利拿到。
而由于resnet的model已經(jīng)不可以用model[i]的形式索引,所以無法使用第一種方式。
# -*- coding: utf-8 -*-
from PIL import Image
from torchvision import models
from torchvision import transforms
# load model. If pretrained is True, there will be a downloading process
model = models.resnet18(pretrained=True)
model.eval()
model.requires_grad_(False)
model.to('cuda')
# check module name
for named_module in model.named_modules():
name = named_module[0]
module = named_module[1]
print('-------- %s --------' % name)
print(module)
print()
# load and preprocess image
preprocess = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
transforms.Resize(size=(224, 224))
])
image = Image.open('lena_std.bmp')
image = preprocess(image)
inputs = image.unsqueeze(0) # add batch dimension
inputs = inputs.cuda()
class FeatureHook:
def __init__(self, module):
self.inputs = None
self.output = None
self.hook = module.register_forward_hook(self.get_features)
def get_features(self, module, inputs, output):
self.inputs = inputs
self.output = output
layer_names = [
'conv1',
'layer1.0.relu',
'layer2.0.conv1'
]
hook_modules = []
for named_module in model.named_modules():
name = named_module[0]
module = named_module[1]
if name in layer_names:
hook_modules.append(module)
hooks = [FeatureHook(module) for module in hook_modules]
output = model(inputs)
features = [hook.output for hook in hooks]
for feature in features:
print(feature.shape)問題來了,resnet這種類型的網(wǎng)絡(luò)結(jié)構(gòu)怎么截?cái)啵?/p>
使用如下命令就可以,print查看需要截?cái)嗟侥睦铮缓笥胣n.Sequential重組即可。
需注意重組后網(wǎng)絡(luò)的module_name會發(fā)生變化。
print(list(model.children()) model = torch.nn.Sequential(*list(model.children())[:6])
以上就是利用Pytorch實(shí)現(xiàn)獲取特征圖的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Pytorch獲取特征圖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python--shutil移動文件到另一個(gè)路徑的操作
這篇文章主要介紹了python--shutil移動文件到另一個(gè)路徑的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
3分鐘看懂Python后端必須知道的Django的信號機(jī)制
這篇文章主要介紹了3分鐘看懂Python后端必須知道的Django的信號機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
python35種繪圖函數(shù)詳細(xì)總結(jié)
Python有許多用于繪圖的函數(shù)和庫,比如Matplotlib,Plotly,Bokeh,Seaborn等,這只是一些常用的繪圖函數(shù)和庫,Python還有其他繪圖工具,如Pandas、ggplot等,選擇適合你需求的庫,可以根據(jù)你的數(shù)據(jù)類型、圖形需求和個(gè)人偏好來決定,本文給大家總結(jié)了python35種繪圖函數(shù)2023-08-08
讓python json encode datetime類型
python2.6+ 自帶的json模塊,不支持datetime的json encode,每次都需要手動轉(zhuǎn)為字符串,很累人,我們可以自己封裝一個(gè)簡單的方法處理此問題。2010-12-12
Python多進(jìn)程multiprocessing、進(jìn)程池用法實(shí)例分析
這篇文章主要介紹了Python多進(jìn)程multiprocessing、進(jìn)程池用法,結(jié)合實(shí)例形式分析了Python多進(jìn)程multiprocessing、進(jìn)程池相關(guān)概念、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-03-03

