theodoredc commited on
Commit
657c0f0
·
verified ·
1 Parent(s): b0f94fb

Uploaded model

Browse files
model/attention_weighted_pooling.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ class AttentionWeightedPooling(nn.Module):
6
+ def __init__(self, in_dim, hidden_dim=128):
7
+ super().__init__()
8
+
9
+ # equivalent to conv blocks in paper → here MLP over time
10
+ self.attn = nn.Sequential(
11
+ nn.Linear(in_dim, hidden_dim),
12
+ nn.ReLU(),
13
+ nn.Linear(hidden_dim, 1),
14
+ nn.Sigmoid()
15
+ )
16
+
17
+ def forward(self, x):
18
+ """
19
+ x: (B, T, C)
20
+ """
21
+ # compute attention weights
22
+ weights = self.attn(x) # (B, T, 1)
23
+
24
+ # apply weights
25
+ weighted = x * weights # (B, T, C)
26
+
27
+ # weighted average pooling
28
+ pooled = weighted.sum(dim=1) / (weights.sum(dim=1) + 1e-8)
29
+
30
+ return pooled # (B, C)
model/chordbeat_encoder.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ class PositionalEncoding(nn.Module):
6
+ def __init__(self, d_model, max_len=500):
7
+ super().__init__()
8
+
9
+ pe = torch.zeros(max_len, d_model)
10
+ position = torch.arange(0, max_len).unsqueeze(1)
11
+
12
+ div_term = torch.exp(
13
+ torch.arange(0, d_model, 2) * (-torch.log(torch.tensor(10000.0)) / d_model)
14
+ )
15
+
16
+ pe[:, 0::2] = torch.sin(position * div_term)
17
+ pe[:, 1::2] = torch.cos(position * div_term)
18
+
19
+ self.pe = pe.unsqueeze(0) # (1, T, D)
20
+
21
+ def forward(self, x):
22
+ return x + self.pe[:, :x.size(1)].to(x.device)
23
+
24
+
25
+ class ChordBeatEncoder(nn.Module):
26
+ def __init__(self, input_dim=13, d_model=128, nhead=4, num_layers=3):
27
+ super().__init__()
28
+
29
+ # project input → model dim
30
+ self.input_proj = nn.Linear(input_dim, d_model)
31
+
32
+ self.pos_enc = PositionalEncoding(d_model)
33
+
34
+ encoder_layer = nn.TransformerEncoderLayer(
35
+ d_model=d_model,
36
+ nhead=nhead,
37
+ batch_first=True
38
+ )
39
+
40
+ self.transformer = nn.TransformerEncoder(
41
+ encoder_layer,
42
+ num_layers=num_layers
43
+ )
44
+
45
+ # pooling (same idea as your audio side)
46
+ self.pool = nn.Sequential(
47
+ nn.Linear(d_model, 1),
48
+ nn.Softmax(dim=1)
49
+ )
50
+
51
+ self.output_proj = nn.Linear(d_model, d_model)
52
+
53
+ def forward(self, x):
54
+ """
55
+ x: (B, T, 13)
56
+ """
57
+
58
+ x = self.input_proj(x) # (B, T, D)
59
+ x = self.pos_enc(x)
60
+
61
+ x = self.transformer(x) # (B, T, D)
62
+
63
+ # attention pooling
64
+ weights = self.pool(x) # (B, T, 1)
65
+ h = (x * weights).sum(dim=1)
66
+
67
+ z = self.output_proj(h)
68
+
69
+ return z, h
model/model.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ from transformers import EncodecModel, EncodecConfig
4
+ from model.attention_weighted_pooling import AttentionWeightedPooling
5
+ from model.projection import ProjectionHead
6
+ from model.chordbeat_encoder import ChordBeatEncoder
7
+
8
+ class MusicConRec(nn.Module):
9
+ def __init__(self, codebook_size=1024, feature_dim=128, proj_dim=128):
10
+ super().__init__()
11
+
12
+ # === AUDIO SIDE ===
13
+ self.encodec = EncodecModel.from_pretrained("facebook/encodec_24khz")
14
+
15
+ # Do not freeze EncodecModel parameters — allow fine-tuning
16
+ for param in self.encodec.parameters():
17
+ param.requires_grad = True
18
+
19
+ self.code_embedding = nn.Embedding(codebook_size, feature_dim)
20
+
21
+ self.audio_pool = AttentionWeightedPooling(feature_dim)
22
+ self.audio_proj = ProjectionHead(feature_dim, out_dim=proj_dim)
23
+
24
+ # === CHORD SIDE ===
25
+ self.chord_encoder = ChordBeatEncoder(
26
+ input_dim=13,
27
+ d_model=feature_dim
28
+ )
29
+
30
+ def forward(self, audio, chord):
31
+ """
32
+ audio: (B, 1, T)
33
+ chord: (B, T_chord, 13)
34
+ """
35
+
36
+
37
+ # =========================
38
+ # ENCODE
39
+ # =========================
40
+
41
+ encoder_outputs = self.encodec.encode(audio)
42
+
43
+ audio_codes = encoder_outputs['audio_codes'].long()
44
+ audio_scales = encoder_outputs['audio_scales']
45
+
46
+
47
+ codes = audio_codes.squeeze(0).permute(0, 2, 1)
48
+ codes = self.code_embedding(codes) # (B, T, Q, D)
49
+ codes = codes.mean(dim=2) # (B, T, D)
50
+
51
+ # =========================
52
+ # POOL + PROJECT
53
+ # =========================
54
+ h_audio = self.audio_pool(codes) # (B, D)
55
+ z_audio = self.audio_proj(h_audio) # (B, proj_dim)
56
+
57
+ # =========================
58
+ # RECONSTRUCTION
59
+ # =========================
60
+ x_recon = self.encodec.decode(audio_codes, audio_scales)['audio_values']
61
+ x_recon = torch.tanh(x_recon).clamp(-1.0, 1.0)
62
+
63
+ # =========================
64
+ # CHORD BRANCH
65
+ # =========================
66
+ z_chord, h_chord = self.chord_encoder(chord)
67
+
68
+ return {
69
+ "x_recon": x_recon,
70
+ "z_audio": z_audio,
71
+ "z_chord": z_chord,
72
+ "h_audio": h_audio,
73
+ "h_chord": h_chord
74
+ }
model/projection.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ class ProjectionHead(nn.Module):
6
+ def __init__(self, in_dim, hidden_dim=512, out_dim=128):
7
+ super().__init__()
8
+
9
+ self.net = nn.Sequential(
10
+ nn.Linear(in_dim, hidden_dim),
11
+ nn.BatchNorm1d(hidden_dim),
12
+ nn.ReLU(),
13
+ nn.Linear(hidden_dim, out_dim)
14
+ )
15
+
16
+ def forward(self, x):
17
+ return self.net(x)