Skip to content

Commit 84a206a

Browse files
Mleyliabadimarota
andauthored
Ml wip upgrade tests (#114)
* Setup file updated with sections for test and doc * circleci config updated wrt updates in setup * grid2op and lightsim versions updated * setup package lists updated * Am accelerated tau transform (#113) * providing a faster transform_tau method if topologies are given in list * adding back test for leap_net, accelerated_tau_transform especially * Delete Test_extract_tau.py * Update leap_net.py * adding a warning for a probably very rare case that should later be able to deal with * Update leap_net.py * typo in variable name, tau instead of extract_tau * no need to scale topo_vect as values revolve around 1, that it is about categorical variables, and that it is re-encoded afterwards Co-authored-by: marota <antoine-marot@live.fr>
1 parent 44299c4 commit 84a206a

File tree

14 files changed

+258
-31
lines changed

14 files changed

+258
-31
lines changed

.circleci/config.yml

+2-20
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: 2.1
22

33
references:
44
dep_key: &dep_key
5-
deps2-{{ .Branch }}-{{ checksum "requirements.txt" }}
5+
deps4-{{ .Branch }}-{{ checksum "requirements.txt" }}
66

77
executors:
88
docker-executor:
@@ -23,18 +23,8 @@ commands:
2323
python3 -m venv venv
2424
. venv/bin/activate
2525
pip install --upgrade pip
26-
pip install -r requirements.txt
27-
pip install -U .
28-
pip install pytest
26+
pip install -U .[test]
2927
pip install nbmake pytest-xdist
30-
pip install ipykernel
31-
pip install pylint
32-
pip install pylint-exit
33-
pip install jupytext --upgrade
34-
pip install sphinx
35-
pip install sphinx-rtd-theme
36-
pip install sphinxcontrib_trio
37-
pip install autodocsumm
3828
- change_owner
3929
- save_cache_dep
4030

@@ -206,14 +196,6 @@ workflows:
206196
ignore:
207197
- gh-pages
208198

209-
- run_pylint:
210-
requires:
211-
- build_dep
212-
filters:
213-
branches:
214-
ignore:
215-
- gh-pages
216-
217199
- run_notebook_test:
218200
requires:
219201
- run_python_tests

lips/augmented_simulators/tensorflow_models/leap_net.py

+90-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from typing import Union
1414
import json
1515
import warnings
16+
import copy
1617

1718
import numpy as np
1819

@@ -25,12 +26,12 @@
2526
except ImportError as err:
2627
raise RuntimeError("You need to install the leap_net package to use this class") from err
2728

28-
2929
from ..tensorflow_simulator import TensorflowSimulator
3030
from ...logger import CustomLogger
3131
from ...config import ConfigManager
3232
from ...dataset import DataSet
3333
from ...dataset.scaler import Scaler
34+
import tensorflow as tf
3435

3536

3637
class LeapNet(TensorflowSimulator):
@@ -97,6 +98,8 @@ def __init__(self,
9798
# model parameters
9899
self.params = self.sim_config.get_options_dict()
99100
self.params.update(kwargs)
101+
self.attr_tau=kwargs['attr_tau']
102+
100103
# optimizer
101104
# optimizer
102105
if "optimizer" in kwargs:
@@ -122,7 +125,7 @@ def _create_proxy(self):
122125
train_batch_size=self.params["train_batch_size"],
123126
attr_x=self.bench_config.get_option("attr_x"),
124127
attr_y=self.bench_config.get_option("attr_y"),
125-
attr_tau=self.bench_config.get_option("attr_tau"),
128+
attr_tau=self.attr_tau,#self.bench_config.get_option("attr_tau"),
126129
sizes_enc=self.params["sizes_enc"],
127130
sizes_main=self.params["sizes_main"],
128131
sizes_out=self.params["sizes_out"],
@@ -137,6 +140,7 @@ def _create_proxy(self):
137140
scale_input_dec_layer=self.params["scale_input_dec_layer"], # scale the input of the decoder
138141
scale_input_enc_layer=self.params["scale_input_enc_layer"], # scale the input of the encoder
139142
layer_act=self.params["activation"]
143+
140144
)
141145

142146
def process_dataset(self, dataset: DataSet, training: bool=False) -> tuple:
@@ -169,14 +173,25 @@ def process_dataset(self, dataset: DataSet, training: bool=False) -> tuple:
169173
(extract_x, extract_tau), extract_y = self.scaler.fit_transform(dataset)
170174
else:
171175
(extract_x, extract_tau), extract_y = dataset.extract_data(concat=False)
172-
extract_tau = self._transform_tau(dataset, extract_tau)
176+
173177
else:
174178
if self.scaler is not None:
175179
(extract_x, extract_tau), extract_y = self.scaler.transform(dataset)
176180
else:
177181
(extract_x, extract_tau), extract_y = dataset.extract_data(concat=False)
182+
183+
184+
185+
is_given_topo_list = (len(self._leap_net_model.kwargs_tau) >= 1)
186+
if (is_given_topo_list):
187+
extract_tau = self._transform_tau_given_list(extract_tau)
188+
else:
178189
extract_tau = self._transform_tau(dataset, extract_tau)
179190

191+
#if len(self._leap_net_model.attr_tau) > 1 :
192+
# extract_tau = np.concatenate((extract_tau[0], extract_tau[1]), axis=1)
193+
194+
180195
return (extract_x, extract_tau), extract_y
181196

182197
def _post_process(self, dataset, predictions):
@@ -206,6 +221,76 @@ def _transform_tau(self, dataset, tau):
206221
dtype=np.float32))
207222
return tau
208223

224+
def _transform_tau_given_list(self, tau,with_tf=True):
225+
"""Transform only the tau vector with respect to LeapNet encodings given a list of predefined topological actions
226+
Parameters
227+
----------
228+
tau : list of raw topology representations (line_status, topo_vect)
229+
230+
with_tf : transformation using tensorflow or numpy operations
231+
232+
Returns
233+
-------
234+
tau
235+
list of encoded topology representations (line_status, topo_vect_encoded)
236+
"""
237+
##############
238+
#WARNING: TO DO
239+
# if we find two topology matches at a same substation, the current code attribute one bit for each
240+
# But only one should be choosen in the end (we are not in a quantum state, or it does not make sense to combine topologies at a same substation in the encoding here
241+
#This can happen when there are several lines disconnected at a substation on which we changed the topology, probably in benchmark 3, but probably not in benchmark 1 and 2
242+
243+
subs_index=self._leap_net_model.subs_index
244+
245+
list_topos=[]
246+
sub_length=[]
247+
for topo_action in self._leap_net_model.kwargs_tau:
248+
topo_vect = np.zeros(tau[1].shape[1], dtype=np.int32)
249+
sub_id=topo_action[0]
250+
sub_topo=np.array(topo_action[1])
251+
sub_index=subs_index[sub_id][0]
252+
n_elements=len(sub_topo)
253+
topo_vect[sub_index:sub_index+n_elements]=sub_topo
254+
list_topos.append(topo_vect)
255+
sub_length.append(n_elements)
256+
257+
list_topos=np.array(list_topos)
258+
259+
#we are here looking for the number of matches for every element of a substation topology in the predefined list for a new topo_vect observation
260+
#if the count is equal to the number of element, then the predefined topology is present in topo_vect observation
261+
#in that case, the binary encoding of that predefined topology is equal to 1, otherwise 0
262+
if with_tf:
263+
#count the number of disconnected lines for each substation of topologies in the prefdefined list.
264+
#These lines could have been connected to either bus_bar1 or bus_bar2, we consider it as a match for that element
265+
line_disconnected_sub = tf.linalg.matmul((list_topos >0).astype(np.int32),(np.transpose(tau[1]) < 0).astype(np.int32))
266+
267+
#we look at the number of elements on bus_bar1 that match, same for the number of elements on bus_bar2
268+
match_tensor_bus_bar1=tf.linalg.matmul((list_topos==1).astype(np.int32),(np.transpose(tau[1])==1).astype(np.int32))
269+
match_tensor_bus_bar2 =tf.linalg.matmul((list_topos==2).astype(np.int32), (np.transpose(tau[1])==2).astype(np.int32))
270+
271+
#the number of matches is equal to the sum of those 3 category of matches
272+
match_tensor_adjusted=match_tensor_bus_bar1+match_tensor_bus_bar2+line_disconnected_sub
273+
274+
#we see if all elements match by dividing by the number of elements. If this proportion is equal to one, we found a topology match
275+
normalised_tensor = match_tensor_adjusted / tf.reshape(np.array(sub_length).astype(np.int32), (-1, 1))
276+
277+
else:#with_numpy
278+
279+
line_disconnected_sub = np.matmul((list_topos >0),1*(np.transpose(tau[1]) < 0))
280+
281+
match_tensor_bus_bar1=np.matmul((list_topos==1),1*(np.transpose(tau[1])==1))
282+
match_tensor_bus_bar2 =np.matmul((list_topos==2), 1*(np.transpose(tau[1])==2))
283+
284+
match_tensor_adjusted=match_tensor_bus_bar1+match_tensor_bus_bar2+line_disconnected_sub
285+
286+
normalised_tensor = match_tensor_adjusted / np.array(sub_length).reshape((-1, 1))
287+
288+
boolean_match_tensor = np.array(normalised_tensor == 1.0).astype(np.int8)
289+
290+
tau[1]=np.transpose(boolean_match_tensor)
291+
return tau
292+
293+
209294
def _make_fake_obs(self, dataset: DataSet):
210295
"""
211296
the underlying _leap_net_model requires some 'class' structure to work properly. This convert the
@@ -245,8 +330,9 @@ def write_history(self, history):
245330

246331
self.train_losses = hist["loss"]
247332
self.val_losses = hist["val_loss"]
333+
metrics=self.params["metrics"]
248334

249-
for metric in ["mae"]:
335+
for metric in metrics:#["mae"]:
250336
tmp_train = []
251337
tmp_val = []
252338
for key in hist.keys():

lips/dataset/scaler/powergrid_scaler.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def transform(self, dataset: PowerGridDataSet):
5555
if attr_nm == "line_status":
5656
res_tau.append((all_data[attr_nm] - m_) / sd_)
5757
elif attr_nm == "topo_vect":
58-
res_tau.append((all_data[attr_nm] - m_) / sd_)
58+
res_tau.append(all_data[attr_nm])#(all_data[attr_nm] - m_) / sd_)
5959
# if self.obss is None:
6060
# self.obss = self._make_fake_obs(dataset)
6161
# res_tau.append(np.array([leap_net_model.topo_vect_handler(obs)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

lips/tests/test_leap_net.py

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import os
2+
import sys
3+
sys.path.insert(0, "../")
4+
5+
import tensorflow as tf
6+
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
7+
8+
gpus = tf.config.experimental.list_physical_devices('GPU')
9+
if gpus:
10+
try:
11+
tf.config.experimental.set_virtual_device_configuration(
12+
gpus[0],[tf.config.experimental.VirtualDeviceConfiguration(memory_limit=5120)])
13+
except RuntimeError as e:
14+
print(e)
15+
16+
from IPython.display import display
17+
import pandas as pd
18+
import warnings
19+
20+
import numpy as np
21+
import grid2op
22+
import copy
23+
24+
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
25+
pd.set_option('display.max_columns', None)
26+
import pathlib
27+
from lips.augmented_simulators.tensorflow_models import TfFullyConnected#, TfFullyConnectedTopoEncoding
28+
from lips.dataset.scaler import StandardScaler
29+
30+
from pprint import pprint
31+
from matplotlib import pyplot as plt
32+
from lips.benchmark.powergridBenchmark import PowerGridBenchmark
33+
from lips.utils import get_path
34+
from lips.augmented_simulators.tensorflow_models import LeapNet
35+
from lips.dataset.scaler import PowerGridScaler, StandardScaler
36+
from sklearn.preprocessing import MinMaxScaler
37+
38+
from lips.config import ConfigManager
39+
40+
#from execution_jobs.utils import init_df_bench1, append_metrics_to_df_bench1, init_df_bench2, append_metrics_to_df_bench2, init_df_bench3, append_metrics_to_df_bench3, filter_bench1, filter_bench2_3
41+
42+
# indicate required paths
43+
# indicate required paths
44+
LIPS_PATH = pathlib.Path(__file__).parent.parent.parent.absolute()
45+
DATA_PATH = LIPS_PATH / "lips" / "tests" / "data" / "powergrid" / "l2rpn_case14_sandbox"
46+
BENCH_CONFIG_PATH = LIPS_PATH / "lips" / "tests" / "configs" / "powergrid" / "benchmarks" / "l2rpn_case14_sandbox.ini"
47+
SIM_CONFIG_PATH = LIPS_PATH / "configurations" / "powergrid" / "simulators"
48+
BASELINES_PATH = LIPS_PATH / "trained_baselines" / "powergrid"
49+
TRAINED_MODEL_PATH = LIPS_PATH / "trained_models" / "powergrid"
50+
EVALUATION_PATH = LIPS_PATH / "evaluation_results" / "PowerGrid"
51+
LOG_PATH = LIPS_PATH / "lips_logs.log"
52+
53+
benchmark1 = PowerGridBenchmark(benchmark_name="Benchmark1",
54+
benchmark_path=DATA_PATH,
55+
load_data_set=True,
56+
log_path=LOG_PATH,
57+
config_path=BENCH_CONFIG_PATH
58+
)
59+
60+
from lips.augmented_simulators.tensorflow_models import LeapNet
61+
62+
from lips.augmented_simulators.tensorflow_models import LeapNet
63+
64+
def test_fast_transform_tau():
65+
66+
bench_config = ConfigManager(section_name="Benchmark1", path=BENCH_CONFIG_PATH)
67+
topo_actions = bench_config.get_option("dataset_create_params")["reference_args"]["topo_actions"]
68+
69+
kwargs_tau = []
70+
for el in topo_actions:
71+
kwargs_tau.append(el["set_bus"]["substations_id"][0])
72+
73+
leap_net1 = LeapNet(name="tf_leapnet",
74+
75+
bench_config_path=BENCH_CONFIG_PATH,
76+
bench_config_name="Benchmark1",
77+
sim_config_path=SIM_CONFIG_PATH / "tf_leapnet.ini",
78+
sim_config_name="DEFAULT",
79+
log_path=LOG_PATH,
80+
81+
loss={"name": "mse"},
82+
lr=1e-4,
83+
activation=tf.keras.layers.LeakyReLU(alpha=0.01),
84+
85+
sizes_enc=(),
86+
sizes_main=(150, 150),
87+
sizes_out=(),
88+
topo_vect_to_tau="given_list",
89+
is_topo_vect_input=False,
90+
kwargs_tau=kwargs_tau,
91+
layer="resnet",
92+
attr_tau=("line_status","topo_vect"),
93+
scale_main_layer=150,
94+
# scale_input_enc_layer = 40,
95+
#scale_input_dec_layer=200,
96+
# topo_vect_as_input = True,
97+
mult_by_zero_lines_pred=False,
98+
topo_vect_as_input=True,
99+
scaler=PowerGridScaler,
100+
101+
)
102+
103+
## add topo_vect (temporary ) in attr_x in benchmark config file
104+
105+
106+
## add topo_vect (temporary ) in attr_x in benchmark config file
107+
##############
108+
nb_timesteps_to_test=1000
109+
indices=[i for i in range(nb_timesteps_to_test)]
110+
for key in benchmark1.train_dataset.data.keys():
111+
benchmark1.train_dataset.data[key]=benchmark1.train_dataset.data[key][indices]
112+
113+
benchmark1.train_dataset.size=len(indices)
114+
115+
leap_net1._leap_net_model.max_row_training_set=len(indices)
116+
dataset=benchmark1.train_dataset
117+
obss = leap_net1._make_fake_obs(dataset)
118+
leap_net1._leap_net_model.init(obss)
119+
120+
121+
(extract_x, extract_tau), extract_y = leap_net1.scaler.fit_transform(dataset)
122+
123+
#####
124+
#Launch two different mathods for transformation and check that they match
125+
tau = copy.deepcopy(extract_tau)
126+
import time
127+
start = time.time()
128+
extract_tau_1 = leap_net1._transform_tau(dataset, extract_tau)
129+
end = time.time()
130+
print(end - start) #3.9s pour 10 000 / Pour 100 000 35.63s
131+
132+
start = time.time()
133+
extract_tau_bis = leap_net1._transform_tau_given_list(tau)
134+
end = time.time()
135+
print(end - start) #0.026s pour 10 000 => 150 fois plus rapide! Pour 100 000, 1,7s
136+
#0.021s with int32, could we only work with boolean ? 0.32s for 100 000 (or 0.82s with numpy matmult, a bit faster with tensorflow then)
137+
138+
assert np.all(extract_tau_1[1].astype((np.bool_))==extract_tau_bis[1])

requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
Grid2Op==1.6.5
1+
Grid2Op==1.7.1
22
leap-net @ https://github.com/BDonnot/leap_net/tarball/master#egg=leap_net
3-
lightsim2grid==0.6.1.post2
3+
lightsim2grid==0.7.0
44
numpy==1.21.5
55
numba==0.55.1
66
pandapower==2.7.0

0 commit comments

Comments
 (0)