首頁 > 軟體

Python基於Pytorch的特徵圖提取範例

2022-03-29 13:03:52

簡述

為了方便理解折積神經網路的執行過程,需要對摺積神經網路的執行結果進行視覺化的展示。

大致可分為如下步驟:

  • 單個圖片的提取
  • 神經網路的構建
  • 特徵圖的提取
  • 視覺化展示

單個圖片的提取

根據目標要求,需要對單個圖片進行折積運算,但是Pytorch中讀取資料主要用到torch.utils.data.DataLoader類,因此我們需要編寫單個圖片的讀取程式

def get_picture(picture_dir, transform):
    '''
    該演演算法實現了讀取圖片,並將其型別轉化為Tensor
    '''
    tmp = []
    img = skimage.io.imread(picture_dir)
    tmp.append(img)
    img = skimage.io.imread('./picture/4.jpg')
    tmp.append(img)
    img256 = [skimage.transform.resize(img, (256, 256)) for img in tmp]
    img256 = np.asarray(img256)
    img256 = img256.astype(np.float32)

    return transform(img256[0])

注意: 神經網路的輸入是四維形式,我們返回的圖片是三維形式,需要使用unsqueeze()插入一個維度

神經網路的構建

網路的基於LeNet構建,不過為了方便展示,將其中的引數按照2562563進行的引數的修正

網路構建如下:

class LeNet(nn.Module):
    '''
    該類繼承了torch.nn.Modul類
    構建LeNet神經網路模型
    '''
    def __init__(self):
        super(LeNet, self).__init__()

        # 第一層神經網路,包括折積層、線性啟用函數、池化層
        self.conv1 = nn.Sequential( 
            nn.Conv2d(3, 32, 5, 1, 2),   # input_size=(3*256*256),padding=2
            nn.ReLU(),                  # input_size=(32*256*256)
            nn.MaxPool2d(kernel_size=2, stride=2),  # output_size=(32*128*128)
        )

        # 第二層神經網路,包括折積層、線性啟用函數、池化層
        self.conv2 = nn.Sequential(
            nn.Conv2d(32, 64, 5, 1, 2),  # input_size=(32*128*128)
            nn.ReLU(),            # input_size=(64*128*128)
            nn.MaxPool2d(2, 2)    # output_size=(64*64*64)
        )

        # 全連線層(將神經網路的神經元的多維輸出轉化為一維)
        self.fc1 = nn.Sequential(
            nn.Linear(64 * 64 * 64, 128),  # 進行線性變換
            nn.ReLU()                    # 進行ReLu啟用
        )

        # 輸出層(將全連線層的一維輸出進行處理)
        self.fc2 = nn.Sequential(
            nn.Linear(128, 84),
            nn.ReLU()
        )

        # 將輸出層的資料進行分類(輸出預測值)
        self.fc3 = nn.Linear(84, 62)

    # 定義前向傳播過程,輸入為x
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # nn.Linear()的輸入輸出都是維度為一的值,所以要把多維度的tensor展平成一維
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

特徵圖的提取

直接上程式碼:

class FeatureExtractor(nn.Module):
    def __init__(self, submodule, extracted_layers):
        super(FeatureExtractor, self).__init__()
        self.submodule = submodule
        self.extracted_layers = extracted_layers
 
    def forward(self, x):
        outputs = []
        for name, module in self.submodule._modules.items():
        # 目前不展示全連線層
            if "fc" in name: 
                x = x.view(x.size(0), -1)
            print(module)
            x = module(x)
            print(name)
            if name in self.extracted_layers:
                outputs.append(x)
        return outputs

視覺化展示

視覺化展示使用matplotlib

程式碼如下:

    # 特徵輸出視覺化
    for i in range(32):
        ax = plt.subplot(6, 6, i + 1)
        ax.set_title('Feature {}'.format(i))
        ax.axis('off')
        plt.imshow(x[0].data.numpy()[0,i,:,:],cmap='jet')
    plt.plot()

完整程式碼

在此貼上完整程式碼

import os
import torch
import torchvision as tv
import torchvision.transforms as transforms
import torch.nn as nn
import torch.optim as optim
import argparse
import skimage.data
import skimage.io
import skimage.transform
import numpy as np
import matplotlib.pyplot as plt

# 定義是否使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Load training and testing datasets.
pic_dir = './picture/3.jpg'

# 定義資料預處理方式(將輸入的類似numpy中arrary形式的資料轉化為pytorch中的張量(tensor))
transform = transforms.ToTensor()


def get_picture(picture_dir, transform):
    '''
    該演演算法實現了讀取圖片,並將其型別轉化為Tensor
    '''
    img = skimage.io.imread(picture_dir)
    img256 = skimage.transform.resize(img, (256, 256))
    img256 = np.asarray(img256)
    img256 = img256.astype(np.float32)

    return transform(img256)


def get_picture_rgb(picture_dir):
    '''
    該函數實現了顯示圖片的RGB三通道顏色
    '''
    img = skimage.io.imread(picture_dir)
    img256 = skimage.transform.resize(img, (256, 256))
    skimage.io.imsave('./picture/4.jpg',img256)

    # 取單一通道值顯示
    # for i in range(3):
    #     img = img256[:,:,i]
    #     ax = plt.subplot(1, 3, i + 1)
    #     ax.set_title('Feature {}'.format(i))
    #     ax.axis('off')
    #     plt.imshow(img)

    # r = img256.copy()
    # r[:,:,0:2]=0
    # ax = plt.subplot(1, 4, 1)
    # ax.set_title('B Channel')
    # # ax.axis('off')
    # plt.imshow(r)

    # g = img256.copy()
    # g[:,:,0]=0
    # g[:,:,2]=0
    # ax = plt.subplot(1, 4, 2)
    # ax.set_title('G Channel')
    # # ax.axis('off')
    # plt.imshow(g)

    # b = img256.copy()
    # b[:,:,1:3]=0
    # ax = plt.subplot(1, 4, 3)
    # ax.set_title('R Channel')
    # # ax.axis('off')
    # plt.imshow(b)

    # img = img256.copy()
    # ax = plt.subplot(1, 4, 4)
    # ax.set_title('image')
    # # ax.axis('off')
    # plt.imshow(img)

    img = img256.copy()
    ax = plt.subplot()
    ax.set_title('image')
    # ax.axis('off')
    plt.imshow(img)

    plt.show()


class LeNet(nn.Module):
    '''
    該類繼承了torch.nn.Modul類
    構建LeNet神經網路模型
    '''
    def __init__(self):
        super(LeNet, self).__init__()

        # 第一層神經網路,包括折積層、線性啟用函數、池化層
        self.conv1 = nn.Sequential( 
            nn.Conv2d(3, 32, 5, 1, 2),   # input_size=(3*256*256),padding=2
            nn.ReLU(),                  # input_size=(32*256*256)
            nn.MaxPool2d(kernel_size=2, stride=2),  # output_size=(32*128*128)
        )

        # 第二層神經網路,包括折積層、線性啟用函數、池化層
        self.conv2 = nn.Sequential(
            nn.Conv2d(32, 64, 5, 1, 2),  # input_size=(32*128*128)
            nn.ReLU(),            # input_size=(64*128*128)
            nn.MaxPool2d(2, 2)    # output_size=(64*64*64)
        )

        # 全連線層(將神經網路的神經元的多維輸出轉化為一維)
        self.fc1 = nn.Sequential(
            nn.Linear(64 * 64 * 64, 128),  # 進行線性變換
            nn.ReLU()                    # 進行ReLu啟用
        )

        # 輸出層(將全連線層的一維輸出進行處理)
        self.fc2 = nn.Sequential(
            nn.Linear(128, 84),
            nn.ReLU()
        )

        # 將輸出層的資料進行分類(輸出預測值)
        self.fc3 = nn.Linear(84, 62)

    # 定義前向傳播過程,輸入為x
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # nn.Linear()的輸入輸出都是維度為一的值,所以要把多維度的tensor展平成一維
        x = x.view(x.size()[0], -1)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

# 中間特徵提取
class FeatureExtractor(nn.Module):
    def __init__(self, submodule, extracted_layers):
        super(FeatureExtractor, self).__init__()
        self.submodule = submodule
        self.extracted_layers = extracted_layers
 
    def forward(self, x):
        outputs = []
        print(self.submodule._modules.items())
        for name, module in self.submodule._modules.items():
            if "fc" in name: 
                print(name)
                x = x.view(x.size(0), -1)
            print(module)
            x = module(x)
            print(name)
            if name in self.extracted_layers:
                outputs.append(x)
        return outputs


def get_feature():
    # 輸入資料
    img = get_picture(pic_dir, transform)
    # 插入維度
    img = img.unsqueeze(0)

    img = img.to(device)

    # 特徵輸出
    net = LeNet().to(device)
    # net.load_state_dict(torch.load('./model/net_050.pth'))
    exact_list = ["conv1","conv2"]
    myexactor = FeatureExtractor(net, exact_list)
    x = myexactor(img)

    # 特徵輸出視覺化
    for i in range(32):
        ax = plt.subplot(6, 6, i + 1)
        ax.set_title('Feature {}'.format(i))
        ax.axis('off')
        plt.imshow(x[0].data.numpy()[0,i,:,:],cmap='jet')

    plt.show()

# 訓練
if __name__ == "__main__":
    get_picture_rgb(pic_dir)
    # get_feature()
    

總結

到此這篇關於Python基於Pytorch的特徵圖提取的文章就介紹到這了,更多相關Pytorch特徵圖提取內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com