alwaysgood commited on
Commit
b444514
·
verified ·
1 Parent(s): e7d8f04

Update inference.py

Browse files
Files changed (1) hide show
  1. inference.py +73 -30
inference.py CHANGED
@@ -11,8 +11,9 @@ import json # 👈 JSON 라이브러리 추가
11
  import sys
12
  sys.path.append('.')
13
 
14
- from models import TimeXer # 사용하는 모델에 맞게 수정
15
- from utils.metrics import metric # 성능 평가를 위해 추가
 
16
 
17
  # --- 1. 인자 파싱 (수정 없음) ---
18
  parser = argparse.ArgumentParser(description='Time Series Prediction')
@@ -48,81 +49,123 @@ parser.add_argument('--freq', type=str, default='t', help='freq for time feature
48
  args = parser.parse_args()
49
 
50
 
 
 
 
 
 
 
 
 
 
51
  # --- 2. 공통 함수: 모델 및 스케일러 로드 (수정 없음) ---
52
  def load_model_and_scaler(args):
53
  device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
54
- # ⭐️ 수정 사항 2: args에 device 정보 추가 (TimeXer 모델 초기화 시 필요할 수 있음)
55
  args.device = device
56
  model = TimeXer.Model(args).float().to(device)
57
  model.load_state_dict(torch.load(args.checkpoint_path, map_location=device))
58
  model.eval()
59
  scaler = joblib.load(args.scaler_path)
60
- # 진행 상황을 stderr로 출력하여 stdout의 JSON 결과와 분리
61
  print(f"Using device: {device}", file=sys.stderr)
62
  print("Model and scaler loaded successfully.", file=sys.stderr)
63
  return model, scaler, device
64
 
65
- # --- 3. 모드 1: 단일 미래 예측 함수 (수정 없음) ---
66
  def predict_future(args, model, scaler, device):
67
- # ... (이전과 동일한 코드) ...
68
- # 이 함수는 예측 결과(prediction)만 반환하면 됩니다.
69
  df_input = pd.read_csv(args.predict_input_file)
70
- if 'date' in df_input.columns:
71
- df_input = df_input.drop(columns=['date'])
72
- raw_input = df_input.tail(args.seq_len).values
 
73
 
 
 
74
  input_scaled = scaler.transform(raw_input)
75
  batch_x = torch.from_numpy(input_scaled).float().unsqueeze(0).to(device)
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  with torch.no_grad():
78
- # TimeXer 모델의 forward 함수에 맞게 인자 전달
79
- # 여기서는 batch_x만 필요하다고 가정. 필요 시 batch_x_mark 등 추가
80
- outputs = model(batch_x)
81
 
82
  prediction_scaled = outputs.detach().cpu().numpy()[0]
83
 
84
- # 스케일 복원 로직
85
- if args.features == 'MS' and scaler.n_features_in_ > 1:
86
  padding = np.zeros((prediction_scaled.shape[0], scaler.n_features_in_ - args.c_out))
87
- # 예측 결과를 마지막 feature 자리에 위치
88
  prediction_padded = np.concatenate((padding, prediction_scaled), axis=1)
89
  prediction = scaler.inverse_transform(prediction_padded)[:, -args.c_out:]
90
  else:
91
  prediction = scaler.inverse_transform(prediction_scaled)
92
-
93
  return prediction
94
 
95
-
96
- # --- 4. 모드 2: 전체 기간 롤링 평가 함수 (수정 없음) ---
97
  def evaluate_performance(args, model, scaler, device):
98
- # ... (이전과 동일한 코드) ...
99
- # 이 함수는 예측값들과 실제값들을 반환하면 됩니다.
100
  df_eval = pd.read_csv(args.evaluate_file)
101
- if 'date' in df_eval.columns:
102
- df_eval = df_eval.drop(columns=['date'])
103
- raw_data = df_eval.values
 
 
104
  data_scaled = scaler.transform(raw_data)
 
 
105
 
106
  preds_unscaled = []
107
  trues_unscaled = []
108
 
109
  num_samples = len(data_scaled) - args.seq_len - args.pred_len + 1
110
  for i in tqdm(range(num_samples), desc="Evaluating", file=sys.stderr):
 
111
  s_begin = i
112
  s_end = s_begin + args.seq_len
113
- input_scaled = data_scaled[s_begin:s_end]
114
- batch_x = torch.from_numpy(input_scaled).float().unsqueeze(0).to(device)
115
-
 
116
  true_begin = s_end
117
  true_end = true_begin + args.pred_len
118
  true_scaled = data_scaled[true_begin:true_end]
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  with torch.no_grad():
121
- outputs = model(batch_x)
122
 
123
  pred_scaled = outputs.detach().cpu().numpy()[0]
124
-
125
- if args.features == 'MS' and scaler.n_features_in_ > 1:
 
126
  padding = np.zeros((pred_scaled.shape[0], scaler.n_features_in_ - args.c_out))
127
  pred_padded = np.concatenate((padding, pred_scaled), axis=1)
128
  pred_unscaled = scaler.inverse_transform(pred_padded)[:, -args.c_out:]
 
11
  import sys
12
  sys.path.append('.')
13
 
14
+ from models import TimeXer
15
+ from utils.metrics import metric
16
+ from utils.timefeatures import time_features
17
 
18
  # --- 1. 인자 파싱 (수정 없음) ---
19
  parser = argparse.ArgumentParser(description='Time Series Prediction')
 
49
  args = parser.parse_args()
50
 
51
 
52
+
53
+ prediction_padded = np.concatenate((padding, prediction_scaled), axis=1)
54
+ prediction = scaler.inverse_transform(prediction_padded)[:, -args.c_out:]
55
+ else:
56
+ prediction = scaler.inverse_transform(prediction_scaled)
57
+
58
+ return prediction
59
+
60
+
61
  # --- 2. 공통 함수: 모델 및 스케일러 로드 (수정 없음) ---
62
  def load_model_and_scaler(args):
63
  device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
 
64
  args.device = device
65
  model = TimeXer.Model(args).float().to(device)
66
  model.load_state_dict(torch.load(args.checkpoint_path, map_location=device))
67
  model.eval()
68
  scaler = joblib.load(args.scaler_path)
 
69
  print(f"Using device: {device}", file=sys.stderr)
70
  print("Model and scaler loaded successfully.", file=sys.stderr)
71
  return model, scaler, device
72
 
73
+ # --- 3. 모드 1: 단일 미래 예측 함수 ---
74
  def predict_future(args, model, scaler, device):
 
 
75
  df_input = pd.read_csv(args.predict_input_file)
76
+ df_input['date'] = pd.to_datetime(df_input['date'])
77
+
78
+ # ⭐️ 알려주신 정확한 컬럼 이름으로 수정
79
+ cols_to_scale = ['air_pres', 'wind_dir', 'wind_speed', 'air_temp', 'residual']
80
 
81
+ # 1. 인코더 입력(x_enc) 생성
82
+ raw_input = df_input[cols_to_scale].tail(args.seq_len).values
83
  input_scaled = scaler.transform(raw_input)
84
  batch_x = torch.from_numpy(input_scaled).float().unsqueeze(0).to(device)
85
 
86
+ # 2. 인코더 시간 정보(x_mark_enc) 생성
87
+ df_stamp_enc = df_input.tail(args.seq_len)[['date']].reset_index(drop=True)
88
+ enc_mark = time_features(df_stamp_enc, timeenc=0, freq=args.freq)
89
+ batch_x_mark = torch.from_numpy(enc_mark).float().unsqueeze(0).to(device)
90
+
91
+ # 3. 디코더 입력(x_dec) 생성
92
+ dec_inp_label = input_scaled[-args.label_len:]
93
+ dec_inp_pred = np.zeros([args.pred_len, args.enc_in])
94
+ decoder_input = np.concatenate([dec_inp_label, dec_inp_pred], axis=0)
95
+ batch_y = torch.from_numpy(decoder_input).float().unsqueeze(0).to(device)
96
+
97
+ # 4. 디코더 시간 정보(x_mark_dec) 생성
98
+ last_date = df_stamp_enc['date'].iloc[-1]
99
+ future_dates = pd.date_range(start=last_date, periods=args.pred_len + 1, freq='5T')[1:] # 5분 단위 가정
100
+ df_stamp_dec = pd.DataFrame({'date': list(df_stamp_enc['date'].values[-args.label_len:]) + list(future_dates)})
101
+ dec_mark = time_features(df_stamp_dec, timeenc=0, freq=args.freq)
102
+ batch_y_mark = torch.from_numpy(dec_mark).float().unsqueeze(0).to(device)
103
+
104
+ # 5. 모델 호출
105
  with torch.no_grad():
106
+ outputs = model(batch_x, batch_x_mark, batch_y, batch_y_mark)
 
 
107
 
108
  prediction_scaled = outputs.detach().cpu().numpy()[0]
109
 
110
+ # 스케일 복원
111
+ if scaler.n_features_in_ > 1:
112
  padding = np.zeros((prediction_scaled.shape[0], scaler.n_features_in_ - args.c_out))
 
113
  prediction_padded = np.concatenate((padding, prediction_scaled), axis=1)
114
  prediction = scaler.inverse_transform(prediction_padded)[:, -args.c_out:]
115
  else:
116
  prediction = scaler.inverse_transform(prediction_scaled)
 
117
  return prediction
118
 
119
+ # --- 4. 모드 2: 전체 기간 롤링 평가 함수 (⭐️⭐️⭐️ 이 함수를 완성했습니다 ⭐️⭐️⭐️) ---
 
120
  def evaluate_performance(args, model, scaler, device):
 
 
121
  df_eval = pd.read_csv(args.evaluate_file)
122
+ df_eval['date'] = pd.to_datetime(df_eval['date'])
123
+
124
+ # ⭐️ 알려주신 정확한 컬럼 이름으로 수정
125
+ cols_to_scale = ['air_pres', 'wind_dir', 'wind_speed', 'air_temp', 'residual']
126
+ raw_data = df_eval[cols_to_scale].values
127
  data_scaled = scaler.transform(raw_data)
128
+
129
+ df_stamp = time_features(df_eval[['date']], timeenc=0, freq=args.freq)
130
 
131
  preds_unscaled = []
132
  trues_unscaled = []
133
 
134
  num_samples = len(data_scaled) - args.seq_len - args.pred_len + 1
135
  for i in tqdm(range(num_samples), desc="Evaluating", file=sys.stderr):
136
+ # 1. 인코더/디코더 입력 생성 (매 스텝마다)
137
  s_begin = i
138
  s_end = s_begin + args.seq_len
139
+
140
+ batch_x = data_scaled[s_begin:s_end]
141
+ batch_x_mark = df_stamp[s_begin:s_end]
142
+
143
  true_begin = s_end
144
  true_end = true_begin + args.pred_len
145
  true_scaled = data_scaled[true_begin:true_end]
146
 
147
+ dec_inp_label = batch_x[-args.label_len:]
148
+ dec_inp_pred = np.zeros([args.pred_len, args.enc_in])
149
+ batch_y = np.concatenate([dec_inp_label, dec_inp_pred], axis=0)
150
+
151
+ dec_mark_label = df_stamp[s_end-args.label_len:s_end]
152
+ dec_mark_pred = df_stamp[true_begin:true_end]
153
+ batch_y_mark = np.concatenate([dec_mark_label, dec_mark_pred], axis=0)
154
+
155
+ # 텐서로 변환
156
+ batch_x = torch.from_numpy(batch_x).float().unsqueeze(0).to(device)
157
+ batch_x_mark = torch.from_numpy(batch_x_mark).float().unsqueeze(0).to(device)
158
+ batch_y = torch.from_numpy(batch_y).float().unsqueeze(0).to(device)
159
+ batch_y_mark = torch.from_numpy(batch_y_mark).float().unsqueeze(0).to(device)
160
+
161
+ # 2. 모델 호출
162
  with torch.no_grad():
163
+ outputs = model(batch_x, batch_x_mark, batch_y, batch_y_mark)
164
 
165
  pred_scaled = outputs.detach().cpu().numpy()[0]
166
+
167
+ # 3. 스케일 복원
168
+ if scaler.n_features_in_ > 1:
169
  padding = np.zeros((pred_scaled.shape[0], scaler.n_features_in_ - args.c_out))
170
  pred_padded = np.concatenate((padding, pred_scaled), axis=1)
171
  pred_unscaled = scaler.inverse_transform(pred_padded)[:, -args.c_out:]