modnn 3.0.2__tar.gz → 3.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modnn-3.0.2 → modnn-3.0.4}/PKG-INFO +1 -1
- modnn-3.0.4/Update_Log.md +36 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Config.py +11 -8
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Dataset.py +2 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Models/ModNN_data.py +60 -9
- modnn-3.0.4/modnn/Models/PolicyNN.py +41 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Play.py +8 -4
- {modnn-3.0.2 → modnn-3.0.4}/modnn/run.py +2 -1
- {modnn-3.0.2 → modnn-3.0.4}/modnn.egg-info/PKG-INFO +1 -1
- {modnn-3.0.2 → modnn-3.0.4}/modnn.egg-info/SOURCES.txt +1 -0
- {modnn-3.0.2 → modnn-3.0.4}/pyproject.toml +10 -1
- modnn-3.0.2/modnn/Models/PolicyNN.py +0 -75
- {modnn-3.0.2 → modnn-3.0.4}/LICENSE +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/README.md +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Models/BaseNN.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Models/ModNN_phy.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Models/ModNN_phy_back.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/Models/__init__.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/__init__.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/hyper_tune.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn/utils.py +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn.egg-info/dependency_links.txt +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn.egg-info/requires.txt +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/modnn.egg-info/top_level.txt +0 -0
- {modnn-3.0.2 → modnn-3.0.4}/setup.cfg +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# 🧠 Update log
|
|
2
|
+
|
|
3
|
+
# 🧠 [2.0.0] 2025 May 9
|
|
4
|
+
To further improve physical consistency,
|
|
5
|
+
|
|
6
|
+
I replaced heat transfer module by set of energy balance equations,
|
|
7
|
+
|
|
8
|
+
Start from version 2.0.0
|
|
9
|
+
|
|
10
|
+
# 🧠 [2.0.1] 2025 May 10
|
|
11
|
+
Add another parameter: "envelop_mdl",
|
|
12
|
+
|
|
13
|
+
Allow user to use the new physics based module or previous data driven module.
|
|
14
|
+
|
|
15
|
+
# 🧠 [2.0.2] 2025 May 10
|
|
16
|
+
Fix bug due to parameter: "envelop_mdl",
|
|
17
|
+
|
|
18
|
+
Vectorize calculation,speed improved by ~6 times.
|
|
19
|
+
|
|
20
|
+
# 🧠 [3.0.0] 2025 June 11
|
|
21
|
+
Update datadriven modnn
|
|
22
|
+
RC based envelop_mdl really hard to tune on new dataset
|
|
23
|
+
|
|
24
|
+
# 🧠 [3.0.1] 2025 June 11
|
|
25
|
+
Add a step function for one step ahead prediction
|
|
26
|
+
|
|
27
|
+
# 🧠 [3.0.2] 2025 June 11
|
|
28
|
+
Fix bug for step function
|
|
29
|
+
|
|
30
|
+
# 🧠 [3.0.3] 2025 June 11
|
|
31
|
+
Fix bug for step function
|
|
32
|
+
|
|
33
|
+
# 🧠 [3.0.4] 2025 Sept 10
|
|
34
|
+
Didn't work on it for 3 months, just update the latest version
|
|
35
|
+
Will use it for BESTOpt building dynamic model
|
|
36
|
+
|
|
@@ -8,10 +8,10 @@ def _paras(**kwargs):
|
|
|
8
8
|
"Int_in": 3, "Int_h": 12, "Int_out": 1,
|
|
9
9
|
|
|
10
10
|
# External disturbance module
|
|
11
|
-
"Ext_in":
|
|
11
|
+
"Ext_in": 2, "Ext_h": 18, "Ext_out": 1,
|
|
12
12
|
|
|
13
13
|
# Zone module
|
|
14
|
-
"Zone_in": 1, "Zone_out": 1,
|
|
14
|
+
"Zone_in": 1, "Zone_h": 12, "Zone_out": 1,
|
|
15
15
|
|
|
16
16
|
# HVAC module
|
|
17
17
|
"HVAC_in": 1, "HVAC_out": 1,
|
|
@@ -22,14 +22,16 @@ def _paras(**kwargs):
|
|
|
22
22
|
# LSTM baseline
|
|
23
23
|
"LSTM_h" : 24,
|
|
24
24
|
|
|
25
|
-
"
|
|
26
|
-
"
|
|
25
|
+
"current_meas_dim": 7,
|
|
26
|
+
"future_disturbance_dim": 6,
|
|
27
|
+
"horizon": 96,
|
|
28
|
+
"hidden_dim": 256,
|
|
27
29
|
"policy_epochs":200, "policy_lr":0.01,
|
|
28
30
|
|
|
29
31
|
# Training hyperparameters
|
|
30
32
|
"lr": 0.01,
|
|
31
33
|
"epochs": 30,
|
|
32
|
-
"patience":
|
|
34
|
+
"patience": 6, #Early stop
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
# Allow override from kwargs
|
|
@@ -77,6 +79,7 @@ def _args(**kwargs):
|
|
|
77
79
|
# "datapath": "/home/zjiang19/Documents/GitHub/Eplus_ModNN_Compare/dataset/Eplus/EPlus_train_case1.csv",
|
|
78
80
|
# "datapath": "/home/zjiang19/Documents/GitHub/Physical-Incorporated-Neural-Network-BEM/update/403_new_dyn.csv",
|
|
79
81
|
"datapath": "/home/zjiang19/Documents/GitHub/ModNN-RL-403/dataset/Data_Process/data_coe_update.csv",
|
|
82
|
+
# "datapath":"/home/zjiang19/Documents/GitHub/BEST_OPT/dataset/dataset_1.csv",
|
|
80
83
|
"device": "cuda:1",
|
|
81
84
|
"save_name": "Eplus",
|
|
82
85
|
|
|
@@ -86,8 +89,8 @@ def _args(**kwargs):
|
|
|
86
89
|
"resolution": 15, # 15 minutes data
|
|
87
90
|
"enLen": 48, # "Kind of warm-up"
|
|
88
91
|
"deLen": 96, # Prediction horizon, 96 is for 24 hours
|
|
89
|
-
"startday":
|
|
90
|
-
"trainday":
|
|
92
|
+
"startday": 384, # Training data selection
|
|
93
|
+
"trainday": 180, # Training data selection
|
|
91
94
|
"testday": 1, # Testing data selection
|
|
92
95
|
"training_batch": 1024*1,
|
|
93
96
|
"multi_deLen": [4, 8, 16, 24, 32, 48],
|
|
@@ -96,7 +99,7 @@ def _args(**kwargs):
|
|
|
96
99
|
"ext_mdl": "RNN", # We provide LSTM and RNN module, for RNN, we can apply positive constraint easily
|
|
97
100
|
# But LSTM has Hadamard product, making this constraint hard to integrate
|
|
98
101
|
# However, disturbance variables always have similiar distribution, in other word, is this constraint really necessary?
|
|
99
|
-
"plott": '
|
|
102
|
+
"plott": 'all', # all: If want to see how model response to max heating/cooling; else: only Tzone prediction
|
|
100
103
|
"modeltype": 'PI-modnn', # We also have "LSTM", "PI-modnn", "PI-modnn|C", "PI-modnn|L", "PI-modnn|LC" for fun
|
|
101
104
|
# LSTM is the baseline, |C means no constraints, |L means no loss adjustment
|
|
102
105
|
"scale": 1, # scaling factor for HVAC power
|
|
@@ -17,6 +17,20 @@ class zone(nn.Module):
|
|
|
17
17
|
def forward(self, x):
|
|
18
18
|
return self.scale(x)
|
|
19
19
|
|
|
20
|
+
# --- Zone Module ---
|
|
21
|
+
# class zone(nn.Module):
|
|
22
|
+
# def __init__(self, input_size, hidden_size, output_size, num_layers=1):
|
|
23
|
+
# super(zone, self).__init__()
|
|
24
|
+
# self.dym = nn.RNN(input_size=input_size, hidden_size=hidden_size,
|
|
25
|
+
# num_layers=num_layers, batch_first=True, bias=True)
|
|
26
|
+
# self.fc = nn.Linear(hidden_size, output_size)
|
|
27
|
+
#
|
|
28
|
+
# def forward(self, deltaq, hidden):
|
|
29
|
+
# Tpred, hidden = self.dym(deltaq, hidden)
|
|
30
|
+
# out = self.fc(Tpred)
|
|
31
|
+
#
|
|
32
|
+
# return out, hidden
|
|
33
|
+
|
|
20
34
|
# --- Internal Gain Module ---
|
|
21
35
|
class internal(nn.Module):
|
|
22
36
|
"""
|
|
@@ -165,8 +179,9 @@ class external(nn.Module):
|
|
|
165
179
|
self.hidden_size = hidden_size
|
|
166
180
|
|
|
167
181
|
def forward(self, x_input, hidden_state):
|
|
168
|
-
|
|
169
|
-
# ext_mdl_out, hidden = self.ext_mdl((x_input[:, :, [
|
|
182
|
+
# Need more work to explore weather we input the deltaT or just Tamb and Tspace toghether
|
|
183
|
+
# ext_mdl_out, hidden = self.ext_mdl((x_input[:, :, [1]] - x_input[:, :, [0]]), hidden_state)
|
|
184
|
+
ext_mdl_out, hidden = self.ext_mdl((x_input[:, :, [0,1]]), hidden_state)
|
|
170
185
|
last_output = ext_mdl_out[:, -1:, :]
|
|
171
186
|
out = self.relu(self.fc1(last_output))
|
|
172
187
|
out = self.fc2(out)
|
|
@@ -177,6 +192,29 @@ class external(nn.Module):
|
|
|
177
192
|
|
|
178
193
|
return out, hidden+solargain.permute(1, 0, 2)
|
|
179
194
|
|
|
195
|
+
class external_CNN(nn.Module):
|
|
196
|
+
"""
|
|
197
|
+
CNN-based External Module to learn heat gain from T_zone, T_ambient, and Solar radiation.
|
|
198
|
+
Models thermal lag with a convolution kernel of 6 hours (24 time steps).
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def __init__(self, input_channels=3, kernel_size=24):
|
|
202
|
+
super(external_CNN, self).__init__()
|
|
203
|
+
self.conv1 = nn.Conv1d(in_channels=input_channels, out_channels=8,
|
|
204
|
+
kernel_size=kernel_size, padding=0, bias=False)
|
|
205
|
+
self.relu = nn.ReLU()
|
|
206
|
+
self.conv2 = nn.Conv1d(in_channels=8, out_channels=1, kernel_size=1, padding=0, bias=False)
|
|
207
|
+
self.fc = nn.Linear(1, 1)
|
|
208
|
+
|
|
209
|
+
def forward(self, x_input, hidden_state=None):
|
|
210
|
+
# Input: (batch, window, features) → select 3 features and permute
|
|
211
|
+
x = x_input[:, :, [0, 1, 2]].permute(0, 2, 1) # → (B, 3, T)
|
|
212
|
+
out = self.relu(self.conv1(x)) # → (B, 8, T - k + 1)
|
|
213
|
+
out = self.relu(self.conv2(out)) # → (B, 1, T - k + 1)
|
|
214
|
+
out = out[:, :, -1:] # → take last time step → (B, 1, 1)
|
|
215
|
+
return self.fc(out.transpose(1, 2)), None # → (B, 1, 1)
|
|
216
|
+
|
|
217
|
+
|
|
180
218
|
# --- Modular Physics-Informed Neural Network ---
|
|
181
219
|
class ModNN(nn.Module):
|
|
182
220
|
"""
|
|
@@ -189,10 +227,11 @@ class ModNN(nn.Module):
|
|
|
189
227
|
self.device = args['device']
|
|
190
228
|
self.window = para["window"]
|
|
191
229
|
self.ext_mdl = args["ext_mdl"]
|
|
192
|
-
|
|
230
|
+
# self.Ext = external_CNN(input_channels=3, kernel_size=para["window"])
|
|
193
231
|
self.Ext = external(para["Ext_in"], para["Ext_h"], para["Ext_out"], self.ext_mdl, para["window"])
|
|
194
232
|
self.Zone = zone(para["Zone_in"], para["Zone_out"])
|
|
195
233
|
self.HVAC = hvac(para["HVAC_in"], para["HVAC_out"])
|
|
234
|
+
# self.Zone = zone(para["Zone_in"], para["Zone_h"], para["Zone_out"])
|
|
196
235
|
self.Int = internal(para["Int_in"], para["Int_h"], para["Int_out"])
|
|
197
236
|
|
|
198
237
|
def forward(self, input_X):
|
|
@@ -216,6 +255,8 @@ class ModNN(nn.Module):
|
|
|
216
255
|
else:
|
|
217
256
|
ext_hidd = torch.ones(1, Ext_X.shape[0], self.Ext.ext_mdl.hidden_size).to(self.device)
|
|
218
257
|
ext_cell = torch.ones(1, Ext_X.shape[0], self.Ext.ext_mdl.hidden_size).to(self.device)
|
|
258
|
+
|
|
259
|
+
# zone_hidd = torch.ones(1, input_X.shape[0], self.Zone.dym.hidden_size).to(self.device)
|
|
219
260
|
# This is the look back window
|
|
220
261
|
# I strongly suggest to use it, if you are using MLP external module
|
|
221
262
|
# The value if how long you want to look back, typically, larger value for heavy structures
|
|
@@ -248,6 +289,7 @@ class ModNN(nn.Module):
|
|
|
248
289
|
input_X[:, i-window_size+1:i+1, [0]] * ratio + TOut_list[:, i-window_size+1:i+1, :] * (1 - ratio),
|
|
249
290
|
Ext_X[:, i-window_size+1:i+1, :]
|
|
250
291
|
], dim=2)
|
|
292
|
+
# ext_flux, _ = self.Ext(ext_embed, None)
|
|
251
293
|
if self.ext_mdl == "RNN" or self.ext_mdl == "GRU":
|
|
252
294
|
ext_flux, ext_hidd = self.Ext(ext_embed, ext_hidd)
|
|
253
295
|
else:
|
|
@@ -258,14 +300,17 @@ class ModNN(nn.Module):
|
|
|
258
300
|
# For a well controlled space, it's not important
|
|
259
301
|
# But if you are interested in extreme case, please add Tzone for Int input
|
|
260
302
|
int_flux = self.Int(Int_X[:, i:i+1, :])
|
|
261
|
-
total_flux = ext_flux + hvac_flux
|
|
303
|
+
total_flux = ext_flux + int_flux+ hvac_flux
|
|
262
304
|
HVAC_list[:, i, :] = hvac_flux.squeeze(1)
|
|
263
305
|
Ext_list[:, i, :] = ext_flux.squeeze(1)
|
|
264
306
|
Int_list[:, i, :] = int_flux.squeeze(1)
|
|
265
307
|
deltaQ_list[:, i, :] = total_flux.squeeze(1)
|
|
266
308
|
|
|
267
309
|
# After get total flux, we can predict the ΔTzone, and use residual connection to predict Tzone step by step
|
|
268
|
-
E_Zone_T = input_X[:, i:i+1, [0]] + self.Zone(total_flux)
|
|
310
|
+
# E_Zone_T = input_X[:, i:i+1, [0]] + self.Zone(total_flux)
|
|
311
|
+
# deltaT, zone_hidd = self.Zone(total_flux, zone_hidd)
|
|
312
|
+
deltaT = self.Zone(total_flux)
|
|
313
|
+
E_Zone_T = input_X[:, i:i+1, [0]] + deltaT
|
|
269
314
|
|
|
270
315
|
# --- Decoding Phase ---
|
|
271
316
|
# Just transfer encoder module here
|
|
@@ -281,16 +326,21 @@ class ModNN(nn.Module):
|
|
|
281
326
|
else:
|
|
282
327
|
ext_flux, (ext_hidd, ext_cell) = self.Ext(ext_embed, (ext_hidd, ext_cell))
|
|
283
328
|
|
|
329
|
+
ext_flux, _ = self.Ext(ext_embed, None)
|
|
284
330
|
hvac_flux = self.HVAC(HVAC_X[:, i:i+1, :])
|
|
285
331
|
int_flux = self.Int(Int_X[:, i:i+1, :])
|
|
286
|
-
total_flux = ext_flux + hvac_flux
|
|
332
|
+
total_flux = ext_flux + int_flux+ hvac_flux
|
|
287
333
|
|
|
288
334
|
HVAC_list[:, i, :] = hvac_flux.squeeze(1)
|
|
289
335
|
Ext_list[:, i, :] = ext_flux.squeeze(1)
|
|
290
336
|
Int_list[:, i, :] = int_flux.squeeze(1)
|
|
291
337
|
deltaQ_list[:, i, :] = total_flux.squeeze(1)
|
|
292
338
|
# No self-learning during decoder stage
|
|
293
|
-
E_Zone_T = E_Zone_T + self.Zone(total_flux)
|
|
339
|
+
# E_Zone_T = E_Zone_T + self.Zone(total_flux)
|
|
340
|
+
# deltaT, zone_hidd = self.Zone(total_flux, zone_hidd)
|
|
341
|
+
deltaT = self.Zone(total_flux)
|
|
342
|
+
E_Zone_T = E_Zone_T + deltaT
|
|
343
|
+
|
|
294
344
|
|
|
295
345
|
# Return not only temperature, but also latent flux
|
|
296
346
|
# Not sure how to use these fluxes right now, but leave for placeholder
|
|
@@ -301,7 +351,7 @@ class ModNN_step(nn.Module):
|
|
|
301
351
|
We form it as a time-stepper model, in other words, we are predict the ΔTzone for each timestep
|
|
302
352
|
"""
|
|
303
353
|
def __init__(self, args):
|
|
304
|
-
super(
|
|
354
|
+
super(ModNN_step, self).__init__()
|
|
305
355
|
para = args["para"]
|
|
306
356
|
self.encoLen = args["enLen"]
|
|
307
357
|
self.device = args['device']
|
|
@@ -309,7 +359,8 @@ class ModNN_step(nn.Module):
|
|
|
309
359
|
self.ext_mdl = args["ext_mdl"]
|
|
310
360
|
|
|
311
361
|
self.Ext = external(para["Ext_in"], para["Ext_h"], para["Ext_out"], self.ext_mdl, para["window"])
|
|
312
|
-
self.Zone = zone(para["Zone_in"], para["Zone_out"])
|
|
362
|
+
# self.Zone = zone(para["Zone_in"], para["Zone_out"])
|
|
363
|
+
self.Zone = zone(para["Zone_in"], para["Zone_h"], para["Zone_out"])
|
|
313
364
|
self.HVAC = hvac(para["HVAC_in"], para["HVAC_out"])
|
|
314
365
|
self.Int = internal(para["Int_in"], para["Int_h"], para["Int_out"])
|
|
315
366
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import torch.nn as nn
|
|
3
|
+
|
|
4
|
+
class Policy(nn.Module):
|
|
5
|
+
def __init__(self, args):
|
|
6
|
+
super(Policy, self).__init__()
|
|
7
|
+
para = args["para"]
|
|
8
|
+
self.device = args["device"]
|
|
9
|
+
|
|
10
|
+
self.horizon = 96
|
|
11
|
+
input_dim = para["current_meas_dim"] + para["future_disturbance_dim"] * self.horizon
|
|
12
|
+
hidden_dim = para["hidden_dim"]
|
|
13
|
+
|
|
14
|
+
self.model = nn.Sequential(
|
|
15
|
+
nn.Linear(input_dim, hidden_dim),
|
|
16
|
+
nn.ReLU(),
|
|
17
|
+
nn.Linear(hidden_dim, hidden_dim),
|
|
18
|
+
nn.ReLU(),
|
|
19
|
+
nn.Linear(hidden_dim, self.horizon),
|
|
20
|
+
nn.Tanh()
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def forward(self, obs):
|
|
24
|
+
"""
|
|
25
|
+
obs: [batch, 144, 10]
|
|
26
|
+
"0.T_zone, 1.T_ambient, 2.solar, 3.day_sin, 4.day_cos,
|
|
27
|
+
5.occ, 6.phvac, 7.setpt_cool, 8.setpt_heat, 9.price"
|
|
28
|
+
Returns: [batch, 96] predicted control trajectory
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# 1. Current measurements at t=47 (T_zone + 6 others)
|
|
32
|
+
current = obs[:, 47, [0, 1, 2, 5, 7, 8, 9]] # [batch, 7]
|
|
33
|
+
|
|
34
|
+
# 2. Future known disturbances (exclude T_zone and phvac)
|
|
35
|
+
future = obs[:, 48:, [1, 2, 5, 7, 8, 9]] # [batch, 96, 6]
|
|
36
|
+
future = future.reshape(obs.shape[0], -1) # [batch, 768]
|
|
37
|
+
|
|
38
|
+
# Combine
|
|
39
|
+
x_input = torch.cat([current, future], dim=1) # [batch, 775]
|
|
40
|
+
|
|
41
|
+
return self.model(x_input).unsqueeze(-1)
|
|
@@ -144,13 +144,17 @@ def train_model(model, train_loader, valid_loader, test_loader, lr, epochs,
|
|
|
144
144
|
try:
|
|
145
145
|
# Positive Hard Constraints
|
|
146
146
|
model.Zone.scale.weight.data.clamp_(0)
|
|
147
|
+
# model.Zone.dym.weight_ih_l0.data.clamp_(0)
|
|
148
|
+
# model.Zone.dym.weight_hh_l0.data.clamp_(0)
|
|
149
|
+
# model.Zone.fc.weight.data.clamp_(0)
|
|
147
150
|
model.Int.scale.weight.data.clamp_(0)
|
|
148
151
|
model.HVAC.scale.weight.data.clamp_(0)
|
|
149
152
|
|
|
150
153
|
|
|
151
154
|
# model.Ext.conduction.weight.data.clamp_(0)
|
|
152
155
|
if ext_mdl == 'RNN':
|
|
153
|
-
model.Ext.rnn.
|
|
156
|
+
model.Ext.rnn.weight_ih_l0.data.clamp_(0)
|
|
157
|
+
model.Ext.rnn.weight_hh_l0.data.clamp_(0)
|
|
154
158
|
else:
|
|
155
159
|
pass
|
|
156
160
|
except:
|
|
@@ -255,7 +259,7 @@ def train_model(model, train_loader, valid_loader, test_loader, lr, epochs,
|
|
|
255
259
|
tem = Temp_out_denorm[timestep][:test_len - timestep]
|
|
256
260
|
ax.plot_date(rawdf.index[timestep:timestep + pred_len][:test_len - timestep],
|
|
257
261
|
tem, '-', linewidth=1, color="gray", label=name)
|
|
258
|
-
ax.set_ylim(meas.min()-1, meas.max()+1)
|
|
262
|
+
# ax.set_ylim(meas.min()-1, meas.max()+1)
|
|
259
263
|
# for timestep in [24, 48, 72]:
|
|
260
264
|
# tem_other = Temp_out_denorm[timestep][:test_len - timestep]
|
|
261
265
|
# tem_other = (tem_other - 32) * 5 / 9
|
|
@@ -609,7 +613,7 @@ def control_model(dynamic_mdl, control_mdl, control_loader, args, test_loader, h
|
|
|
609
613
|
u_denorm = (u_opt - range_min) / (range_max - range_min) * (data_max - data_min) + data_min
|
|
610
614
|
price = torch.sum(torch.square(u_denorm/1000*data[:, args['enLen']-1:-1, [9]]))
|
|
611
615
|
|
|
612
|
-
to_loss = price
|
|
616
|
+
to_loss = price + vio*10
|
|
613
617
|
to_loss.backward()
|
|
614
618
|
optimizer.step()
|
|
615
619
|
|
|
@@ -618,7 +622,7 @@ def control_model(dynamic_mdl, control_mdl, control_loader, args, test_loader, h
|
|
|
618
622
|
price_loss += price.item() * data.size(0)
|
|
619
623
|
|
|
620
624
|
control_mdl.eval()
|
|
621
|
-
res =
|
|
625
|
+
res = 10
|
|
622
626
|
if epoch % res == 0:
|
|
623
627
|
with torch.no_grad(): # No gradients needed
|
|
624
628
|
for data, _ in test_loader:
|
|
@@ -13,10 +13,11 @@ Mod = Mod(args=args)
|
|
|
13
13
|
Mod.data_ready()
|
|
14
14
|
Mod.train()
|
|
15
15
|
Mod.load()
|
|
16
|
+
# Mod.load('/home/zjiang19/Documents/GitHub/Physical-Incorporated-Neural-Network-BEM/update/Saved/Eplus/Trained_mdlEnco48_Deco96/PI-modnn_150daysTest_on06-30.pth')
|
|
16
17
|
Mod.test()
|
|
17
18
|
Mod.prediction_show()
|
|
18
19
|
Mod.check()
|
|
19
20
|
Mod.dynamiccheck()
|
|
20
21
|
Mod.check_show()
|
|
21
|
-
|
|
22
|
+
# Mod.policy_train()
|
|
22
23
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "modnn"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.4"
|
|
8
8
|
description = "Physics-Informed Modularized Neural Network for Building Energy Modeling"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.7"
|
|
@@ -25,3 +25,12 @@ dependencies = [
|
|
|
25
25
|
|
|
26
26
|
[tool.setuptools.packages.find]
|
|
27
27
|
include = ["modnn", "modnn.*"]
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
include-package-data = true
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.package-data]
|
|
33
|
+
mypackage = ["*.md"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.data-files]
|
|
36
|
+
"." = ["Update_Log.md"]
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import torch
|
|
2
|
-
import torch.nn as nn
|
|
3
|
-
import torch.autograd as autograd
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class LSTM_encoder(nn.Module):
|
|
7
|
-
|
|
8
|
-
def __init__(self, input_size, hidden_size, output_size, num_layers=1):
|
|
9
|
-
super(LSTM_encoder, self).__init__()
|
|
10
|
-
self.input_size = input_size
|
|
11
|
-
self.output_size = output_size
|
|
12
|
-
self.hidden_size = hidden_size
|
|
13
|
-
self.num_layers = num_layers
|
|
14
|
-
self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size,
|
|
15
|
-
num_layers=num_layers, batch_first=True, bias=True)
|
|
16
|
-
self.Enfc = nn.Linear(in_features=hidden_size, out_features=output_size, bias=True)
|
|
17
|
-
|
|
18
|
-
def forward(self, x_input):
|
|
19
|
-
lstm_out, self.hidden = self.lstm(x_input)
|
|
20
|
-
output = self.Enfc(lstm_out)
|
|
21
|
-
|
|
22
|
-
return output, self.hidden
|
|
23
|
-
|
|
24
|
-
def init_hidden(self, batch_size):
|
|
25
|
-
return torch.zeros(self.num_layers, batch_size, self.hidden_size)
|
|
26
|
-
|
|
27
|
-
class LSTM_decoder(nn.Module):
|
|
28
|
-
|
|
29
|
-
def __init__(self, input_size, hidden_size, output_size, num_layers=1):
|
|
30
|
-
super(LSTM_decoder, self).__init__()
|
|
31
|
-
self.input_size = input_size
|
|
32
|
-
self.output_size = output_size
|
|
33
|
-
self.hidden_size = hidden_size
|
|
34
|
-
self.num_layers = num_layers
|
|
35
|
-
self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size,
|
|
36
|
-
num_layers=num_layers, batch_first=True, bias=True)
|
|
37
|
-
self.fc = nn.Linear(in_features=hidden_size, out_features=output_size, bias=True)
|
|
38
|
-
|
|
39
|
-
def forward(self, x_input, encoder_hidden_states):
|
|
40
|
-
lstm_out, self.hidden = self.lstm(x_input, encoder_hidden_states)
|
|
41
|
-
output = self.fc(lstm_out)
|
|
42
|
-
|
|
43
|
-
return output
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class Policy(nn.Module):
|
|
47
|
-
def __init__(self, args):
|
|
48
|
-
super().__init__()
|
|
49
|
-
para = args["para"]
|
|
50
|
-
self.encoder = LSTM_encoder(input_size=para["en_policy_in"],
|
|
51
|
-
hidden_size=para["en_policy_hidden"],
|
|
52
|
-
output_size=para["en_policy_out"])
|
|
53
|
-
self.decoder = LSTM_decoder(input_size=para["de_policy_in"],
|
|
54
|
-
hidden_size=para["de_policy_hidden"],
|
|
55
|
-
output_size=para["de_policy_out"])
|
|
56
|
-
self.device = args['device']
|
|
57
|
-
self.enLen = args['enLen']
|
|
58
|
-
|
|
59
|
-
def forward(self, obs):
|
|
60
|
-
"""
|
|
61
|
-
0.T_zone, 1.T_ambient, 2.solar, 3.day_sin, 4.day_cos,
|
|
62
|
-
5.occ, 6.phvac, 7.setpt_cool, 8.setpt_heat, 9.price
|
|
63
|
-
|
|
64
|
-
:param input_X:
|
|
65
|
-
:return: u_opt (96 steps)
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
# Encoder
|
|
69
|
-
Encoder_X = obs[:, :self.enLen, [0, 1, 2]]
|
|
70
|
-
# Decoder
|
|
71
|
-
Decoder_X = obs[:, self.enLen-1:-1, [1, 2, 5, 7, 8, 9]]
|
|
72
|
-
encoder_out, encoder_hidden = self.encoder(Encoder_X)
|
|
73
|
-
decoder_out = self.decoder(Decoder_X, encoder_hidden_states = encoder_hidden)
|
|
74
|
-
|
|
75
|
-
return torch.tanh(decoder_out)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|