Transformer encoder based 모델을 만드는 중 의문이 들어서 질문 드립니다.
일단 제가 할려는 application은 물체에 변형률을 가했을 때, 출력되는 응력예측입니다. 그래서 제가 가지고 있는 data의 형태는 input: (6200, 25,4), output: (6200,25, 4)로 서로 대응 된다고 보시면 되고(sample, sequence, features)라고 보시면 될 것 같습니다.
여기서 저는 예를들어, 변형률의 전체 sequence의 step 1에서 step 13을 넣었을 때, step 13에서의 응력을 예측. 최대로는, 변형률 step1에서 step 25을 넣었을 때, step 25에서의 응력 예측을 하고 싶습니다. 여기서 당연히 mask를 써서 future에에서 오는 attention은 생략을 하게 됩니다.
이 모델에서 data shape의 형태 흐름을 살펴보면 처음 input data를 linear에 통과하여 (batch, sequence, features) -->(batch, sequence, d_model)이 되고 encoder에 들어가게 되면 최종 output도 마찬가지로 (batch,sequence,d_model)의 형태로 출력이 됩니다.
그다음 MLP를 통해 현재 step에서의 응력을 출력하고 싶은데 여기서 encoder에서 출력된 output의 마지막 sequence만 가져와서 mlp의 입력으로 사용하는게 맞는 방법일 까요? 그러면 현재 step에서의 (batch,d_model)->(batch,features)로 예측이 가능하게 되긴 합니다.
코드는 다음과 같습니다.
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset, random_split
import math
Model Definition
class TransformerModel(nn.Module):
def init(self, input_size,output_size, d_model, nhead, num_layers, dim_feedforward, dropout=0):
super(TransformerModel, self).init()
self.pos_encoder = PositionalEncoding(d_model, dropout)
encoder_layers = nn.TransformerEncoderLayer(d_model=d_model, nhead=nhead, dim_feedforward=dim_feedforward, dropout=dropout)
self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers=num_layers)
self.encoder = nn.Linear(input_size, d_model)
self.decoder = nn.Sequential(
nn.Linear(d_model, 128),
nn.ReLU(),
nn.Linear(128, output_size)
)
self.d_model = d_model
def generate_mask(self, sz):
mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
return mask
def forward(self, src, seq_len):
src = self.encoder(src) * math.sqrt(self.d_model)
src = self.pos_encoder(src)
mask = self.generate_mask(seq_len).to(src.device)
output = self.transformer_encoder(src.transpose(0, 1), mask).transpose(0, 1)
current_step_output = self.decoder(output[:,-1,:])
return current_step_output
class PositionalEncoding(nn.Module):
def init(self, d_model, dropout=0, max_len=500):
super(PositionalEncoding, self).init()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return self.dropout(x)
위의 방법말고,
변형률(input data)에 대해서만 attention을 진행하고 MLP에서 (batch, sequence, d_model) -->(batch, sequence, features)방법은 괜찮은가요??
위의 코드의 단점은 하나의sequence데이터 하나당 총 sequence의 step갯수만큼 학습을 해줘야하는 것 같습니다. 예를 들어 step1~1, 1~2, 1~3...1~25에 대해서 학습을 해줘야 해서 시간이 오래 걸리게됩니다.