diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/dalunwen11.iml b/.idea/dalunwen11.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/dalunwen11.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..b361e46 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7e572ab --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d581fc --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1836ae1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/GNN_GRU.docx b/GNN_GRU.docx new file mode 100644 index 0000000..f786d47 Binary files /dev/null and b/GNN_GRU.docx differ diff --git a/GNN_GRU.py b/GNN_GRU.py new file mode 100644 index 0000000..b34c327 --- /dev/null +++ b/GNN_GRU.py @@ -0,0 +1,221 @@ +import os +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.utils.data import Dataset, DataLoader +from torch_geometric.nn import GCNConv +import numpy as np + + +# 图神经网络模块 +class GNNModule(nn.Module): + def __init__(self, input_dim, hidden_dim, output_dim): + super(GNNModule, self).__init__() + self.conv1 = GCNConv(input_dim, hidden_dim) + self.conv2 = GCNConv(hidden_dim, output_dim) + + def forward(self, x, edge_index): + x = F.relu(self.conv1(x, edge_index)) + x = F.relu(self.conv2(x, edge_index)) + return x + + +# GRU时序网络模块 +class GRUNetwork(nn.Module): + def __init__(self, input_dim, hidden_dim, num_layers): + super(GRUNetwork, self).__init__() + self.gru = nn.GRU(input_dim, hidden_dim, num_layers, batch_first=True) + self.fc = nn.Linear(hidden_dim, 3) # 3个行为类别 + + def forward(self, x): + out, _ = self.gru(x) + out = self.fc(out[:, -1, :]) # 使用最后时刻的输出进行分类 + return out + + +# 主网络(结合GNN和GRU) +class GNN_GRU_Network(nn.Module): + def __init__(self, input_dim, hidden_dim_gnn, hidden_dim_gru, num_layers_gru, num_keypoints=17): + super(GNN_GRU_Network, self).__init__() + self.gnn = GNNModule(input_dim=2, hidden_dim=hidden_dim_gnn, output_dim=hidden_dim_gnn) # 17个关键点的(x, y) + self.gru = GRUNetwork(input_dim=num_keypoints * hidden_dim_gnn, hidden_dim=hidden_dim_gru, + num_layers=num_layers_gru) + + def forward(self, keypoints, edge_index, seq_length): + batch_size = keypoints.shape[0] + num_keypoints = keypoints.shape[1] + + # 对每个时刻的关键点使用GNN提取空间特征 + spatial_features = [] + for t in range(seq_length): + x = keypoints[:, t, :].view(batch_size * num_keypoints, 2) + spatial_feature = self.gnn(x, edge_index) # (batch_size * num_keypoints, hidden_dim_gnn) + spatial_features.append(spatial_feature) + + spatial_features = torch.stack(spatial_features, dim=1) # (batch_size * num_keypoints, seq_len, hidden_dim_gnn) + + gru_input = spatial_features.view(batch_size, seq_length, num_keypoints * hidden_dim_gnn) + + # 传递给GRU进行时序建模 + output = self.gru(gru_input) + return output + + +# 数据集类 +class KeypointDataset(Dataset): + def __init__(self, root_dir, behavior_labels, seq_length=5): + """ + :param root_dir: 包含三个行为文件夹的根目录 + :param behavior_labels: 每个文件夹对应的行为标签 + :param seq_length: 每个视频的时长(秒),每秒20帧 + """ + self.root_dir = root_dir + self.behavior_labels = behavior_labels + self.seq_length = seq_length # 每个视频5秒,假设每秒20帧 + + self.videos = [] + self.labels = [] + + # 遍历根目录,获取每个视频路径和标签 + for idx, behavior in enumerate(behavior_labels): + behavior_dir = os.path.join(root_dir, behavior) + for video_name in os.listdir(behavior_dir): + video_path = os.path.join(behavior_dir, video_name) + if os.path.isdir(video_path): + video_files = sorted(os.listdir(video_path)) # 按帧数排序文件 + self.videos.append(video_files) + self.labels.append(idx) # 标签为行为类别索引 + + def __len__(self): + return len(self.videos) + + def __getitem__(self, idx): + video_files = self.videos[idx] + label = self.labels[idx] + + # 每个视频加载时,读取关键点数据 + keypoints = [] + for frame_file in video_files: + frame_path = os.path.join(self.root_dir, frame_file) + keypoints.append(self.load_keypoints(frame_path)) + + keypoints = np.array(keypoints) # shape: (num_frames, num_persons, 34) -> (num_frames, num_persons, 17*2) + return torch.tensor(keypoints, dtype=torch.float32), torch.tensor(label, dtype=torch.long) + + def load_keypoints(self, frame_path): + """ + 读取每一帧的关键点数据,每帧数据包含每个人的17个关键点 + :param frame_path: 每帧的txt文件路径 + :return: 该帧的所有人物的17个关键点坐标 + """ + keypoints = [] + with open(frame_path, 'r') as f: + for line in f.readlines(): + data = list(map(float, line.strip().split())) + person_id = int(data[0]) + frame_id = int(data[1]) + coordinates = data[2:] # 后面的34个数值是17个关键点的(x, y)坐标 + keypoints.append(coordinates) + + return np.array(keypoints) # shape: (num_persons, 17*2) + + +# 训练过程 +def train(model, train_loader, criterion, optimizer, device): + model.train() + total_loss = 0 + for data, label in train_loader: + data = data.to(device) + label = label.to(device) + + optimizer.zero_grad() + output = model(data) # 前向传播 + loss = criterion(output, label) # 计算损失 + loss.backward() # 反向传播 + optimizer.step() # 更新参数 + + total_loss += loss.item() + + return total_loss / len(train_loader) + + +# 验证过程 +def evaluate(model, val_loader, criterion, device): + model.eval() + total_loss = 0 + correct = 0 + total = 0 + with torch.no_grad(): + for data, label in val_loader: + data = data.to(device) + label = label.to(device) + + output = model(data) + loss = criterion(output, label) + total_loss += loss.item() + + _, predicted = torch.max(output, 1) + correct += (predicted == label).sum().item() + total += label.size(0) + + accuracy = correct / total + return total_loss / len(val_loader), accuracy + + +# 主函数 +def main(): + root_dir = "/path/to/your/data" # 数据集根目录 + behavior_labels = ["behavior1", "behavior2", "behavior3"] + + # 创建数据集与加载器 + train_dataset = KeypointDataset(root_dir, behavior_labels) + train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True) + + # 模型设置 + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + model = GNN_GRU_Network(input_dim=2, hidden_dim_gnn=64, hidden_dim_gru=128, num_layers_gru=2) + model.to(device) + + # 损失函数与优化器 + criterion = nn.CrossEntropyLoss() + optimizer = torch.optim.Adam(model.parameters(), lr=0.001) + + # 训练与验证 + for epoch in range(1, 101): + train_loss = train(model, train_loader, criterion, optimizer, device) + print(f"Epoch {epoch}, Train Loss: {train_loss:.4f}") + + # 可选:每个epoch结束时进行验证 + # val_loss, val_accuracy = evaluate(model, val_loader, criterion, device) + # print(f"Val Loss: {val_loss:.4f}, Val Accuracy: {val_accuracy:.4f}") + + +if __name__ == '__main__': + main() +''' +代码说明: + +数据集处理(KeypointDataset): +假设你的数据集文件夹结构如下: +data / +├── behavior1 / +│ ├── video1 / +│ │ ├── frame1.txt +│ │ ├── frame2.txt +│ │ └── ... +│ ├── video2 / +│ └── ... +├── behavior2 / +└── behavior3 / +每个视频文件夹包含若干个.txt +文件,每个文件代表一帧,记录了每个人的关键点位置(17 +个关键点,每个关键点的(x, y) +坐标)。 +模型(GNN_GRU_Network): +使用 +GNN +对每一帧的关键点进行空间特征提取。 +然后将提取的空间特征传入 +GRU +网络进行时序建模,最后通过 +''' \ No newline at end of file diff --git a/SBA.png b/SBA.png new file mode 100644 index 0000000..52c35e0 Binary files /dev/null and b/SBA.png differ diff --git a/dlo7qcz3q.jpg b/dlo7qcz3q.jpg new file mode 100644 index 0000000..c92e09e Binary files /dev/null and b/dlo7qcz3q.jpg differ diff --git a/lls开题报告.docx b/lls开题报告.docx index dd0f9cb..1bdddda 100644 Binary files a/lls开题报告.docx and b/lls开题报告.docx differ diff --git a/新建 文本文档.txt b/新建 文本文档.txt new file mode 100644 index 0000000..e69de29