File size: 6,536 Bytes
17f1f54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import torch
import numpy as np

from data import Dataset, make_data_iter
from helpers import calculate_dtw
from batch import Batch
from model import Model
from constants import PAD_TOKEN


# Validate epoch given a dataset
# def validate_on_data(model: Model,
#                      data: Dataset,
#                      batch_size: int,
#                      max_output_length: int,
#                      eval_metric: str,
#                      loss_function: torch.nn.Module = None,
#                      batch_type: str = "sentence",
#                      type = "val",
#                      BT_model = None):

#     valid_iter = make_data_iter(
#         dataset=data, batch_size=batch_size,
#         shuffle=True, train=False)

#     pad_index = model.src_vocab.stoi[PAD_TOKEN]
#     # disable dropout
#     model.eval()
#     # don't track gradients during validation
#     with torch.no_grad():
#         valid_hypotheses = []
#         valid_references = []
#         valid_inputs = []
#         file_paths = []
#         all_dtw_scores = []

#         valid_loss = 0
#         total_ntokens = 0
#         total_nseqs = 0

#         batches = 0
#         for valid_batch in iter(valid_iter):
#             # Extract batch
#             batch = Batch(torch_batch=valid_batch,
#                           pad_index=pad_index,
#                           model=model)
#             targets = batch.trg_input

#             # run as during training with teacher forcing
#             if loss_function is not None and batch.trg is not None:
#                 # Get the loss for this batch
#                 batch_loss = model.get_loss_for_batch(is_train=True,
#                                                          batch=batch,
#                                                          loss_function=loss_function)

#                 valid_loss += batch_loss
#                 total_ntokens += batch.ntokens
#                 total_nseqs += batch.nseqs

#             output = model.forward(src=batch.src,
#                                        trg_input=batch.trg_input[:, :, :150],
#                                        src_mask=batch.src_mask,
#                                        src_lengths=batch.src_lengths,
#                                        trg_mask=batch.trg_mask,
#                                        is_train=False)
            
#             output = torch.cat((output, batch.trg_input[:, :, 150:]), dim=-1)
            
#             # Add references, hypotheses and file paths to list
#             valid_references.extend(targets)
#             valid_hypotheses.extend(output)
#             file_paths.extend(batch.file_paths)
#             # Add the source sentences to list, by using the model source vocab and batch indices
#             valid_inputs.extend([[model.src_vocab.itos[batch.src[i][j]] for j in range(len(batch.src[i]))] for i in
#                                  range(len(batch.src))])

#             # Calculate the full Dynamic Time Warping score - for evaluation
#             dtw_score = calculate_dtw(targets, output)
#             all_dtw_scores.extend(dtw_score)

#             # Can set to only run a few batches
#             # if batches == math.ceil(20/batch_size):
#             #     break
#             batches += 1

#         # Dynamic Time Warping scores
#         current_valid_score = np.mean(all_dtw_scores)

#     return current_valid_score, valid_loss, valid_references, valid_hypotheses, \
#            valid_inputs, all_dtw_scores, file_paths
def validate_on_data(model: Model,
                     data: Dataset,
                     batch_size: int,
                     max_output_length: int,
                     eval_metric: str,
                     loss_function: torch.nn.Module = None,
                     vocab=None,
                     # tok_fun=None,
                     trg_size: int = 150,
                     BT_model=None):

    # Build validation DataLoader
    valid_iter = make_data_iter(
        dataset=data,
        batch_size=batch_size,
        vocab=vocab,
        # tok_fun=tok_fun,
        trg_size=trg_size,
        shuffle=False
    )

    pad_index = model.src_vocab.stoi[PAD_TOKEN]
    model.eval()

    with torch.no_grad():
        valid_hypotheses = []
        valid_references = []
        valid_inputs = []
        file_paths = []
        all_dtw_scores = []

        valid_loss = 0
        total_ntokens = 0
        total_nseqs = 0

        batches = 0
        for valid_batch in iter(valid_iter):
            # Wrap into Batch
            batch = Batch(torch_batch=valid_batch,
                          pad_index=pad_index,
                          model=model)
            targets = batch.trg_input

            # Compute loss if available
            if loss_function is not None and batch.trg is not None:
                batch_loss = model.get_loss_for_batch(
                    is_train=True,
                    batch=batch,
                    loss_function=loss_function
                )
                valid_loss += batch_loss
                total_ntokens += batch.ntokens
                total_nseqs += batch.nseqs

            # Forward pass
            output = model.forward(
                src=batch.src,
                trg_input=batch.trg_input[:, :, :trg_size],
                src_mask=batch.src_mask,
                src_lengths=batch.src_lengths,
                trg_mask=batch.trg_mask,
                is_train=False
            )

            # Concatenate remainder of target
            output = torch.cat((output, batch.trg_input[:, :, trg_size:]), dim=-1)

            # Collect results
            valid_references.extend(targets)
            valid_hypotheses.extend(output)
            file_paths.extend(batch.file_paths)
            valid_inputs.extend([
                [model.src_vocab.itos[batch.src[i][j]] for j in range(len(batch.src[i]))]
                for i in range(len(batch.src))
            ])

            # Dynamic Time Warping score
            dtw_score = calculate_dtw(targets, output)
            all_dtw_scores.extend(dtw_score)

            batches += 1
            
            # Clean up memory periodically during validation
            if batches % 10 == 0:
                torch.cuda.empty_cache()

        current_valid_score = np.mean(all_dtw_scores)

    return (
        current_valid_score,
        valid_loss,
        valid_references,
        valid_hypotheses,
        valid_inputs,
        all_dtw_scores,
        file_paths
    )