EcoMindAI / src /interface /interface.py
soury
adapt to hf requirements and upgrade versions (#4)
7e77c34
"""
Description of the interface content
"""
from os import path
import gradio as gr
import pandas as pd
from src.services.serviceLLM.doc import load_doc
from src.interface.handlers import handle_launch
csv_path = path.join(path.dirname(__file__), "../../assets/data/")
# Point d'entrée de l'application
with gr.Blocks(title="EcoMindAI",
analytics_enabled=False) as io:
title = gr.HTML("""<h1 class=\"logo\">EcoMindAI</h1>
<p>Estimating the environmental impact of an language model project </p>""")
with gr.Tabs() as tabs:
# Onglet des paramètres d'entrée
with gr.Tab("📝 Input parameters", id=0, elem_classes="page") as calculator:
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("## 📝 Input parameters")
launch_btn = gr.Button("⯈ Launch impact estimation",
variant="primary", scale=1, interactive=True)
# Choix du mode
mode = gr.Radio(
["Project's impact"], label="Mode", value="Project's impact")
# Mode "impact projet"
with gr.Column(visible=True) as project_impact:
gr.HTML("<hr>", padding=False)
project_duration = gr.Number(value=5, label="Estimated project duration (in years)",
minimum=1, maximum=50)
gr.Markdown("### Algorithm")
with gr.Row() as algorithm:
dataframe = pd.read_csv(
csv_path + "input_parameters_llm.csv")
model_details = gr.Dropdown(label="Model details",
choices=list(dict.fromkeys(
dataframe["model"].tolist())),
value="llama3")
model_details_df = dataframe[(
dataframe["model"] == "llama3")]
parameters_count = gr.Dropdown(label="Parameters",
choices=list(dict.fromkeys(
model_details_df["parameters"].tolist())),
value="13b")
model_parameters_df = model_details_df[
(model_details_df["parameters"] == "13b")]
framework = gr.Dropdown(label="Framework",
choices=list(dict.fromkeys(
model_parameters_df["framework"].tolist())),
value="llamacpp")
model_parameters_framework_df = model_parameters_df[
(model_details_df["framework"] == "llamacpp")]
quantization = gr.Dropdown(label="Quantization",
choices=list(dict.fromkeys(
model_parameters_framework_df["quantization"]
.tolist())),
value="8bit0")
def handle_model_details(selected_model):
"""
Met à jour les listes déroulantes en fonction du modèle sélectionné par
l'utilisateur
"""
filtered_df = dataframe[(
dataframe["model"] == selected_model)]
return (
gr.Dropdown(label="Parameters",
choices=list(dict.fromkeys(
filtered_df["parameters"].tolist())),
value=filtered_df.iloc[0]["parameters"]),
gr.Dropdown(label="Framework",
choices=list(dict.fromkeys(
filtered_df["framework"].tolist())),
value=filtered_df.iloc[0]["framework"]),
gr.Dropdown(label="Quantization", choices=list(
dict.fromkeys(filtered_df["quantization"].tolist())),
value=filtered_df.iloc[0]["quantization"]))
model_details.change(handle_model_details, inputs=model_details,
outputs=[parameters_count, framework, quantization])
def handle_parameters_count(
selected_model, selected_parameters):
"""
Met à jour les listes déroulantes en fonction du modèle et du nombre de
paramètres associé, sélectionnés par l'utilisateur
"""
filtered_df = dataframe[(dataframe["model"] == selected_model) &
(dataframe["parameters"] == selected_parameters)]
return (
gr.Dropdown(label="Framework", choices=list(dict.fromkeys(
filtered_df["framework"].tolist())),
value=filtered_df.iloc[0]["framework"]),
gr.Dropdown(label="Quantization", choices=list(dict.fromkeys(
filtered_df["quantization"].tolist())),
value=filtered_df.iloc[0]["quantization"]))
parameters_count.change(handle_parameters_count,
inputs=[model_details,
parameters_count],
outputs=[framework, quantization])
def handle_framework(
selected_model, selected_parameters, selected_framework):
"""
Met à jour les listes déroulantes en fonction du modèle, du nombre de
paramètres associé et du framework, sélectionnés par l'utilisateur
"""
filtered_df = dataframe[(dataframe["model"] == selected_model) &
(dataframe["parameters"] == selected_parameters) &
(dataframe["framework"] == selected_framework)]
return (
gr.Dropdown(label="Quantization", choices=list(
dict.fromkeys(filtered_df["quantization"].tolist())),
value=filtered_df.iloc[0]["quantization"]))
framework.change(handle_framework,
inputs=[model_details,
parameters_count, framework],
outputs=quantization)
# Affichage dynamique des étapes
gr.Markdown("### Stages")
# La phase d'inférence est cochée par défaut
stages = gr.CheckboxGroup(
choices=["Inference", "Finetuning ⚠️"], show_label=False, value="Inference")
with gr.Column(visible=True) as inference_stage:
gr.Markdown("#### Inference")
with gr.Column():
with gr.Row():
inference_users = gr.Number(
label="Number of users per year", minimum=1, maximum=1000000000,
value=10000, elem_classes="inference")
inference_requests = gr.Number(
label="Average number of requests per year", minimum=1,
maximum=1000000000, value=200, elem_classes="inference")
inference_tokens = gr.Number(
label="Average number of tokens generated per request",
minimum=1, maximum=1000000000, value=500, elem_classes="inference"
)
inference_total_tokens_str = gr.Text(
label="⤇ Total number of generated tokens", value="5.0G",
interactive=False, elem_classes="inference")
with gr.Column(visible=False, elem_classes="wip") as finetuning_stage:
gr.Markdown(
"""#### 🏗️ Finetuning WIP: it will not be taken into account in your \
estimation
We will need more data to factor it into the estimate""")
with gr.Row():
finetuning_type = gr.Radio(
["supervised finetuning", "RLHF"],
label="Type of finetuning", interactive=False)
finetuning_data_size = gr.Number(
label="Size of the new dataset (in GB)", minimum=1, maximum=1000000000,
value=500, interactive=False)
finetuning_epochs_number = gr.Number(label="Number of epochs",
minimum=1, maximum=1000000000,
value=12, interactive=False)
finetuning_batch_size = gr.Number(label="Size of the batch",
minimum=1, maximum=1000000000,
value=10000, interactive=False)
finetuning_peft = gr.Dropdown(label="PEFT method used",
choices=["LoRA", "prefix tuning", "p-tuning",
"prompt tuning"])
def show_stages(selected_stages):
"""
Gère l'affichage des formulaires en fonction des étapes sélectionnées
"""
return gr.update(visible="Inference" in selected_stages), gr.update(
visible="Finetuning ⚠️" in selected_stages)
stages.change(show_stages, inputs=stages,
outputs=[inference_stage, finetuning_stage])
gr.HTML("<hr>", padding=False)
gr.Markdown("### Infrastructure")
with gr.Row():
infra_type = gr.Dropdown(label="Type",
choices=["Server", "Desktop", "Laptop",
"AI Cloud Service"])
with gr.Column() as infra_dedicated:
with gr.Row():
infra_cpu_cores = gr.Number(
label="CPU cores", minimum=0, maximum=1024, value=30, interactive=False,
elem_classes="show-disabled")
infra_gpu_count = gr.Number(
label="GPU count", minimum=0, maximum=1024, value=2, interactive=False,
elem_classes="show-disabled")
infra_gpu_memory = gr.Number(
label="GPU memory (GB)", minimum=0, maximum=2048, value=32,
interactive=False, elem_classes="show-disabled")
infra_memory = gr.Number(
label="RAM size (GB)", minimum=1, maximum=2048, value=64,
interactive=False, elem_classes="show-disabled")
gr.Markdown("#### Power effectiveness")
with gr.Row():
infra_pue_datacenter = gr.Number(
label="Datacenter PUE", minimum=1, maximum=10, value=1.5, step=0.01,
info="To learn more about the Power Usage Effectiveness and how it \
is calculated, check this page related to \
[PUE](https://en.wikipedia.org/wiki/Power_usage_effectiveness).",
elem_classes="show-disabled")
infra_pue_machine = gr.Number(
label="Complementary PUE", minimum=1, maximum=10, value=1.3, step=0.01,
info="Power used for the operating of OS, virtualization, control plan,\
idle... To learn more about it, visit our documentation page.",)
with gr.Column(visible=False) as infra_service:
gr.HTML(
"<div class=\"not-implemented\">🏗️ Not implemented yet</div>")
def handle_inference_total_tokens(
duration, nb_inference_users, nb_inference_requests, nb_inference_tokens):
"""
Calcul du nombre total de tokens générés sur la durée du projet
"""
total = duration * nb_inference_users * \
nb_inference_requests * nb_inference_tokens
if total > 1000000000:
total_str = str(round(total / 1000000000, 3)) + "G"
elif total > 1000000:
total_str = str(round(total / 1000000, 3)) + "M"
elif total > 1000:
total_str = str(round(total / 1000, 3)) + "k"
else:
total_str = str(total)
return gr.update(value=total_str)
project_duration.change(
handle_inference_total_tokens,
inputs=[project_duration, inference_users, inference_requests,
inference_tokens],
outputs=inference_total_tokens_str)
inference_users.change(
handle_inference_total_tokens,
inputs=[project_duration, inference_users, inference_requests,
inference_tokens],
outputs=inference_total_tokens_str)
inference_requests.change(
handle_inference_total_tokens,
inputs=[project_duration, inference_users, inference_requests,
inference_tokens],
outputs=inference_total_tokens_str)
inference_tokens.change(
handle_inference_total_tokens,
inputs=[project_duration, inference_users, inference_requests,
inference_tokens],
outputs=inference_total_tokens_str)
def handle_infra_type(infra_type_name):
"""
Gestion des champs en fonction du type d'infrastructure sélectionné
"""
if infra_type_name == "AI Cloud Service":
return gr.update(visible=False), gr.update(
visible=True), None, None, None, None, None
if infra_type_name == "Desktop":
return gr.update(visible=True), gr.update(visible=False), gr.update(
value=1.0, interactive=False), gr.update(value=8), gr.update(
value=1), gr.update(value=12), gr.update(value=32)
if infra_type_name == "Laptop":
return gr.update(visible=True), gr.update(visible=False), gr.update(
value=1.0, interactive=False), gr.update(value=8), gr.update(
value=0), gr.update(value=0), gr.update(value=16)
# infratype = "Server"
return gr.update(visible=True), gr.update(visible=False), gr.update(
value=1.5, interactive=True), gr.update(value=30), gr.update(
value=2), gr.update(value=32), gr.update(value=64)
infra_type.change(handle_infra_type, inputs=infra_type,
outputs=[infra_dedicated, infra_service, infra_pue_datacenter,
infra_cpu_cores, infra_gpu_count, infra_gpu_memory,
infra_memory])
def enable_launch_button(infra_type_value, mode_selected, selected_stages):
"""
Permettre d'appuyer sur le bouton uniquement quand les champs nécessaires
sont remplis
"""
if (infra_type_value != "AI Cloud Service" and
mode_selected == "Project's impact" and
"Inference" in selected_stages):
return gr.update(interactive=True)
return gr.update(interactive=False)
infra_type.change(enable_launch_button, inputs=[infra_type, mode, stages],
outputs=launch_btn)
mode.change(enable_launch_button, inputs=[infra_type, mode, stages],
outputs=launch_btn)
stages.change(enable_launch_button, inputs=[infra_type, mode, stages],
outputs=launch_btn)
gr.HTML("<hr>", padding=False)
gr.Markdown("### Energy efficiency")
with gr.Row() as energy_efficiency:
location_df = pd.read_csv(csv_path + "mixelecs.csv")
location = gr.Dropdown(label="Location", choices=list(dict.fromkeys(
location_df["location"].tolist())),
value="Germany")
# Onglet des résultats
with gr.Tab("📊 Results", id=1, visible=False, elem_classes="page") as results:
with gr.Row(elem_classes="duration"):
results_title = gr.Markdown("## 📊 Results for X years")
duration_slider = gr.Slider(
1, 5, value=3, step=1,
label='Choose the duration for which you want to visualize your impact',
elem_classes="slider")
gr.Markdown("### Environmental impact "
"<small>(for both stages use and embodied)</small>")
with gr.Row():
energy_consumption = gr.Text(label="⚡ Energy consumption", value="X Wh",
elem_classes="result")
carbon_footprint = gr.Text(label="🌫️ Carbon footprint", value="X gCO2eq",
elem_classes="result")
abiotic_resource_usage = gr.Text(label="⛏️ Abiotic resource use", value="X gSbeq",
elem_classes="result")
water_usage = gr.Text(
label="💧 Water usage *", value="X mL", elem_classes="result")
with gr.Row():
gr.Markdown("↕", elem_classes="equiv")
gr.Markdown("↕", elem_classes="equiv")
gr.Markdown("↕", elem_classes="equiv")
gr.Markdown("↕", elem_classes="equiv")
with gr.Row():
eq_energy_consumption = gr.Text(label="Energy consumption", value="X hours",
elem_classes="result")
eq_carbon_footprint = gr.Text(label="Carbon footprint", value="X",
elem_classes="result")
eq_abiotic_resources = gr.Text(label="Abiotic resources", value="X",
elem_classes="result")
eq_water_usage = gr.Text(
label="Water usage", value="X", elem_classes="result")
gr.Markdown(
"\\* the water usage is calculated only for the scope 3 because of the lack \
of open data about the water usage related to energy consumption",
elem_classes="asterisk")
gr.Markdown(
"### Visualize the proportion of use and embodied impacts")
with gr.Row():
carbon_footprint_chart = gr.Plot(
show_label=False, container=False)
abiotic_resource_chart = gr.Plot(
show_label=False, container=False)
water_usage_chart = gr.Plot(show_label=False, container=False)
gr.HTML("<hr>", padding=False)
gr.Markdown("## 🌳 How to do better?")
gr.Markdown("### Recommendations")
with gr.Column(elem_classes="grid-css"):
gr.Markdown("### Type", elem_classes="reco")
gr.Markdown("### Topic", elem_classes="reco")
gr.Markdown("### Example", elem_classes="reco")
gr.Markdown("### Expected reduction",
elem_classes="reco")
gr.Markdown("Quantified", elem_classes="reco")
gr.Markdown("⚡ Use the right quantization !",
elem_classes="reco")
gr.Markdown(
"""On llamacpp, using q4ks instead of no quantization can lead to a reduction \
of impact by""",
elem_classes="reco")
gr.Markdown("## 33%", elem_classes="reco")
gr.Markdown("Quantified", elem_classes="reco")
gr.Markdown("⚡ Use the right framework !", elem_classes="reco")
gr.Markdown(
"""Using the framework vllm instead of llamacpp for some model can lead
to a reduction of impact by""", elem_classes="reco")
gr.Markdown("## 18%", elem_classes="reco")
gr.Markdown("Quantified", elem_classes="reco")
gr.Markdown(
"⚡ Use the lightest possible model that meets your needs !",
elem_classes="reco")
gr.Markdown(
"""Using the model llama3-8b instead of 13b can lead to a reduction of impact\
by""",
elem_classes="reco")
gr.Markdown("## 30%", elem_classes="reco")
gr.Markdown("Quantified", elem_classes="reco")
gr.Markdown(
"""🌫️ Locate servers in a country where energy production has less impact""",
elem_classes="reco")
gr.Markdown(
"""Using a server located in Sweden instead of United-States can lead
to a reduction of impact by""", elem_classes="reco")
gr.Markdown("## 93%", elem_classes="reco")
gr.Markdown("Quantified", elem_classes="reco")
gr.Markdown(
"""🌫️⛏️💧 Use as few resources as possible
(i.e. the smallest possible machine/server) to suit the need""",
elem_classes="reco")
gr.Markdown(
"""Using a small gpu server instead of a big one can lead to a reduction of \
impact by""",
elem_classes="reco")
gr.Markdown("## 41%", elem_classes="reco")
gr.Markdown("Calculated", elem_classes="reco")
gr.Markdown(
"⚡ Use the most frugal configuration", elem_classes="reco")
more_frugal_conf = gr.Markdown(elem_classes="reco")
percentage_reduction = gr.Markdown(elem_classes="reco")
launch_btn.click(
fn=handle_launch,
inputs=[mode, project_duration, project_duration, model_details, parameters_count,
framework, quantization, stages, inference_users, inference_requests,
inference_tokens, finetuning_data_size, finetuning_epochs_number,
finetuning_batch_size, finetuning_peft, infra_type, infra_cpu_cores,
infra_gpu_count, infra_gpu_memory, infra_memory, infra_pue_datacenter,
infra_pue_machine, location],
outputs=[tabs, results, results_title, energy_consumption, carbon_footprint,
abiotic_resource_usage, water_usage, eq_energy_consumption,
eq_carbon_footprint, eq_abiotic_resources, eq_water_usage,
carbon_footprint_chart, abiotic_resource_chart, water_usage_chart,
more_frugal_conf, percentage_reduction, duration_slider])
duration_slider.change(
fn=handle_launch,
inputs=[mode, project_duration, duration_slider, model_details, parameters_count,
framework, quantization, stages, inference_users, inference_requests,
inference_tokens, finetuning_data_size, finetuning_epochs_number,
finetuning_batch_size, finetuning_peft, infra_type, infra_cpu_cores,
infra_gpu_count, infra_gpu_memory, infra_memory, infra_pue_datacenter,
infra_pue_machine, location],
outputs=[tabs, results, results_title, energy_consumption, carbon_footprint,
abiotic_resource_usage, water_usage, eq_energy_consumption,
eq_carbon_footprint, eq_abiotic_resources, eq_water_usage,
carbon_footprint_chart, abiotic_resource_chart, water_usage_chart,
more_frugal_conf, percentage_reduction, duration_slider])
# Onglet de la documentation
with gr.Tab("📗 Documentation", id=2) as documentation:
gr.Markdown(
load_doc(path.join(path.dirname(__file__), "../../assets/docs/doc.md")))