目錄

1140619 meeting

前言

為在 $SSSD^{S4}$ 模型中嵌入 $MRTS$ 並進行預測,本次修改相關儲存預測的程式碼。

報錯

在執行原先程式碼時會出現以下錯誤。

執行結果參考
 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
(sssd) u6025091@omciystest1140615-2jhh4:~/SSSD_CP$ ./scripts/diffusion/inference_job.sh -m configs/model.yaml -i configs/inference.yaml
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-15 12:01:12,468 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-15 12:01:12,699 - sssd.utils.logger - INFO - Current time: 2025-06-15 12:01:12
2025-06-15 12:01:40,463 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-15 12:01:40,464 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_200_with_custom/tf/200/original/tf/T200_beta00.0001_betaT0.02/max
2025-06-15 12:01:45,795 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
Traceback (most recent call last):
  File "/home/u6025091/SSSD_CP/scripts/diffusion/infer.py", line 117, in <module>
    run_job(model_config, inference_config, device, args.ckpt_iter)
  File "/home/u6025091/SSSD_CP/scripts/diffusion/infer.py", line 96, in run_job
    ).generate()
  File "/home/u6025091/.local/lib/python3.10/site-packages/sssd/inference/generator.py", line 144, in generate
    sampling(
  File "/home/u6025091/.local/lib/python3.10/site-packages/sssd/utils/utils.py", line 155, in sampling
    epsilon_theta = net(
  File "/home/u6025091/.local/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1511, in _wrapped_call_impl
    return self._call_impl(*args, **kwargs)
  File "/home/u6025091/.local/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1520, in _call_impl
    return forward_call(*args, **kwargs)
  File "/home/u6025091/.local/lib/python3.10/site-packages/torch/nn/parallel/data_parallel.py", line 183, in forward
    return self.module(*inputs[0], **module_kwargs[0])
  File "/home/u6025091/.local/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1511, in _wrapped_call_impl
    return self._call_impl(*args, **kwargs)
  File "/home/u6025091/.local/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1520, in _call_impl
    return forward_call(*args, **kwargs)
  File "/home/u6025091/.local/lib/python3.10/site-packages/sssd/core/imputers/SSSDS4Imputer.py", line 242, in forward
    noise, conditional, mask, diffusion_steps, frk_basis = input_data
ValueError: not enough values to unpack (expected 5, got 4)

從錯誤訊息可知,錯誤發生在 /sssd/core/imputers/SSSDS4Imputer.py 中的函數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    def forward(self, input_data):
        noise, conditional, mask, diffusion_steps, frk_basis = input_data

        # Handle mask and concatenate it to the conditional input
        conditional = conditional * mask
        conditional = torch.cat([conditional, mask.float(), frk_basis], dim=1)

        # Forward pass through the network
        x = noise  # Ensure x is 3D (B, C, L)
        x = self.init_conv(x)
        x = self.residual_layer((x, conditional, diffusion_steps))
        y = self.final_conv(x)

        return y

其中的第 2 行被告知 input_data 只包含 4 個元素,但這裡想將它拆成 5 個變數。追尋源頭發現問題出現在 /sssd/inference/generator.py 的函數:

 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
def sampling(
    net: torch.nn.Module,
    size: Tuple[int, int, int],
    diffusion_hyperparams: Dict[str, torch.Tensor],
    cond: torch.Tensor,
    mask: torch.Tensor,
    only_generate_missing: int = 0,
    device: Union[torch.device, str] = "cpu",
) -> torch.Tensor:
    """
    Perform the complete sampling step according to p(x_0|x_T) = \prod_{t=1}^T p_{\theta}(x_{t-1}|x_t).

    Args:
        net (torch.nn.Module): The wavenet model.
        size (Tuple[int, int, int]): Size of tensor to be generated, usually (number of audios to generate, channels=1, length of audio).
        diffusion_hyperparams (Dict[str, torch.Tensor]): Dictionary of diffusion hyperparameters returned by calc_diffusion_hyperparams. Note, the tensors need to be cuda tensors.
        cond (torch.Tensor): Conditioning tensor.
        mask (torch.Tensor): Mask tensor.
        only_generate_missing (int, optional): Flag indicating whether to only generate missing values (default is 0).
        device (Union[torch.device, str], optional): Device to place tensors (default is 'cpu').

    Returns:
        torch.Tensor: The generated audio(s) in torch.Tensor, shape=size.
    """

    _dh = diffusion_hyperparams
    T, Alpha, Alpha_bar, Sigma = _dh["T"], _dh["Alpha"], _dh["Alpha_bar"], _dh["Sigma"]
    assert len(Alpha) == T
    assert len(Alpha_bar) == T
    assert len(Sigma) == T
    assert len(size) == 3

    x = std_normal(size, device)

    with torch.no_grad():
        for t in range(T - 1, -1, -1):
            if only_generate_missing == 1:
                x = x * (1 - mask).float() + cond * mask.float()
            diffusion_steps = (t * torch.ones((size[0], 1))).to(
                device
            )  # use the corresponding reverse step
            epsilon_theta = net(
                (x, cond, mask, diffusion_steps)
            )  # predict \epsilon according to \epsilon_\theta
            # update x_{t-1} to \mu_\theta(x_t)
            x = (
                x - (1 - Alpha[t]) / torch.sqrt(1 - Alpha_bar[t]) * epsilon_theta
            ) / torch.sqrt(Alpha[t])
            if t > 0:
                x = x + Sigma[t] * std_normal(
                    size, device
                )  # add the variance term to x_{t-1}

    return x

而錯誤出現在第 42 行中,此處應該要包含 frk_basis 這個參數。因此,修改如下:

 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
def sampling(
    net: torch.nn.Module,
    size: Tuple[int, int, int],
    diffusion_hyperparams: Dict[str, torch.Tensor],
    cond: torch.Tensor,
    mask: torch.Tensor,
    frk_basis: torch.Tensor,
    only_generate_missing: int = 0,
    device: Union[torch.device, str] = "cpu",
) -> torch.Tensor:
    """
    Perform the complete sampling step according to p(x_0|x_T) = \prod_{t=1}^T p_{\theta}(x_{t-1}|x_t).

    Args:
        net (torch.nn.Module): The wavenet model.
        size (Tuple[int, int, int]): Size of tensor to be generated, usually (number of audios to generate, channels=1, length of audio).
        diffusion_hyperparams (Dict[str, torch.Tensor]): Dictionary of diffusion hyperparameters returned by calc_diffusion_hyperparams. Note, the tensors need to be cuda tensors.
        cond (torch.Tensor): Conditioning tensor.
        mask (torch.Tensor): Mask tensor.
        only_generate_missing (int, optional): Flag indicating whether to only generate missing values (default is 0).
        device (Union[torch.device, str], optional): Device to place tensors (default is 'cpu').

    Returns:
        torch.Tensor: The generated audio(s) in torch.Tensor, shape=size.
    """

    _dh = diffusion_hyperparams
    T, Alpha, Alpha_bar, Sigma = _dh["T"], _dh["Alpha"], _dh["Alpha_bar"], _dh["Sigma"]
    assert len(Alpha) == T
    assert len(Alpha_bar) == T
    assert len(Sigma) == T
    assert len(size) == 3

    x = std_normal(size, device)

    with torch.no_grad():
        for t in range(T - 1, -1, -1):
            if only_generate_missing == 1:
                x = x * (1 - mask).float() + cond * mask.float()
            diffusion_steps = (t * torch.ones((size[0], 1))).to(
                device
            )  # use the corresponding reverse step
            epsilon_theta = net(
                (x, cond, mask, diffusion_steps, frk_basis)
            )  # predict \epsilon according to \epsilon_\theta
            # update x_{t-1} to \mu_\theta(x_t)
            x = (
                x - (1 - Alpha[t]) / torch.sqrt(1 - Alpha_bar[t]) * epsilon_theta
            ) / torch.sqrt(Alpha[t])
            if t > 0:
                x = x + Sigma[t] * std_normal(
                    size, device
                )  # add the variance term to x_{t-1}

    return x

因此,從 /sssd/inference/generator.py 呼叫此處的函數也需要修改:

 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
    def generate(self) -> list:
        """Generate samples using the given neural network model."""
        all_mses = []
        all_mapes = []
        for index, (batch,) in enumerate(self.dataloader):
            batch = batch.to(self.device)
            mask = self._update_mask(batch)

            if torch.isnan(mask).any():  # debug
                print(f"[Batch {index}] NaN in mask!")

            batch = torch.nan_to_num(batch, nan=0.0)  # Replace NaN with 0.0

            if torch.isnan(batch).any():  # debug
                print(f"[NaN DETECTED] Batch {index} has NaNs!")

            batch = batch.permute(0, 2, 1)

            generated_series = (
                sampling(
                    net=self.net,
                    size=batch.shape,
                    diffusion_hyperparams=self.diffusion_hyperparams,
                    cond=batch,
                    mask=mask,
                    frk_basis=self.frk_basis,
                    only_generate_missing=self.only_generate_missing,
                    device=self.device,
                )
                .detach()
                .cpu()
                .numpy()
            )
 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
import logging
import os
from typing import Dict, Iterable, Optional, Union

import numpy as np
import torch
import torch.nn as nn
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
from torch.utils.data import DataLoader

from sssd.core.model_specs import MASK_FN
from sssd.utils.logger import setup_logger
from sssd.utils.utils import find_max_epoch, sampling

from sssd.core.mrts.mrts import MRTS

LOGGER = setup_logger()


class DiffusionGenerator:
    """
    Generate data based on ground truth.

    Args:
        net (torch.nn.Module): The neural network model.
        device (Optional[Union[torch.device, str]]): The device to run the model on (e.g., 'cuda' or 'cpu').
        diffusion_hyperparams (dict): Dictionary of diffusion hyperparameters.
        local_path (str): Local path format for the model.
        testing_data (torch.Tensor): Tensor containing testing data.
        output_directory (str): Path to save generated samples.
        batch_size (int): Number of samples to generate.
        ckpt_path (str): Checkpoint directory.
        ckpt_iter (str): Pretrained checkpoint to load; 'max' selects the maximum iteration.
        masking (str): Type of masking: 'mnr' (missing not at random), 'bm' (black-out), 'rm' (random missing).
        missing_k (int): Number of missing time points for each channel across the length.
        only_generate_missing (int): Whether to generate only missing portions of the signal:
                                      - 0 (all sample diffusion),
                                      - 1 (generate missing portions only).
        saved_data_names (Iterable[str], optional): Names of data arrays to save (default is ("imputation", "original", "mask")).
        logger (Optional[logging.Logger], optional): Logger object for logging messages (default is None).
    """

    def __init__(
        self,
        net: torch.nn.Module,
        device: Optional[Union[torch.device, str]],
        diffusion_hyperparams: dict,
        local_path: str,
        dataloader: DataLoader,
        output_directory: str,
        batch_size: int,
        ckpt_path: str,
        ckpt_iter: str,
        masking: str,
        missing_k: int,
        only_generate_missing: int,
        saved_data_names: Iterable[str] = ("imputation", "original", "mask"),
        logger: Optional[logging.Logger] = None,
        locs: Optional[torch.Tensor] = None
    ):
        self.net = net
        self.device = device
        self.diffusion_hyperparams = diffusion_hyperparams
        self.local_path = local_path
        self.dataloader = dataloader
        self.batch_size = batch_size
        self.masking = masking
        self.missing_k = missing_k
        self.only_generate_missing = only_generate_missing
        self.logger = logger or LOGGER

        self.output_directory = self._prepare_output_directory(
            output_directory, local_path, ckpt_iter
        )
        self.saved_data_names = saved_data_names
        self._load_checkpoint(ckpt_path, ckpt_iter)


        self.locs = locs
        frk = MRTS(locs=self.locs, device=self.device)
        self.frk_basis = frk()
        batch_size_shape, time_shape, loc_shape = next(iter(dataloader))[0].shape
        
        #print(f"self.frk_basis is None, initializing...")
        frk_linear = nn.Linear(self.frk_basis.shape[1], time_shape).to(self.device)
        loc_embed = nn.Embedding(loc_shape, time_shape).to(self.device)

        self.frk_basis = frk_linear(self.frk_basis)  # [26, 29] → [26, 2000]
        loc_ids = torch.arange(loc_shape, device=self.device)
        self.frk_basis += loc_embed(loc_ids)  # 加入地點特徵
        self.frk_basis = self.frk_basis.unsqueeze(0).expand(batch_size_shape, -1, -1)  # [1, 26, 2000]
        self.frk_basis = self.frk_basis.detach()
        #print(f"frk unsqueeze shape: {self.frk_basis.shape}")
        #print(f"frk original shape: {self.frk_basis.shape}")

/scripts/diffusion/infer.py

  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
import argparse
from typing import Optional, Union

import torch
import torch.nn as nn
import yaml

from sssd.core.model_specs import MODEL_PATH_FORMAT, setup_model
from sssd.data.utils import get_dataloader
from sssd.inference.generator import DiffusionGenerator
from sssd.utils.logger import setup_logger
from sssd.utils.utils import calc_diffusion_hyperparams, display_current_time

import numpy as np

LOGGER = setup_logger()


def fetch_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-m",
        "--model_config",
        type=str,
        default="configs/model.yaml",
        help="Model configuration",
    )
    parser.add_argument(
        "-i",
        "--inference_config",
        type=str,
        default="configs/inference_config.yaml",
        help="Inference configuration",
    )
    parser.add_argument(
        "-ckpt_iter",
        "--ckpt_iter",
        default="max",
        help='Which checkpoint to use; assign a number or "max" to find the latest checkpoint',
    )
    return parser.parse_args()

# New function to load locations
def get_locations_loader(location_path, device: torch.device) -> torch.Tensor:
    locations = np.load(location_path)
    locations_tensor = torch.from_numpy(locations).float().to(device)
    return locations_tensor


def run_job(
    model_config: dict,
    inference_config: dict,
    device: Optional[Union[torch.device, str]],
    ckpt_iter: Union[str, int],
) -> None:
    trials = inference_config.get("trials")
    batch_size = inference_config["batch_size"]
    dataloader = get_dataloader(
        inference_config["data"]["test_path"],
        batch_size,
        device=device,
    )

    local_path = MODEL_PATH_FORMAT.format(
        T=model_config["diffusion"]["T"],
        beta_0=model_config["diffusion"]["beta_0"],
        beta_T=model_config["diffusion"]["beta_T"],
    )

    diffusion_hyperparams = calc_diffusion_hyperparams(
        **model_config["diffusion"], device=device
    )
    LOGGER.info(display_current_time())
    net = setup_model(inference_config["use_model"], model_config, device)

    # Check if multiple GPUs are available
    if torch.cuda.device_count() > 0:
        net = nn.DataParallel(net)

    data_names = ["imputation", "original", "mask"]
    directory = inference_config["output_directory"]

    if trials > 1:
        directory += "_{trial}"

    locations_loder = get_locations_loader(inference_config["data"]["location_path"], device)

    for trial in range(1, trials + 1):
        LOGGER.info(f"The {trial}th inference trial")
        saved_data_names = data_names if trial == 0 else data_names[0]

        mses, mapes = DiffusionGenerator(
            net=net,
            device=device,
            diffusion_hyperparams=diffusion_hyperparams,
            dataloader=dataloader,
            local_path=local_path,
            output_directory=directory.format(trial=trial) if trials > 1 else directory,
            ckpt_path=inference_config["ckpt_path"],
            ckpt_iter=ckpt_iter,
            batch_size=batch_size,
            masking=inference_config["masking"],
            missing_k=inference_config["missing_k"],
            only_generate_missing=inference_config["only_generate_missing"],
            saved_data_names=saved_data_names,
            locs=locations_loder,
        ).generate()

        LOGGER.info(f"Average MSE: {sum(mses) / len(mses)}")
        LOGGER.info(f"Average MAPE: {sum(mapes) / len(mapes)}")
        LOGGER.info(display_current_time())

/configs/inference.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Inference configuration
batch_size: 1  # Batch size for inference
output_directory: "./results/real_time/train_200_with_custom/tf/200/original/tf"  # Output directory for inference results
ckpt_path: "./results/real_time/checkpoints/test"  # Path to checkpoint for inference
trials: 1 # Replications

# Additional training settings
only_generate_missing: true  # Generate missing values only
use_model: 2  # Model to use for training
masking: "forecast"  # Masking strategy for missing values
missing_k: 200  # Number of missing values

# Data paths
data:
  test_path: "./datasets/real_time/pollutants_test.npy"  # Path to test data
  location_path: "./datasets/real_time/locations.npy"  # Path to location data

運行

目前仍可正常進行訓練,使用的 MRTS 函數如下:

  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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
"""
Title: Multi-Resolution Thin-plate Spline basis function for Spatial Data, and calculate the basis function by using rectangular or spherical coordinates.
Author: Hsu, Yao-Chih
Version: 1140611
Reference: Resolution Adaptive Fixed Rank Kringing by ShengLi Tzeng & Hsin-Cheng Huang
"""

# import modules
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from scipy.integrate import quad
from scipy.sparse.linalg import eigsh
from typing import Optional, Union
import logging
#import colorlog
#import datetime

## logger config
logger = logging.getLogger()
#handler = colorlog.StreamHandler()
#handler.setFormatter(colorlog.ColoredFormatter(
#    fmt='%(log_color)s%(asctime)s %(levelname)s: %(message)s',
#    datefmt='%Y-%m-%d %H:%M:%S',
#    log_colors={
#        'INFO': 'green',
#        'WARNING': 'yellow',
#        'ERROR': 'red',
#        'DEBUG': 'cyan',
#        'CRITICAL': 'bold_red',
#    }
#))
#logger.addHandler(handler)
#logger.setLevel(logging.INFO)

# classes
class MRTS(nn.Module):
    def __init__(self, locs: torch.Tensor, 
                 k: int=None, 
                 device: Optional[Union[torch.device, str]]=None, 
                 calculate_with_spherical: bool=False, 
                 standardize: bool=True, 
                 unbiased_std: bool=False
                 ):
        """
        Multi-Resolution Thin-plate Spline basis function.
        
        Args:
            locs: [N, d] tensor of spatial locations.
            k: (Optional) parameter for controlling resolution.
            device: (Optional) PyTorch device to use.
            calculate_with_spherical: (Optional) If True, use spherical coordinates for TPS calculation (default is False) (only supported when d == 2).
            standardize: (Optional) If True, perform standardization on locs (Recommended).
            unbiased_std: (Optional) If True, use unbiased standard deviation (dividing by N-1) (Recommended); 
                          if False, use biased standard deviation (dividing by N).
        """
        super().__init__()
        try:
            if device is None:
                self.device = torch.device('cpu')
                logger.warning(f'Parameter "device" was not set. Default value "cpu" is used.')
            else:
                self.device = torch.device(device)
                logger.info(f'Successfully using device "{self.device}".')
        except (TypeError, ValueError) as e:
            self.device = torch.device('cpu')
            logger.warning(f'Parameter "device" is not a valid device ({device}). Default value "cpu" is used. Error: {e}')

        self.register_buffer("locs", locs.to(self.device))
        self.N, self.d = locs.shape

        # number of basis
        max_k = self.N + self.d
        try:
            if k is None:
                self.k = max_k
                logger.warning(f'Parameter "k" was not set. Default value {self.k} is used.')
            elif 0 < k <= (max_k):
                self.k = k
            else:
                self.k = max_k
                logger.warning(f'Parameter "k" is out of valid range, it should be between 1 to {self.k}. Default value {self.k} is used.')
        except TypeError:
            self.k = max_k
            logger.warning(f'Parameter "k" is not an integer, the type you input is "{type(k).__name__}." Default value {self.k} is used.')

        self.calculate_with_spherical = calculate_with_spherical
        if type(self.calculate_with_spherical) is not bool:
            self.calculate_with_spherical = False
            logger.warning(f'Parameter "calculate_with_spherical" should be a boolean, the type you input is "{type(calculate_with_spherical).__name__}". Default value False is used.')
        elif self.calculate_with_spherical and self.d != 2:
            self.calculate_with_spherical = False
            logger.warning(f'Spherical TPS not implemented for d = {self.d}, only d = 2 is supported. Using rectangular coordinate system instead.')
        
        if self.calculate_with_spherical:
            logger.info(f'Calculate TPS with spherical coordinates.')
        else:
            logger.info(f'Calculate TPS with rectangular coordinates.')

        self.standardize = standardize
        if type(self.standardize) is not bool:
            self.standardize = True
            logger.warning(f'Parameter "standardize" should be a boolean, the type you input is "{type(standardize).__name__}". Default value True is used.')

        self.unbiased_std = unbiased_std
        if type(self.unbiased_std) is not bool:
            self.unbiased_std = False
            logger.warning(f'Parameter "unbiased_std" should be a boolean, the type you input is "{type(unbiased_std).__name__}". Default value False is used.')

    def _tps_phi(self, locs: torch.Tensor, calculate_with_spherical: bool=False) -> torch.Tensor:
        """
        Compute the Thin Plate Spline (TPS) radial basis matrix for input locations.

        Args:
            locs: [N, d] tensor of spatial locations.
            calculate_with_spherical: (Optional) If True, use spherical coordinates for TPS calculation (default is False) (only supported when d == 2).

        Returns:
            A [N, N] tensor representing the TPS radial basis matrix.
        """       

        # rectangular coordinate system
        if not calculate_with_spherical:
            return self.__calculate_phi_by_rectangular_coordinate(locs)
        
        # spherical coordinate system
        else:
            # convert to spherical coordinates
            ret = torch.zeros((self.N, self.N), device=locs.device)
            locs = locs * torch.pi / 180.0
            x = locs[:, 0]
            y = locs[:, 1]
            for i in range(self.N):
                for j in range(self.N):
                    ret[i, j] = self.__calculate_phi_by_spherical_coordinate(x[i], y[i], x[j], y[j])
            return ret

    def __calculate_phi_by_rectangular_coordinate(self, locs: torch.Tensor) -> torch.Tensor:
        """
        Calculate the TPS radial basis matrix using rectangular (Euclidean) coordinates.

        Args:
            locs: [N, d] tensor of spatial locations.

        Returns:
            A [N, N] tensor representing the TPS radial basis matrix.
        """
        dists = torch.cdist(locs, locs)  # Euclidean distances
        if self.d == 1:
            return (dists ** 3) / 12
        elif self.d == 2:
            mask = dists != 0
            ret = torch.zeros_like(dists)
            ret[mask] = (dists[mask] ** 2) * torch.log(dists[mask]) / (8 * torch.pi)
            return ret
        elif self.d == 3:
            return -dists / 8
        else:
            raise NotImplementedError(f"TPS not implemented for d = {self.d}")

    def __calculate_phi_by_spherical_coordinate(self, x1: float, y1: float, x2: float, y2: float) -> float:
        """
        Calculate the TPS radial basis function using spherical coordinates.
        
        Args:
            x1, y1: Spherical coordinates of the first point (in radians).
            x2, y2: Spherical coordinates of the second point (in radians). 

        Returns:
            A float representing the TPS radial basis function value.
        """
        cos_theta = torch.sin(x1) * torch.sin(x2) + torch.cos(x1) * torch.cos(x2) * torch.cos(y1 - y2)
        cos_theta = torch.clamp(cos_theta, -1.0, 1.0)
        #theta = torch.acos(cos_theta)
        ret = 1 - (torch.pi ** 2) / 6

        if not torch.isclose(cos_theta, torch.tensor(-1.0, device=cos_theta.device)):
            cos_theta = cos_theta.item()
            upper = (cos_theta + 1) / 2
            lower = 0
            result, _ = quad(self.__integrand_for_spherical_in_tps, lower, upper, epsabs=1e-6, epsrel=1e-6, limit=50)
            result = torch.tensor(result, dtype=torch.float32, device=self.device)
            ret -= result
        return ret
    
        # # method by GPT can just use tenser to calculate and efficient
        # # spherical coordinate system
        # locs_rad = locs * torch.pi / 180.0  # convert to radians
        # lat1 = locs_rad[:, 0].unsqueeze(1)  # [N, 1]
        # lon1 = locs_rad[:, 1].unsqueeze(1)  # [N, 1]
        # lat2 = locs_rad[:, 0].unsqueeze(0)  # [1, N]
        # lon2 = locs_rad[:, 1].unsqueeze(0)  # [1, N]

        # # Cosine of angular distance
        # cos_theta = (
        #     torch.sin(lat1) @ torch.sin(lat2) + torch.cos(lat1) @ torch.cos(lat2) * torch.cos(lon1 - lon2)
        # )
        # cos_theta = torch.clamp(cos_theta, -1.0, 1.0)

        # # Compute integral using trapezoidal rule
        # N = 100  # Number of steps in the integral approximation
        # x = torch.linspace(1e-6, 1.0, N, device=locs.device)  # avoid x=0
        # ln_term = torch.log(1 - x) / x  # [N]

        # def trapezoid_integrate(upper):  # upper: [N, N]
        #     upper = torch.clamp(upper, 1e-6, 1.0)
        #     area = torch.zeros_like(upper)
        #     for i in range(N - 1):
        #         x0, x1 = x[i], x[i + 1]
        #         y0, y1 = ln_term[i], ln_term[i + 1]
        #         h = x1 - x0
        #         area += h * (y0 + y1) / 2 * ((upper >= x1).float())  # only add where upper > x1
        #     return area

        # upper_bound = (cos_theta + 1) / 2  # [N, N]
        # integral_vals = trapezoid_integrate(upper_bound)  # [N, N]
        # ret = 1 - (torch.pi ** 2) / 6 - integral_vals
        # return ret
    
    def __integrand_for_spherical_in_tps(self, x):
        """
        Integrand function for the spherical TPS radial basis function.

        Args:
            x: The variable of integration.

        Returns:
            The value of the integrand at x.
        """
        return np.log(1 - x) / x
        
    def _standardize(self, x: torch.Tensor, unbiased_std: Optional[bool] = None) -> torch.Tensor:
        """
        A function to standardize the input tensor x.

        Args:
            x: Input tensor to be standardized.
            unbiased_std: (Optional) If True, use unbiased standard deviation (dividing by N-1); 
                          if False, use biased standard deviation (dividing by N).
                          Default is None, which uses the class attribute self.unbiased_std.

        Returns:
            A standardized tensor with mean 0 and standard deviation 1.
        """
        if unbiased_std is None:
            unbiased_std = self.unbiased_std
        mean = x.mean(dim=0, keepdim=True)  # keepdim=True to keep the same shape
        std = x.std(dim=0, unbiased=unbiased_std, keepdim=True)  # unbiased=False for population std
        std[std == 0] = 1.0
        x = (x - mean) / std
        return x

    def forward(self) -> torch.Tensor:
        """
        Forward pass to compute the basis functions. Constructs the basis functions based on the input locations and parameters.

        Returns:
            A tensor of shape [N, k] representing the basis functions.
        """

        # Construct X = [1, x1, x2, ..., xd]
        ones = torch.ones(self.N, 1, device=self.device)
        X = torch.cat([ones, self.locs], dim=1)  # [N, d+1]

        if self.k == 1:
            return ones
        elif self.k <= self.d:
            if self.standardize:
                X[:, 1:self.k] = self._standardize(X[:, 1:self.k])
            return X[:, :self.k]
        

        # TPS basis
        Phi = self._tps_phi(locs=self.locs, calculate_with_spherical=self.calculate_with_spherical)  # [N, N]
        
        # Q = I - X(XᵗX)⁻¹Xᵗ
        try:
            XtX_inv = torch.inverse(X.T @ X)  # [(d+1), (d+1)]
        except RuntimeError as e:
            logger.warning(f'torch.inverse failed due to {e}, this implies "X.T @ X" didn\'t have inverse. Using torch.linalg.pinv instead.')
            XtX_inv = torch.linalg.pinv(X.T @ X)
        Q = torch.eye(self.N, device=self.device) - X @ XtX_inv @ X.T

        # Eigen-decomposition
        G = Q @ Phi @ Q
        #eigenvalues, eigenvectors = torch.linalg.eigh(G)  # ascending order
        
        G = G.detach().cpu().numpy()
        eigenvalues, eigenvectors = eigsh(G, k=self.k - self.d - 1, which='LM')  # 'LM': Largest Magnitude, max k < N
        eigenvalues = torch.from_numpy(eigenvalues).to(self.device) 
        eigenvectors = torch.from_numpy(eigenvectors).to(self.device)

        # Filter out near-zero eigenvalues and sort descending
        #valid = eigenvalues > 1e-10
        #eigenvalues[~valid] *= -1.0  # make them positive
        #eigenvectors[:, ~valid] *= -1.0  # make them positive
        idx_desc = torch.argsort(eigenvalues, descending=True)
        eigenvalues = eigenvalues[idx_desc]
        eigenvectors = eigenvectors[:, idx_desc]

        Basis_high = eigenvectors * torch.sqrt(torch.tensor(self.N, dtype=torch.float32))

        # # Construct basis functions
        # Basis_high = (Phi.T - Phi @ X @ XtX_inv @ X.T).T @ eigenvectors @ torch.diag(1.0 / eigenvalues).to(self.device)
        
        # # the for loop
        # Basis_high_1 = torch.zeros(self.N, self.N, device=self.locs.device)
        # for i in range(self.N):
        #     phi_i = Phi[i, :]
        #     x_i = X[i, :]
        #     Phi_XXtXinv_x = (phi_i.T - Phi @ X @ XtX_inv @ x_i.T).T
        #     for j in range(self.N):
        #         lambda_j = 1 / eigenvalues[j]
        #         v_j = eigenvectors[:, j]
        #         Basis_high_1[i, j] = lambda_j * Phi_XXtXinv_x @ v_j
        # print(f'Basis_high:\n{Basis_high}, \n\nBasis_high_1:\n{Basis_high_1}')
        # print(torch.mean((Basis_high - Basis_high_1)**2))

        # Concatenate [1, x1, ..., xd] and B_high

        Basis_low = X  # [N, d+1]

        # Standardize
        if self.standardize:
            Basis_low[:, 1:(self.d + 1)] = self._standardize(Basis_low[:, 1:(self.d + 1)])

        F = torch.cat([Basis_low, Basis_high], dim=1)

        # Output k basis
        F = F[:, :self.k]

        # print('1')
        # eigenvalues = eigenvalues[:self.k - self.d - 1]  # Select top k - (d + 1) eigenvalues
        # eigenvectors = eigenvectors[:, :self.k - self.d - 1]  # Select top k - (d + 1) eigenvectors

        # # compute BBBH and UZ
        # BBB = XtX_inv @ X.T
        # BBBH = BBB @ Phi
        # BBB_gamma = BBB @ eigenvectors
        # B_BBB_gamma = X @ BBB_gamma
        # gammas = (eigenvectors - B_BBB_gamma) / eigenvalues.reshape(1, -1) * torch.sqrt(torch.tensor(self.N, dtype=torch.float32))
        # print('2')
        # col_sd = self.locs.std(dim=0, unbiased=True)
        # adjustment = torch.sqrt(torch.tensor(self.N / (self.N - 1), dtype=col_sd.dtype, device=col_sd.device))
        # diag_values = (adjustment / col_sd).cpu().numpy()
        # xobs_diag = np.diag(diag_values)
        # print('3')
        # # 初始化组合矩阵
        # UZ = np.zeros((self.N + self.d + 1, self.k))
        # print('4')
        # # 区块填充
        # UZ[:self.N, :self.k - self.d - 1] = gammas      # 左上区块
        # UZ[self.N, self.k - self.d - 1] = 1.0           # 中心单位元素
        # UZ[self.N + 1:, self.k - self.d:] = xobs_diag  # 右下对角区块

        return F  # [N, d+1 + k]
    
# functions


# main program
if __name__ == "__main__":
    # time
    start_time = datetime.datetime.now()

    # Load locations
    locations = np.load(f'locations.npy')

    print(f'locations:\n{locations}')
    print(f'locations shape: {locations.shape}')

    # Convert to tensor
    locs = torch.tensor(locations, dtype=torch.float32)

    # Create FRK basis
    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    frk_basis = MRTS(locs, device=device, calculate_with_spherical=False)

    # Forward pass
    #F = pd.DataFrame(frk_basis().detach().cpu().numpy())
    F = pd.DataFrame(frk_basis())
    #.detach().cpu().numpy()

    print(f'F:\n{F}')
    # print(f'F sum:\n{np.sum(F**2, axis=0)}')
    # print(f'F shape: {F.shape}')

    # time
    end_time = datetime.datetime.now()
    use_time = end_time - start_time
    print(f'Use time: {use_time}')





    # bx = pd.DataFrame(np.load('bx.npy'))
    # print(f'bx:\n{bx}')
    # print(f'bx shape: {bx.shape}')
    # print(f'bx sum:\n{np.sum(bx**2, axis=0)}')


    # # Compare with bx
    # temp = F.iloc[:, :bx.shape[1]] - bx
    # print(f'F - bx:\n{temp}')
    # print(f'F - bx sum**2:\n{np.sum(temp**2, axis=0)}')

    # from scipy.optimize import linear_sum_assignment

    # # 假設 F 和 bx 是 numpy array
    # # 計算 cost matrix(F[i] 和 bx[j] 的差異平方)
    # cost_matrix = np.array([[np.sum((F[i] - bx[j])**2) for j in range(bx.shape[0])] for i in range(F.shape[0])])

    # # 使用匈牙利演算法找出最小成本配對
    # row_ind, col_ind = linear_sum_assignment(cost_matrix)

    # # 印出結果
    # for i, j in zip(row_ind, col_ind):
    #     print(f'F[{i}] 對應到 bx[{j}], 差異平方: {cost_matrix[i, j]:.4f}')

    # # 如果你想印出總差異平方和
    # total_cost = cost_matrix[row_ind, col_ind].sum()
    # print(f'總差異平方和: {total_cost:.4f}')

運行過程如下:

執行結果參考
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
(sssd) u6025091@uuidi1test1140615-9hs5j:~/SSSD_CP$ ./scripts/diffusion/training_job.sh -m configs/model.yaml -t configs/training.yaml
Intializing conda
Activating Conda Env: sssd
[Execution - Training]
/home/u6025091/SSSD_CP/scripts/diffusion/train.py --model_config configs/model.yaml --training_config configs/training.yaml
2025-06-15 16:02:21,232 - sssd.utils.logger - INFO - Model spec: {'wavenet': {'input_channels': 26, 'output_channels': 26, 'residual_layers': 36, 'residual_channels': 256, 'skip_channels': 256, 'diffusion_step_embed_dim_input': 128, 'diffusion_step_embed_dim_hidden': 512, 'diffusion_step_embed_dim_output': 512, 's4_max_sequence_length': 2000, 's4_state_dim': 64, 's4_dropout': 0.0, 's4_bidirectional': True, 's4_use_layer_norm': True}, 'diffusion': {'T': 200, 'beta_0': 0.0001, 'beta_T': 0.02}}
2025-06-15 16:02:21,232 - sssd.utils.logger - INFO - Training spec: {'batch_size': 1, 'output_directory': './results/real_time/checkpoints/test', 'ckpt_iter': 'max', 'iters_per_ckpt': 100, 'iters_per_logging': 100, 'n_iters': 2000, 'learning_rate': 0.001, 'only_generate_missing': True, 'use_model': 2, 'masking': 'forecast', 'missing_k': 200, 'data': {'train_path': './datasets/real_time/pollutants_train.npy', 'location_path': './datasets/real_time/locations.npy'}}
2025-06-15 16:02:21,244 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-15 16:02:21,270 - sssd.utils.logger - INFO - Using device: cuda
2025-06-15 16:02:21,270 - sssd.utils.logger - INFO - Output directory ./results/real_time/checkpoints/test/T200_beta00.0001_betaT0.02
2025-06-15 16:02:56,388 - sssd.utils.logger - INFO - Current time: 2025-06-15 16:02:56
Parameter "k" was not set. Default value 28 is used.
self.frk_basis is None, initializing...
frk unsqueeze shape: torch.Size([1, 26, 2000])
2025-06-15 16:03:08,526 - sssd.utils.logger - INFO - Successfully loaded model at iteration 300
2025-06-15 16:03:08,530 - sssd.utils.logger - INFO - Start the 301 iteration
100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:09<00:00,  1.98s/it]
100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:06<00:00,  1.24s/it]
100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:06<00:00,  1.24s/it]
100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:06<00:00,  1.24s/it]
100%|██████████████████████████████████████████████████████████████████████████████████| 5/5 [00:06<00:00,  1.25s/it]

GPU 資源如下:

執行結果參考
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Every 0.1s: nvidia-smi                   uuidi1test1140615-9hs5j: Sun Jun 15 16:06:30 2025

Sun Jun 15 16:06:30 2025
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.161.08             Driver Version: 535.161.08   CUDA Version: 12.8     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  Tesla V100-SXM2-32GB           On  | 00000000:3D:00.0 Off |                    0 |
| N/A   31C    P0             197W / 300W |  27039MiB / 32768MiB |    100%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
+---------------------------------------------------------------------------------------+

惟需注意此處無法使用先前所訓練之結果,因 MRTS 基底有所改變,故需重新訓練。

發現

為節約訓練時間,本次檢查原專案 egpivo/SSSD_CP 發現其有不完整敘述,如下圖:

https://raw.githubusercontent.com/Josh-test-lab/website-assets-repository/refs/heads/main/posts/1140619%20meeting/螢幕擷取畫面%202025-06-15%20160957.png
原儲存庫之自述文件敘述。

此處未寫清楚如何於本地端(local)採用多 GPU 進行運算。因此,在研究 torch 的多 GPU 運行模式後,以下選擇較簡單的解法,使用 torch.nn.DataParallel() 函數進行拆分模型並於多 GPU 訓練。

此處修改 /scripts/diffusion/train.py 中的函數如下:

 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
def run_job(
    model_config: dict,
    training_config: dict,
    device: Optional[Union[torch.device, str]],
) -> None:
    output_directory = setup_output_directory(model_config, training_config)
    dataloader = get_dataloader(
        training_config["data"]["train_path"],
        batch_size=training_config.get("batch_size"),
        device=device,
    )

    locations_loder = get_locations_loader(training_config["data"]["location_path"], device)

    diffusion_hyperparams = calc_diffusion_hyperparams(
        **model_config["diffusion"], device=device
    )
    net = setup_model(training_config["use_model"], model_config, device)


    ## 包裝成 DataParallel(多 GPU)
    #if torch.cuda.device_count() > 1:
    #    LOGGER.info(f"Wrapping model with DataParallel across {torch.cuda.device_count()} GPUs")
    #    net = torch.nn.DataParallel(net)
    #net = net.to(device)


    LOGGER.info(display_current_time())
    trainer = DiffusionTrainer(
        dataloader=dataloader,
        diffusion_hyperparams=diffusion_hyperparams,
        net=net,
        device=device,
        output_directory=output_directory,
        ckpt_iter=training_config.get("ckpt_iter"),
        n_iters=training_config.get("n_iters"),
        iters_per_ckpt=training_config.get("iters_per_ckpt"),
        iters_per_logging=training_config.get("iters_per_logging"),
        learning_rate=training_config.get("learning_rate"),
        only_generate_missing=training_config.get("only_generate_missing"),
        masking=training_config.get("masking"),
        missing_k=training_config.get("missing_k"),
        batch_size=training_config.get("batch_size"),
        logger=LOGGER,
        locs=locations_loder,
    )
    trainer.train()

    LOGGER.info(display_current_time())

其註解部分為此次新增之處。需使用 CUDA_VISIBLE_DEVICES=0,1 的寫法啟用多 GPU 支援。範例如下:

範例
1
CUDA_VISIBLE_DEVICES=0,1 ./scripts/diffusion/training_job.sh -m configs/model.yaml -t configs/training.yaml

但於運行多 GPU 時仍會報錯(此處使用 2 顆 GPU),原因如下:

  • DataParallel() 的原理是將 batch size 平均分配給每個 GPU 進行運算,但我用於訓練的 batch_size = 1 ,這將會與使用單一 GPU 運算是相同的。
  • 即使將大小設為 batch_size = 2 ,但因為資料集的形狀為 (5, 200, 26) , 5 無法均分給 2 個 GPU,有機會出問題。
  • 有些運算會先離開 GPU,當最後又使用 .to(device) 時,又會出現有一些資料集在 0 號 GPU,一些在 1 號 GPU,導致資料割裂無法運算。

故因為以上的錯誤,要使用多 GPU 運算,必須先統一程式碼內部使用 .to(device) 方法傳遞的函數,讓外部運算完畢後能回到正確的 GPU 繼續運算。此部分修改處可能過大,因此暫時停止開發,先專注於資料的填補。

填補

填補結果:

執行結果參考
  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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
(sssd) u6025091@jn9kc9test1140617-xd5qh:~/SSSD_CP$ ./inference_per_miss.sh
執行 missing_k=12, masking=forecast ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 14:24:49,760 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 14:24:49,984 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:24:49
2025-06-17 14:25:24,210 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 14:25:24,212 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_12_with_custom/tf/12/original/forecast/T200_beta00.0001_betaT0.02/max
2025-06-17 14:25:29,735 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 14:25:29,755 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 14:25:29,755 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 14:25:29,755 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 14:32:49,991 - sssd.utils.logger - INFO - Average MSE: 0.04452039524912834
2025-06-17 14:32:49,991 - sssd.utils.logger - INFO - Average MAPE: 0.2639411389827728
2025-06-17 14:32:49,991 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:32:49
Inference Job completed
執行 missing_k=12, masking=rm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 14:32:54,265 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 14:32:54,417 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:32:54
2025-06-17 14:33:27,286 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 14:33:27,288 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_12_with_custom/tf/12/original/rm/T200_beta00.0001_betaT0.02/max
2025-06-17 14:33:28,326 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 14:33:28,349 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 14:33:28,349 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 14:33:28,349 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 14:40:46,003 - sssd.utils.logger - INFO - Average MSE: 0.03280486762523651
2025-06-17 14:40:46,003 - sssd.utils.logger - INFO - Average MAPE: 0.2803750991821289
2025-06-17 14:40:46,004 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:40:46
Inference Job completed
執行 missing_k=12, masking=mnr ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 14:40:50,223 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 14:40:50,371 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:40:50
2025-06-17 14:41:22,932 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 14:41:22,934 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_12_with_custom/tf/12/original/mnr/T200_beta00.0001_betaT0.02/max
2025-06-17 14:41:24,044 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 14:41:24,060 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 14:41:24,060 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 14:41:24,061 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 14:48:41,825 - sssd.utils.logger - INFO - Average MSE: 0.054531391710042953
2025-06-17 14:48:41,826 - sssd.utils.logger - INFO - Average MAPE: 0.6076512455940246
2025-06-17 14:48:41,826 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:48:41
Inference Job completed
執行 missing_k=12, masking=bm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 14:48:46,021 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 14:48:46,138 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:48:46
2025-06-17 14:49:18,674 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 14:49:18,676 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_12_with_custom/tf/12/original/bm/T200_beta00.0001_betaT0.02/max
2025-06-17 14:49:19,781 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 14:49:19,832 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 14:49:19,832 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 14:49:19,832 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 14:56:37,841 - sssd.utils.logger - INFO - Average MSE: 0.08220569193363189
2025-06-17 14:56:37,842 - sssd.utils.logger - INFO - Average MAPE: 0.679029792547226
2025-06-17 14:56:37,842 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:56:37
Inference Job completed
執行 missing_k=24, masking=forecast ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 14:56:42,054 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 14:56:42,167 - sssd.utils.logger - INFO - Current time: 2025-06-17 14:56:42
2025-06-17 14:57:15,155 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 14:57:15,158 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_24_with_custom/tf/24/original/forecast/T200_beta00.0001_betaT0.02/max
2025-06-17 14:57:16,263 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 14:57:16,268 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 14:57:16,268 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 14:57:16,268 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:04:34,309 - sssd.utils.logger - INFO - Average MSE: 0.07742066234350205
2025-06-17 15:04:34,309 - sssd.utils.logger - INFO - Average MAPE: 0.2457350790500641
2025-06-17 15:04:34,310 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:04:34
Inference Job completed
執行 missing_k=24, masking=rm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:04:38,616 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:04:38,768 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:04:38
2025-06-17 15:05:11,415 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:05:11,417 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_24_with_custom/tf/24/original/rm/T200_beta00.0001_betaT0.02/max
2025-06-17 15:05:12,441 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:05:12,446 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:05:12,446 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:05:12,446 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:12:30,538 - sssd.utils.logger - INFO - Average MSE: 0.03197858259081841
2025-06-17 15:12:30,538 - sssd.utils.logger - INFO - Average MAPE: 0.30044960379600527
2025-06-17 15:12:30,538 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:12:30
Inference Job completed
執行 missing_k=24, masking=mnr ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:12:34,951 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:12:35,111 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:12:35
2025-06-17 15:13:08,193 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:13:08,195 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_24_with_custom/tf/24/original/mnr/T200_beta00.0001_betaT0.02/max
2025-06-17 15:13:09,278 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:13:09,303 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:13:09,303 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:13:09,303 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:20:27,703 - sssd.utils.logger - INFO - Average MSE: 0.03101613149046898
2025-06-17 15:20:27,703 - sssd.utils.logger - INFO - Average MAPE: 0.4463586062192917
2025-06-17 15:20:27,703 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:20:27
Inference Job completed
執行 missing_k=24, masking=bm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:20:31,906 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:20:32,056 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:20:32
2025-06-17 15:21:05,167 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:21:05,168 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_24_with_custom/tf/24/original/bm/T200_beta00.0001_betaT0.02/max
2025-06-17 15:21:06,276 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:21:06,297 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:21:06,297 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:21:06,297 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:28:24,216 - sssd.utils.logger - INFO - Average MSE: 0.05375478081405163
2025-06-17 15:28:24,216 - sssd.utils.logger - INFO - Average MAPE: 0.5050143867731094
2025-06-17 15:28:24,216 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:28:24
Inference Job completed
執行 missing_k=200, masking=forecast ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:28:28,359 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:28:28,498 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:28:28
2025-06-17 15:29:01,936 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:29:01,939 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_200_with_custom/tf/200/original/forecast/T200_beta00.0001_betaT0.02/max
2025-06-17 15:29:03,041 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:29:03,068 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:29:03,069 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:29:03,069 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:36:21,366 - sssd.utils.logger - INFO - Average MSE: 0.039383457601070405
2025-06-17 15:36:21,366 - sssd.utils.logger - INFO - Average MAPE: 0.2943285584449768
2025-06-17 15:36:21,367 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:36:21
Inference Job completed
執行 missing_k=200, masking=rm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:36:25,440 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:36:25,601 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:36:25
2025-06-17 15:36:58,212 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:36:58,213 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_200_with_custom/tf/200/original/rm/T200_beta00.0001_betaT0.02/max
2025-06-17 15:36:59,244 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:36:59,267 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:36:59,267 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:36:59,267 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:44:17,370 - sssd.utils.logger - INFO - Average MSE: 0.10192955136299134
2025-06-17 15:44:17,370 - sssd.utils.logger - INFO - Average MAPE: 0.5133300304412842
2025-06-17 15:44:17,370 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:44:17
Inference Job completed
執行 missing_k=200, masking=mnr ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:44:21,535 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:44:21,704 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:44:21
2025-06-17 15:44:55,144 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:44:55,145 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_200_with_custom/tf/200/original/mnr/T200_beta00.0001_betaT0.02/max
2025-06-17 15:44:56,212 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:44:56,235 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:44:56,236 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:44:56,236 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 15:52:14,069 - sssd.utils.logger - INFO - Average MSE: 0.09088289812207222
2025-06-17 15:52:14,069 - sssd.utils.logger - INFO - Average MAPE: 0.7056139945983887
2025-06-17 15:52:14,069 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:52:14
Inference Job completed
執行 missing_k=200, masking=bm ...
Intializing conda
Activating Conda Env: sssd
[Execution - Inference]
/home/u6025091/SSSD_CP/scripts/diffusion/infer.py --model_config configs/model.yaml --inference_config configs/inference.yaml
2025-06-17 15:52:18,488 - sssd.utils.logger - INFO - Using 1 GPUs!
2025-06-17 15:52:18,606 - sssd.utils.logger - INFO - Current time: 2025-06-17 15:52:18
2025-06-17 15:52:51,743 - sssd.utils.logger - INFO - The 1th inference trial
2025-06-17 15:52:51,745 - sssd.utils.logger - INFO - Output directory: ./results/real_time/train_200_with_custom/tf/200/original/bm/T200_beta00.0001_betaT0.02/max
2025-06-17 15:52:53,009 - sssd.utils.logger - INFO - Successfully loaded model at iteration 2700
2025-06-17 15:52:53,015 - sssd.utils.logger - INFO - Successfully using device "cuda".
2025-06-17 15:52:53,016 - sssd.utils.logger - WARNING - Parameter "k" was not set. Default value 28 is used.
2025-06-17 15:52:53,016 - sssd.utils.logger - INFO - Calculate TPS with rectangular coordinates.
2025-06-17 16:00:11,029 - sssd.utils.logger - INFO - Average MSE: 0.08462466970086098
2025-06-17 16:00:11,030 - sssd.utils.logger - INFO - Average MAPE: 0.614367663860321
2025-06-17 16:00:11,030 - sssd.utils.logger - INFO - Current time: 2025-06-17 16:00:11
Inference Job completed

統整以上結果:

missing_kmaskingAvg MSEAvg MAPE
12forecast0.013520.27675
12rm0.016150.31982
12mnr0.023370.36655
12bm0.025710.47934
24forecast0.077420.24574
24rm0.031980.30045
24mnr0.031020.44636
24bm0.053750.50501
200forecast0.039380.29433
200rm0.101930.51333
200mnr0.090880.70561
200bm0.084620.61437

MSE

  • forecast masking 在每個 missing_k 下,幾乎都是 MSE 最低(尤其是 k=12, 200)。
  • MSE 明顯隨 k 上升而增加,表示缺失比例對模型表現有顯著影響。

MAPE

  • k = 12 整體表現最佳,MAPE 都低於 0.5。
  • forecast 一致取得最低 MAPE(即預測誤差較小)或次低。
  • mnr 與 bm 的 MAPE 在 k = 200 時皆超過 0.6,代表對大規模缺失處理能力較弱。

以下是分析結果:

執行結果參考
 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
RM: 12
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.0008432089553375721
MSPE (per polluant): [0.00117824 0.00060066 0.00082218 0.00083799 0.00077697]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.91it/s]
BM: 12
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.0020280764532541835
MSPE (per polluant): [0.00090764 0.00658069 0.00088254 0.00101575 0.00075376]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.92it/s]
MNR: 12
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.001264052932918028
MSPE (per polluant): [0.00086441 0.00190658 0.00084853 0.00106907 0.00163167]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.90it/s]
TF: 12
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.001126299277898192
MSPE (per polluant): [0.00123651 0.00113123 0.00106289 0.00112292 0.00107795]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.90it/s]
RM: 24
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.0015890958435139959
MSPE (per polluant): [0.0015957  0.00190802 0.0015648  0.00145854 0.00141841]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.90it/s]
BM: 24
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.002633397703545542
MSPE (per polluant): [0.00131936 0.00105603 0.00687749 0.00148756 0.00242654]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.91it/s]
MNR: 24
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.001541527787880978
MSPE (per polluant): [0.00216814 0.00208698 0.00142031 0.00137693 0.00065529]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:13<00:00,  1.87it/s]
TF: 24
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.0037722312727362637
MSPE (per polluant): [0.00387845 0.00379054 0.00373233 0.0036643  0.00379554]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:12<00:00,  2.01it/s]
RM: 200
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.040819488247708764
MSPE (per polluant): [0.0354449  0.0493968  0.0451148  0.0328515  0.04128944]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:12<00:00,  2.02it/s]
BM: 200
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.032062961408641066
MSPE (per polluant): [0.05920136 0.05211573 0.02009791 0.01980364 0.00909616]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:12<00:00,  2.09it/s]
MNR: 200
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.03637180626470659
MSPE (per polluant): [0.06253705 0.06469499 0.01767138 0.01850751 0.0184481 ]
MSPE: 0.03637180626470659
MSPE (per polluant): [0.06253705 0.06469499 0.01767138 0.01850751 0.0184481 ]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:11<00:00,  2.18it/s] 
TF: 200
Shape: (5, 26, 500)
NAs: 0
MSPE: 0.01576908332060547
MSPE (per polluant): [0.01596002 0.01542586 0.0159918  0.01558863 0.01587911]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 26/26 [00:12<00:00,  2.10it/s] 

整理如下

missing_kmaskingAvg MSPEMSPE per pollutant (“CO”, “NOx”, “O3”, “PM2.5”, “SO2”)
12RM0.000843[0.00118, 0.00060, 0.00082, 0.00084, 0.00078]
12BM0.002028[0.00091, 0.00658, 0.00088, 0.00102, 0.00075]
12MNR0.001264[0.00086, 0.00191, 0.00085, 0.00107, 0.00163]
12TF0.001126[0.00124, 0.00113, 0.00106, 0.00112, 0.00108]
24RM0.001589[0.00160, 0.00191, 0.00156, 0.00146, 0.00142]
24BM0.002633[0.00132, 0.00106, 0.00688, 0.00149, 0.00243]
24MNR0.001542[0.00217, 0.00209, 0.00142, 0.00138, 0.00066]
24TF0.003772[0.00388, 0.00379, 0.00373, 0.00366, 0.00380]
200RM0.040819[0.03544, 0.04940, 0.04511, 0.03285, 0.04129]
200BM0.032063[0.05920, 0.05212, 0.02010, 0.01980, 0.00910]
200MNR0.036372[0.06254, 0.06469, 0.01767, 0.01851, 0.01845]
200TF0.015769[0.01596, 0.01543, 0.01599, 0.01559, 0.01588]

12

bm

gallery_made_with_nanogallery2-12-bm

rm

gallery_made_with_nanogallery2-12-rm

mnr

gallery_made_with_nanogallery2-12-mnr

forecast

gallery_made_with_nanogallery2-12-forecast

24

bm

gallery_made_with_nanogallery2-24-bm

rm

gallery_made_with_nanogallery2-24-rm

mnr

gallery_made_with_nanogallery2-24-mnr

forecast

gallery_made_with_nanogallery2-24-forecast

200

bm

gallery_made_with_nanogallery2-200-bm

rm

gallery_made_with_nanogallery2-200-rm

mnr

gallery_made_with_nanogallery2-200-mnr

forecast

gallery_made_with_nanogallery2-200-forecast

結語

此次進行資料推論程式碼的修補,期望能進行準確預測。在預測時,因為使用的空間坐標組成的 $MRTS$ 的關係,因此輸入的時間序列資料的測站順序需與原先一致,對於結果應該才能有較好的預測。但明顯地,目前的空間與時間模型的結合出現極大的水土不服,使得結合後的預測效力不佳,需要重新考慮結合方法。

運行環境

  • 本機作業系統:Windows 11 24H2
    • 程式語言:Python 3.12.9
  • 計算平臺:財團法人國家實驗研究院國家高速網路與計算中心臺灣 AI 雲
    • 作業系統:Ubuntu
    • Miniconda
    • GPU:NVIDIA Tesla V100 32GB GPU
    • CUDA 12.8 driver
    • 程式語言:Python 3.10.16 for Linux

延伸學習

參考資料