https://www.kiise.or.kr/conference/kcc/2024/
import torch
import torch.nn as nn
import torch.nn.functional as F
# Audio-guided Attention Layer
# 이 클래스는 오디오 정보를 사용하여 비디오의 중요한 부분에 주의를 집중하는 구조입니다.
# 오디오와 비디오 간의 상호작용을 계산하여, 비디오에서 어떤 부분이 중요한지 결정하는데 도움을 줍니다.
class PositionAttn(nn.Module):
def __init__(self, embed_dim, dim):
super(PositionAttn, self).__init__()
# 오디오 임베딩을 위한 선형 변환
self.affine_audio = nn.Linear(embed_dim, dim)
# 비디오 임베딩을 위한 선형 변환
self.affine_video = nn.Linear(512, dim)
# 비디오 attention 맵 생성을 위한 선형 변환 (주의 계산을 위한 부분)
self.affine_v = nn.Linear(dim, 49, bias=False)
# 오디오 attention 맵 생성을 위한 선형 변환
self.affine_g = nn.Linear(dim, 49, bias=False)
# attention score를 계산하는 마지막 선형 변환
self.affine_h = nn.Linear(49, 1, bias=False)
# 최종 attention 된 비디오 특징에 대한 선형 변환
self.affine_feat = nn.Linear(512, dim)
# 비선형 활성화 함수 ReLU
self.relu = nn.ReLU()
# forward 함수는 비디오와 오디오 데이터를 입력으로 받아 attention을 계산합니다.
def forward(self, video, audio):
# 비디오 데이터를 flatten해서 변환 (Batch * 시퀀스 길이, 512 크기의 특징 벡터로 변환)
v_t = video.view(video.size(0) * video.size(1), -1, 512).contiguous()
V = v_t # 원래 비디오 특징 저장
# 비디오와 오디오 데이터를 임베딩하고, 활성화 함수 적용
v_t = self.relu(self.affine_video(v_t))
a_t = audio.view(-1, audio.size(-1)) # 오디오 데이터를 일렬로 변환
a_t = self.relu(self.affine_audio(a_t))
# 비디오와 오디오 데이터를 결합하여 attention 값을 생성 (음성 가이드된 주의력)
content_v = self.affine_v(v_t) + self.affine_g(a_t).unsqueeze(2)
# tanh 활성화 함수와 선형 변환을 거쳐 attention score 계산
z_t = self.affine_h(torch.tanh(content_v)).squeeze(2)
# attention score를 softmax로 정규화하여 주의 맵 생성
alpha_t = F.softmax(z_t, dim=-1).view(z_t.size(0), -1, z_t.size(1))
# attention 맵을 비디오 특징에 적용해 중요한 부분을 강조 (가중합)
c_t = torch.bmm(alpha_t, V).view(-1, 512)
video_t = c_t.view(video.size(0), -1, 512)
# 최종적으로 attention된 비디오 특징에 선형 변환을 적용
video_t = self.affine_feat(video_t)
return video_t
# Bottom-Up Attention Layer for video and audio fusion
# 이 클래스는 비디오와 오디오를 결합하기 위한 attention 메커니즘을 적용합니다.
# 비디오와 오디오 간의 상호작용을 통해 비디오에서 중요한 부분을 선택하고 강조합니다.
class BottomUpExtract(nn.Module):
def __init__(self, emed_dim, dim):
super(BottomUpExtract, self).__init__()
# PositionAttn 클래스를 이용하여 오디오 기반의 비디오 attention을 적용
self.attn = PositionAttn(emed_dim, dim)
def forward(self, video, audio):
# PositionAttn을 사용하여 비디오와 오디오 간의 상호작용된 특징을 생성
feat = self.attn(video, audio)
return feat
# Main model class with LSTM/GRU and cross-attention layers
# 이 모델은 오디오와 비디오 데이터를 각각의 특성 추출기를 통해 처리하고,
# 교차 주의 메커니즘을 사용해 두 모달리티 간의 중요한 정보를 상호 교환합니다.
class DCNWithRCNN(nn.Module):
def __init__(self, opt):
super(DCNWithRCNN, self).__init__()
print("Initializing DCNWithRCNN...")
# 오디오 추출 레이어 (GRU 또는 LSTM 사용)
# 옵션에 따라 GRU 또는 LSTM을 사용하여 오디오 데이터를 처리합니다.
if opt.rnn == "GRU":
self.audio_extract = GRU(128, opt.audio_size, opt.num_layers, opt.droprnn, residual_embeddings=True)
self.video_extract = GRU(opt.video_size, opt.video_size, opt.num_layers, opt.droprnn, residual_embeddings=True)
else:
self.audio_extract = LSTM(128, opt.audio_size, opt.num_layers, opt.droprnn, residual_embeddings=True)
self.video_extract = LSTM(opt.video_size, opt.video_size, opt.num_layers, opt.droprnn, residual_embeddings=True)
# 입력 데이터를 정규화하는 레이어
self.normalize = Normalization()
# 비디오 attention 레이어 (오디오 정보를 사용해 비디오의 중요한 부분을 선택)
self.video_attn = BottomUpExtract(opt.audio_size, opt.video_size)
# 교차 주의 레이어 (오디오와 비디오의 결합된 특징을 처리)
self.coattn = DCNLayer(opt.video_size, opt.audio_size, opt.num_seq, opt.dropout)
# 최종 예측을 위한 레이어
self.predict = PredictLayer(opt.video_size, opt.audio_size, opt.num_classes, opt.dropout)
# 네트워크 가중치 초기화
self.init_weights()
# 가중치 초기화 함수 (Xavier 또는 다른 방법으로 초기화 가능)
def init_weights(self, init_type='xavier', init_gain=1):
def init_func(m):
classname = m.__class__.__name__
if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
if init_type == 'normal':
init.uniform_(m.weight.data, 0.0, init_gain)
elif init_type == 'xavier':
init.xavier_uniform_(m.weight.data, gain=init_gain)
elif init_type == 'kaiming':
init.kaiming_uniform_(m.weight.data, a=0, mode='fan_in')
elif init_type == 'orthogonal':
init.orthogonal_(m.weight.data, gain=init_gain)
else:
raise NotImplementedError(f'initialization method {init_type} is not implemented')
if hasattr(m, 'bias') and m.bias is not None:
init.constant_(m.bias.data, 0.0)
print(f'Initializing network with {init_type}')
self.apply(init_func)
# forward 함수는 오디오와 비디오 데이터를 받아 처리하고 최종적으로 예측값을 반환
def forward(self, audio, video):
# 입력 데이터를 정규화
audio, video = self.normalize(audio, video)
# 오디오와 비디오 특징을 추출
audio = self.audio_extract(audio)
video = self.video_attn(video, audio) # 오디오 정보를 사용한 비디오 attention
video = self.video_extract(video)
# 오디오와 비디오 간의 상호작용을 적용 (joint cross-attention)
video, audio = self.coattn(video, audio)
# 최종 예측을 수행
score = self.predict(video, audio)
return score
graph TB
A1(Start) --> A2(Get_Dataset)
A2 --> A3(Set_Dataset)
A3 --> A4(Load_Dataset)
A4 -->|Video Processing| B1(Read_Video)
B1 --> B2(Video_Resize)
B2 --> B3(Downsample)
B3 --> B4(Normalized)
A4 -->|Audio Processing| C1(Read_Audio)
C1 --> C2(Downsample_MFCC)
C2 --> C3(Imaging)
C3 --> C4(Normalized)
B4 --> D(Data_Fusion)
C4 --> D
D --> E1(Pre-Trained_Encoder)
E1 --> F(Pooling_Layer)
F --> G(Normalization_Layer)
G --> H(FC_Layer)
E1 <-- Load_model
H --> I(End)
https://www.kiise.or.kr/conference/kcc/2024/


