m0_61183062 2025-05-21 15:32 采纳率: 0%
浏览 10

我的CNN如何提高准确率

我想制作一个手工特征融合cnn深度网络的宝石分类模型,发现各种融合之后效果没有得到提升,准确率在15轮的时候基本就停在78%-80%,怎么办!是否有方法优化这种特征融合!

#这是混合模型,把cnn提取的特征和手动提取的特征相融合,融合时用了动态加权。
class HybridGemClassifier(nn.Module):
    def __init__(self, hand_feat_dim):
        super().__init__()
        # 深度特征提取器
        self.cnn = models.mobilenet_v2(pretrained=True)
        self.cnn_feat = nn.Sequential(
            *list(self.cnn.children())[:-1],
            nn.AdaptiveAvgPool2d((1,1)),
            nn.Flatten()
        )

        # 手工特征处理
        self.hand_fc = nn.Sequential(
            nn.Linear(hand_feat_dim, 128),
            nn.BatchNorm1d(128),
            nn.ReLU(inplace=True)
        )

        # 动态特征加权
        self.attention = nn.Sequential(
            nn.Linear(1280 + 128, 64),
            nn.ReLU(inplace=True),
            nn.Linear(64, 2),
            nn.Softmax(dim=1)
        )

        # 分类器
        self.classifier = nn.Sequential(
            nn.Linear(1280 + 128, 512),
            nn.BatchNorm1d(512),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(512, Config.num_classes)
        )

        # 深度特征和手工特征权重
        self.weights_w_cnn = 0
        self.weights_w_hand = 0

    def forward(self, img, hand_feat):
        # 深度特征
        cnn_feat = self.cnn_feat(img)

        # 手工特征
        hand_feat = self.hand_fc(hand_feat)

        # 动态加权
        combined = torch.cat([cnn_feat, hand_feat], dim=1)
        weights = self.attention(combined)
        self.weights_w_cnn = weights[:, 0].mean()
        self.weights_w_hand = weights[:, 1].mean()

        weighted_cnn = cnn_feat * weights[:, 0].unsqueeze(1)
        weighted_hand = hand_feat * weights[:, 1].unsqueeze(1)

        # 特征融合
        fused = torch.cat([weighted_cnn, weighted_hand], dim=1)
        return self.classifier(fused)


#这是特征提取的函数,提取了图片的颜色,纹理,边缘密度信息。
    def extract_handcrafted(self, img):
        # 颜色特征 (HSV直方图)

        hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
        hist_hsv = cv2.calcHist([hsv], [0, 1, 2], None,
                                [8, 8, 8], [0, 180, 0, 256, 0, 256])
        hist_hsv = cv2.normalize(hist_hsv, None).flatten()

        # 纹理特征 (LBP)
        gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        lbp = local_binary_pattern(gray, 8, 1, method='uniform')
        hist_lbp, _ = np.histogram(lbp, bins=np.arange(0, 10), density=True)

        # 结构特征 (边缘密度)
        edges = cv2.Canny(gray, 100, 200)
        edge_density = np.sum(edges) / (img.size / 3)

        return np.concatenate([hist_hsv, hist_lbp, [edge_density]]).astype(np.float32)


  • 写回答

5条回答 默认 最新

  • 檀越@新空间 2025-05-21 15:33
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    从你的描述来看,你正在尝试构建一个结合深度学习(CNN)和手工特征的混合模型来实现宝石分类任务。然而,模型的表现似乎没有达到预期,准确率在15轮后停滞在78%-80%之间。以下是一些可能的原因以及对应的优化方案,帮助你进一步提升模型性能。


    问题分析

    1. 手工特征的质量

      • 手工特征可能不够有效或与目标分类任务的相关性较低。例如,颜色、纹理和边缘密度等特征是否能充分表征不同种类的宝石?
      • 手工特征的维度可能过大,导致模型难以有效利用这些信息。
    2. 特征融合方式

      • 当前使用的是动态加权融合,但可能无法很好地捕捉深度特征和手工特征之间的复杂关系。
      • 融合后的特征可能对分类任务不敏感,导致模型性能瓶颈。
    3. 模型容量不足

      • 当前模型的分类器部分(classifier)可能过于简单,不足以充分利用融合后的特征。
      • 模型可能存在过拟合或欠拟合的问题。
    4. 训练过程

      • 训练过程中可能没有足够的数据增强或正则化策略。
      • 学习率可能设置不当,导致训练停滞。

    优化方案

    1. 改进手工特征提取

    • 增加特征维度:尝试提取更多类型的特征,如形状特征、频域特征等,以丰富手工特征的信息。
    • 特征归一化:确保手工特征的分布范围一致,避免因特征尺度差异影响模型训练。
    • 特征选择:使用特征重要性评估方法(如PCA、Lasso回归)筛选出对分类任务贡献较大的手工特征。
    def extract_handcrafted(self, img):
        hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
        hist_hsv = cv2.calcHist([hsv], [0, 1, 2], None, [8, 8, 8], [0, 180, 0, 256, 0, 256])
        hist_hsv = cv2.normalize(hist_hsv, None).flatten()
    
        gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        lbp = local_binary_pattern(gray, 8, 1, method='uniform')
        hist_lbp, _ = np.histogram(lbp, bins=np.arange(0, 10), density=True)
    
        edges = cv2.Canny(gray, 100, 200)
        edge_density = np.sum(edges) / (img.size / 3)
    
        # 添加形状特征(如Hu矩)
        moments = cv2.moments(gray)
        hu_moments = cv2.HuMoments(moments).flatten()
    
        return np.concatenate([hist_hsv, hist_lbp, [edge_density], hu_moments]).astype(np.float32)
    

    2. 改进特征融合方式

    • 非线性融合:当前使用的是简单的加权融合,可以尝试更复杂的融合方式,如注意力机制(如Transformer)、多头注意力或特征交互模块。
    • 特征嵌入:将手工特征和深度特征分别通过全连接层映射到相同维度后再融合,以增强特征的一致性。
    # 修改动态加权部分
    self.attention = nn.Sequential(
        nn.Linear(1280 + 128, 64),
        nn.ReLU(inplace=True),
        nn.Linear(64, 1)  # 单通道权重
    )
    
    # 修改特征融合方式
    def forward(self, img, hand_feat):
        cnn_feat = self.cnn_feat(img)
        hand_feat = self.hand_fc(hand_feat)
    
        combined = torch.cat([cnn_feat, hand_feat], dim=1)
        weights = self.attention(combined).squeeze()  # 单通道权重
        weighted_cnn = cnn_feat * weights.unsqueeze(1)
        weighted_hand = hand_feat * (1 - weights).unsqueeze(1)
    
        fused = torch.cat([weighted_cnn, weighted_hand], dim=1)
        return self.classifier(fused)
    

    3. 增强模型容量

    • 增加分类器层数:扩展classifier部分的结构,增加更多的隐藏层或神经元。
    • 正则化:引入Dropout、BatchNorm等正则化技术,防止过拟合。
    self.classifier = nn.Sequential(
        nn.Linear(1280 + 128, 1024),
        nn.BatchNorm1d(1024),
        nn.ReLU(inplace=True),
        nn.Dropout(0.5),
        nn.Linear(1024, 512),
        nn.BatchNorm1d(512),
        nn.ReLU(inplace=True),
        nn.Dropout(0.5),
        nn.Linear(512, Config.num_classes)
    )
    

    4. 改进训练过程

    • 数据增强:使用图像增强技术(如旋转、缩放、裁剪、颜色变换等)扩充数据集。
    • 学习率调整:使用学习率调度器(如StepLR、ReduceLROnPlateau)动态调整学习率。
    • 早停法:在验证集上监控性能,当性能不再提升时提前停止训练。
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=5)
    early_stopping = EarlyStopping(patience=10, verbose=True)
    

    5. 检查数据分布

    • 确保训练集和测试集的数据分布一致,避免类别不平衡问题。
    • 如果类别不平衡,可以使用加权损失函数或过采样/欠采样技术。

    总结

    通过以上优化措施,你可以逐步提升模型的性能。以下是最终的改进版本代码片段:

    class HybridGemClassifier(nn.Module):
        def __init__(self, hand_feat_dim):
            super().__init__()
            self.cnn = models.mobilenet_v2(pretrained=True)
            self.cnn_feat = nn.Sequential(
                *list(self.cnn.children())[:-1],
                nn.AdaptiveAvgPool2d((1,1)),
                nn.Flatten()
            )
            self.hand_fc = nn.Sequential(
                nn.Linear(hand_feat_dim, 128),
                nn.BatchNorm1d(128),
                nn.ReLU(inplace=True)
            )
            self.attention = nn.Sequential(
                nn.Linear(1280 + 128, 64),
                nn.ReLU(inplace=True),
                nn.Linear(64, 1),
                nn.Sigmoid()  # 使用Sigmoid输出权重
            )
            self.classifier = nn.Sequential(
                nn.Linear(1280 + 128, 1024),
                nn.BatchNorm1d(1024),
                nn.ReLU(inplace=True),
                nn.Dropout(0.5),
                nn.Linear(1024, 512),
                nn.BatchNorm1d(512),
                nn.ReLU(inplace=True),
                nn.Dropout(0.5),
                nn.Linear(512, Config.num_classes)
            )
    
        def forward(self, img, hand_feat):
            cnn_feat = self.cnn_feat(img)
            hand_feat = self.hand_fc(hand_feat)
            combined = torch.cat([cnn_feat, hand_feat], dim=1)
            weights = self.attention(combined).squeeze()
            weighted_cnn = cnn_feat * weights.unsqueeze(1)
            weighted_hand = hand_feat * (1 - weights).unsqueeze(1)
            fused = torch.cat([weighted_cnn, weighted_hand], dim=1)
            return self.classifier(fused)
    

    希望这些建议对你有所帮助!如果仍有问题,欢迎继续提问!

    评论

报告相同问题?

问题事件

  • 创建了问题 5月21日