Skip to content

Commit 8992b3f

Browse files
iLampardclaude
andcommitted
Fix ANHN construction and sampled-state shapes
ANHN was unusable: it subscripted ModelConfig (which has no __getitem__), so construction raised TypeError, and compute_states_at_sample_times computed the same tensor seq_len times in a loop and stacked the copies, returning a 5-D tensor that crashed loglike_loss. Use attribute access on the config and return the single (already correctly broadcast) state tensor. Add construction, loss/backward, and shape tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 4d68a68 commit 8992b3f

2 files changed

Lines changed: 80 additions & 12 deletions

File tree

easy_tpp/model/torch_model/torch_anhn.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ def __init__(self, model_config):
1818
"""
1919
super(ANHN, self).__init__(model_config)
2020

21-
self.d_time = model_config['time_emb_size']
22-
self.use_norm = model_config['use_ln']
21+
self.d_time = model_config.time_emb_size
22+
self.use_norm = model_config.use_ln
2323

24-
self.n_layers = model_config['num_layers']
25-
self.n_head = model_config['num_heads']
26-
self.dropout = model_config['dropout']
24+
self.n_layers = model_config.num_layers
25+
self.n_head = model_config.num_heads
26+
self.dropout = model_config.dropout_rate
2727

2828
self.layer_rnn = nn.LSTM(input_size=self.hidden_size, hidden_size=self.hidden_size, batch_first=True)
2929

@@ -230,14 +230,8 @@ def compute_states_at_sample_times(self, intensity_base, intensity_alpha, intens
230230
# [batch_size, seq_len, num_samples, 1, 1]
231231
sample_dtimes_ = sample_dtimes[:, :, :, None, None]
232232

233-
states_samples = []
234-
seq_len = intensity_base.size()[1]
235-
for _ in range(seq_len):
236-
states_samples_ = self.compute_states_at_event_times(mu, alpha, delta, base_elapses + sample_dtimes_)
237-
states_samples.append(states_samples_)
238-
239233
# [batch_size, seq_len, num_sample, hidden_size]
240-
states_samples = torch.stack(states_samples, dim=1)
234+
states_samples = self.compute_states_at_event_times(mu, alpha, delta, base_elapses + sample_dtimes_)
241235
return states_samples
242236

243237
def compute_intensities_at_sample_times(self, time_seqs, time_delta_seqs, type_seqs, sample_dtimes, **kwargs):

tests/test_anhn.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import torch
2+
3+
from easy_tpp.config_factory import ModelConfig
4+
from easy_tpp.model import TorchANHN
5+
6+
7+
def make_model_config():
8+
return ModelConfig.parse_from_yaml_config({
9+
'model_id': 'ANHN',
10+
'hidden_size': 8,
11+
'time_emb_size': 8,
12+
'num_layers': 1,
13+
'num_heads': 1,
14+
'num_event_types': 3,
15+
'num_event_types_pad': 4,
16+
'event_pad_index': 3,
17+
'gpu': -1,
18+
'loss_integral_num_sample_per_step': 5,
19+
})
20+
21+
22+
def make_batch():
23+
time_delta_seqs = torch.tensor([
24+
[0.0, 0.4, 0.6, 0.5, 0.7],
25+
[0.0, 0.3, 0.2, 0.6, 0.4],
26+
])
27+
time_seqs = torch.cumsum(time_delta_seqs, dim=-1)
28+
type_seqs = torch.tensor([
29+
[0, 1, 2, 0, 1],
30+
[2, 1, 0, 2, 1],
31+
], dtype=torch.long)
32+
seq_non_pad_mask = torch.ones_like(type_seqs, dtype=torch.bool)
33+
attention_mask = torch.triu(torch.ones(2, 5, 5, dtype=torch.bool), diagonal=1)
34+
return {
35+
'time_seqs': time_seqs,
36+
'time_delta_seqs': time_delta_seqs,
37+
'type_seqs': type_seqs,
38+
'seq_non_pad_mask': seq_non_pad_mask,
39+
'attention_mask': attention_mask,
40+
}
41+
42+
43+
def test_construction():
44+
TorchANHN(make_model_config())
45+
46+
47+
def test_loglike_loss_runs():
48+
model = TorchANHN(make_model_config())
49+
50+
loss, num_events = model.loglike_loss(**make_batch())
51+
52+
assert torch.isfinite(loss)
53+
assert num_events > 0
54+
assert loss.requires_grad
55+
loss.backward()
56+
57+
58+
def test_sample_states_shape():
59+
model = TorchANHN(make_model_config())
60+
batch = make_batch()
61+
dtime_seqs = batch['time_delta_seqs'][:, 1:]
62+
type_seqs = batch['type_seqs'][:, :-1]
63+
attention_mask = batch['attention_mask'][:, 1:, :-1]
64+
65+
_, (intensity_base, intensity_alpha, intensity_delta), (base_dtime, _) = model.forward(
66+
dtime_seqs, type_seqs, attention_mask
67+
)
68+
sample_dtimes = model.make_dtime_loss_samples(dtime_seqs)
69+
states = model.compute_states_at_sample_times(
70+
intensity_base, intensity_alpha, intensity_delta, base_dtime, sample_dtimes
71+
)
72+
73+
assert states.ndim == 4
74+
assert states.shape == (2, 4, 5, 8)

0 commit comments

Comments
 (0)