如何提取神经网络中间层特征向量

方法一   钩子(Hook)函数

举个实例来讲解,假设搭建的神经网络结构为一个简单的CNN,代码见下:

class CNN(nn.Module): #n=101   (n+2p-f)/s+1
    def __init__(self):
        super(CNN, self).__init__()
        self.cnn=nn.Sequential(
            #Layer1
            nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=0), #n=97
            nn.BatchNorm2d(16),
            nn.ReLU(),
            # nn.Dropout2d(0.1),
            nn.MaxPool2d(kernel_size=2, stride=2), #48

            #Layer2
            nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=0), #44
            nn.BatchNorm2d(32),
            nn.ReLU(),
            # nn.Dropout2d(0.1),
            nn.MaxPool2d(kernel_size=2, stride=2), #22

            #Layer3
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=4, stride=1, padding=0), #19
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),  # 9

            #Layer4
            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=4, stride=1, padding=0),  # 6
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2) #3
        )

        self.linear=nn.Sequential(
            nn.Linear(3*3*128,256),
            nn.ReLU(),
            nn.Linear(256,4)
        )

    def forward(self, x):
        x=self.cnn(x)
        x = x.view(x.shape[0], -1) 
        x=self.linear(x)

        return x

我们如果想要提取出全连接层中第一个线性层输出的特征向量,linear中nn.Linear(3*3*128,256)输出的维度为256的特征向量,那么我们可以这样做:

# 定义hook函数
fmap_black0={}
def forward_hook0(model,inp,outp):
    fmap_black0['input']=inp
    fmap_black0['output'] = outp

model.linear[0].register_forward_hook(forward_hook0)  # linear[0]代表运行linear中第一行的结果(每一行代表一层),特征向量即从网络中第一个FC输出的维度为128的向量

feature = tensor_list_train.append(fmap_black0["output"])

这样就可以将所需特征向量提取出来啦。

但是,该方法适用于结构较简单的神将网络,如果是比较复杂的网络,比如主干网络中还嵌套了其他网络(如下代码,只是举个例子,可以看到网络内嵌套了Feature_Net、TransformerModel等网络),但又想提取出嵌套网络中某一层的特征,就只能望洋兴叹了,因此下面提供方法二

class TFFusion_Net_double(nn.Module):
    def __init__(self, feature_dim=128, d_model=256, img_size=16, patch_size=16, embed_dim=128, depth=4, num_heads=4, output_dim=4):
        super(TFFusion_Net_double, self).__init__()

        self.feature_model = Feature_Net(feature_dim=feature_dim)
        self.attention = TransformerModel(d_model=d_model)
        self.xcit_model = XCiT(img_size=img_size,
                               patch_size=patch_size, embed_dim=embed_dim, depth=depth, num_heads=num_heads, mlp_ratio=4, 
                               qkv_bias=True,norm_layer=partial(nn.LayerNorm, eps=1e-6), eta=1.0, tokens_norm=False)
        self.Dense = nn.Sequential(
            nn.Linear(embed_dim*4*4, 1024),
            nn.Mish(),
            nn.Linear(1024, 128),
            nn.Mish(),
            nn.Linear(128, output_dim)
        )
    
    def forward(self, x, y):
        x, y = self.feature_model(x), self.feature_model(y) # (64,128)
        mix = torch.cat((x, y), dim=1) # (64,256)
        mix = torch.unsqueeze(mix, dim=1) # (64,1,256)
        mix = self.attention(mix)
        mix = mix.view(x.shape[0], 1, 16, 16)
        mix = mix.expand(-1, 3, -1, -1)
        mix = self.xcit_model(mix)
        mix = mix[0]
        mix = mix.contiguous().view(mix.shape[0], -1)
        mix = self.Dense(mix)

        return mix

方法二  torchextractor

Github开源地址:antoinebrl/torchextractor: Feature extraction made simple with torchextractor

Github中的讲解也很清楚,这里依然举一个实例来讲解:

import torchextractor as tx # PyTorch Intermediate Feature Extraction

if __name__ == '__main__':

    # 下载网络模型
    model = CNN_Net(output_dim=4)
    model_weight = r'XXXXXXXX.pth'
    model.load_state_dict(torch.load(model_weight))
    model.to(device)
    print(tx.list_module_names(model)) # 打印出网络结构
    '''
    ['', 'cnn', 'cnn.0', 'cnn.1', 'cnn.2', 'cnn.3', 'cnn.4', 'cnn.5', 'cnn.6', 'cnn.7', 'cnn.8', 'cnn.9', 'cnn.10', 'cnn.11', 
    'fc', 'fc.0', 'fc.1', 'fc.2']
    '''
    model = tx.Extractor(model, "fc.1") # 想要得到全连接层中第1层的输出
    model.eval()
    
    # 下面的inputs可从使用的数据集中选取一个样本,根据实际数据集来获取
    _, feature = model(inputs.float())
    feature = feature['fc.1']
    feature = feature.view(feature.shape[0],-1)[0]
    feature = feature.cpu().detach().numpy()
    # 保存特征向量
    scipy.io.savemat('XXXXXX.mat', {'data':feature})

比较复杂,含有嵌套网络的结构也可以打印出来,如:

'''
    ['', 'feature_model', 'feature_model.cnn', 'feature_model.cnn.0', 'feature_model.cnn.1', 
    'feature_model.cnn.2', 'feature_model.cnn.3', 'feature_model.cnn.4', 'feature_model.cnn.5', 
    'feature_model.cnn.6', 'feature_model.cnn.7', 'feature_model.cnn.8', 'feature_model.cnn.9', 
    'feature_model.cnn.10', 'feature_model.cnn.11', 'feature_model.fc', 'timexer_model', 
    'timexer_model.self_attn', 'timexer_model.self_attn.self_attn', 
    'timexer_model.self_attn.self_attn.out_proj', 'timexer_model.self_attn.linear1', 
    'timexer_model.self_attn.dropout', 'timexer_model.self_attn.linear2', 
    'timexer_model.self_attn.norm1', 'timexer_model.self_attn.norm2', 
    'timexer_model.self_attn.dropout1', 'timexer_model.self_attn.dropout2', 
    'timexer_model.cross_attn', 'timexer_model.cross_attn.self_attn', 
    'timexer_model.cross_attn.self_attn.out_proj', 'timexer_model.cross_attn.linear1', 
    'timexer_model.cross_attn.dropout', 'timexer_model.cross_attn.linear2', 
    'timexer_model.cross_attn.norm1', 'timexer_model.cross_attn.norm2', 
    'timexer_model.cross_attn.dropout1', 'timexer_model.cross_attn.dropout2']
'''

需要提取哪一层的输出特征,直接按照上述实例将"fc.1"替换即可。

<think>好的,我现在要帮用户理解神经网络中间层的实现与作用。首先,我需要回忆一下神经网络的基本结构。输入接收数据,中间层处理特征,输出给出结果。中间层通常包括隐藏,比如全连接、卷积、池化等,每种有不同的功能。 用户提到了引用中的内容,特别是可视化中间层输出的重要性。我需要结合这些引用,说明中间层如何提取特征,以及为什么可视化有助于理解网络行为。比如引用[1]提到可视化中间层输出帮助理解特征学习,引用[3]比较了不同卷积学到的内容差异,这些都可以作为例子。 接下来,我需要分点说明中间层的作用:特征抽象、非线性建模、信息压缩和传递。每个点要举例说明,比如卷积检测边缘,全连接整合信息。然后讨论实现方式,如全连接、卷积、池化和注意力机制的结构,并引用相关文献。 还要考虑用户可能的深需求,比如中间层如何影响模型性能,或者如何选择中间层的结构。最后,生成相关问题,引导用户深入思考优化方法、可视化技术等,参考提供的引用内容,确保问题相关且有依据。</think>### 神经网络中间层的实现与作用 神经网络中间层(也称为隐藏)是模型实现复杂特征学习和数据抽象的核心部分。以下从作用和实现两方面展开说明: --- #### **中间层的作用** 1. **特征抽象与组合** 中间层通过逐变换,将原始输入数据逐步抽象为高阶特征。例如: - 在卷积神经网络(CNN)中,浅中间层可能检测边缘、纹理(如引用[3]中提到的卷积核学习内容对比),深则组合这些特征识别物体部件或整体[^3]。 - 在全连接网络中,中间层通过线性变换和非线性激活函数(如ReLU)实现特征的非线性组合。 2. **非线性建模能力** 中间层引入非线性激活函数(如Sigmoid、ReLU),使网络能够拟合复杂函数。例如: $$f(x) = W_2 \cdot \text{ReLU}(W_1 x + b_1) + b_2$$ 其中$W_1, W_2$为权重矩阵,通过多叠加增强表达能力。 3. **信息压缩与传递** 中间层通过降维操作(如池化)过滤冗余信息,保留关键特征。例如最大池化: $$\text{MaxPool}(x)_{i,j} = \max_{p,q \in 窗口} x_{i+p,j+q}$$ 这种操作提升了模型对平移、旋转的鲁棒性(如引用[2]中提到的特征简化和模拟过程)[^2]。 --- #### **中间层的实现方式** 1. **全连接(Dense Layer)** 实现公式: $$h = \sigma(Wx + b)$$ - $W$为权重矩阵,$b$为偏置项,$\sigma$为激活函数。 - 适用于全局特征整合,但参数量大。 2. **卷积(Convolutional Layer)** 实现局部感受野和权值共享: $$h_{i,j} = \sum_{m} \sum_{n} W_{m,n} \cdot x_{i+m,j+n} + b$$ - 高效提取空间特征,广泛用于图像处理(如引用[3]中的卷积核特征分析)[^3]。 3. **池化(Pooling Layer)** 通过下采样减少计算量,常用最大值或平均值池化。例如: $$h_{i,j} = \frac{1}{k^2} \sum_{p=0}^{k-1} \sum_{q=0}^{k-1} x_{i \cdot s + p, j \cdot s + q}$$ ($k$为窗口大小,$s$为步长) 4. **注意力机制** 通过自注意力权重动态分配特征重要性: $$\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$ 适用于序列数据或跨模态特征融合。 --- #### **可视化中间层的意义** 如引用[1]所述,可视化中间层输出(如特征图或激活值分布)可直观理解网络学习到的特征模式,例如: - 浅CNN检测边缘/颜色,深识别语义部件[^1]。 - 通过特征图叠加分析模型关注区域(如Grad-CAM技术)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值