NimaBoscarino commited on
Commit
73834eb
1 Parent(s): 04a30fc

WIP: Substra orchestrator

Browse files
app.py CHANGED
@@ -5,8 +5,12 @@ from substra_launcher import launch_substra_space
5
  api = HfApi()
6
 
7
  gr.Interface(
 
8
  fn=lambda *args, **kwargs: launch_substra_space(api, *args, **kwargs),
9
- inputs="text",
 
 
 
10
  outputs="text",
11
- examples=[["NimaBoscarino/substra-test"]]
12
  ).launch()
 
5
  api = HfApi()
6
 
7
  gr.Interface(
8
+ title="Susbtra Demo - Orchestrator",
9
  fn=lambda *args, **kwargs: launch_substra_space(api, *args, **kwargs),
10
+ inputs=[
11
+ gr.Slider(label="num_hospitals", value=3, minimum=2, maximum=5, step=1),
12
+ gr.Text(label="space_name")
13
+ ],
14
  outputs="text",
15
+ examples=[[2, "substra-test"]]
16
  ).launch()
substra_launcher.py CHANGED
@@ -1,11 +1,13 @@
1
  from huggingface_hub import HfApi, RepoUrl
2
 
3
 
4
- def launch_substra_space(hf_api: HfApi, repo_id: str) -> RepoUrl:
 
 
5
  repo_url = hf_api.create_repo(
6
  repo_id=repo_id,
7
  repo_type="space",
8
- space_sdk="docker"
9
  )
10
 
11
  hf_api.upload_folder(
@@ -14,4 +16,15 @@ def launch_substra_space(hf_api: HfApi, repo_id: str) -> RepoUrl:
14
  folder_path="substra_template/"
15
  )
16
 
 
 
 
 
 
 
 
 
 
 
 
17
  return repo_url
 
1
  from huggingface_hub import HfApi, RepoUrl
2
 
3
 
4
+ def launch_substra_space(hf_api: HfApi, num_hospitals: int, repo_id: str) -> RepoUrl:
5
+ repo_id = "NimaBoscarino/" + repo_id
6
+
7
  repo_url = hf_api.create_repo(
8
  repo_id=repo_id,
9
  repo_type="space",
10
+ space_sdk="docker",
11
  )
12
 
13
  hf_api.upload_folder(
 
16
  folder_path="substra_template/"
17
  )
18
 
19
+ ENV_FILE = f"""\
20
+ SUBSTRA_NUM_HOSPITALS={num_hospitals}
21
+ """
22
+
23
+ hf_api.upload_file(
24
+ repo_id=repo_id,
25
+ path_or_fileobj=ENV_FILE.encode(),
26
+ path_in_repo=".env",
27
+ repo_type="space",
28
+ )
29
+
30
  return repo_url
substra_template/Dockerfile CHANGED
@@ -1,13 +1,15 @@
1
- FROM python:3.10-slim-bullseye
2
 
3
  # Set the working directory to /code
4
  WORKDIR /code
5
 
6
  # Copy the current directory contents into the container at /code
7
  COPY ./requirements.txt /code/requirements.txt
 
8
 
9
  # Install requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
 
11
 
12
  # Set up a new user named "user" with user ID 1000
13
  RUN useradd -m -u 1000 user
@@ -23,5 +25,7 @@ WORKDIR $HOME/app
23
  # Copy the current directory contents into the container at $HOME/app setting the owner to the user
24
  COPY --chown=user . $HOME/app
25
 
 
 
26
  EXPOSE 7860
27
- CMD ["bash", "-c", "/code/run.sh"]
 
1
+ FROM python:3.10
2
 
3
  # Set the working directory to /code
4
  WORKDIR /code
5
 
6
  # Copy the current directory contents into the container at /code
7
  COPY ./requirements.txt /code/requirements.txt
8
+ COPY ./mlflow-2.1.2.dev0-py3-none-any.whl /code/mlflow-2.1.2.dev0-py3-none-any.whl
9
 
10
  # Install requirements.txt
11
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
12
+ RUN chmod -R 777 /usr/local/lib/python3.10/site-packages/
13
 
14
  # Set up a new user named "user" with user ID 1000
15
  RUN useradd -m -u 1000 user
 
25
  # Copy the current directory contents into the container at $HOME/app setting the owner to the user
26
  COPY --chown=user . $HOME/app
27
 
28
+ RUN chmod -R 777 $HOME/app/
29
+
30
  EXPOSE 7860
31
+ CMD ["bash", "run.sh"]
substra_template/app.py DELETED
@@ -1,13 +0,0 @@
1
- import gradio as gr
2
-
3
-
4
- def read_logs():
5
- with open("output.log", "r") as f:
6
- return f.read()
7
-
8
-
9
- with gr.Blocks() as demo:
10
- logs = gr.Plot()
11
- demo.load(read_logs, None, logs, every=1)
12
-
13
- demo.queue().launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
substra_template/mlflow_live_performances.py CHANGED
@@ -6,7 +6,7 @@ import time
6
  import os
7
  from glob import glob
8
 
9
- TIMEOUT = 60 # Number of seconds to stop the script after the last update of the json file
10
  POLLING_FREQUENCY = 10 # Try to read the updates in the file every 10 seconds
11
 
12
  # Wait for the file to be found
 
6
  import os
7
  from glob import glob
8
 
9
+ TIMEOUT = 240 # Number of seconds to stop the script after the last update of the json file
10
  POLLING_FREQUENCY = 10 # Try to read the updates in the file every 10 seconds
11
 
12
  # Wait for the file to be found
substra_template/requirements.txt CHANGED
@@ -9,4 +9,5 @@ Pillow
9
  transformers
10
  matplotlib
11
  pandas
12
- mlflow
 
 
9
  transformers
10
  matplotlib
11
  pandas
12
+ python-dotenv
13
+ ./mlflow-2.1.2.dev0-py3-none-any.whl
substra_template/run.sh CHANGED
@@ -1,3 +1,13 @@
1
- PYTHONPATH=/Users/nima/Work/society-ethics/substra/substra_template python run_compute_plan.py &
2
- PYTHONPATH=/Users/nima/Work/society-ethics/substra/substra_template python mlflow_live_performances.py &
3
- mlflow ui
 
 
 
 
 
 
 
 
 
 
 
1
+ PYTHONPATH=$HOME/app python run_compute_plan.py &
2
+ PYTHONPATH=$HOME/app python mlflow_live_performances.py &
3
+
4
+ SITE_PACKAGES=$(python -c 'import site; print(site.getsitepackages()[0])')
5
+
6
+ # Fix for the UI code being embedded in an iframe
7
+ # Replace window.parent.location.origin with *
8
+ for i in $SITE_PACKAGES/mlflow/server/js/build/static/js/*.js; do
9
+ sed -i 's/window\.parent\.location\.origin)/"*")/' $i
10
+ sed 's/window.top?.location.href || window.location.href/window.location.href/g' -i $i
11
+ done
12
+
13
+ mlflow ui --port 7860 --host 0.0.0.0
substra_template/run_compute_plan.py CHANGED
@@ -5,13 +5,19 @@ from substrafl.strategies import FedAvg
5
 
6
  import torch
7
 
 
 
 
 
 
 
8
  seed = 42
9
  torch.manual_seed(seed)
10
  model = CNN()
11
  optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
12
  criterion = torch.nn.CrossEntropyLoss()
13
 
14
- runner = SubstraRunner()
15
  runner.set_up_clients()
16
  runner.prepare_data()
17
  runner.register_data()
 
5
 
6
  import torch
7
 
8
+ from dotenv import load_dotenv
9
+ import os
10
+ load_dotenv()
11
+
12
+ NUM_CLIENTS = int(os.environ["NUM_CLIENTS"])
13
+
14
  seed = 42
15
  torch.manual_seed(seed)
16
  model = CNN()
17
  optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
18
  criterion = torch.nn.CrossEntropyLoss()
19
 
20
+ runner = SubstraRunner(num_clients=NUM_CLIENTS)
21
  runner.set_up_clients()
22
  runner.prepare_data()
23
  runner.register_data()
substra_template/substra_helpers/substra_runner.py CHANGED
@@ -30,8 +30,8 @@ import torch
30
 
31
 
32
  class SubstraRunner:
33
- def __init__(self):
34
- self.num_clients = 3
35
  self.clients = {}
36
  self.algo_provider: Optional[Client] = None
37
 
 
30
 
31
 
32
  class SubstraRunner:
33
+ def __init__(self, num_clients: int):
34
+ self.num_clients = num_clients
35
  self.clients = {}
36
  self.algo_provider: Optional[Client] = None
37