import torch from torchvision import models, transforms from torchvision.io import read_image from torch import nn device = torch.device("cuda" if torch.cuda.is_available() else "cpu") backbone_spatial = models.mobilenet_v3_large(weights='DEFAULT').features.to(device) backbone_motion = models.mobilenet_v3_small(weights='DEFAULT').features.to(device) backbone_spatial.eval() backbone_motion.eval() pool = nn.AdaptiveAvgPool2d(1) norm = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) resize = transforms.Resize((224, 224)) def extract_features(frame_paths): imgs = [] for p in frame_paths: img = read_image(p).float() / 255.0 imgs.append(norm(resize(img))) imgs = torch.stack(imgs).to(device) with torch.no_grad(): spatial = imgs[::3] spatial_feat = pool(backbone_spatial(spatial)).flatten(1) diffs = imgs[1:] - imgs[:-1] diffs = torch.where(torch.abs(diffs) > 0.08, diffs, torch.zeros_like(diffs)) motion_feat = pool(backbone_motion(diffs)).flatten(1) if spatial_feat.shape[0] < motion_feat.shape[0]: pad = motion_feat.shape[0] - spatial_feat.shape[0] spatial_feat = torch.cat([spatial_feat, spatial_feat[-1:].repeat(pad, 1)]) else: spatial_feat = spatial_feat[:motion_feat.shape[0]] features = torch.cat([spatial_feat, motion_feat], dim=1) return features.cpu()