import gradio as gr
import uuid
import asyncio
from substra_launcher import launch_substra_space
from huggingface_hub import HfApi
hf_api = HfApi()
theme = gr.themes.Default(primary_hue="blue").set(
background_fill_primary="#F9F2EA",
block_background_fill="#FFFFFF",
)
async def launch_experiment(hospital_a, hospital_b):
experiment_id = str(uuid.uuid4())
asyncio.create_task(launch_substra_space(
hf_api=hf_api,
repo_id=experiment_id,
hospital_a=hospital_a,
hospital_b=hospital_b,
))
url = f"https://hf.space/owkin/trainer-{experiment_id}"
return (
gr.Button.update(interactive=False),
gr.Markdown.update(
visible=True,
value=f"Your experiment is available at [hf.space/owkin/trainer-{experiment_id}]({url})!"
)
gr.Markdown.update(
visible=True,
value="If the image does not build in under a minute, please refresh and try again"
)
)
demo = gr.Blocks(theme=theme, css="""\
@font-face {
font-family: "Didact Gothic";
src: url('https://huggingface.co/datasets/NimaBoscarino/assets/resolve/main/substra/DidactGothic-Regular.ttf') format('truetype');
}
@font-face {
font-family: "Inter";
src: url('https://huggingface.co/datasets/NimaBoscarino/assets/resolve/main/substra/Inter-Regular.ttf') format('truetype');
}
h1 {
font-family: "Didact Gothic";
font-size: 40px !important;
}
p {
font-family: "Inter";
}
.gradio-container {
min-width: 100% !important;
}
.margin-top {
margin-top: 20px;
}
.white {
background-color: white;
}
.column {
border-radius: 20px;
padding: 30px;
}
.blue {
background-image: url("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/substra-banner.png");
background-size: cover;
}
.blue p {
color: white !important;
}
.blue strong {
color: white !important;
}
.info-box {
background: transparent !important;
border-radius: 20px !important;
border-color: white !important;
border-width: 4px !important;
padding: 20px !important;
}
""")
with demo:
gr.HTML("""
""")
gr.Markdown("# Federated Learning with Substra")
with gr.Row():
with gr.Column(scale=1, elem_classes=["blue", "column"]):
gr.Markdown("Here you can run a **quick simulation of Federated Learning**.")
gr.Markdown("Check out the accompanying blog post to learn more.")
with gr.Box(elem_classes=["info-box"]):
gr.Markdown("""\
This space is an introduction to federated learning. \
We will create new spaces soon where you will be able to control the models, datasets and \
federation strategies.\
""")
with gr.Column(scale=3, elem_classes=["white", "column"]):
gr.Markdown("""\
Data scientists doing medical research often face a shortage of high quality and diverse data to \
effectively train models. This challenge can be overcome by securely allowing training on protected \
data through Federated Learning. [Substra](https://docs.substra.org/) is a Python based Federated \
Learning software that enables researchers to easily train ML models on remote data regardless of the \
ML library they are using or the data type they are working with.
""")
gr.Markdown("### Here we show an example of image data located in **two different hospitals**.")
gr.Markdown("""\
By playing with the distribution of data in the two simulated hospitals, you'll be able to compare how \
the federated models compare with models trained on single datasets. The data used is from the \
Camelyon17 dataset, a commonly used benchmark in the medical world that comes from \
[this challenge](https://camelyon17.grand-challenge.org/). The sample below shows normal cells on the \
left compared with cancer cells on the right.
""")
gr.HTML("""
""")
gr.Markdown("""\
A problem often faced by researchers is that datasets lack the necessary amount of positive samples \
(samples containing cancer tissues) that are needed to reliably classify cancer. In this interface you \
can use the slider to control the percentage of negative and positive samples in each hospital. \
Setting this slider to minimum will mean there are 0 positive samples, whereas 50 would mean that \
half the dataset contains slides with positive tumor samples.\
""")
with gr.Row(elem_classes=["margin-top"]):
hospital_a_slider = gr.Slider(
label="Percentage of positive samples in Hospital A",
value=50,
)
hospital_b_slider = gr.Slider(
label="Percentage of positive samples in Hospital B",
value=50,
)
launch_experiment_button = gr.Button(value="Launch Experiment 🚀")
visit_experiment_text = gr.Markdown(visible=False)
launch_experiment_button.click(
fn=launch_experiment,
inputs=[hospital_a_slider, hospital_b_slider],
outputs=[launch_experiment_button, visit_experiment_text]
)
demo.launch()