""" 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("""

EcoMindAI

Estimating the environmental impact of an language model project

""") 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("
", 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("
", 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( "
🏗️ Not implemented yet
") 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("
", 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 " "(for both stages use and embodied)") 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("
", 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")))