-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransformer2.py
More file actions
133 lines (106 loc) · 4.88 KB
/
Copy pathtransformer2.py
File metadata and controls
133 lines (106 loc) · 4.88 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""
IMUTransformerEncoder model
"""
import torch
from torch import nn
from torch.nn import TransformerEncoder, TransformerEncoderLayer
class IMUTransformerEncoder(nn.Module):
def __init__(self, input_dim,
num_classes,
transformer_dim=64,
n_heads=8,
dim_feedforward=128,
num_encoder_layers=6,
dropout=0.5,
transformer_activation="gelu",
encode_position = True):
"""
config: (dict) configuration of the model
"""
super().__init__()
self.transformer_dim = transformer_dim
self.input_proj = nn.Sequential(nn.Conv1d(input_dim[1], self.transformer_dim, 1), nn.GELU(),
nn.Conv1d(self.transformer_dim, self.transformer_dim, 1), nn.GELU(),
nn.Conv1d(self.transformer_dim, self.transformer_dim, 1), nn.GELU(),
nn.Conv1d(self.transformer_dim, self.transformer_dim, 1), nn.GELU())
self.window_size = input_dim[0]
self.encode_position = encode_position
encoder_layer = TransformerEncoderLayer(d_model = self.transformer_dim,
nhead = n_heads,
dim_feedforward = dim_feedforward,
dropout = dropout,
activation = transformer_activation)
self.transformer_encoder = TransformerEncoder(encoder_layer,
num_layers = num_encoder_layers,
norm = nn.LayerNorm(self.transformer_dim))
self.cls_token = nn.Parameter(torch.zeros((1, self.transformer_dim)), requires_grad=True)
if self.encode_position:
self.position_embed = nn.Parameter(torch.randn(self.window_size + 1, 1, self.transformer_dim))
num_classes = num_classes
self.imu_head = nn.Sequential(
nn.LayerNorm(self.transformer_dim),
nn.Linear(self.transformer_dim, self.transformer_dim//4),
nn.GELU(),
nn.Dropout(0.1),
nn.Linear(self.transformer_dim//4, num_classes)
)
self.log_softmax = nn.LogSoftmax(dim=1)
# init
for p in self.parameters():
if p.dim() > 1:
nn.init.xavier_uniform_(p)
def forward(self, data):
src = data # Shape N x S x C with S = sequence length, N = batch size, C = channels
# Embed in a high dimensional space and reshape to Transformer's expected shape
src = self.input_proj(src.transpose(1, 2)).permute(2, 0, 1)
# Prepend class token
cls_token = self.cls_token.unsqueeze(1).repeat(1, src.shape[1], 1)
src = torch.cat([cls_token, src])
# Add the position embedding
if self.encode_position:
src += self.position_embed
# Transformer Encoder pass
target = self.transformer_encoder(src)[0]
# Class probability
target = self.log_softmax(self.imu_head(target))
return target
def get_activation(activation):
"""Return an activation function given a string"""
if activation == "relu":
return nn.ReLU(inplace=True)
if activation == "gelu":
return nn.GELU()
raise RuntimeError("Activation {} not supported".format(activation))
class IMUCLSBaseline(nn.Module):
def __init__(self, input_dim, num_classes, transformer_dim=64, dropout_prob=0.5):
super(IMUCLSBaseline, self).__init__()
self.conv1 = nn.Sequential(nn.Conv1d(input_dim[1], transformer_dim, kernel_size=1), nn.ReLU())
self.conv2 = nn.Sequential(nn.Conv1d(transformer_dim, transformer_dim, kernel_size=1), nn.ReLU())
self.dropout = nn.Dropout(dropout_prob)
self.maxpool = nn.MaxPool1d(2) # Collapse T time steps to T/2
self.fc1 = nn.Linear(input_dim[0]*(transformer_dim//2), transformer_dim, nn.ReLU())
self.fc2 = nn.Linear(transformer_dim, num_classes)
self.log_softmax = nn.LogSoftmax(dim=1)
# init
for p in self.parameters():
if p.dim() > 1:
nn.init.xavier_uniform_(p)
def forward(self, data):
"""
Forward pass
:param x: B X M x T tensor reprensting a batch of size B of M sensors (measurements) X T time steps (e.g. 128 x 6 x 100)
:return: B X N weight for each mode per sample
"""
data = data.swapaxes(1, 2)
# print(data.shape)
# # data = data.transpose(1, 2)
# # print(data.shape)
x = data
x = self.conv1(x)
x = self.conv2(x)
x = self.dropout(x)
x = self.maxpool(x) # return B X C/2 x M
x = x.view(x.size(0), -1) # B X C/2*M
x = self.fc1(x)
x = self.log_softmax(self.fc2(x))
return x # B X N