1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| import torch import torch.nn as nn from typing import Tuple
class ModifiedDenseNet(nn.Module): """ Modified DenseNet-161 for Dynamic Hand Gesture Recognition 修改点: 1. 输入从单帧改为40帧序列 2. 第一层卷积改为3D卷积处理时序 3. 输出层改为手势分类 """ def __init__(self, num_classes: int = 12, input_channels: int = 3): super().__init__() self.backbone = torch.hub.load('pytorch/vision', 'densenet161', pretrained=True) original_first = self.backbone.features.conv0 self.backbone.features.conv0 = nn.Conv3d( input_channels, 96, kernel_size=(3, 7, 7), stride=(1, 2, 2), padding=(1, 3, 3), bias=False ) self.backbone.classifier = nn.Sequential( nn.Linear(2208, 512), nn.ReLU(), nn.Dropout(0.3), nn.Linear(512, num_classes), ) def forward(self, x: torch.Tensor) -> torch.Tensor: """ Args: x: (B, C, T, H, W) — 40帧序列 Returns: logits: (B, num_classes) """ B, C, T, H, W = x.shape x = x.permute(0, 2, 1, 3, 4) x = self.backbone.features.conv0(x) B2, C2, T2, H2, W2 = x.shape x = x.permute(0, 2, 1, 3, 4).reshape(B2 * T2, C2, H2, W2) for name in list(self.backbone.features.children())[1:]: x = name(x) x = x.mean(dim=[2, 3]) x = x.reshape(B, -1) return self.backbone.classifier(x)
class LateFusionModel: """ Late Fusion: 训练独立单模态网络,决策级融合 论文发现:Late Fusion > Mid Fusion 原因:各模态特征空间差异大,早期融合引入噪声 """ def __init__(self, modalities: list = ["depth", "ir", "rgb"]): self.modalities = modalities self.models = {m: ModifiedDenseNet(num_classes=12) for m in modalities} def predict( self, depth_input: torch.Tensor = None, ir_input: torch.Tensor = None, rgb_input: torch.Tensor = None, ) -> torch.Tensor: """ Late Fusion 预测 各模态独立预测,然后平均 """ inputs = {"depth": depth_input, "ir": ir_input, "rgb": rgb_input} scores = [] for mod in self.modalities: if inputs[mod] is not None: with torch.no_grad(): logits = self.models[mod](inputs[mod]) scores.append(torch.softmax(logits, dim=1)) fused = torch.stack(scores).mean(dim=0) return fused
if __name__ == "__main__": model = ModifiedDenseNet(num_classes=12) x = torch.randn(4, 3, 40, 224, 224) output = model(x) print(f"输出: {output.shape}") print(f"参数: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M")
|