New ideas
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
# %%
|
||||
import torch
|
||||
from aiRNN import dataloader, models, losses
|
||||
import pathlib
|
||||
|
||||
# %%
|
||||
file_list = pathlib.Path("/home/lars/Documents/Studium/UiO/data_analysis/project3/Code/cpp/known_routes_and_aircraft.csv")
|
||||
base_path = file_list.parent
|
||||
file_list = file_list.read_text().splitlines()
|
||||
file_list = [(base_path / f).resolve() for f in file_list]
|
||||
|
||||
# %%
|
||||
dataset = dataloader.EvenlySpacedDataset(
|
||||
filepaths=file_list[:500],
|
||||
n_input=30*10, # 10 minutes input
|
||||
n_output=30*1, # 1 minutes output
|
||||
n_windows_per_file=5,
|
||||
step=1,
|
||||
feature_columns=("lat", "lon", "alt", "ias"),
|
||||
context_columns=("last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
time_columns=("timestamp", "dt"),
|
||||
target_columns=("lat", "lon", "alt"),
|
||||
)
|
||||
|
||||
# %%
|
||||
len(dataset)
|
||||
|
||||
# %%
|
||||
test_model = models.ThreeInputRNN(
|
||||
time_in=2,
|
||||
feat_in=4,
|
||||
context_in=4,
|
||||
hidden_size=128,
|
||||
rnn_size=256,
|
||||
out_size=3,
|
||||
)
|
||||
|
||||
# %%
|
||||
# Example training
|
||||
optimizer = torch.optim.Adam(test_model.parameters(), lr=1e-2)
|
||||
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=5, factor=0.5)
|
||||
criterion = torch.nn.HuberLoss()
|
||||
for epoch in range(50):
|
||||
losses = []
|
||||
for X_f, X_t, y, X_c in torch.utils.data.DataLoader(dataset, batch_size=256, shuffle=True):
|
||||
optimizer.zero_grad()
|
||||
y_pred, _ = test_model(X_t, X_f, X_c, 300, 30)
|
||||
loss = criterion(y_pred, y)
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
losses.append(loss.item())
|
||||
loss = sum(losses) / len(losses)
|
||||
scheduler.step(loss)
|
||||
print(f"Epoch {epoch}: loss={loss}, lr={optimizer.param_groups[0]['lr']}")
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class BaseDataset(Dataset):
|
||||
n_windows_per_file,
|
||||
step=1,
|
||||
feature_columns=("lat", "lon", "alt", "ias"),
|
||||
context_columns=(f"type_encoding_{i}" for i in range(4), "last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
context_columns=(*[f"type_encoding_{i}" for i in range(4)], "last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
time_columns=("timestamp",),
|
||||
target_columns=("lat", "lon", "alt"),
|
||||
device="cpu",
|
||||
@@ -33,6 +33,7 @@ class BaseDataset(Dataset):
|
||||
|
||||
# Which columns to use
|
||||
sample = pd.read_csv(self.filepaths[0], nrows=5)
|
||||
sample = self._modify_df(sample)
|
||||
self.feature_cols = list(feature_columns)
|
||||
self.context_cols = list(context_columns)
|
||||
self.time_cols = list(time_columns)
|
||||
@@ -69,27 +70,36 @@ class BaseDataset(Dataset):
|
||||
|
||||
def _modify_df(self, df):
|
||||
"""Hook for subclasses to modify dataframe before slicing windows."""
|
||||
df.loc[:, ["lat", "lon", "alt"]] = preprocessors.norm_coords(
|
||||
lat_norm, lon_norm, alt_norm = preprocessors.norm_coords(
|
||||
df["lat"].values, df["lon"].values, df["alt"].values
|
||||
)
|
||||
df.loc[:, "lat"] = lat_norm
|
||||
df.loc[:, "lon"] = lon_norm
|
||||
df.loc[:, "alt"] = alt_norm
|
||||
df.loc[:, "ias"] = preprocessors.norm_ias(df["ias"].values)
|
||||
df.loc[:, "dt"] = df["timestamp"].diff()
|
||||
df.loc[:, "dt"] = preprocessors.fillna_with_mean(df["dt"], allow_nan_mean=False)
|
||||
df.loc[:, "timestamp"] = preprocessors.norm_time(df["timestamp"].values)
|
||||
for col in ["lat", "lon", "alt", "ias"]:
|
||||
df.loc[:, col] = preprocessors.fillna_with_mean(df[col])
|
||||
if df[col].isnull().all() and col != "ias":
|
||||
raise ValueError(f"All values in column {col} are NaN.")
|
||||
df.loc[:, col] = preprocessors.fillna_with_mean(df[col], allow_nan_mean=(col == "ias"))
|
||||
|
||||
mapped_df = preprocessors.map_categories(df, preprocessors.category_mappings)
|
||||
X_a_1 = F.one_hot(torch.tensor(mapped_df["R_1_IDX"].values)).float()
|
||||
X_a_2 = F.one_hot(torch.tensor(mapped_df["R_2_IDX"].values)).float()
|
||||
X_t = F.one_hot(torch.tensor(mapped_df["T_IDX"].values)).float()
|
||||
max_values = list(preprocessors.category_max_limits.values())
|
||||
X_a_1 = F.one_hot(torch.tensor(mapped_df["R_1_IDX"].values), max_values[0]).float()
|
||||
X_a_2 = F.one_hot(torch.tensor(mapped_df["R_2_IDX"].values), max_values[1]).float()
|
||||
X_t = F.one_hot(torch.tensor(mapped_df["T_IDX"].values), max_values[2]).float()
|
||||
df.loc[:, [f"type_encoding_{i}" for i in range(4)]] = preprocessors.encode_features(
|
||||
X_a_1, X_a_2, X_t
|
||||
)
|
||||
last_row = df.iloc[-1][["lat", "lon", "alt", "ias"]]
|
||||
last_row = df.iloc[-1][["lat", "lon", "alt", "ias", "timestamp"]]
|
||||
|
||||
df.loc[:, "last_lat"] = last_row["lat"]
|
||||
df.loc[:, "last_lon"] = last_row["lon"]
|
||||
df.loc[:, "last_alt"] = last_row["alt"]
|
||||
df.loc[:, "last_ias"] = last_row["ias"]
|
||||
df.loc[:, "last_timestamp"] = last_row["timestamp"]
|
||||
|
||||
return df
|
||||
|
||||
@@ -103,7 +113,7 @@ class EvenlySpacedDataset(BaseDataset):
|
||||
n_windows_per_file,
|
||||
step=1,
|
||||
feature_columns=("lat", "lon", "alt", "ias"),
|
||||
context_columns=("r","t"),
|
||||
context_columns=(*[f"type_encoding_{i}" for i in range(4)], "last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
time_columns=("timestamp",),
|
||||
target_columns=("lat", "lon", "alt"),
|
||||
device="cpu",
|
||||
@@ -145,7 +155,7 @@ class EvenlySpacedDataset(BaseDataset):
|
||||
|
||||
X_feat = window.iloc[: self.n_input][self.feature_cols].to_numpy(np.float32)
|
||||
if len(self.context_cols) > 0:
|
||||
X_context = window.iloc[: self.n_input][self.context_cols].to_numpy(np.float32)
|
||||
X_context = window.iloc[0][self.context_cols].to_numpy(np.float32)
|
||||
else:
|
||||
X_context = None
|
||||
X_time = window.iloc[: self.window_size][self.time_cols].to_numpy(np.float32)
|
||||
@@ -166,7 +176,7 @@ class EvenlySpacedStreamingDataset(BaseDataset):
|
||||
n_windows_per_file,
|
||||
step=1,
|
||||
feature_columns=("lat", "lon", "alt", "ias"),
|
||||
context_columns=("r","t"),
|
||||
context_columns=(*[f"type_encoding_{i}" for i in range(4)], "last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
time_columns=("timestamp",),
|
||||
target_columns=("lat", "lon", "alt"),
|
||||
device="cpu",
|
||||
@@ -232,7 +242,7 @@ def get_datasets(
|
||||
n_windows_per_file: int,
|
||||
step: int = 1,
|
||||
feature_columns=("lat", "lon", "alt", "ias"),
|
||||
context_columns=("r","t"),
|
||||
context_columns=(*[f"type_encoding_{i}" for i in range(4)], "last_lat", "last_lon", "last_alt", "last_ias"),
|
||||
time_columns=("timestamp",),
|
||||
target_columns=("lat", "lon", "alt"),
|
||||
device="cpu",
|
||||
@@ -298,14 +308,3 @@ def get_datasets(
|
||||
|
||||
return train_dataset, val_dataset, test_dataset
|
||||
|
||||
|
||||
class EncodingDataset(Dataset):
|
||||
def __init__(self, X_a_1, X_a_2, X_b):
|
||||
super().__init__()
|
||||
self.X_a_1 = X_a_1
|
||||
self.X_a_2 = X_a_2
|
||||
self.X_b = X_b
|
||||
def __len__(self):
|
||||
return self.X_a_1.shape[0]
|
||||
def __getitem__(self, idx):
|
||||
return self.X_a_1[idx], self.X_a_2[idx], self.X_b[idx]
|
||||
@@ -1,6 +1,7 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from aiRNN.preprocessors import denorm_coords
|
||||
import math
|
||||
|
||||
|
||||
@@ -18,10 +19,12 @@ class HaversineMSEAltitudeLoss(nn.Module):
|
||||
lat/lon expected in degrees.
|
||||
alt in meters (or same unit in pred/target).
|
||||
"""
|
||||
lat1 = torch.deg2rad(pred[..., 0])
|
||||
lon1 = torch.deg2rad(pred[..., 1])
|
||||
lat2 = torch.deg2rad(target[..., 0])
|
||||
lon2 = torch.deg2rad(target[..., 1])
|
||||
lat1, lon1, alt1 = denorm_coords(pred[...,0], pred[...,1], pred[...,2])
|
||||
lat2, lon2, alt2 = denorm_coords(target[...,0], target[...,1], target[...,2])
|
||||
lat1 = torch.deg2rad(lat1)
|
||||
lon1 = torch.deg2rad(lon1)
|
||||
lat2 = torch.deg2rad(lat2)
|
||||
lon2 = torch.deg2rad(lon2)
|
||||
|
||||
dlat = lat2 - lat1
|
||||
dlon = lon2 - lon1
|
||||
@@ -38,11 +41,52 @@ class HaversineMSEAltitudeLoss(nn.Module):
|
||||
haversine_mse = torch.mean(dist_km ** 2)
|
||||
|
||||
# Altitude penalty
|
||||
delta_alt = pred[..., 2] - target[..., 2]
|
||||
delta_alt = alt2 - alt1
|
||||
alt_penalty = self.alt_const * torch.mean(delta_alt ** 2)
|
||||
|
||||
return haversine_mse + alt_penalty
|
||||
|
||||
class HaversineAltitudeLoss(nn.Module):
|
||||
def __init__(self, alt_const=1.0, earth_radius_km=6371.0):
|
||||
super().__init__()
|
||||
self.alt_const = alt_const
|
||||
self.R = earth_radius_km
|
||||
|
||||
def forward(self, pred, target):
|
||||
"""
|
||||
pred: (..., 3) -> [lat, lon, alt]
|
||||
target: (..., 3) -> [lat, lon, alt]
|
||||
|
||||
lat/lon expected in degrees.
|
||||
alt in meters (or same unit in pred/target).
|
||||
"""
|
||||
lat1, lon1, alt1 = denorm_coords(pred[...,0], pred[...,1], pred[...,2])
|
||||
lat2, lon2, alt2 = denorm_coords(target[...,0], target[...,1], target[...,2])
|
||||
lat1 = torch.deg2rad(lat1)
|
||||
lon1 = torch.deg2rad(lon1)
|
||||
lat2 = torch.deg2rad(lat2)
|
||||
lon2 = torch.deg2rad(lon2)
|
||||
|
||||
dlat = lat2 - lat1
|
||||
dlon = lon2 - lon1
|
||||
|
||||
# Haversine formula
|
||||
a = (
|
||||
torch.sin(dlat / 2) ** 2
|
||||
+ torch.cos(lat1) * torch.cos(lat2) * torch.sin(dlon / 2) ** 2
|
||||
)
|
||||
c = 2 * torch.atan2(torch.sqrt(a), torch.sqrt(1 - a))
|
||||
dist_km = self.R * c # great-circle distance
|
||||
|
||||
# Mean distance
|
||||
haversine_loss = torch.mean(dist_km)
|
||||
|
||||
# Altitude penalty
|
||||
delta_alt = alt2 - alt1
|
||||
alt_penalty = self.alt_const * torch.mean(delta_alt ** 2)
|
||||
|
||||
return haversine_loss + alt_penalty
|
||||
|
||||
class WeightedMSELoss(nn.Module):
|
||||
def __init__(self, weights):
|
||||
super().__init__()
|
||||
|
||||
@@ -3,98 +3,80 @@ import torch.nn as nn
|
||||
|
||||
|
||||
class BaseRNN(nn.Module):
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size, out_size, rnn_type="RNN"):
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size,
|
||||
rnn_size, out_size, rnn_type="RNN"):
|
||||
super().__init__()
|
||||
self.time_in = time_in
|
||||
self.feat_in = feat_in
|
||||
self.context_in = context_in
|
||||
self.hidden_size = hidden_size
|
||||
self.out_size = out_size
|
||||
|
||||
# Projecters to a common RNN input size
|
||||
self.time_proj = nn.Linear(time_in, hidden_size)
|
||||
self.feat_proj = nn.Linear(feat_in, hidden_size)
|
||||
if context_in is not None:
|
||||
self.context_proj = nn.Linear(context_in, hidden_size)
|
||||
self.context_proj = (
|
||||
nn.Linear(context_in, hidden_size) if context_in is not None else None
|
||||
)
|
||||
|
||||
# RNN cell
|
||||
if rnn_type == "RNN":
|
||||
self.rnn = nn.RNNCell(input_size=hidden_size, hidden_size=hidden_size)
|
||||
self.rnn = nn.RNN(
|
||||
input_size=hidden_size,
|
||||
hidden_size=rnn_size,
|
||||
batch_first=True
|
||||
)
|
||||
elif rnn_type == "LSTM":
|
||||
self.rnn = nn.LSTMCell(input_size=hidden_size, hidden_size=hidden_size)
|
||||
self.rnn = nn.LSTM(
|
||||
input_size=hidden_size,
|
||||
hidden_size=rnn_size,
|
||||
batch_first=True
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unsupported rnn_type: {rnn_type}")
|
||||
raise ValueError("Unsupported rnn_type")
|
||||
|
||||
# Readout: predict from hidden state (optionally conditioned on time and context too)
|
||||
readout_in_size = hidden_size + time_in
|
||||
readout_in = rnn_size + time_in
|
||||
if context_in is not None:
|
||||
readout_in_size += context_in
|
||||
self.readout = nn.Linear(readout_in_size, out_size)
|
||||
readout_in += context_in
|
||||
self.readout = nn.Linear(readout_in, out_size)
|
||||
|
||||
self.context_in = context_in
|
||||
self.rnn_size = rnn_size
|
||||
|
||||
def forward(self, time_seq, feat_init=None, context=None,
|
||||
init_steps=0, pred_steps=0, offset=0, hidden=None):
|
||||
|
||||
def forward(self, time_seq, feat_init=None, context=None, init_steps=0, pred_steps=0, offset=0, hidden=None):
|
||||
b, total_len, _ = time_seq.shape
|
||||
assert init_steps <= total_len
|
||||
assert init_steps + offset <= total_len
|
||||
|
||||
# Project everything once
|
||||
time_proj = self.time_proj(time_seq) # (b, T, hidden)
|
||||
if context is not None:
|
||||
assert self.context_proj is not None
|
||||
ctx = self.context_proj(context).unsqueeze(1) # (b,1,hidden)
|
||||
ctx = ctx.expand(-1, total_len, -1) # broadcast
|
||||
else:
|
||||
ctx = torch.zeros(b, total_len, time_proj.size(-1),
|
||||
device=time_seq.device)
|
||||
|
||||
# Build the RNN input sequence
|
||||
rnn_input = time_proj + ctx
|
||||
|
||||
if feat_init is not None:
|
||||
assert feat_init.shape[0] == b and feat_init.shape[1] == init_steps
|
||||
feat_proj = self.feat_proj(feat_init) # (b, init_steps, hidden)
|
||||
# Insert feat input *only* in first init_steps
|
||||
rnn_input[:, :init_steps, :] += feat_proj
|
||||
|
||||
if hidden is None:
|
||||
hidden = torch.zeros(b, self.hidden_size, device=time_seq.device)
|
||||
# Run the RNN over full sequence
|
||||
outputs, hidden_next = self.rnn(rnn_input, hidden)
|
||||
|
||||
if self.context_in is not None:
|
||||
assert context is not None and context.shape[0] == b
|
||||
context_proj = self.context_proj(context) # (b, hidden_size)
|
||||
else:
|
||||
context_proj = torch.zeros(b, self.hidden_size, device=time_seq.device)
|
||||
# Prediction window
|
||||
pred_h = outputs[:, init_steps:init_steps + pred_steps] # (b, pred, rnn_size)
|
||||
|
||||
# --- Initialization phase: feed time + feature in parallel for init_steps ---
|
||||
for t in range(init_steps + offset):
|
||||
t_in = time_seq[:, t, :] # (b, time_in)
|
||||
t_proj = self.time_proj(t_in) # (b, hidden_size)
|
||||
# Build readout input
|
||||
time_raw = time_seq[:, init_steps:init_steps + pred_steps]
|
||||
|
||||
rnn_in = t_proj + context_proj # start with time + context
|
||||
if feat_init is not None and t < init_steps:
|
||||
f_in = feat_init[:, t, :] # (b, feat_in)
|
||||
f_proj = self.feat_proj(f_in) # (b, hidden_size)
|
||||
rnn_in = rnn_in + f_proj # combine with feature input
|
||||
read_list = [pred_h, time_raw]
|
||||
if context is not None:
|
||||
read_list.append(context.unsqueeze(1).expand(-1, pred_steps, -1))
|
||||
read_in = torch.cat(read_list, dim=-1)
|
||||
|
||||
if isinstance(self.rnn, nn.LSTMCell):
|
||||
if isinstance(hidden, tuple):
|
||||
h_t, c_t = hidden
|
||||
else:
|
||||
h_t = hidden
|
||||
c_t = torch.zeros(b, self.hidden_size, device=time_seq.device)
|
||||
h_t, c_t = self.rnn(rnn_in, (h_t, c_t))
|
||||
hidden = (h_t, c_t)
|
||||
else:
|
||||
hidden = self.rnn(rnn_in, hidden)
|
||||
preds = self.readout(read_in)
|
||||
return preds, hidden_next
|
||||
|
||||
# --- Prediction phase: feed only time (+ context) inputs for pred_steps ---
|
||||
preds = []
|
||||
for p in range(pred_steps):
|
||||
t_idx = init_steps + p
|
||||
assert t_idx < total_len, "time_seq too short for requested pred_steps"
|
||||
t_in = time_seq[:, t_idx, :] # (b, time_in)
|
||||
t_proj = self.time_proj(t_in) # project time input
|
||||
|
||||
rnn_in = t_proj + context_proj # RNN input: time + context
|
||||
|
||||
if isinstance(self.rnn, nn.LSTMCell):
|
||||
h_t, c_t = hidden
|
||||
h_t, c_t = self.rnn(rnn_in, (h_t, c_t)) # update hidden
|
||||
hidden = (h_t, c_t)
|
||||
else:
|
||||
hidden = self.rnn(rnn_in, hidden) # update hidden
|
||||
|
||||
# Readout uses hidden + raw time (+ raw context input)
|
||||
read_inputs = [hidden if not isinstance(hidden, tuple) else hidden[0], t_in]
|
||||
if self.context_in is not None:
|
||||
read_inputs.append(context)
|
||||
read = torch.cat(read_inputs, dim=-1)
|
||||
out = self.readout(read) # (b, out_size)
|
||||
preds.append(out.unsqueeze(1))
|
||||
preds = torch.cat(preds, dim=1) # (b, pred_steps, out_size)
|
||||
return preds, hidden
|
||||
|
||||
|
||||
|
||||
@@ -107,8 +89,8 @@ class TwoInputRNN(BaseRNN):
|
||||
After init_steps, only time inputs are provided and the model predicts a sequence.
|
||||
Predictions can be compared to targets with a specified `offset`.
|
||||
"""
|
||||
def __init__(self, time_in, feat_in, hidden_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=None, hidden_size=hidden_size, out_size=out_size)
|
||||
def __init__(self, time_in, feat_in, hidden_size, rnn_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=None, hidden_size=hidden_size, rnn_size=rnn_size, out_size=out_size)
|
||||
|
||||
class ThreeInputRNN(BaseRNN):
|
||||
"""
|
||||
@@ -119,8 +101,8 @@ class ThreeInputRNN(BaseRNN):
|
||||
After init_steps, only time and context inputs are provided and the model predicts a sequence.
|
||||
Predictions can be compared to targets with a specified `offset`.
|
||||
"""
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=context_in, hidden_size=hidden_size, out_size=out_size)
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size, rnn_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=context_in, hidden_size=hidden_size, rnn_size=rnn_size, out_size=out_size)
|
||||
|
||||
class TwoInputLSTM(BaseRNN):
|
||||
"""
|
||||
@@ -130,8 +112,8 @@ class TwoInputLSTM(BaseRNN):
|
||||
After init_steps, only time inputs are provided and the model predicts a sequence.
|
||||
Predictions can be compared to targets with a specified `offset`.
|
||||
"""
|
||||
def __init__(self, time_in, feat_in, hidden_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=None, hidden_size=hidden_size, out_size=out_size, rnn_type="LSTM")
|
||||
def __init__(self, time_in, feat_in, hidden_size, rnn_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=None, hidden_size=hidden_size, rnn_size=rnn_size, out_size=out_size, rnn_type="LSTM")
|
||||
|
||||
class ThreeInputLSTM(BaseRNN):
|
||||
"""
|
||||
@@ -142,5 +124,5 @@ class ThreeInputLSTM(BaseRNN):
|
||||
After init_steps, only time and context inputs are provided and the model predicts a sequence.
|
||||
Predictions can be compared to targets with a specified `offset`.
|
||||
"""
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=context_in, hidden_size=hidden_size, out_size=out_size, rnn_type="LSTM")
|
||||
def __init__(self, time_in, feat_in, context_in, hidden_size, rnn_size, out_size):
|
||||
super().__init__(time_in, feat_in, context_in=context_in, hidden_size=hidden_size, rnn_size=rnn_size, out_size=out_size, rnn_type="LSTM")
|
||||
@@ -2,7 +2,8 @@ import torch
|
||||
from torch import nn
|
||||
import pathlib
|
||||
import json
|
||||
from aiRNN.dataloader import EncodingDataset
|
||||
import numpy as np
|
||||
from torch.utils.data import Dataset
|
||||
|
||||
|
||||
MIN_LAT, MAX_LAT = 57.0, 72.0
|
||||
@@ -36,13 +37,32 @@ def denorm_ias(ias_norm):
|
||||
return min_max_denormalize(ias_norm, MIN_IAS, MAX_IAS)
|
||||
|
||||
def norm_time(timestamp_series):
|
||||
invalid_mask = (timestamp_series < 1672527600) | np.isnan(timestamp_series) # Jan 1, 2023
|
||||
if sum(invalid_mask) == len(timestamp_series):
|
||||
raise ValueError("All timestamps are invalid or NaN.")
|
||||
timestamp_series[invalid_mask] = timestamp_series[~invalid_mask].mean()
|
||||
min_time = timestamp_series.min()
|
||||
return (timestamp_series - min_time) * TIME_NORM_FACTOR
|
||||
|
||||
def fillna_with_mean(series):
|
||||
def fillna_with_mean(series, allow_nan_mean=True):
|
||||
mean_value = series.mean()
|
||||
if np.isnan(mean_value):
|
||||
if not allow_nan_mean:
|
||||
raise ValueError("Mean is NaN and allow_nan_mean is False.")
|
||||
mean_value = 0.0
|
||||
return series.fillna(mean_value)
|
||||
|
||||
class EncodingDataset(Dataset):
|
||||
def __init__(self, X_a_1, X_a_2, X_b):
|
||||
super().__init__()
|
||||
self.X_a_1 = X_a_1
|
||||
self.X_a_2 = X_a_2
|
||||
self.X_b = X_b
|
||||
def __len__(self):
|
||||
return self.X_a_1.shape[0]
|
||||
def __getitem__(self, idx):
|
||||
return self.X_a_1[idx], self.X_a_2[idx], self.X_b[idx]
|
||||
|
||||
class AutoEncoder(nn.Module):
|
||||
def __init__(self, input_a_1_size, input_a_2_size, input_b_size, latent_size):
|
||||
super(AutoEncoder, self).__init__()
|
||||
|
||||
Reference in New Issue
Block a user