This blog series has several versions, each covering different aspects and techniques. Check out the following resources:
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow using a code-first approach. Available on:
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow in Azure AI Studio Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow in Azure AI / ML Studio using a low-code approach. Available on:
Evaluate Fine-tuned Phi-3 / Phi-3.5 Models in Azure AI Studio Focusing on Microsoft's Responsible AI Detailed instructions for evaluating the Phi-3 / Phi-3.5 model in Azure AI Studio using a low-code approach. Available on:
Phi-3 is a family of small language models (SLMs) developed by Microsoft that delivers exceptional performance and cost-effectiveness. In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models. This tutorial is divided into three series:
Series 1: Set up Azure resources and Prepare for fine-tuning
Create Azure Machine Learning workspace: Set up an Azure Machine Learning workspace, which serves as the hub for managing machine learning experiments and models.
Request GPU quotas: Request GPU quotas in your Azure subscription to ensure sufficient resources for model fine-tuning.
Add role assignment: Set up a User Assigned Managed Identity (UAI) and assign it necessary permissions (Contributor, Storage Blob Data Reader, AcrPull) to access resources like storage accounts and container registries.
Set up the project: Create a local environment, set up a virtual environment, install required packages, and create a script (download_dataset.py) to download the dataset (ULTRACHAT_200k) required for fine-tuning.
Series 2: Fine-tune and Deploy the Phi-3 model
Define fine-tuning process: Add code to thefine_tune.pyfile to define the fine-tuning process, including data loading, preprocessing, and training configurations.
Fine-tune the Phi-3 model: Add code to and run thesetup_ml.pyfile to set up the compute environment, define the fine-tuning job, and submit it to Azure Machine Learning.
Deploy the Fine-tuned model: Once fine-tuning is complete, Add code to thedeploy_model.pyfile to register the fine-tuned model in Azure Machine Learning, create an online endpoint, and deploy the model for real-time inference.
Series 3: Integrate the custom Phi-3 model with Prompt flow
Build Prompt flow: Add code to theflow.dag.ymlfile to build a flow.
Integrate with Prompt flow: Add code tointegrate_with_promptflowfile to integrate the custom Phi-3 model with Prompt flow.
Here is an overview of this tutorial.
Note
Microsoft has released the Phi-3.5 models, featuring enhanced multi-language support, improved vision capabilities, and advanced Intelligence Mixture of Experts (MOEs). Although this tutorial primarily focuses on Phi-3, you can apply the same steps to fine-tune and integrate the Phi-3.5 model for even better performance. A tip on how to modify the fine_tune.py script to switch to the Phi-3.5 model is included below at Fine-tune the Phi-3 model section.
For more detailed information and to explore additional resources about Phi-3 and Phi-3.5, please visit the Phi-3CookBook.
Series 1: Set Up Azure resources and prepare for fine-tuning
Create Azure Machine Learning workspace
Request GPU quotas in Azure subscription
Set up the project and install the libraries
Set up project files in Visual Studio Code
Prepare dataset for fine-tuning
Series 2: Fine-tune and Deploy the Phi-3 model
Fine-tune the Phi-3 model
Deploy the fine-tuned Phi-3 model
Series 3: Integrate the custom Phi-3 model with Prompt flow
Integrate the custom Phi-3 model with Prompt flow
Congratulation!
Series 1: Set up Azure resources and Prepare for fine-tuning
Create Azure Machine Learning Workspace
In this exercise, you will:
Create an Azure Machine Learning Workspace.
Create an Azure Machine Learning Workspace
Typeazure machine learningin thesearch barat the top of the portal page and selectAzure Machine Learningfrom the options that appear.
Select+ Createfrom the navigation menu.
SelectNew workspacefrom the navigation menu.
Perform the following tasks:
Select your AzureSubscription.
Select theResource groupto use (create a new one if needed).
EnterWorkspace Name. It must be a unique value.
Select theRegionyou'd like to use.
Select theStorage accountto use (create a new one if needed).
Select theKey vaultto use (create a new one if needed).
Select theApplication insightsto use (create a new one if needed).
Select theContainer registry to use (create a new one if needed).
Tip
When you create or use a Storage account in Azure Machine Learning, a container named "azureml" is automatically created within the Storage account. This container is used for storing model artifacts, training outputs, and other data generated during the machine learning process. In this tutorial, you will use the "azureml" container to manage and store all the necessary files and outputs related to our machine learning workflows.
SelectReview + Create.
SelectCreate.
Request GPU quotas in Azure Subscription
In this tutorial, you will learn how to fine-tune and deploy a Phi-3 model, using GPUs. For fine-tuning, you will use theStandard_NC24ads_A100_v4 GPU, which requires a quota request. For deployment, you will use theStandard_E4s_v3CPU, which does not require a quota request.
Note
Only Pay-As-You-Go subscriptions (the standard subscription type) are eligible for GPU allocation; benefit subscriptions are not currently supported.
For those using benefit subscriptions (such as Visual Studio Enterprise Subscription) or those looking to quickly test the fine-tuning and deployment process, this tutorial also provides guidance for fine-tuning with a minimal dataset using a CPU. However, it is important to note that fine-tuning results are significantly better when using a GPU with larger datasets.
Perform the following tasks to requestStandard NCADSA100v4 Family quota:
SelectQuotafrom the left side tab.
Select theVirtual machine familyto use. For example, selectStandard NCADSA100v4 Family Cluster Dedicated vCPUs, which includes theStandard_NC24ads_A100_v4GPU.
Select theRequest quotafrom the navigation menu.
Inside the Request quota page, enter theNew cores limityou'd like to use. For example, 24.
Inside the Request quota page, selectSubmitto request the GPU quota.
To fine-tune and deploy your models, you must first ceate a User Assigned Managed Identity (UAI) and assign it the appropriate permissions. This UAI will be used for authentication during deployment, so it is critical to grant it access to the storage accounts, container registry, and resource group.
In this exercise, you will:
Create User Assigned Managed Identity(UAI).
Add Contributor role assignment to Managed Identity.
Add Storage Blob Data Reader role assignment to Managed Identity.
Add AcrPull role assignment to Managed Identity.
Create User Assigned Managed Identity(UAI)
Typemanaged identitiesin thesearch barat the top of the portal page and selectManaged Identitiesfrom the options that appear.
Select+ Create.
Perform the following tasks to navigate to Add role assignment page:
Select your AzureSubscription.
Select theResource groupto use (create a new one if needed).
Select theRegionyou'd like to use.
Enter theName. It must be a unique value.
SelectReview + create.
Select+ Create.
Add Contributor role assignment to Managed Identity
Navigate to the Managed Identity resource that you created.
SelectAzure role assignmentsfrom the left side tab.
Select+Add role assignmentfrom the navigation menu.
Inside Add role assignment page, Perform the following tasks:
Select theScopetoResource group.
Select your AzureSubscription.
Select theResource groupto use.
Select theRoletoContributor.
SelectSave.
Add Storage Blob Data Reader role assignment to Managed Identity
Typeazure storage accountsin thesearch barat the top of the portal page and selectStorage accountsfrom the options that appear.
Select the storage account that associated with the Azure Machine Learning workspace. For example,finetunephistorage.
Perform the following tasks to navigate to Add role assignment page:
Navigate to the Azure Storage account that you created.
SelectAccess Control (IAM)from the left side tab.
Select+ Addfrom the navigation menu.
SelectAdd role assignmentfrom the navigation menu.
Inside Add role assignment page, Perform the following tasks:
Inside the Role page, typeStorage Blob Data Readerin thesearch barand selectStorage Blob Data Readerfrom the options that appear.
Inside the Role page, selectNext.
Inside the Members page, selectAssign access toManaged identity.
Inside the Members page, select+ Select members.
Inside Select managed identities page, select your AzureSubscription.
In this exercise, you will create the essential files for our project. These files include scripts for downloading the dataset, setting up the Azure Machine Learning environment, fine-tuning the Phi-3 model, and deploying the fine-tuned model. You will also create aconda.ymlfile to set up the fine-tuning environment.
In this exercise, you will:
Create adownload_dataset.pyfile to download the dataset.
Create asetup_ml.pyfile to set up the Azure Machine Learning environment.
Create afine_tune.pyfile in thefinetuning_dirfolder to fine-tune the Phi-3 model using the dataset.
Create aconda.ymlfile to setup fine-tuning environment.
Create adeploy_model.pyfile to deploy the fine-tuned model.
Create aintegrate_with_promptflow.pyfile, to integrate the fine-tuned model and execute the model using Prompt flow.
Create a flow.dag.yml file, to set up the workflow structure for Prompt flow.
Perform the following tasks to add the Azure Subscription ID:
Typesubscriptionsin thesearch barat the top of the portal page and selectSubscriptionsfrom the options that appear.
Select the Azure Subscription you are currently using.
Copy and paste your Subscription ID into theconfig.pyfile.
Perform the following tasks to add the Azure Workspace Name:
Navigate to the Azure Machine Learning resource that you created.
Copy and paste your account name into theconfig.pyfile.
Perform the following tasks to add the Azure Resource Group Name:
Navigate to the Azure Machine Learning resource that you created.
Copy and paste your Azure Resource Group Name into theconfig.pyfile.
Perform the following tasks to add the Azure Managed Identity name
Navigate to the Managed Identities resource that you created.
Copy and paste your Azure Managed Identity name into theconfig.pyfile.
Prepare Dataset for Fine-tuning
In this exercise, you will run thedownload_dataset.pyfile to download theultrachat_200kdatasets to your local environment. You will then use this datasets to fine-tune the Phi-3 model in Azure Machine Learning.
In this exercise, you will:
Add code to thedownload_dataset.pyfile to download the datasets.
Run thedownload_dataset.pyfile to download datasets to your local environment.
Download your dataset usingdownload_dataset.py
Open thedownload_dataset.pyfile in Visual Studio Code.
Add the following code intodownload_dataset.py.
import json
import os
from datasets import load_dataset
from config import (
TRAIN_DATA_PATH,
TEST_DATA_PATH)
def load_and_split_dataset(dataset_name, config_name, split_ratio):
"""
Load and split a dataset.
"""
# Load the dataset with the specified name, configuration, and split ratio
dataset = load_dataset(dataset_name, config_name, split=split_ratio)
print(f"Original dataset size: {len(dataset)}")
# Split the dataset into train and test sets (80% train, 20% test)
split_dataset = dataset.train_test_split(test_size=0.2)
print(f"Train dataset size: {len(split_dataset['train'])}")
print(f"Test dataset size: {len(split_dataset['test'])}")
return split_dataset
def save_dataset_to_jsonl(dataset, filepath):
"""
Save a dataset to a JSONL file.
"""
# Create the directory if it does not exist
os.makedirs(os.path.dirname(filepath), exist_ok=True)
# Open the file in write mode
with open(filepath, 'w', encoding='utf-8') as f:
# Iterate over each record in the dataset
for record in dataset:
# Dump the record as a JSON object and write it to the file
json.dump(record, f)
# Write a newline character to separate records
f.write('\n')
print(f"Dataset saved to {filepath}")
def main():
"""
Main function to load, split, and save the dataset.
"""
# Load and split the ULTRACHAT_200k dataset with a specific configuration and split ratio
dataset = load_and_split_dataset("HuggingFaceH4/ultrachat_200k", 'default', 'train_sft[:1%]')
# Extract the train and test datasets from the split
train_dataset = dataset['train']
test_dataset = dataset['test']
# Save the train dataset to a JSONL file
save_dataset_to_jsonl(train_dataset, TRAIN_DATA_PATH)
# Save the test dataset to a separate JSONL file
save_dataset_to_jsonl(test_dataset, TEST_DATA_PATH)
if __name__ == "__main__":
main()
Tip
Guidance for fine-tuning with a minimal dataset using a CPU
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
Type the following command inside your terminal to run the script and download the dataset to your local environment.
python download_dataset.py
Verify that the datasets were saved successfully to your localfinetune-phi/datadirectory.
Note
Note on dataset size and fine-tuning time
In this tutorial, you use only 1% of the dataset (train_sft[:1%]). This significantly reduces the amount of data, speeding up both the upload and fine-tuning processes. You can adjust the percentage to find the right balance between training time and model performance. Using a smaller subset of the dataset reduces the time required for fine-tuning, making the process more manageable for a tutorial.
Series 2: Fine-tune and Deploy the Phi-3 model
Fine-tune the Phi-3 model
In this exercise, you will fine-tune the Phi-3 model using the provided dataset. First, you will define the fine-tuning process in thefine_tune.pyfile. Then, you will configure the Azure Machine Learning environment and initiate the fine-tuning process by running thesetup_ml.pyfile. This script ensures that the fine-tuning occurs within the Azure Machine Learning environment.
By runningsetup_ml.py, you will run the fine-tuning process in the Azure Machine Learning environment.
In this exercise, you will:
Set up Azure CLI to authenticate environment
Add code to thefine_tune.pyfile to fine-tune the model.
Add code to and run thesetup_ml.pyfile to initiate the fine-tuning process in Azure Machine Learning.
Run thesetup_ml.pyfile to fine-tune the Phi-3 model using Azure Machine Learning.
Set up Azure CLI
You need to set up Azure CLI to authenticate your environment. Azure CLI allows you to manage Azure resources directly from the command line and provides the credentials necessary for Azure Machine Learning to access these resources. To get started installAzure CLI
Open a terminal window and type the following command to log in to your Azure account.
az login
Select your Azure account to use.
Select your Azure subscription to use.
Tip
Having trouble signing in to Azure? Try using a device code
Open a terminal window and type the following command to log in to your Azure account.
az login --use-device-code
Visit the website displayed in the terminal window and enter the provided code on that site.
Inside the website, selectNext.
Inside the website, select the account to use in this tutorial
Inside the website, selectcontinueto complete login.
After successful login, go back to your terminal and select your Azure subscription to use.
Add code to thefine_tune.pyfile
Navigate to thefinetuning_dirfolder and Open thefine_tune.pyfile in Visual Studio Code.
Add the following code intofine_tune.py.
import argparse
import sys
import logging
import os
from datasets import load_dataset
import torch
import mlflow
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from trl import SFTTrainer
# To avoid the INVALID_PARAMETER_VALUE error in MLflow, disable MLflow integration
os.environ["DISABLE_MLFLOW_INTEGRATION"] = "True"
# Logging setup
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[logging.StreamHandler(sys.stdout)],
level=logging.WARNING
)
logger = logging.getLogger(__name__)
def initialize_model_and_tokenizer(model_name, model_kwargs):
"""
Initialize the model and tokenizer with the given pretrained model name and arguments.
"""
model = AutoModelForCausalLM.from_pretrained(model_name, **model_kwargs)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.model_max_length = 2048
tokenizer.pad_token = tokenizer.unk_token
tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
tokenizer.padding_side = 'right'
return model, tokenizer
def apply_chat_template(example, tokenizer):
"""
Apply a chat template to tokenize messages in the example.
"""
messages = example["messages"]
if messages[0]["role"] != "system":
messages.insert(0, {"role": "system", "content": ""})
example["text"] = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=False
)
return example
def load_and_preprocess_data(train_filepath, test_filepath, tokenizer):
"""
Load and preprocess the dataset.
"""
train_dataset = load_dataset('json', data_files=train_filepath, split='train')
test_dataset = load_dataset('json', data_files=test_filepath, split='train')
column_names = list(train_dataset.features)
train_dataset = train_dataset.map(
apply_chat_template,
fn_kwargs={"tokenizer": tokenizer},
num_proc=10,
remove_columns=column_names,
desc="Applying chat template to train dataset",
)
test_dataset = test_dataset.map(
apply_chat_template,
fn_kwargs={"tokenizer": tokenizer},
num_proc=10,
remove_columns=column_names,
desc="Applying chat template to test dataset",
)
return train_dataset, test_dataset
def train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, output_dir):
"""
Train and evaluate the model.
"""
training_args = TrainingArguments(
bf16=True,
do_eval=True,
output_dir=output_dir,
eval_strategy="epoch",
learning_rate=5.0e-06,
logging_steps=20,
lr_scheduler_type="cosine",
num_train_epochs=3,
overwrite_output_dir=True,
per_device_eval_batch_size=4,
per_device_train_batch_size=4,
remove_unused_columns=True,
save_steps=500,
seed=0,
gradient_checkpointing=True,
gradient_accumulation_steps=1,
warmup_ratio=0.2,
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=test_dataset,
max_seq_length=2048,
dataset_text_field="text",
tokenizer=tokenizer,
packing=True
)
train_result = trainer.train()
trainer.log_metrics("train", train_result.metrics)
mlflow.transformers.log_model(
transformers_model={"model": trainer.model, "tokenizer": tokenizer},
artifact_path=output_dir,
)
tokenizer.padding_side = 'left'
eval_metrics = trainer.evaluate()
eval_metrics["eval_samples"] = len(test_dataset)
trainer.log_metrics("eval", eval_metrics)
def main(train_file, eval_file, model_output_dir):
"""
Main function to fine-tune the model.
"""
model_kwargs = {
"use_cache": False,
"trust_remote_code": True,
"torch_dtype": torch.bfloat16,
"device_map": None,
"attn_implementation": "eager"
}
pretrained_model_name = "microsoft/Phi-3.5-mini-instruct"
# pretrained_model_name = "microsoft/Phi-3-mini-4k-instruct"
with mlflow.start_run():
model, tokenizer = initialize_model_and_tokenizer(pretrained_model_name, model_kwargs)
train_dataset, test_dataset = load_and_preprocess_data(train_file, eval_file, tokenizer)
train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, model_output_dir)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--train-file", type=str, required=True, help="Path to the training data")
parser.add_argument("--eval-file", type=str, required=True, help="Path to the evaluation data")
parser.add_argument("--model_output_dir", type=str, required=True, help="Directory to save the fine-tuned model")
args = parser.parse_args()
main(args.train_file, args.eval_file, args.model_output_dir)
Save and close thefine_tune.pyfile.
Tip
You can fine-tune Phi-3.5 model
In fine_tune.py file, you can change the pretrained_model_name from "microsoft/Phi-3-mini-4k-instruct" to any model you want to fine-tune. For example, if you change it to "microsoft/Phi-3.5-mini-instruct", you'll be using the Phi-3.5-mini-instruct model for fine-tuning. To find and use the model name you prefer, visit Hugging Face, search for the model you're interested in, and then copy and paste its name into the pretrained_model_name field in your script.
Add code to thesetup_ml.pyfile
Open thesetup_ml.pyfile in Visual Studio Code.
Add the following code intosetup_ml.py.
import logging
from azure.ai.ml import MLClient, command, Input
from azure.ai.ml.entities import Environment, AmlCompute
from azure.identity import AzureCliCredential
from config import (
AZURE_SUBSCRIPTION_ID,
AZURE_RESOURCE_GROUP_NAME,
AZURE_ML_WORKSPACE_NAME,
TRAIN_DATA_PATH,
TEST_DATA_PATH
)
# Constants
# Uncomment the following lines to use a CPU instance for training
# COMPUTE_INSTANCE_TYPE = "Standard_E16s_v3" # cpu
# COMPUTE_NAME = "cpu-e16s-v3"
# DOCKER_IMAGE_NAME = "mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest"
# Uncomment the following lines to use a GPU instance for training
COMPUTE_INSTANCE_TYPE = "Standard_NC24ads_A100_v4"
COMPUTE_NAME = "gpu-nc24s-a100-v4"
DOCKER_IMAGE_NAME = "mcr.microsoft.com/azureml/curated/acft-hf-nlp-gpu:59"
CONDA_FILE = "conda.yml"
LOCATION = "eastus2" # Replace with the location of your compute cluster
FINETUNING_DIR = "./finetuning_dir" # Path to the fine-tuning script
TRAINING_ENV_NAME = "phi-3-training-environment" # Name of the training environment
MODEL_OUTPUT_DIR = "./model_output" # Path to the model output directory in azure ml
# Logging setup to track the process
logger = logging.getLogger(__name__)
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
level=logging.WARNING
)
def get_ml_client():
"""
Initialize the ML Client using Azure CLI credentials.
"""
credential = AzureCliCredential()
return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)
def create_or_get_environment(ml_client):
"""
Create or update the training environment in Azure ML.
"""
env = Environment(
image=DOCKER_IMAGE_NAME, # Docker image for the environment
conda_file=CONDA_FILE, # Conda environment file
name=TRAINING_ENV_NAME, # Name of the environment
)
return ml_client.environments.create_or_update(env)
def create_or_get_compute_cluster(ml_client, compute_name, COMPUTE_INSTANCE_TYPE, location):
"""
Create or update the compute cluster in Azure ML.
"""
try:
compute_cluster = ml_client.compute.get(compute_name)
logger.info(f"Compute cluster '{compute_name}' already exists. Reusing it for the current run.")
except Exception:
logger.info(f"Compute cluster '{compute_name}' does not exist. Creating a new one with size {COMPUTE_INSTANCE_TYPE}.")
compute_cluster = AmlCompute(
name=compute_name,
size=COMPUTE_INSTANCE_TYPE,
location=location,
tier="Dedicated", # Tier of the compute cluster
min_instances=0, # Minimum number of instances
max_instances=1 # Maximum number of instances
)
ml_client.compute.begin_create_or_update(compute_cluster).wait() # Wait for the cluster to be created
return compute_cluster
def create_fine_tuning_job(env, compute_name):
"""
Set up the fine-tuning job in Azure ML.
"""
return command(
code=FINETUNING_DIR, # Path to fine_tune.py
command=(
"python fine_tune.py "
"--train-file ${{inputs.train_file}} "
"--eval-file ${{inputs.eval_file}} "
"--model_output_dir ${{inputs.model_output}}"
),
environment=env, # Training environment
compute=compute_name, # Compute cluster to use
inputs={
"train_file": Input(type="uri_file", path=TRAIN_DATA_PATH), # Path to the training data file
"eval_file": Input(type="uri_file", path=TEST_DATA_PATH), # Path to the evaluation data file
"model_output": MODEL_OUTPUT_DIR
}
)
def main():
"""
Main function to set up and run the fine-tuning job in Azure ML.
"""
# Initialize ML Client
ml_client = get_ml_client()
# Create Environment
env = create_or_get_environment(ml_client)
# Create or get existing compute cluster
create_or_get_compute_cluster(ml_client, COMPUTE_NAME, COMPUTE_INSTANCE_TYPE, LOCATION)
# Create and Submit Fine-Tuning Job
job = create_fine_tuning_job(env, COMPUTE_NAME)
returned_job = ml_client.jobs.create_or_update(job) # Submit the job
ml_client.jobs.stream(returned_job.name) # Stream the job logs
# Capture the job name
job_name = returned_job.name
print(f"Job name: {job_name}")
if __name__ == "__main__":
main()
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andLOCATIONwith your specific details.
# Uncomment the following lines to use a GPU instance for training
COMPUTE_INSTANCE_TYPE = "Standard_NC24ads_A100_v4"
COMPUTE_NAME = "gpu-nc24s-a100-v4"
...
LOCATION = "eastus2"# Replace with the location of your compute cluster
Tip
Guidance for fine-tuning with a minimal dataset using a CPU
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
Open thesetup_mlfile.
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andDOCKER_IMAGE_NAMEwith the following. If you do not have access toStandard_E16s_v3, you can use an equivalent CPU instance or request a new quota.
Replace LOCATIONwith your specific details.
# Uncomment the following lines to use a CPU instance for training
COMPUTE_INSTANCE_TYPE = "Standard_E16s_v3"# cpu
COMPUTE_NAME = "cpu-e16s-v3"
DOCKER_IMAGE_NAME = "mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest"
LOCATION = "eastus2"# Replace with the location of your compute cluster
Type the following command to run thesetup_ml.pyscript and start the fine-tuning process in Azure Machine Learning.
python setup_ml.py
In this exercise, you successfully fine-tuned the Phi-3 model using Azure Machine Learning. By running thesetup_ml.pyscript, you have set up the Azure Machine Learning environment and initiated the fine-tuning process defined infine_tune.pyfile. Please note that the fine-tuning process can take a considerable amount of time. After running thepython setup_ml.pycommand, you need to wait for the process to complete. You can monitor the status of the fine-tuning job by following the link provided in the terminal to the Azure Machine Learning portal. In the next series, you will deploy the fine-tuned model and integrate it with Prompt flow.
Deploy the fine-tuned model
To integrate the fine-tuned Phi-3 model with Prompt Flow, you need to deploy the model to make it accessible for real-time inference. This process involves registering the model, creating an online endpoint, and deploying the model.
In this exercise, you will:
Set the model name, endpoint name, and deployment name for deployment.
Register the fine-tuned model in the Azure Machine Learning workspace.
Create an online endpoint.
Deploy the registered fine-tuned Phi-3 model.
Set the model name, endpoint name, and deployment name for deployment
Openconfig.pyfile.
ReplaceAZURE_MODEL_NAME = "your_fine_tuned_model_name"with the desired name for your model.
ReplaceAZURE_ENDPOINT_NAME = "your_fine_tuned_model_endpoint_name"with the desired name for your endpoint.
ReplaceAZURE_DEPLOYMENT_NAME = "your_fine_tuned_model_deployment_name"with the desired name for your deployment.
Deploy the fine-tuned model
Running thedeploy_model.pyfile automates the entire deployment process. It registers the model, creates an endpoint, and executes the deployment based on the settings specified in the config.py file, which includes the model name, endpoint name, and deployment name.
Open thedeploy_model.pyfile in Visual Studio Code.
Add the following code intodeploy_model.py.
import logging
from azure.identity import AzureCliCredential
from azure.ai.ml import MLClient
from azure.ai.ml.entities import Model, ProbeSettings, ManagedOnlineEndpoint, ManagedOnlineDeployment, IdentityConfiguration, ManagedIdentityConfiguration, OnlineRequestSettings
from azure.ai.ml.constants import AssetTypes
# Configuration imports
from config import (
AZURE_SUBSCRIPTION_ID,
AZURE_RESOURCE_GROUP_NAME,
AZURE_ML_WORKSPACE_NAME,
AZURE_MANAGED_IDENTITY_RESOURCE_ID,
AZURE_MANAGED_IDENTITY_CLIENT_ID,
AZURE_MODEL_NAME,
AZURE_ENDPOINT_NAME,
AZURE_DEPLOYMENT_NAME
)
# Constants
JOB_NAME = "your-job-name"
COMPUTE_INSTANCE_TYPE = "Standard_E4s_v3"
deployment_env_vars = {
"SUBSCRIPTION_ID": AZURE_SUBSCRIPTION_ID,
"RESOURCE_GROUP_NAME": AZURE_RESOURCE_GROUP_NAME,
"UAI_CLIENT_ID": AZURE_MANAGED_IDENTITY_CLIENT_ID,
}
# Logging setup
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
level=logging.DEBUG
)
logger = logging.getLogger(__name__)
def get_ml_client():
"""Initialize and return the ML Client."""
credential = AzureCliCredential()
return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)
def register_model(ml_client, model_name, job_name):
"""Register a new model."""
model_path = f"azureml://jobs/{job_name}/outputs/artifacts/paths/model_output"
logger.info(f"Registering model {model_name} from job {job_name} at path {model_path}.")
run_model = Model(
path=model_path,
name=model_name,
description="Model created from run.",
type=AssetTypes.MLFLOW_MODEL,
)
model = ml_client.models.create_or_update(run_model)
logger.info(f"Registered model ID: {model.id}")
return model
def delete_existing_endpoint(ml_client, endpoint_name):
"""Delete existing endpoint if it exists."""
try:
endpoint_result = ml_client.online_endpoints.get(name=endpoint_name)
logger.info(f"Deleting existing endpoint {endpoint_name}.")
ml_client.online_endpoints.begin_delete(name=endpoint_name).result()
logger.info(f"Deleted existing endpoint {endpoint_name}.")
except Exception as e:
logger.info(f"No existing endpoint {endpoint_name} found to delete: {e}")
def create_or_update_endpoint(ml_client, endpoint_name, description=""):
"""Create or update an endpoint."""
delete_existing_endpoint(ml_client, endpoint_name)
logger.info(f"Creating new endpoint {endpoint_name}.")
endpoint = ManagedOnlineEndpoint(
name=endpoint_name,
description=description,
identity=IdentityConfiguration(
type="user_assigned",
user_assigned_identities=[ManagedIdentityConfiguration(resource_id=AZURE_MANAGED_IDENTITY_RESOURCE_ID)]
)
)
endpoint_result = ml_client.online_endpoints.begin_create_or_update(endpoint).result()
logger.info(f"Created new endpoint {endpoint_name}.")
return endpoint_result
def create_or_update_deployment(ml_client, endpoint_name, deployment_name, model):
"""Create or update a deployment."""
logger.info(f"Creating deployment {deployment_name} for endpoint {endpoint_name}.")
deployment = ManagedOnlineDeployment(
name=deployment_name,
endpoint_name=endpoint_name,
model=model.id,
instance_type=COMPUTE_INSTANCE_TYPE,
instance_count=1,
environment_variables=deployment_env_vars,
request_settings=OnlineRequestSettings(
max_concurrent_requests_per_instance=3,
request_timeout_ms=180000,
max_queue_wait_ms=120000
),
liveness_probe=ProbeSettings(
failure_threshold=30,
success_threshold=1,
period=100,
initial_delay=500,
),
readiness_probe=ProbeSettings(
failure_threshold=30,
success_threshold=1,
period=100,
initial_delay=500,
),
)
deployment_result = ml_client.online_deployments.begin_create_or_update(deployment).result()
logger.info(f"Created deployment {deployment.name} for endpoint {endpoint_name}.")
return deployment_result
def set_traffic_to_deployment(ml_client, endpoint_name, deployment_name):
"""Set traffic to the specified deployment."""
try:
# Fetch the current endpoint details
endpoint = ml_client.online_endpoints.get(name=endpoint_name)
# Log the current traffic allocation for debugging
logger.info(f"Current traffic allocation: {endpoint.traffic}")
# Set the traffic allocation for the deployment
endpoint.traffic = {deployment_name: 100}
# Update the endpoint with the new traffic allocation
endpoint_poller = ml_client.online_endpoints.begin_create_or_update(endpoint)
updated_endpoint = endpoint_poller.result()
# Log the updated traffic allocation for debugging
logger.info(f"Updated traffic allocation: {updated_endpoint.traffic}")
logger.info(f"Set traffic to deployment {deployment_name} at endpoint {endpoint_name}.")
return updated_endpoint
except Exception as e:
# Log any errors that occur during the process
logger.error(f"Failed to set traffic to deployment: {e}")
raise
def main():
ml_client = get_ml_client()
registered_model = register_model(ml_client, AZURE_MODEL_NAME, JOB_NAME)
logger.info(f"Registered model ID: {registered_model.id}")
endpoint = create_or_update_endpoint(ml_client, AZURE_ENDPOINT_NAME, "Endpoint for finetuned Phi-3 model")
logger.info(f"Endpoint {AZURE_ENDPOINT_NAME} is ready.")
try:
deployment = create_or_update_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME, registered_model)
logger.info(f"Deployment {AZURE_DEPLOYMENT_NAME} is created for endpoint {AZURE_ENDPOINT_NAME}.")
set_traffic_to_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME)
logger.info(f"Traffic is set to deployment {AZURE_DEPLOYMENT_NAME} at endpoint {AZURE_ENDPOINT_NAME}.")
except Exception as e:
logger.error(f"Failed to create or update deployment: {e}")
if __name__ == "__main__":
main()
Perform the following tasks to get theJOB_NAME:
Navigate to Azure Machine Learning resource that you created.
SelectStudio web URLto open the Azure Machine Learning workspace.
SelectJobsfrom the left side tab.
Select the experiment for fine-tuning. For example,finetunephi.
Select the job that you created.
Copy and paste your job Name into theJOB_NAME = "your-job-name"indeploy_model.pyfile.
ReplaceCOMPUTE_INSTANCE_TYPEwith your specific details.
Type the following command to run thedeploy_model.pyscript and start the deployment process in Azure Machine Learning.
python deploy_model.py
Warning
To avoid additional charges to your account, make sure to delete the created endpoint in the Azure Machine Learning workspace.
Check deployment status in Azure Machine Learning Workspace
Navigate to Azure Machine Learning workspace that you created.
SelectStudio web URLto open the Azure Machine Learning workspace.
Select Endpoints from the left side tab.
Select endpoint that you created.
On this page, you can manage the endpoints created during the deployment process.
Series 3: Integrate the custom Phi-3 model with Prompt flow
Integrate the custom Phi-3 model with Prompt Flow
After successfully deploying your fine-tuned model, you can now integrate it with Prompt Flow to use your model in real-time applications, enabling a variety of interactive tasks with your custom Phi-3 model.
In this exercise, you will:
Set api key and endpoint uri of the fine-tuned Phi-3 model.
Add code to theflow.dag.ymlfile.
Add code to theintegrate_with_promptflow.pyfile.
Test your custom Phi-3 model on Prompt flow.
Set api key and endpoint uri of the fine-tuned Phi-3 model
Navigate to the Azure Machine learning workspace that you created.
Here's an example of the results: Now you can chat with your custom Phi-3 model. It is recommended to ask questions based on the data used for fine-tuning.
Congratulations!
You've completed this tutorial
Congratulations! You have successfully completed the tutorial on fine-tuning and integrating custom Phi-3 models with Prompt flow. This tutorial introduced the simplest method of fine-tuning, avoiding additional techniques such as LoRA or QLoRA, and using MLflow to streamline the fine-tuning and deployment process. Advanced techniques and detailed explanations will be covered in the next series.
Clean Up Azure Resources
Cleanup your Azure resources to avoid additional charges to your account. Go to the Azure portal and delete the following resources:
The Azure Machine Learning resource.
The Azure Machine Learning model endpoint.
Source Code for the Tutorial
You can find the complete source code for this tutorial in the following repository:
Update (July 25, 2024): Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide
I've updated the tutorial to use theULTRACHAT_200Kdataset and fixed some issues.
Updates:
Using ULTRACHAT_200K Dataset: Updated to utilize theULTRACHAT_200Kdataset for fine-tuning.
Resolved Package Version Issues: Fixed package version issues in the fine-tuning environment.
GPU Optimization: Modified to use theStandard_NC24ads_A100_v4GPU for enhanced fine-tuning performance.
Confirmation of Changes:
As of July 24, 2024, these changes have been verified to ensure that fine-tuning, deployment, and integration with Prompt flow are functioning correctly in the updated GPU environment.
"}},"componentScriptGroups({\"componentId\":\"custom.widget.MicrosoftFooter\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/QueryHandler\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageCoverImage\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageCoverImage-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeTitle\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeTitle-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTimeToRead\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTimeToRead-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserRank\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserRank-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageCustomFields\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageCustomFields-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRevision\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRevision-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageReplyButton\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageReplyButton-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageAuthorBio\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/ranks/UserRankLabel\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserRegistrationDate\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserRegistrationDate-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeAvatar-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeDescription\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeDescription-1745160788452"}],"message({\"id\":\"message:4200663\"})":{"__ref":"BlogReplyMessage:message:4200663"},"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"components/tags/TagView/TagViewChip\"]})":[{"__ref":"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1745160788452"}],"cachedText({\"lastModified\":\"1745160788452\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745160788452"}]},"CachedAsset:pages-1744410071420":{"__typename":"CachedAsset","id":"pages-1744410071420","value":[{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"UserBlogPermissions.Page","type":"COMMUNITY","urlPath":"/c/user-blog-permissions/page","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllEvents","type":"CUSTOM","urlPath":"/Events","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"CommunityHub.Page","type":"CUSTOM","urlPath":"/Directory","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1730819800000,"localOverride":null,"page":{"id":"AllBlogs.Page","type":"CUSTOM","urlPath":"/blogs","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1744410071420,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Deleted","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"MMM dd yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":"en","possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"Category:category:EducationSector":{"__typename":"Category","id":"category:EducationSector","entityType":"CATEGORY","displayId":"EducationSector","nodeType":"category","depth":3,"title":"Education Sector","shortTitle":"Education Sector","parent":{"__ref":"Category:category:solutions"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top","entityType":"CATEGORY","shortTitle":"Top"},"Category:category:communities":{"__typename":"Category","id":"category:communities","displayId":"communities","nodeType":"category","depth":1,"parent":{"__ref":"Category:category:top"},"title":"Communities","entityType":"CATEGORY","shortTitle":"Communities"},"Category:category:solutions":{"__typename":"Category","id":"category:solutions","displayId":"solutions","nodeType":"category","depth":2,"parent":{"__ref":"Category:category:communities"},"title":"Topics","entityType":"CATEGORY","shortTitle":"Topics"},"Blog:board:EducatorDeveloperBlog":{"__typename":"Blog","id":"board:EducatorDeveloperBlog","entityType":"BLOG","displayId":"EducatorDeveloperBlog","nodeType":"board","depth":4,"conversationStyle":"BLOG","title":"Educator Developer Blog","description":"","avatar":null,"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:EducationSector"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:gxcuf89792"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:communities"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:solutions"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:EducationSector"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"boardPolicies":{"__typename":"BoardPolicies","canPublishArticleOnCreate":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","args":[]}}},"shortTitle":"Educator Developer Blog","repliesProperties":{"__typename":"RepliesProperties","sortOrder":"REVERSE_PUBLISH_TIME","repliesFormat":"threaded"},"eventPath":"category:EducationSector/category:solutions/category:communities/community:gxcuf89792board:EducatorDeveloperBlog/","tagProperties":{"__typename":"TagNodeProperties","tagsEnabled":{"__typename":"PolicyResult","failureReason":null}},"requireTags":false,"tagType":"FREEFORM_ONLY"},"Rank:rank:35":{"__typename":"Rank","id":"rank:35","position":16,"name":"Iron Contributor","color":"333333","icon":null,"rankStyle":"TEXT"},"User:user:2076234":{"__typename":"User","id":"user:2076234","uid":2076234,"login":"Minseok_Song","deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/dS0yMDc2MjM0LTUyMTI2MmlDRjAzQ0Q1OUIwNDRFOTJB"},"rank":{"__ref":"Rank:rank:35"},"email":"","messagesCount":28,"biography":null,"topicsCount":8,"kudosReceivedCount":17,"kudosGivenCount":65,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":null,"registrationTime":"2023-10-11T02:25:07.343-07:00","confirmEmailStatus":null},"followersCount":null,"solutionsCount":1,"entityType":"USER","eventPath":"community:gxcuf89792/user:2076234"},"BlogTopicMessage:message:4178612":{"__typename":"BlogTopicMessage","uid":4178612,"subject":"Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide","id":"message:4178612","revisionNum":73,"repliesCount":1,"author":{"__ref":"User:user:2076234"},"depth":0,"hasGivenKudo":false,"board":{"__ref":"Blog:board:EducatorDeveloperBlog"},"conversation":{"__ref":"Conversation:conversation:4178612"},"messagePolicies":{"__typename":"MessagePolicies","canPublishArticleOnEdit":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","args":[]}},"canModerateSpamMessage":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","key":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","args":[]}}},"contentWorkflow":{"__typename":"ContentWorkflow","state":"PUBLISH","scheduledPublishTime":null,"scheduledTimezone":null,"userContext":{"__typename":"MessageWorkflowContext","canSubmitForReview":null,"canEdit":false,"canRecall":null,"canSubmitForPublication":null,"canReturnToAuthor":null,"canPublish":null,"canReturnToReview":null,"canSchedule":false},"shortScheduledTimezone":null},"readOnly":false,"editFrozen":false,"moderationData":{"__ref":"ModerationData:moderation_data:4178612"},"teaser":"
\n
In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt Flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models.
\n
","body":"
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide
This blog series has several versions, each covering different aspects and techniques. Check out the following resources:
\n
\n
\n
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow using a code-first approach. Available on:\n
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow in Azure AI Studio Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow in Azure AI / ML Studio using a low-code approach. Available on:\n
Evaluate Fine-tuned Phi-3 / Phi-3.5 Models in Azure AI Studio Focusing on Microsoft's Responsible AI Detailed instructions for evaluating the Phi-3 / Phi-3.5 model in Azure AI Studio using a low-code approach. Available on:\n
Phi-3 is a family of small language models (SLMs) developed by Microsoft that delivers exceptional performance and cost-effectiveness. In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models. This tutorial is divided into three series:
\n
\n
Series 1: Set up Azure resources and Prepare for fine-tuning
\n\n
\n
Create Azure Machine Learning workspace: Set up an Azure Machine Learning workspace, which serves as the hub for managing machine learning experiments and models.
\n
\n
\n
Request GPU quotas: Request GPU quotas in your Azure subscription to ensure sufficient resources for model fine-tuning.
\n
\n
\n
Add role assignment: Set up a User Assigned Managed Identity (UAI) and assign it necessary permissions (Contributor, Storage Blob Data Reader, AcrPull) to access resources like storage accounts and container registries.
\n
\n
\n
Set up the project: Create a local environment, set up a virtual environment, install required packages, and create a script (download_dataset.py) to download the dataset (ULTRACHAT_200k) required for fine-tuning.
\n
\n\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n\n
\n
Define fine-tuning process: Add code to thefine_tune.pyfile to define the fine-tuning process, including data loading, preprocessing, and training configurations.
\n
\n
\n
Fine-tune the Phi-3 model: Add code to and run thesetup_ml.pyfile to set up the compute environment, define the fine-tuning job, and submit it to Azure Machine Learning.
\n
\n
\n
Deploy the Fine-tuned model: Once fine-tuning is complete, Add code to thedeploy_model.pyfile to register the fine-tuned model in Azure Machine Learning, create an online endpoint, and deploy the model for real-time inference.
\n
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
\n\n
\n
Build Prompt flow: Add code to theflow.dag.ymlfile to build a flow.
\n
\n
\n
Integrate with Prompt flow: Add code tointegrate_with_promptflowfile to integrate the custom Phi-3 model with Prompt flow.
\n
\n\n
\n
Here is an overview of this tutorial.
\n
\n
\n
\n
\n
\n
Note\n
Microsoft has released the Phi-3.5 models, featuring enhanced multi-language support, improved vision capabilities, and advanced Intelligence Mixture of Experts (MOEs). Although this tutorial primarily focuses on Phi-3, you can apply the same steps to fine-tune and integrate the Phi-3.5 model for even better performance. A tip on how to modify the fine_tune.py script to switch to the Phi-3.5 model is included below at Fine-tune the Phi-3 model section.
\n
\n
For more detailed information and to explore additional resources about Phi-3 and Phi-3.5, please visit the Phi-3CookBook.
Series 1: Set Up Azure resources and prepare for fine-tuning
\n
\n\n
Create Azure Machine Learning workspace
\n
Request GPU quotas in Azure subscription
\n
Set up the project and install the libraries
\n
Set up project files in Visual Studio Code
\n
Prepare dataset for fine-tuning
\n\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n\n
Fine-tune the Phi-3 model
\n
Deploy the fine-tuned Phi-3 model
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
\n\n
Integrate the custom Phi-3 model with Prompt flow
\n
Congratulation!
\n\n
\n
Series 1: Set up Azure resources and Prepare for fine-tuning
\n
\n
Create Azure Machine Learning Workspace
\n
\n
In this exercise, you will:
\n
\n
Create an Azure Machine Learning Workspace.
\n
\n
\n
Create an Azure Machine Learning Workspace
\n
\n\n
\n
Typeazure machine learningin thesearch barat the top of the portal page and selectAzure Machine Learningfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select+ Createfrom the navigation menu.
\n
\n
\n
SelectNew workspacefrom the navigation menu.
\n
\n
\n
\n\n
\n
\n
\n
\n
Perform the following tasks:
\n
\n
Select your AzureSubscription.
\n
Select theResource groupto use (create a new one if needed).
\n
EnterWorkspace Name. It must be a unique value.
\n
Select theRegionyou'd like to use.
\n
Select theStorage accountto use (create a new one if needed).
\n
Select theKey vaultto use (create a new one if needed).
\n
Select theApplication insightsto use (create a new one if needed).
\n
Select theContainer registry to use (create a new one if needed).
\n
\n
\n
\n
\n\n
\n
\n
Tip\n
When you create or use a Storage account in Azure Machine Learning, a container named \"azureml\" is automatically created within the Storage account. This container is used for storing model artifacts, training outputs, and other data generated during the machine learning process. In this tutorial, you will use the \"azureml\" container to manage and store all the necessary files and outputs related to our machine learning workflows.
\n
\n
\n
\n
\n
\n
\n
SelectReview + Create.
\n
\n
\n
SelectCreate.
\n
\n\n
\n
Request GPU quotas in Azure Subscription
\n
\n
In this tutorial, you will learn how to fine-tune and deploy a Phi-3 model, using GPUs. For fine-tuning, you will use theStandard_NC24ads_A100_v4 GPU, which requires a quota request. For deployment, you will use theStandard_E4s_v3CPU, which does not require a quota request.
\n
\n
\n
Note\n
Only Pay-As-You-Go subscriptions (the standard subscription type) are eligible for GPU allocation; benefit subscriptions are not currently supported.
\n
For those using benefit subscriptions (such as Visual Studio Enterprise Subscription) or those looking to quickly test the fine-tuning and deployment process, this tutorial also provides guidance for fine-tuning with a minimal dataset using a CPU. However, it is important to note that fine-tuning results are significantly better when using a GPU with larger datasets.
Perform the following tasks to requestStandard NCADSA100v4 Family quota:
\n
\n
SelectQuotafrom the left side tab.
\n
\n
Select theVirtual machine familyto use. For example, selectStandard NCADSA100v4 Family Cluster Dedicated vCPUs, which includes theStandard_NC24ads_A100_v4GPU.
\n
\n
\n
Select theRequest quotafrom the navigation menu.
\n
\n
\n
\n\n
\n
\n
\n
\n
Inside the Request quota page, enter theNew cores limityou'd like to use. For example, 24.
\n
\n
\n
Inside the Request quota page, selectSubmitto request the GPU quota.
To fine-tune and deploy your models, you must first ceate a User Assigned Managed Identity (UAI) and assign it the appropriate permissions. This UAI will be used for authentication during deployment, so it is critical to grant it access to the storage accounts, container registry, and resource group.
\n
In this exercise, you will:
\n
\n
\n
Create User Assigned Managed Identity(UAI).
\n
Add Contributor role assignment to Managed Identity.
\n
Add Storage Blob Data Reader role assignment to Managed Identity.
\n
Add AcrPull role assignment to Managed Identity.
\n
\n
Create User Assigned Managed Identity(UAI)
\n
\n\n
\n
Typemanaged identitiesin thesearch barat the top of the portal page and selectManaged Identitiesfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select+ Create.
\n
\n
\n
\n\n
\n
\n
\n
\n
Perform the following tasks to navigate to Add role assignment page:
\n
\n
Select your AzureSubscription.
\n
Select theResource groupto use (create a new one if needed).
\n
Select theRegionyou'd like to use.
\n
Enter theName. It must be a unique value.
\n
\n
\n
\n
\n\n
\n
\n
\n
\n
SelectReview + create.
\n
\n
\n
Select+ Create.
\n
\n\n
\n
Add Contributor role assignment to Managed Identity
\n
\n\n
\n
Navigate to the Managed Identity resource that you created.
\n
\n
\n
SelectAzure role assignmentsfrom the left side tab.
\n
\n
\n
Select+Add role assignmentfrom the navigation menu.
\n
\n
\n
Inside Add role assignment page, Perform the following tasks:
\n
\n
Select theScopetoResource group.
\n
Select your AzureSubscription.
\n
Select theResource groupto use.
\n
Select theRoletoContributor.
\n
\n
\n
\n
\n\n
\n
\n
\n
\n
SelectSave.
\n
\n\n
\n
Add Storage Blob Data Reader role assignment to Managed Identity
\n
\n\n
\n
Typeazure storage accountsin thesearch barat the top of the portal page and selectStorage accountsfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select the storage account that associated with the Azure Machine Learning workspace. For example,finetunephistorage.
\n
\n
\n
Perform the following tasks to navigate to Add role assignment page:
\n
\n
Navigate to the Azure Storage account that you created.
\n
SelectAccess Control (IAM)from the left side tab.
\n
Select+ Addfrom the navigation menu.
\n
SelectAdd role assignmentfrom the navigation menu.
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
Inside Add role assignment page, Perform the following tasks:
\n
\n
\n
Inside the Role page, typeStorage Blob Data Readerin thesearch barand selectStorage Blob Data Readerfrom the options that appear.
\n
\n
\n
\n
\n
\n
\n
\n
Inside the Role page, selectNext.
\n
\n
\n
Inside the Members page, selectAssign access toManaged identity.
\n
\n
\n
Inside the Members page, select+ Select members.
\n
\n
\n
Inside Select managed identities page, select your AzureSubscription.
In this exercise, you will create the essential files for our project. These files include scripts for downloading the dataset, setting up the Azure Machine Learning environment, fine-tuning the Phi-3 model, and deploying the fine-tuned model. You will also create aconda.ymlfile to set up the fine-tuning environment.
\n
In this exercise, you will:
\n
\n
Create adownload_dataset.pyfile to download the dataset.
\n
Create asetup_ml.pyfile to set up the Azure Machine Learning environment.
\n
Create afine_tune.pyfile in thefinetuning_dirfolder to fine-tune the Phi-3 model using the dataset.
\n
Create aconda.ymlfile to setup fine-tuning environment.
\n
Create adeploy_model.pyfile to deploy the fine-tuned model.
\n
Create aintegrate_with_promptflow.pyfile, to integrate the fine-tuned model and execute the model using Prompt flow.
\n
Create a flow.dag.yml file, to set up the workflow structure for Prompt flow.
Perform the following tasks to add the Azure Subscription ID:
\n
\n
Typesubscriptionsin thesearch barat the top of the portal page and selectSubscriptionsfrom the options that appear.
\n
\n
\n\n
\n
\n
\n
Select the Azure Subscription you are currently using.
\n
Copy and paste your Subscription ID into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Workspace Name:
\n
\n
Navigate to the Azure Machine Learning resource that you created.
\n
Copy and paste your account name into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Resource Group Name:
\n
\n
Navigate to the Azure Machine Learning resource that you created.
\n
Copy and paste your Azure Resource Group Name into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Managed Identity name
\n
\n
Navigate to the Managed Identities resource that you created.
\n
Copy and paste your Azure Managed Identity name into theconfig.pyfile.
\n
\n
\n
\n\n
Prepare Dataset for Fine-tuning
\n
\n
In this exercise, you will run thedownload_dataset.pyfile to download theultrachat_200kdatasets to your local environment. You will then use this datasets to fine-tune the Phi-3 model in Azure Machine Learning.
\n
In this exercise, you will:
\n
\n
Add code to thedownload_dataset.pyfile to download the datasets.
\n
Run thedownload_dataset.pyfile to download datasets to your local environment.
\n
\n
\n
Download your dataset usingdownload_dataset.py
\n
\n\n
\n
Open thedownload_dataset.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intodownload_dataset.py.
\n
import json\nimport os\nfrom datasets import load_dataset\nfrom config import (\n TRAIN_DATA_PATH,\n TEST_DATA_PATH)\n\ndef load_and_split_dataset(dataset_name, config_name, split_ratio):\n \"\"\"\n Load and split a dataset.\n \"\"\"\n # Load the dataset with the specified name, configuration, and split ratio\n dataset = load_dataset(dataset_name, config_name, split=split_ratio)\n print(f\"Original dataset size: {len(dataset)}\")\n \n # Split the dataset into train and test sets (80% train, 20% test)\n split_dataset = dataset.train_test_split(test_size=0.2)\n print(f\"Train dataset size: {len(split_dataset['train'])}\")\n print(f\"Test dataset size: {len(split_dataset['test'])}\")\n \n return split_dataset\n\ndef save_dataset_to_jsonl(dataset, filepath):\n \"\"\"\n Save a dataset to a JSONL file.\n \"\"\"\n # Create the directory if it does not exist\n os.makedirs(os.path.dirname(filepath), exist_ok=True)\n \n # Open the file in write mode\n with open(filepath, 'w', encoding='utf-8') as f:\n # Iterate over each record in the dataset\n for record in dataset:\n # Dump the record as a JSON object and write it to the file\n json.dump(record, f)\n # Write a newline character to separate records\n f.write('\\n')\n \n print(f\"Dataset saved to {filepath}\")\n\ndef main():\n \"\"\"\n Main function to load, split, and save the dataset.\n \"\"\"\n # Load and split the ULTRACHAT_200k dataset with a specific configuration and split ratio\n dataset = load_and_split_dataset(\"HuggingFaceH4/ultrachat_200k\", 'default', 'train_sft[:1%]')\n \n # Extract the train and test datasets from the split\n train_dataset = dataset['train']\n test_dataset = dataset['test']\n\n # Save the train dataset to a JSONL file\n save_dataset_to_jsonl(train_dataset, TRAIN_DATA_PATH)\n \n # Save the test dataset to a separate JSONL file\n save_dataset_to_jsonl(test_dataset, TEST_DATA_PATH)\n\nif __name__ == \"__main__\":\n main()\n
\n
\n
\n
Tip\n
Guidance for fine-tuning with a minimal dataset using a CPU
\n
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
Type the following command inside your terminal to run the script and download the dataset to your local environment.
\n
python download_dataset.py\n
\n
\n
\n
Verify that the datasets were saved successfully to your localfinetune-phi/datadirectory.
\n
\n\n
\n
Note\n
Note on dataset size and fine-tuning time
\n
In this tutorial, you use only 1% of the dataset (train_sft[:1%]). This significantly reduces the amount of data, speeding up both the upload and fine-tuning processes. You can adjust the percentage to find the right balance between training time and model performance. Using a smaller subset of the dataset reduces the time required for fine-tuning, making the process more manageable for a tutorial.
\n
\n
\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n
Fine-tune the Phi-3 model
\n
\n
In this exercise, you will fine-tune the Phi-3 model using the provided dataset. First, you will define the fine-tuning process in thefine_tune.pyfile. Then, you will configure the Azure Machine Learning environment and initiate the fine-tuning process by running thesetup_ml.pyfile. This script ensures that the fine-tuning occurs within the Azure Machine Learning environment.
\n
By runningsetup_ml.py, you will run the fine-tuning process in the Azure Machine Learning environment.
\n
In this exercise, you will:
\n
\n
Set up Azure CLI to authenticate environment
\n
Add code to thefine_tune.pyfile to fine-tune the model.
\n
Add code to and run thesetup_ml.pyfile to initiate the fine-tuning process in Azure Machine Learning.
\n
Run thesetup_ml.pyfile to fine-tune the Phi-3 model using Azure Machine Learning.
\n
\n
\n
Set up Azure CLI
\n
\n
You need to set up Azure CLI to authenticate your environment. Azure CLI allows you to manage Azure resources directly from the command line and provides the credentials necessary for Azure Machine Learning to access these resources. To get started installAzure CLI
\n\n
\n
Open a terminal window and type the following command to log in to your Azure account.
\n
az login\n
\n
\n
\n
Select your Azure account to use.
\n
\n
\n
Select your Azure subscription to use.
\n
\n
\n
\n\n
\n
\n
\n\n
\n
Tip\n
Having trouble signing in to Azure? Try using a device code
\n
\n\n
Open a terminal window and type the following command to log in to your Azure account.
\n
az login --use-device-code
\n
\n\n\n
Visit the website displayed in the terminal window and enter the provided code on that site.
\n\n
\n\n
Inside the website, selectNext.
\n
\n
\n
Inside the website, select the account to use in this tutorial
\n
\n
\n
Inside the website, selectcontinueto complete login.
\n
After successful login, go back to your terminal and select your Azure subscription to use.
\n
\n
\n\n
\n
\n
\n
Add code to thefine_tune.pyfile
\n
\n\n
\n
Navigate to thefinetuning_dirfolder and Open thefine_tune.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intofine_tune.py.
\n
import argparse\nimport sys\nimport logging\nimport os\nfrom datasets import load_dataset\nimport torch\nimport mlflow\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments\nfrom trl import SFTTrainer\n\n# To avoid the INVALID_PARAMETER_VALUE error in MLflow, disable MLflow integration\nos.environ[\"DISABLE_MLFLOW_INTEGRATION\"] = \"True\"\n\n# Logging setup\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n handlers=[logging.StreamHandler(sys.stdout)],\n level=logging.WARNING\n)\nlogger = logging.getLogger(__name__)\n\ndef initialize_model_and_tokenizer(model_name, model_kwargs):\n \"\"\"\n Initialize the model and tokenizer with the given pretrained model name and arguments.\n \"\"\"\n model = AutoModelForCausalLM.from_pretrained(model_name, **model_kwargs)\n tokenizer = AutoTokenizer.from_pretrained(model_name)\n tokenizer.model_max_length = 2048\n tokenizer.pad_token = tokenizer.unk_token\n tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n tokenizer.padding_side = 'right'\n return model, tokenizer\n\ndef apply_chat_template(example, tokenizer):\n \"\"\"\n Apply a chat template to tokenize messages in the example.\n \"\"\"\n messages = example[\"messages\"]\n if messages[0][\"role\"] != \"system\":\n messages.insert(0, {\"role\": \"system\", \"content\": \"\"})\n example[\"text\"] = tokenizer.apply_chat_template(\n messages, tokenize=False, add_generation_prompt=False\n )\n return example\n\ndef load_and_preprocess_data(train_filepath, test_filepath, tokenizer):\n \"\"\"\n Load and preprocess the dataset.\n \"\"\"\n train_dataset = load_dataset('json', data_files=train_filepath, split='train')\n test_dataset = load_dataset('json', data_files=test_filepath, split='train')\n column_names = list(train_dataset.features)\n\n train_dataset = train_dataset.map(\n apply_chat_template,\n fn_kwargs={\"tokenizer\": tokenizer},\n num_proc=10,\n remove_columns=column_names,\n desc=\"Applying chat template to train dataset\",\n )\n\n test_dataset = test_dataset.map(\n apply_chat_template,\n fn_kwargs={\"tokenizer\": tokenizer},\n num_proc=10,\n remove_columns=column_names,\n desc=\"Applying chat template to test dataset\",\n )\n\n return train_dataset, test_dataset\n\ndef train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, output_dir):\n \"\"\"\n Train and evaluate the model.\n \"\"\"\n training_args = TrainingArguments(\n bf16=True,\n do_eval=True,\n output_dir=output_dir,\n eval_strategy=\"epoch\",\n learning_rate=5.0e-06,\n logging_steps=20,\n lr_scheduler_type=\"cosine\",\n num_train_epochs=3,\n overwrite_output_dir=True,\n per_device_eval_batch_size=4,\n per_device_train_batch_size=4,\n remove_unused_columns=True,\n save_steps=500,\n seed=0,\n gradient_checkpointing=True,\n gradient_accumulation_steps=1,\n warmup_ratio=0.2,\n )\n\n trainer = SFTTrainer(\n model=model,\n args=training_args,\n train_dataset=train_dataset,\n eval_dataset=test_dataset,\n max_seq_length=2048,\n dataset_text_field=\"text\",\n tokenizer=tokenizer,\n packing=True\n )\n\n train_result = trainer.train()\n trainer.log_metrics(\"train\", train_result.metrics)\n\n mlflow.transformers.log_model(\n transformers_model={\"model\": trainer.model, \"tokenizer\": tokenizer},\n artifact_path=output_dir,\n )\n\n tokenizer.padding_side = 'left'\n eval_metrics = trainer.evaluate()\n eval_metrics[\"eval_samples\"] = len(test_dataset)\n trainer.log_metrics(\"eval\", eval_metrics)\n\ndef main(train_file, eval_file, model_output_dir):\n \"\"\"\n Main function to fine-tune the model.\n \"\"\"\n model_kwargs = {\n \"use_cache\": False,\n \"trust_remote_code\": True,\n \"torch_dtype\": torch.bfloat16,\n \"device_map\": None,\n \"attn_implementation\": \"eager\"\n }\n \n pretrained_model_name = \"microsoft/Phi-3.5-mini-instruct\"\n # pretrained_model_name = \"microsoft/Phi-3-mini-4k-instruct\"\n\n with mlflow.start_run():\n model, tokenizer = initialize_model_and_tokenizer(pretrained_model_name, model_kwargs)\n train_dataset, test_dataset = load_and_preprocess_data(train_file, eval_file, tokenizer)\n train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, model_output_dir)\n\nif __name__ == \"__main__\":\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--train-file\", type=str, required=True, help=\"Path to the training data\")\n parser.add_argument(\"--eval-file\", type=str, required=True, help=\"Path to the evaluation data\")\n parser.add_argument(\"--model_output_dir\", type=str, required=True, help=\"Directory to save the fine-tuned model\")\n args = parser.parse_args()\n main(args.train_file, args.eval_file, args.model_output_dir)\n
\n
\n
\n
\n
Save and close thefine_tune.pyfile.
\n
\n\n
\n
\n
Tip\n
You can fine-tune Phi-3.5 model
\n
In fine_tune.py file, you can change the pretrained_model_name from \"microsoft/Phi-3-mini-4k-instruct\" to any model you want to fine-tune. For example, if you change it to \"microsoft/Phi-3.5-mini-instruct\", you'll be using the Phi-3.5-mini-instruct model for fine-tuning. To find and use the model name you prefer, visit Hugging Face, search for the model you're interested in, and then copy and paste its name into the pretrained_model_name field in your script.
\n
\n
\n
\n
Add code to thesetup_ml.pyfile
\n
\n\n
\n
Open thesetup_ml.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intosetup_ml.py.
\n
import logging\nfrom azure.ai.ml import MLClient, command, Input\nfrom azure.ai.ml.entities import Environment, AmlCompute\nfrom azure.identity import AzureCliCredential\nfrom config import (\n AZURE_SUBSCRIPTION_ID,\n AZURE_RESOURCE_GROUP_NAME,\n AZURE_ML_WORKSPACE_NAME,\n TRAIN_DATA_PATH,\n TEST_DATA_PATH\n)\n\n# Constants\n\n# Uncomment the following lines to use a CPU instance for training\n# COMPUTE_INSTANCE_TYPE = \"Standard_E16s_v3\" # cpu\n# COMPUTE_NAME = \"cpu-e16s-v3\"\n# DOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest\"\n\n# Uncomment the following lines to use a GPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_NC24ads_A100_v4\"\nCOMPUTE_NAME = \"gpu-nc24s-a100-v4\"\nDOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/curated/acft-hf-nlp-gpu:59\"\n\nCONDA_FILE = \"conda.yml\"\nLOCATION = \"eastus2\" # Replace with the location of your compute cluster\nFINETUNING_DIR = \"./finetuning_dir\" # Path to the fine-tuning script\nTRAINING_ENV_NAME = \"phi-3-training-environment\" # Name of the training environment\nMODEL_OUTPUT_DIR = \"./model_output\" # Path to the model output directory in azure ml\n\n# Logging setup to track the process\nlogger = logging.getLogger(__name__)\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.WARNING\n)\n\ndef get_ml_client():\n \"\"\"\n Initialize the ML Client using Azure CLI credentials.\n \"\"\"\n credential = AzureCliCredential()\n return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)\n\ndef create_or_get_environment(ml_client):\n \"\"\"\n Create or update the training environment in Azure ML.\n \"\"\"\n env = Environment(\n image=DOCKER_IMAGE_NAME, # Docker image for the environment\n conda_file=CONDA_FILE, # Conda environment file\n name=TRAINING_ENV_NAME, # Name of the environment\n )\n return ml_client.environments.create_or_update(env)\n\ndef create_or_get_compute_cluster(ml_client, compute_name, COMPUTE_INSTANCE_TYPE, location):\n \"\"\"\n Create or update the compute cluster in Azure ML.\n \"\"\"\n try:\n compute_cluster = ml_client.compute.get(compute_name)\n logger.info(f\"Compute cluster '{compute_name}' already exists. Reusing it for the current run.\")\n except Exception:\n logger.info(f\"Compute cluster '{compute_name}' does not exist. Creating a new one with size {COMPUTE_INSTANCE_TYPE}.\")\n compute_cluster = AmlCompute(\n name=compute_name,\n size=COMPUTE_INSTANCE_TYPE,\n location=location,\n tier=\"Dedicated\", # Tier of the compute cluster\n min_instances=0, # Minimum number of instances\n max_instances=1 # Maximum number of instances\n )\n ml_client.compute.begin_create_or_update(compute_cluster).wait() # Wait for the cluster to be created\n return compute_cluster\n\ndef create_fine_tuning_job(env, compute_name):\n \"\"\"\n Set up the fine-tuning job in Azure ML.\n \"\"\"\n return command(\n code=FINETUNING_DIR, # Path to fine_tune.py\n command=(\n \"python fine_tune.py \"\n \"--train-file ${{inputs.train_file}} \"\n \"--eval-file ${{inputs.eval_file}} \"\n \"--model_output_dir ${{inputs.model_output}}\"\n ),\n environment=env, # Training environment\n compute=compute_name, # Compute cluster to use\n inputs={\n \"train_file\": Input(type=\"uri_file\", path=TRAIN_DATA_PATH), # Path to the training data file\n \"eval_file\": Input(type=\"uri_file\", path=TEST_DATA_PATH), # Path to the evaluation data file\n \"model_output\": MODEL_OUTPUT_DIR\n }\n )\n\ndef main():\n \"\"\"\n Main function to set up and run the fine-tuning job in Azure ML.\n \"\"\"\n # Initialize ML Client\n ml_client = get_ml_client()\n\n # Create Environment\n env = create_or_get_environment(ml_client)\n \n # Create or get existing compute cluster\n create_or_get_compute_cluster(ml_client, COMPUTE_NAME, COMPUTE_INSTANCE_TYPE, LOCATION)\n\n # Create and Submit Fine-Tuning Job\n job = create_fine_tuning_job(env, COMPUTE_NAME)\n returned_job = ml_client.jobs.create_or_update(job) # Submit the job\n ml_client.jobs.stream(returned_job.name) # Stream the job logs\n \n # Capture the job name\n job_name = returned_job.name\n print(f\"Job name: {job_name}\")\n\nif __name__ == \"__main__\":\n main()\n
\n
\n
\n
\n
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andLOCATIONwith your specific details.
\n
# Uncomment the following lines to use a GPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_NC24ads_A100_v4\"\nCOMPUTE_NAME = \"gpu-nc24s-a100-v4\"\n...\nLOCATION = \"eastus2\"# Replace with the location of your compute cluster\n
\n
\n\n
\n
\n
\n
\n
Tip\n
Guidance for fine-tuning with a minimal dataset using a CPU
\n
\n
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
\n\n
Open thesetup_mlfile.
\n
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andDOCKER_IMAGE_NAMEwith the following. If you do not have access toStandard_E16s_v3, you can use an equivalent CPU instance or request a new quota.
\n
Replace LOCATIONwith your specific details.
\n\n
\n
# Uncomment the following lines to use a CPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_E16s_v3\"# cpu\nCOMPUTE_NAME = \"cpu-e16s-v3\"\nDOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest\"\nLOCATION = \"eastus2\"# Replace with the location of your compute cluster
\n
\n
\n
\n
\n
\n\n
\n
Type the following command to run thesetup_ml.pyscript and start the fine-tuning process in Azure Machine Learning.
\n
python setup_ml.py\n
\n
\n
\n
In this exercise, you successfully fine-tuned the Phi-3 model using Azure Machine Learning. By running thesetup_ml.pyscript, you have set up the Azure Machine Learning environment and initiated the fine-tuning process defined infine_tune.pyfile. Please note that the fine-tuning process can take a considerable amount of time. After running thepython setup_ml.pycommand, you need to wait for the process to complete. You can monitor the status of the fine-tuning job by following the link provided in the terminal to the Azure Machine Learning portal. In the next series, you will deploy the fine-tuned model and integrate it with Prompt flow.
\n\n
\n
\n\n
\n
Deploy the fine-tuned model
\n
\n
To integrate the fine-tuned Phi-3 model with Prompt Flow, you need to deploy the model to make it accessible for real-time inference. This process involves registering the model, creating an online endpoint, and deploying the model.
\n
In this exercise, you will:
\n
\n
Set the model name, endpoint name, and deployment name for deployment.
\n
Register the fine-tuned model in the Azure Machine Learning workspace.
\n
Create an online endpoint.
\n
Deploy the registered fine-tuned Phi-3 model.
\n
\n
Set the model name, endpoint name, and deployment name for deployment
\n
\n\n
\n
Openconfig.pyfile.
\n
\n
\n
ReplaceAZURE_MODEL_NAME = \"your_fine_tuned_model_name\"with the desired name for your model.
\n
\n
\n
ReplaceAZURE_ENDPOINT_NAME = \"your_fine_tuned_model_endpoint_name\"with the desired name for your endpoint.
\n
\n
\n
ReplaceAZURE_DEPLOYMENT_NAME = \"your_fine_tuned_model_deployment_name\"with the desired name for your deployment.
\n
\n\n
Deploy the fine-tuned model
\n
\n
Running thedeploy_model.pyfile automates the entire deployment process. It registers the model, creates an endpoint, and executes the deployment based on the settings specified in the config.py file, which includes the model name, endpoint name, and deployment name.
\n\n
\n
Open thedeploy_model.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intodeploy_model.py.
\n
import logging\nfrom azure.identity import AzureCliCredential\nfrom azure.ai.ml import MLClient\nfrom azure.ai.ml.entities import Model, ProbeSettings, ManagedOnlineEndpoint, ManagedOnlineDeployment, IdentityConfiguration, ManagedIdentityConfiguration, OnlineRequestSettings\nfrom azure.ai.ml.constants import AssetTypes\n\n# Configuration imports\nfrom config import (\n AZURE_SUBSCRIPTION_ID,\n AZURE_RESOURCE_GROUP_NAME,\n AZURE_ML_WORKSPACE_NAME,\n AZURE_MANAGED_IDENTITY_RESOURCE_ID,\n AZURE_MANAGED_IDENTITY_CLIENT_ID,\n AZURE_MODEL_NAME,\n AZURE_ENDPOINT_NAME,\n AZURE_DEPLOYMENT_NAME\n)\n\n# Constants\nJOB_NAME = \"your-job-name\"\nCOMPUTE_INSTANCE_TYPE = \"Standard_E4s_v3\"\n\ndeployment_env_vars = {\n \"SUBSCRIPTION_ID\": AZURE_SUBSCRIPTION_ID,\n \"RESOURCE_GROUP_NAME\": AZURE_RESOURCE_GROUP_NAME,\n \"UAI_CLIENT_ID\": AZURE_MANAGED_IDENTITY_CLIENT_ID,\n}\n\n# Logging setup\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.DEBUG\n)\nlogger = logging.getLogger(__name__)\n\ndef get_ml_client():\n \"\"\"Initialize and return the ML Client.\"\"\"\n credential = AzureCliCredential()\n return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)\n\ndef register_model(ml_client, model_name, job_name):\n \"\"\"Register a new model.\"\"\"\n model_path = f\"azureml://jobs/{job_name}/outputs/artifacts/paths/model_output\"\n logger.info(f\"Registering model {model_name} from job {job_name} at path {model_path}.\")\n run_model = Model(\n path=model_path,\n name=model_name,\n description=\"Model created from run.\",\n type=AssetTypes.MLFLOW_MODEL,\n )\n model = ml_client.models.create_or_update(run_model)\n logger.info(f\"Registered model ID: {model.id}\")\n return model\n\ndef delete_existing_endpoint(ml_client, endpoint_name):\n \"\"\"Delete existing endpoint if it exists.\"\"\"\n try:\n endpoint_result = ml_client.online_endpoints.get(name=endpoint_name)\n logger.info(f\"Deleting existing endpoint {endpoint_name}.\")\n ml_client.online_endpoints.begin_delete(name=endpoint_name).result()\n logger.info(f\"Deleted existing endpoint {endpoint_name}.\")\n except Exception as e:\n logger.info(f\"No existing endpoint {endpoint_name} found to delete: {e}\")\n\ndef create_or_update_endpoint(ml_client, endpoint_name, description=\"\"):\n \"\"\"Create or update an endpoint.\"\"\"\n delete_existing_endpoint(ml_client, endpoint_name)\n logger.info(f\"Creating new endpoint {endpoint_name}.\")\n endpoint = ManagedOnlineEndpoint(\n name=endpoint_name,\n description=description,\n identity=IdentityConfiguration(\n type=\"user_assigned\",\n user_assigned_identities=[ManagedIdentityConfiguration(resource_id=AZURE_MANAGED_IDENTITY_RESOURCE_ID)]\n )\n )\n endpoint_result = ml_client.online_endpoints.begin_create_or_update(endpoint).result()\n logger.info(f\"Created new endpoint {endpoint_name}.\")\n return endpoint_result\n\ndef create_or_update_deployment(ml_client, endpoint_name, deployment_name, model):\n \"\"\"Create or update a deployment.\"\"\"\n\n logger.info(f\"Creating deployment {deployment_name} for endpoint {endpoint_name}.\")\n deployment = ManagedOnlineDeployment(\n name=deployment_name,\n endpoint_name=endpoint_name,\n model=model.id,\n instance_type=COMPUTE_INSTANCE_TYPE,\n instance_count=1,\n environment_variables=deployment_env_vars,\n request_settings=OnlineRequestSettings(\n max_concurrent_requests_per_instance=3,\n request_timeout_ms=180000,\n max_queue_wait_ms=120000\n ),\n liveness_probe=ProbeSettings(\n failure_threshold=30,\n success_threshold=1,\n period=100,\n initial_delay=500,\n ),\n readiness_probe=ProbeSettings(\n failure_threshold=30,\n success_threshold=1,\n period=100,\n initial_delay=500,\n ),\n )\n deployment_result = ml_client.online_deployments.begin_create_or_update(deployment).result()\n logger.info(f\"Created deployment {deployment.name} for endpoint {endpoint_name}.\")\n return deployment_result\n\ndef set_traffic_to_deployment(ml_client, endpoint_name, deployment_name):\n \"\"\"Set traffic to the specified deployment.\"\"\"\n try:\n # Fetch the current endpoint details\n endpoint = ml_client.online_endpoints.get(name=endpoint_name)\n \n # Log the current traffic allocation for debugging\n logger.info(f\"Current traffic allocation: {endpoint.traffic}\")\n \n # Set the traffic allocation for the deployment\n endpoint.traffic = {deployment_name: 100}\n \n # Update the endpoint with the new traffic allocation\n endpoint_poller = ml_client.online_endpoints.begin_create_or_update(endpoint)\n updated_endpoint = endpoint_poller.result()\n \n # Log the updated traffic allocation for debugging\n logger.info(f\"Updated traffic allocation: {updated_endpoint.traffic}\")\n logger.info(f\"Set traffic to deployment {deployment_name} at endpoint {endpoint_name}.\")\n return updated_endpoint\n except Exception as e:\n # Log any errors that occur during the process\n logger.error(f\"Failed to set traffic to deployment: {e}\")\n raise\n\n\ndef main():\n ml_client = get_ml_client()\n\n registered_model = register_model(ml_client, AZURE_MODEL_NAME, JOB_NAME)\n logger.info(f\"Registered model ID: {registered_model.id}\")\n\n endpoint = create_or_update_endpoint(ml_client, AZURE_ENDPOINT_NAME, \"Endpoint for finetuned Phi-3 model\")\n logger.info(f\"Endpoint {AZURE_ENDPOINT_NAME} is ready.\")\n\n try:\n deployment = create_or_update_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME, registered_model)\n logger.info(f\"Deployment {AZURE_DEPLOYMENT_NAME} is created for endpoint {AZURE_ENDPOINT_NAME}.\")\n\n set_traffic_to_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME)\n logger.info(f\"Traffic is set to deployment {AZURE_DEPLOYMENT_NAME} at endpoint {AZURE_ENDPOINT_NAME}.\")\n except Exception as e:\n logger.error(f\"Failed to create or update deployment: {e}\")\n\nif __name__ == \"__main__\":\n main()\n
\n
\n
\n
\n
Perform the following tasks to get theJOB_NAME:
\n
\n
Navigate to Azure Machine Learning resource that you created.
\n
SelectStudio web URLto open the Azure Machine Learning workspace.
\n
SelectJobsfrom the left side tab.
\n
Select the experiment for fine-tuning. For example,finetunephi.
\n
Select the job that you created.
\n
Copy and paste your job Name into theJOB_NAME = \"your-job-name\"indeploy_model.pyfile.
\n
\n
\n
\n
ReplaceCOMPUTE_INSTANCE_TYPEwith your specific details.
\n
\n
\n
Type the following command to run thedeploy_model.pyscript and start the deployment process in Azure Machine Learning.
\n
python deploy_model.py
\n
\n\n
\n
Warning\n
To avoid additional charges to your account, make sure to delete the created endpoint in the Azure Machine Learning workspace.
\n
\n
\n
\n
Check deployment status in Azure Machine Learning Workspace
Navigate to Azure Machine Learning workspace that you created.
\n
\n
\n
SelectStudio web URLto open the Azure Machine Learning workspace.
\n
\n
Select Endpoints from the left side tab.\n
\n
\n
\n\n
\n
\n
\n
\n
Select endpoint that you created.
\n
\n
\n
\n\n
\n
\n
\n
\n
On this page, you can manage the endpoints created during the deployment process.
\n
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
Integrate the custom Phi-3 model with Prompt Flow
\n
\n
After successfully deploying your fine-tuned model, you can now integrate it with Prompt Flow to use your model in real-time applications, enabling a variety of interactive tasks with your custom Phi-3 model.
\n
In this exercise, you will:
\n
\n
\n
Set api key and endpoint uri of the fine-tuned Phi-3 model.
\n
Add code to theflow.dag.ymlfile.
\n
Add code to theintegrate_with_promptflow.pyfile.
\n
Test your custom Phi-3 model on Prompt flow.
\n
\n
\n
Set api key and endpoint uri of the fine-tuned Phi-3 model
\n
\n\n
\n
Navigate to the Azure Machine learning workspace that you created.
Here's an example of the results: Now you can chat with your custom Phi-3 model. It is recommended to ask questions based on the data used for fine-tuning.
\n
\n
\n
\n
\n
\n
\n
\n\n
Congratulations!
\n
\n
You've completed this tutorial
\n
\n
Congratulations! You have successfully completed the tutorial on fine-tuning and integrating custom Phi-3 models with Prompt flow. This tutorial introduced the simplest method of fine-tuning, avoiding additional techniques such as LoRA or QLoRA, and using MLflow to streamline the fine-tuning and deployment process. Advanced techniques and detailed explanations will be covered in the next series.
\n
\n
\n
\n\n
\n
\n
Clean Up Azure Resources
\n
\n
Cleanup your Azure resources to avoid additional charges to your account. Go to the Azure portal and delete the following resources:
\n
\n
The Azure Machine Learning resource.
\n
The Azure Machine Learning model endpoint.
\n
\n
\n
Source Code for the Tutorial
\n
\n
You can find the complete source code for this tutorial in the following repository:
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide
\n
\n
\n\n
This blog series has several versions, each covering different aspects and techniques. Check out the following resources:
\n
\n
\n
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow using a code-first approach. Available on:\n
Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow in Azure AI Studio Detailed instructions for fine-tuning and integrating custom Phi-3 models with Prompt flow in Azure AI / ML Studio using a low-code approach. Available on:\n
Evaluate Fine-tuned Phi-3 / Phi-3.5 Models in Azure AI Studio Focusing on Microsoft's Responsible AI Detailed instructions for evaluating the Phi-3 / Phi-3.5 model in Azure AI Studio using a low-code approach. Available on:\n
Phi-3 is a family of small language models (SLMs) developed by Microsoft that delivers exceptional performance and cost-effectiveness. In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models. This tutorial is divided into three series:
\n
\n
Series 1: Set up Azure resources and Prepare for fine-tuning
\n\n
\n
Create Azure Machine Learning workspace: Set up an Azure Machine Learning workspace, which serves as the hub for managing machine learning experiments and models.
\n
\n
\n
Request GPU quotas: Request GPU quotas in your Azure subscription to ensure sufficient resources for model fine-tuning.
\n
\n
\n
Add role assignment: Set up a User Assigned Managed Identity (UAI) and assign it necessary permissions (Contributor, Storage Blob Data Reader, AcrPull) to access resources like storage accounts and container registries.
\n
\n
\n
Set up the project: Create a local environment, set up a virtual environment, install required packages, and create a script (download_dataset.py) to download the dataset (ULTRACHAT_200k) required for fine-tuning.
\n
\n\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n\n
\n
Define fine-tuning process: Add code to thefine_tune.pyfile to define the fine-tuning process, including data loading, preprocessing, and training configurations.
\n
\n
\n
Fine-tune the Phi-3 model: Add code to and run thesetup_ml.pyfile to set up the compute environment, define the fine-tuning job, and submit it to Azure Machine Learning.
\n
\n
\n
Deploy the Fine-tuned model: Once fine-tuning is complete, Add code to thedeploy_model.pyfile to register the fine-tuned model in Azure Machine Learning, create an online endpoint, and deploy the model for real-time inference.
\n
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
\n\n
\n
Build Prompt flow: Add code to theflow.dag.ymlfile to build a flow.
\n
\n
\n
Integrate with Prompt flow: Add code tointegrate_with_promptflowfile to integrate the custom Phi-3 model with Prompt flow.
\n
\n\n
\n
Here is an overview of this tutorial.
\n
\n
\n
\n
\n
\n
Note\n
Microsoft has released the Phi-3.5 models, featuring enhanced multi-language support, improved vision capabilities, and advanced Intelligence Mixture of Experts (MOEs). Although this tutorial primarily focuses on Phi-3, you can apply the same steps to fine-tune and integrate the Phi-3.5 model for even better performance. A tip on how to modify the fine_tune.py script to switch to the Phi-3.5 model is included below at Fine-tune the Phi-3 model section.
\n
\n
For more detailed information and to explore additional resources about Phi-3 and Phi-3.5, please visit the Phi-3CookBook.
Series 1: Set Up Azure resources and prepare for fine-tuning
\n
\n\n
Create Azure Machine Learning workspace
\n
Request GPU quotas in Azure subscription
\n
Set up the project and install the libraries
\n
Set up project files in Visual Studio Code
\n
Prepare dataset for fine-tuning
\n\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n\n
Fine-tune the Phi-3 model
\n
Deploy the fine-tuned Phi-3 model
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
\n\n
Integrate the custom Phi-3 model with Prompt flow
\n
Congratulation!
\n\n
\n
Series 1: Set up Azure resources and Prepare for fine-tuning
\n
\n
Create Azure Machine Learning Workspace
\n
\n
In this exercise, you will:
\n
\n
Create an Azure Machine Learning Workspace.
\n
\n
\n
Create an Azure Machine Learning Workspace
\n
\n\n
\n
Typeazure machine learningin thesearch barat the top of the portal page and selectAzure Machine Learningfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select+ Createfrom the navigation menu.
\n
\n
\n
SelectNew workspacefrom the navigation menu.
\n
\n
\n
\n\n
\n
\n
\n
\n
Perform the following tasks:
\n
\n
Select your AzureSubscription.
\n
Select theResource groupto use (create a new one if needed).
\n
EnterWorkspace Name. It must be a unique value.
\n
Select theRegionyou'd like to use.
\n
Select theStorage accountto use (create a new one if needed).
\n
Select theKey vaultto use (create a new one if needed).
\n
Select theApplication insightsto use (create a new one if needed).
\n
Select theContainer registry to use (create a new one if needed).
\n
\n
\n
\n
\n\n
\n
\n
Tip\n
When you create or use a Storage account in Azure Machine Learning, a container named \"azureml\" is automatically created within the Storage account. This container is used for storing model artifacts, training outputs, and other data generated during the machine learning process. In this tutorial, you will use the \"azureml\" container to manage and store all the necessary files and outputs related to our machine learning workflows.
\n
\n
\n
\n
\n
\n
\n
SelectReview + Create.
\n
\n
\n
SelectCreate.
\n
\n\n
\n
Request GPU quotas in Azure Subscription
\n
\n
In this tutorial, you will learn how to fine-tune and deploy a Phi-3 model, using GPUs. For fine-tuning, you will use theStandard_NC24ads_A100_v4 GPU, which requires a quota request. For deployment, you will use theStandard_E4s_v3CPU, which does not require a quota request.
\n
\n
\n
Note\n
Only Pay-As-You-Go subscriptions (the standard subscription type) are eligible for GPU allocation; benefit subscriptions are not currently supported.
\n
For those using benefit subscriptions (such as Visual Studio Enterprise Subscription) or those looking to quickly test the fine-tuning and deployment process, this tutorial also provides guidance for fine-tuning with a minimal dataset using a CPU. However, it is important to note that fine-tuning results are significantly better when using a GPU with larger datasets.
Perform the following tasks to requestStandard NCADSA100v4 Family quota:
\n
\n
SelectQuotafrom the left side tab.
\n
\n
Select theVirtual machine familyto use. For example, selectStandard NCADSA100v4 Family Cluster Dedicated vCPUs, which includes theStandard_NC24ads_A100_v4GPU.
\n
\n
\n
Select theRequest quotafrom the navigation menu.
\n
\n
\n
\n\n
\n
\n
\n
\n
Inside the Request quota page, enter theNew cores limityou'd like to use. For example, 24.
\n
\n
\n
Inside the Request quota page, selectSubmitto request the GPU quota.
To fine-tune and deploy your models, you must first ceate a User Assigned Managed Identity (UAI) and assign it the appropriate permissions. This UAI will be used for authentication during deployment, so it is critical to grant it access to the storage accounts, container registry, and resource group.
\n
In this exercise, you will:
\n
\n
\n
Create User Assigned Managed Identity(UAI).
\n
Add Contributor role assignment to Managed Identity.
\n
Add Storage Blob Data Reader role assignment to Managed Identity.
\n
Add AcrPull role assignment to Managed Identity.
\n
\n
Create User Assigned Managed Identity(UAI)
\n
\n\n
\n
Typemanaged identitiesin thesearch barat the top of the portal page and selectManaged Identitiesfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select+ Create.
\n
\n
\n
\n\n
\n
\n
\n
\n
Perform the following tasks to navigate to Add role assignment page:
\n
\n
Select your AzureSubscription.
\n
Select theResource groupto use (create a new one if needed).
\n
Select theRegionyou'd like to use.
\n
Enter theName. It must be a unique value.
\n
\n
\n
\n
\n\n
\n
\n
\n
\n
SelectReview + create.
\n
\n
\n
Select+ Create.
\n
\n\n
\n
Add Contributor role assignment to Managed Identity
\n
\n\n
\n
Navigate to the Managed Identity resource that you created.
\n
\n
\n
SelectAzure role assignmentsfrom the left side tab.
\n
\n
\n
Select+Add role assignmentfrom the navigation menu.
\n
\n
\n
Inside Add role assignment page, Perform the following tasks:
\n
\n
Select theScopetoResource group.
\n
Select your AzureSubscription.
\n
Select theResource groupto use.
\n
Select theRoletoContributor.
\n
\n
\n
\n
\n\n
\n
\n
\n
\n
SelectSave.
\n
\n\n
\n
Add Storage Blob Data Reader role assignment to Managed Identity
\n
\n\n
\n
Typeazure storage accountsin thesearch barat the top of the portal page and selectStorage accountsfrom the options that appear.
\n
\n
\n
\n\n
\n
\n
\n
\n
Select the storage account that associated with the Azure Machine Learning workspace. For example,finetunephistorage.
\n
\n
\n
Perform the following tasks to navigate to Add role assignment page:
\n
\n
Navigate to the Azure Storage account that you created.
\n
SelectAccess Control (IAM)from the left side tab.
\n
Select+ Addfrom the navigation menu.
\n
SelectAdd role assignmentfrom the navigation menu.
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
Inside Add role assignment page, Perform the following tasks:
\n
\n
\n
Inside the Role page, typeStorage Blob Data Readerin thesearch barand selectStorage Blob Data Readerfrom the options that appear.
\n
\n
\n
\n
\n
\n
\n
\n
Inside the Role page, selectNext.
\n
\n
\n
Inside the Members page, selectAssign access toManaged identity.
\n
\n
\n
Inside the Members page, select+ Select members.
\n
\n
\n
Inside Select managed identities page, select your AzureSubscription.
In this exercise, you will create the essential files for our project. These files include scripts for downloading the dataset, setting up the Azure Machine Learning environment, fine-tuning the Phi-3 model, and deploying the fine-tuned model. You will also create aconda.ymlfile to set up the fine-tuning environment.
\n
In this exercise, you will:
\n
\n
Create adownload_dataset.pyfile to download the dataset.
\n
Create asetup_ml.pyfile to set up the Azure Machine Learning environment.
\n
Create afine_tune.pyfile in thefinetuning_dirfolder to fine-tune the Phi-3 model using the dataset.
\n
Create aconda.ymlfile to setup fine-tuning environment.
\n
Create adeploy_model.pyfile to deploy the fine-tuned model.
\n
Create aintegrate_with_promptflow.pyfile, to integrate the fine-tuned model and execute the model using Prompt flow.
\n
Create a flow.dag.yml file, to set up the workflow structure for Prompt flow.
Perform the following tasks to add the Azure Subscription ID:
\n
\n
Typesubscriptionsin thesearch barat the top of the portal page and selectSubscriptionsfrom the options that appear.
\n
\n
\n\n
\n
\n
\n
Select the Azure Subscription you are currently using.
\n
Copy and paste your Subscription ID into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Workspace Name:
\n
\n
Navigate to the Azure Machine Learning resource that you created.
\n
Copy and paste your account name into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Resource Group Name:
\n
\n
Navigate to the Azure Machine Learning resource that you created.
\n
Copy and paste your Azure Resource Group Name into theconfig.pyfile.
\n
\n
\n
\n
\n
Perform the following tasks to add the Azure Managed Identity name
\n
\n
Navigate to the Managed Identities resource that you created.
\n
Copy and paste your Azure Managed Identity name into theconfig.pyfile.
\n
\n
\n
\n\n
Prepare Dataset for Fine-tuning
\n
\n
In this exercise, you will run thedownload_dataset.pyfile to download theultrachat_200kdatasets to your local environment. You will then use this datasets to fine-tune the Phi-3 model in Azure Machine Learning.
\n
In this exercise, you will:
\n
\n
Add code to thedownload_dataset.pyfile to download the datasets.
\n
Run thedownload_dataset.pyfile to download datasets to your local environment.
\n
\n
\n
Download your dataset usingdownload_dataset.py
\n
\n\n
\n
Open thedownload_dataset.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intodownload_dataset.py.
\nimport json\nimport os\nfrom datasets import load_dataset\nfrom config import (\n TRAIN_DATA_PATH,\n TEST_DATA_PATH)\n\ndef load_and_split_dataset(dataset_name, config_name, split_ratio):\n \"\"\"\n Load and split a dataset.\n \"\"\"\n # Load the dataset with the specified name, configuration, and split ratio\n dataset = load_dataset(dataset_name, config_name, split=split_ratio)\n print(f\"Original dataset size: {len(dataset)}\")\n \n # Split the dataset into train and test sets (80% train, 20% test)\n split_dataset = dataset.train_test_split(test_size=0.2)\n print(f\"Train dataset size: {len(split_dataset['train'])}\")\n print(f\"Test dataset size: {len(split_dataset['test'])}\")\n \n return split_dataset\n\ndef save_dataset_to_jsonl(dataset, filepath):\n \"\"\"\n Save a dataset to a JSONL file.\n \"\"\"\n # Create the directory if it does not exist\n os.makedirs(os.path.dirname(filepath), exist_ok=True)\n \n # Open the file in write mode\n with open(filepath, 'w', encoding='utf-8') as f:\n # Iterate over each record in the dataset\n for record in dataset:\n # Dump the record as a JSON object and write it to the file\n json.dump(record, f)\n # Write a newline character to separate records\n f.write('\\n')\n \n print(f\"Dataset saved to {filepath}\")\n\ndef main():\n \"\"\"\n Main function to load, split, and save the dataset.\n \"\"\"\n # Load and split the ULTRACHAT_200k dataset with a specific configuration and split ratio\n dataset = load_and_split_dataset(\"HuggingFaceH4/ultrachat_200k\", 'default', 'train_sft[:1%]')\n \n # Extract the train and test datasets from the split\n train_dataset = dataset['train']\n test_dataset = dataset['test']\n\n # Save the train dataset to a JSONL file\n save_dataset_to_jsonl(train_dataset, TRAIN_DATA_PATH)\n \n # Save the test dataset to a separate JSONL file\n save_dataset_to_jsonl(test_dataset, TEST_DATA_PATH)\n\nif __name__ == \"__main__\":\n main()\n\n
\n
\n
Tip\n
Guidance for fine-tuning with a minimal dataset using a CPU
\n
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
Type the following command inside your terminal to run the script and download the dataset to your local environment.
\n
python download_dataset.py\n
\n
\n
\n
Verify that the datasets were saved successfully to your localfinetune-phi/datadirectory.
\n
\n\n
\n
Note\n
Note on dataset size and fine-tuning time
\n
In this tutorial, you use only 1% of the dataset (train_sft[:1%]). This significantly reduces the amount of data, speeding up both the upload and fine-tuning processes. You can adjust the percentage to find the right balance between training time and model performance. Using a smaller subset of the dataset reduces the time required for fine-tuning, making the process more manageable for a tutorial.
\n
\n
\n
\n
Series 2: Fine-tune and Deploy the Phi-3 model
\n
\n
Fine-tune the Phi-3 model
\n
\n
In this exercise, you will fine-tune the Phi-3 model using the provided dataset. First, you will define the fine-tuning process in thefine_tune.pyfile. Then, you will configure the Azure Machine Learning environment and initiate the fine-tuning process by running thesetup_ml.pyfile. This script ensures that the fine-tuning occurs within the Azure Machine Learning environment.
\n
By runningsetup_ml.py, you will run the fine-tuning process in the Azure Machine Learning environment.
\n
In this exercise, you will:
\n
\n
Set up Azure CLI to authenticate environment
\n
Add code to thefine_tune.pyfile to fine-tune the model.
\n
Add code to and run thesetup_ml.pyfile to initiate the fine-tuning process in Azure Machine Learning.
\n
Run thesetup_ml.pyfile to fine-tune the Phi-3 model using Azure Machine Learning.
\n
\n
\n
Set up Azure CLI
\n
\n
You need to set up Azure CLI to authenticate your environment. Azure CLI allows you to manage Azure resources directly from the command line and provides the credentials necessary for Azure Machine Learning to access these resources. To get started installAzure CLI
\n\n
\n
Open a terminal window and type the following command to log in to your Azure account.
\n
az login\n
\n
\n
\n
Select your Azure account to use.
\n
\n
\n
Select your Azure subscription to use.
\n
\n
\n
\n\n
\n
\n
\n\n
\n
Tip\n
Having trouble signing in to Azure? Try using a device code
\n
\n\n
Open a terminal window and type the following command to log in to your Azure account.
\n
az login --use-device-code
\n
\n\n\n
Visit the website displayed in the terminal window and enter the provided code on that site.
\n\n
\n\n
Inside the website, selectNext.
\n
\n
\n
Inside the website, select the account to use in this tutorial
\n
\n
\n
Inside the website, selectcontinueto complete login.
\n
After successful login, go back to your terminal and select your Azure subscription to use.
\n
\n
\n\n
\n
\n
\n
Add code to thefine_tune.pyfile
\n
\n\n
\n
Navigate to thefinetuning_dirfolder and Open thefine_tune.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intofine_tune.py.
\nimport argparse\nimport sys\nimport logging\nimport os\nfrom datasets import load_dataset\nimport torch\nimport mlflow\nfrom transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments\nfrom trl import SFTTrainer\n\n# To avoid the INVALID_PARAMETER_VALUE error in MLflow, disable MLflow integration\nos.environ[\"DISABLE_MLFLOW_INTEGRATION\"] = \"True\"\n\n# Logging setup\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n handlers=[logging.StreamHandler(sys.stdout)],\n level=logging.WARNING\n)\nlogger = logging.getLogger(__name__)\n\ndef initialize_model_and_tokenizer(model_name, model_kwargs):\n \"\"\"\n Initialize the model and tokenizer with the given pretrained model name and arguments.\n \"\"\"\n model = AutoModelForCausalLM.from_pretrained(model_name, **model_kwargs)\n tokenizer = AutoTokenizer.from_pretrained(model_name)\n tokenizer.model_max_length = 2048\n tokenizer.pad_token = tokenizer.unk_token\n tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n tokenizer.padding_side = 'right'\n return model, tokenizer\n\ndef apply_chat_template(example, tokenizer):\n \"\"\"\n Apply a chat template to tokenize messages in the example.\n \"\"\"\n messages = example[\"messages\"]\n if messages[0][\"role\"] != \"system\":\n messages.insert(0, {\"role\": \"system\", \"content\": \"\"})\n example[\"text\"] = tokenizer.apply_chat_template(\n messages, tokenize=False, add_generation_prompt=False\n )\n return example\n\ndef load_and_preprocess_data(train_filepath, test_filepath, tokenizer):\n \"\"\"\n Load and preprocess the dataset.\n \"\"\"\n train_dataset = load_dataset('json', data_files=train_filepath, split='train')\n test_dataset = load_dataset('json', data_files=test_filepath, split='train')\n column_names = list(train_dataset.features)\n\n train_dataset = train_dataset.map(\n apply_chat_template,\n fn_kwargs={\"tokenizer\": tokenizer},\n num_proc=10,\n remove_columns=column_names,\n desc=\"Applying chat template to train dataset\",\n )\n\n test_dataset = test_dataset.map(\n apply_chat_template,\n fn_kwargs={\"tokenizer\": tokenizer},\n num_proc=10,\n remove_columns=column_names,\n desc=\"Applying chat template to test dataset\",\n )\n\n return train_dataset, test_dataset\n\ndef train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, output_dir):\n \"\"\"\n Train and evaluate the model.\n \"\"\"\n training_args = TrainingArguments(\n bf16=True,\n do_eval=True,\n output_dir=output_dir,\n eval_strategy=\"epoch\",\n learning_rate=5.0e-06,\n logging_steps=20,\n lr_scheduler_type=\"cosine\",\n num_train_epochs=3,\n overwrite_output_dir=True,\n per_device_eval_batch_size=4,\n per_device_train_batch_size=4,\n remove_unused_columns=True,\n save_steps=500,\n seed=0,\n gradient_checkpointing=True,\n gradient_accumulation_steps=1,\n warmup_ratio=0.2,\n )\n\n trainer = SFTTrainer(\n model=model,\n args=training_args,\n train_dataset=train_dataset,\n eval_dataset=test_dataset,\n max_seq_length=2048,\n dataset_text_field=\"text\",\n tokenizer=tokenizer,\n packing=True\n )\n\n train_result = trainer.train()\n trainer.log_metrics(\"train\", train_result.metrics)\n\n mlflow.transformers.log_model(\n transformers_model={\"model\": trainer.model, \"tokenizer\": tokenizer},\n artifact_path=output_dir,\n )\n\n tokenizer.padding_side = 'left'\n eval_metrics = trainer.evaluate()\n eval_metrics[\"eval_samples\"] = len(test_dataset)\n trainer.log_metrics(\"eval\", eval_metrics)\n\ndef main(train_file, eval_file, model_output_dir):\n \"\"\"\n Main function to fine-tune the model.\n \"\"\"\n model_kwargs = {\n \"use_cache\": False,\n \"trust_remote_code\": True,\n \"torch_dtype\": torch.bfloat16,\n \"device_map\": None,\n \"attn_implementation\": \"eager\"\n }\n \n pretrained_model_name = \"microsoft/Phi-3.5-mini-instruct\"\n # pretrained_model_name = \"microsoft/Phi-3-mini-4k-instruct\"\n\n with mlflow.start_run():\n model, tokenizer = initialize_model_and_tokenizer(pretrained_model_name, model_kwargs)\n train_dataset, test_dataset = load_and_preprocess_data(train_file, eval_file, tokenizer)\n train_and_evaluate_model(train_dataset, test_dataset, model, tokenizer, model_output_dir)\n\nif __name__ == \"__main__\":\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--train-file\", type=str, required=True, help=\"Path to the training data\")\n parser.add_argument(\"--eval-file\", type=str, required=True, help=\"Path to the evaluation data\")\n parser.add_argument(\"--model_output_dir\", type=str, required=True, help=\"Directory to save the fine-tuned model\")\n args = parser.parse_args()\n main(args.train_file, args.eval_file, args.model_output_dir)\n\n
\n
\n
\n
Save and close thefine_tune.pyfile.
\n
\n\n
\n
\n
Tip\n
You can fine-tune Phi-3.5 model
\n
In fine_tune.py file, you can change the pretrained_model_name from \"microsoft/Phi-3-mini-4k-instruct\" to any model you want to fine-tune. For example, if you change it to \"microsoft/Phi-3.5-mini-instruct\", you'll be using the Phi-3.5-mini-instruct model for fine-tuning. To find and use the model name you prefer, visit Hugging Face, search for the model you're interested in, and then copy and paste its name into the pretrained_model_name field in your script.
\n
\n
\n
\n
Add code to thesetup_ml.pyfile
\n
\n\n
\n
Open thesetup_ml.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intosetup_ml.py.
\nimport logging\nfrom azure.ai.ml import MLClient, command, Input\nfrom azure.ai.ml.entities import Environment, AmlCompute\nfrom azure.identity import AzureCliCredential\nfrom config import (\n AZURE_SUBSCRIPTION_ID,\n AZURE_RESOURCE_GROUP_NAME,\n AZURE_ML_WORKSPACE_NAME,\n TRAIN_DATA_PATH,\n TEST_DATA_PATH\n)\n\n# Constants\n\n# Uncomment the following lines to use a CPU instance for training\n# COMPUTE_INSTANCE_TYPE = \"Standard_E16s_v3\" # cpu\n# COMPUTE_NAME = \"cpu-e16s-v3\"\n# DOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest\"\n\n# Uncomment the following lines to use a GPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_NC24ads_A100_v4\"\nCOMPUTE_NAME = \"gpu-nc24s-a100-v4\"\nDOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/curated/acft-hf-nlp-gpu:59\"\n\nCONDA_FILE = \"conda.yml\"\nLOCATION = \"eastus2\" # Replace with the location of your compute cluster\nFINETUNING_DIR = \"./finetuning_dir\" # Path to the fine-tuning script\nTRAINING_ENV_NAME = \"phi-3-training-environment\" # Name of the training environment\nMODEL_OUTPUT_DIR = \"./model_output\" # Path to the model output directory in azure ml\n\n# Logging setup to track the process\nlogger = logging.getLogger(__name__)\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.WARNING\n)\n\ndef get_ml_client():\n \"\"\"\n Initialize the ML Client using Azure CLI credentials.\n \"\"\"\n credential = AzureCliCredential()\n return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)\n\ndef create_or_get_environment(ml_client):\n \"\"\"\n Create or update the training environment in Azure ML.\n \"\"\"\n env = Environment(\n image=DOCKER_IMAGE_NAME, # Docker image for the environment\n conda_file=CONDA_FILE, # Conda environment file\n name=TRAINING_ENV_NAME, # Name of the environment\n )\n return ml_client.environments.create_or_update(env)\n\ndef create_or_get_compute_cluster(ml_client, compute_name, COMPUTE_INSTANCE_TYPE, location):\n \"\"\"\n Create or update the compute cluster in Azure ML.\n \"\"\"\n try:\n compute_cluster = ml_client.compute.get(compute_name)\n logger.info(f\"Compute cluster '{compute_name}' already exists. Reusing it for the current run.\")\n except Exception:\n logger.info(f\"Compute cluster '{compute_name}' does not exist. Creating a new one with size {COMPUTE_INSTANCE_TYPE}.\")\n compute_cluster = AmlCompute(\n name=compute_name,\n size=COMPUTE_INSTANCE_TYPE,\n location=location,\n tier=\"Dedicated\", # Tier of the compute cluster\n min_instances=0, # Minimum number of instances\n max_instances=1 # Maximum number of instances\n )\n ml_client.compute.begin_create_or_update(compute_cluster).wait() # Wait for the cluster to be created\n return compute_cluster\n\ndef create_fine_tuning_job(env, compute_name):\n \"\"\"\n Set up the fine-tuning job in Azure ML.\n \"\"\"\n return command(\n code=FINETUNING_DIR, # Path to fine_tune.py\n command=(\n \"python fine_tune.py \"\n \"--train-file ${{inputs.train_file}} \"\n \"--eval-file ${{inputs.eval_file}} \"\n \"--model_output_dir ${{inputs.model_output}}\"\n ),\n environment=env, # Training environment\n compute=compute_name, # Compute cluster to use\n inputs={\n \"train_file\": Input(type=\"uri_file\", path=TRAIN_DATA_PATH), # Path to the training data file\n \"eval_file\": Input(type=\"uri_file\", path=TEST_DATA_PATH), # Path to the evaluation data file\n \"model_output\": MODEL_OUTPUT_DIR\n }\n )\n\ndef main():\n \"\"\"\n Main function to set up and run the fine-tuning job in Azure ML.\n \"\"\"\n # Initialize ML Client\n ml_client = get_ml_client()\n\n # Create Environment\n env = create_or_get_environment(ml_client)\n \n # Create or get existing compute cluster\n create_or_get_compute_cluster(ml_client, COMPUTE_NAME, COMPUTE_INSTANCE_TYPE, LOCATION)\n\n # Create and Submit Fine-Tuning Job\n job = create_fine_tuning_job(env, COMPUTE_NAME)\n returned_job = ml_client.jobs.create_or_update(job) # Submit the job\n ml_client.jobs.stream(returned_job.name) # Stream the job logs\n \n # Capture the job name\n job_name = returned_job.name\n print(f\"Job name: {job_name}\")\n\nif __name__ == \"__main__\":\n main()\n\n
\n
\n
\n
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andLOCATIONwith your specific details.
\n
# Uncomment the following lines to use a GPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_NC24ads_A100_v4\"\nCOMPUTE_NAME = \"gpu-nc24s-a100-v4\"\n...\nLOCATION = \"eastus2\"# Replace with the location of your compute cluster\n
\n
\n\n
\n
\n
\n
\n
Tip\n
Guidance for fine-tuning with a minimal dataset using a CPU
\n
\n
If you want to use a CPU for fine-tuning, this approach is ideal for those with benefit subscriptions (such as Visual Studio Enterprise Subscription) or to quickly test the fine-tuning and deployment process.
\n\n
Open thesetup_mlfile.
\n
ReplaceCOMPUTE_INSTANCE_TYPE,COMPUTE_NAME, andDOCKER_IMAGE_NAMEwith the following. If you do not have access toStandard_E16s_v3, you can use an equivalent CPU instance or request a new quota.
\n
Replace LOCATIONwith your specific details.
\n\n
\n
# Uncomment the following lines to use a CPU instance for training\nCOMPUTE_INSTANCE_TYPE = \"Standard_E16s_v3\"# cpu\nCOMPUTE_NAME = \"cpu-e16s-v3\"\nDOCKER_IMAGE_NAME = \"mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest\"\nLOCATION = \"eastus2\"# Replace with the location of your compute cluster
\n
\n
\n
\n
\n
\n\n
\n
Type the following command to run thesetup_ml.pyscript and start the fine-tuning process in Azure Machine Learning.
\n
python setup_ml.py\n
\n
\n
\n
In this exercise, you successfully fine-tuned the Phi-3 model using Azure Machine Learning. By running thesetup_ml.pyscript, you have set up the Azure Machine Learning environment and initiated the fine-tuning process defined infine_tune.pyfile. Please note that the fine-tuning process can take a considerable amount of time. After running thepython setup_ml.pycommand, you need to wait for the process to complete. You can monitor the status of the fine-tuning job by following the link provided in the terminal to the Azure Machine Learning portal. In the next series, you will deploy the fine-tuned model and integrate it with Prompt flow.
\n\n
\n
\n\n
\n
Deploy the fine-tuned model
\n
\n
To integrate the fine-tuned Phi-3 model with Prompt Flow, you need to deploy the model to make it accessible for real-time inference. This process involves registering the model, creating an online endpoint, and deploying the model.
\n
In this exercise, you will:
\n
\n
Set the model name, endpoint name, and deployment name for deployment.
\n
Register the fine-tuned model in the Azure Machine Learning workspace.
\n
Create an online endpoint.
\n
Deploy the registered fine-tuned Phi-3 model.
\n
\n
Set the model name, endpoint name, and deployment name for deployment
\n
\n\n
\n
Openconfig.pyfile.
\n
\n
\n
ReplaceAZURE_MODEL_NAME = \"your_fine_tuned_model_name\"with the desired name for your model.
\n
\n
\n
ReplaceAZURE_ENDPOINT_NAME = \"your_fine_tuned_model_endpoint_name\"with the desired name for your endpoint.
\n
\n
\n
ReplaceAZURE_DEPLOYMENT_NAME = \"your_fine_tuned_model_deployment_name\"with the desired name for your deployment.
\n
\n\n
Deploy the fine-tuned model
\n
\n
Running thedeploy_model.pyfile automates the entire deployment process. It registers the model, creates an endpoint, and executes the deployment based on the settings specified in the config.py file, which includes the model name, endpoint name, and deployment name.
\n\n
\n
Open thedeploy_model.pyfile in Visual Studio Code.
\n
\n
\n
Add the following code intodeploy_model.py.
\nimport logging\nfrom azure.identity import AzureCliCredential\nfrom azure.ai.ml import MLClient\nfrom azure.ai.ml.entities import Model, ProbeSettings, ManagedOnlineEndpoint, ManagedOnlineDeployment, IdentityConfiguration, ManagedIdentityConfiguration, OnlineRequestSettings\nfrom azure.ai.ml.constants import AssetTypes\n\n# Configuration imports\nfrom config import (\n AZURE_SUBSCRIPTION_ID,\n AZURE_RESOURCE_GROUP_NAME,\n AZURE_ML_WORKSPACE_NAME,\n AZURE_MANAGED_IDENTITY_RESOURCE_ID,\n AZURE_MANAGED_IDENTITY_CLIENT_ID,\n AZURE_MODEL_NAME,\n AZURE_ENDPOINT_NAME,\n AZURE_DEPLOYMENT_NAME\n)\n\n# Constants\nJOB_NAME = \"your-job-name\"\nCOMPUTE_INSTANCE_TYPE = \"Standard_E4s_v3\"\n\ndeployment_env_vars = {\n \"SUBSCRIPTION_ID\": AZURE_SUBSCRIPTION_ID,\n \"RESOURCE_GROUP_NAME\": AZURE_RESOURCE_GROUP_NAME,\n \"UAI_CLIENT_ID\": AZURE_MANAGED_IDENTITY_CLIENT_ID,\n}\n\n# Logging setup\nlogging.basicConfig(\n format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n datefmt=\"%Y-%m-%d %H:%M:%S\",\n level=logging.DEBUG\n)\nlogger = logging.getLogger(__name__)\n\ndef get_ml_client():\n \"\"\"Initialize and return the ML Client.\"\"\"\n credential = AzureCliCredential()\n return MLClient(credential, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP_NAME, AZURE_ML_WORKSPACE_NAME)\n\ndef register_model(ml_client, model_name, job_name):\n \"\"\"Register a new model.\"\"\"\n model_path = f\"azureml://jobs/{job_name}/outputs/artifacts/paths/model_output\"\n logger.info(f\"Registering model {model_name} from job {job_name} at path {model_path}.\")\n run_model = Model(\n path=model_path,\n name=model_name,\n description=\"Model created from run.\",\n type=AssetTypes.MLFLOW_MODEL,\n )\n model = ml_client.models.create_or_update(run_model)\n logger.info(f\"Registered model ID: {model.id}\")\n return model\n\ndef delete_existing_endpoint(ml_client, endpoint_name):\n \"\"\"Delete existing endpoint if it exists.\"\"\"\n try:\n endpoint_result = ml_client.online_endpoints.get(name=endpoint_name)\n logger.info(f\"Deleting existing endpoint {endpoint_name}.\")\n ml_client.online_endpoints.begin_delete(name=endpoint_name).result()\n logger.info(f\"Deleted existing endpoint {endpoint_name}.\")\n except Exception as e:\n logger.info(f\"No existing endpoint {endpoint_name} found to delete: {e}\")\n\ndef create_or_update_endpoint(ml_client, endpoint_name, description=\"\"):\n \"\"\"Create or update an endpoint.\"\"\"\n delete_existing_endpoint(ml_client, endpoint_name)\n logger.info(f\"Creating new endpoint {endpoint_name}.\")\n endpoint = ManagedOnlineEndpoint(\n name=endpoint_name,\n description=description,\n identity=IdentityConfiguration(\n type=\"user_assigned\",\n user_assigned_identities=[ManagedIdentityConfiguration(resource_id=AZURE_MANAGED_IDENTITY_RESOURCE_ID)]\n )\n )\n endpoint_result = ml_client.online_endpoints.begin_create_or_update(endpoint).result()\n logger.info(f\"Created new endpoint {endpoint_name}.\")\n return endpoint_result\n\ndef create_or_update_deployment(ml_client, endpoint_name, deployment_name, model):\n \"\"\"Create or update a deployment.\"\"\"\n\n logger.info(f\"Creating deployment {deployment_name} for endpoint {endpoint_name}.\")\n deployment = ManagedOnlineDeployment(\n name=deployment_name,\n endpoint_name=endpoint_name,\n model=model.id,\n instance_type=COMPUTE_INSTANCE_TYPE,\n instance_count=1,\n environment_variables=deployment_env_vars,\n request_settings=OnlineRequestSettings(\n max_concurrent_requests_per_instance=3,\n request_timeout_ms=180000,\n max_queue_wait_ms=120000\n ),\n liveness_probe=ProbeSettings(\n failure_threshold=30,\n success_threshold=1,\n period=100,\n initial_delay=500,\n ),\n readiness_probe=ProbeSettings(\n failure_threshold=30,\n success_threshold=1,\n period=100,\n initial_delay=500,\n ),\n )\n deployment_result = ml_client.online_deployments.begin_create_or_update(deployment).result()\n logger.info(f\"Created deployment {deployment.name} for endpoint {endpoint_name}.\")\n return deployment_result\n\ndef set_traffic_to_deployment(ml_client, endpoint_name, deployment_name):\n \"\"\"Set traffic to the specified deployment.\"\"\"\n try:\n # Fetch the current endpoint details\n endpoint = ml_client.online_endpoints.get(name=endpoint_name)\n \n # Log the current traffic allocation for debugging\n logger.info(f\"Current traffic allocation: {endpoint.traffic}\")\n \n # Set the traffic allocation for the deployment\n endpoint.traffic = {deployment_name: 100}\n \n # Update the endpoint with the new traffic allocation\n endpoint_poller = ml_client.online_endpoints.begin_create_or_update(endpoint)\n updated_endpoint = endpoint_poller.result()\n \n # Log the updated traffic allocation for debugging\n logger.info(f\"Updated traffic allocation: {updated_endpoint.traffic}\")\n logger.info(f\"Set traffic to deployment {deployment_name} at endpoint {endpoint_name}.\")\n return updated_endpoint\n except Exception as e:\n # Log any errors that occur during the process\n logger.error(f\"Failed to set traffic to deployment: {e}\")\n raise\n\n\ndef main():\n ml_client = get_ml_client()\n\n registered_model = register_model(ml_client, AZURE_MODEL_NAME, JOB_NAME)\n logger.info(f\"Registered model ID: {registered_model.id}\")\n\n endpoint = create_or_update_endpoint(ml_client, AZURE_ENDPOINT_NAME, \"Endpoint for finetuned Phi-3 model\")\n logger.info(f\"Endpoint {AZURE_ENDPOINT_NAME} is ready.\")\n\n try:\n deployment = create_or_update_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME, registered_model)\n logger.info(f\"Deployment {AZURE_DEPLOYMENT_NAME} is created for endpoint {AZURE_ENDPOINT_NAME}.\")\n\n set_traffic_to_deployment(ml_client, AZURE_ENDPOINT_NAME, AZURE_DEPLOYMENT_NAME)\n logger.info(f\"Traffic is set to deployment {AZURE_DEPLOYMENT_NAME} at endpoint {AZURE_ENDPOINT_NAME}.\")\n except Exception as e:\n logger.error(f\"Failed to create or update deployment: {e}\")\n\nif __name__ == \"__main__\":\n main()\n\n
\n
\n
\n
Perform the following tasks to get theJOB_NAME:
\n
\n
Navigate to Azure Machine Learning resource that you created.
\n
SelectStudio web URLto open the Azure Machine Learning workspace.
\n
SelectJobsfrom the left side tab.
\n
Select the experiment for fine-tuning. For example,finetunephi.
\n
Select the job that you created.
\n
Copy and paste your job Name into theJOB_NAME = \"your-job-name\"indeploy_model.pyfile.
\n
\n
\n
\n
ReplaceCOMPUTE_INSTANCE_TYPEwith your specific details.
\n
\n
\n
Type the following command to run thedeploy_model.pyscript and start the deployment process in Azure Machine Learning.
\n
python deploy_model.py
\n
\n\n
\n
Warning\n
To avoid additional charges to your account, make sure to delete the created endpoint in the Azure Machine Learning workspace.
\n
\n
\n
\n
Check deployment status in Azure Machine Learning Workspace
Navigate to Azure Machine Learning workspace that you created.
\n
\n
\n
SelectStudio web URLto open the Azure Machine Learning workspace.
\n
\n
Select Endpoints from the left side tab.\n
\n
\n
\n\n
\n
\n
\n
\n
Select endpoint that you created.
\n
\n
\n
\n\n
\n
\n
\n
\n
On this page, you can manage the endpoints created during the deployment process.
\n
\n\n
\n
Series 3: Integrate the custom Phi-3 model with Prompt flow
\n
Integrate the custom Phi-3 model with Prompt Flow
\n
\n
After successfully deploying your fine-tuned model, you can now integrate it with Prompt Flow to use your model in real-time applications, enabling a variety of interactive tasks with your custom Phi-3 model.
\n
In this exercise, you will:
\n
\n
\n
Set api key and endpoint uri of the fine-tuned Phi-3 model.
\n
Add code to theflow.dag.ymlfile.
\n
Add code to theintegrate_with_promptflow.pyfile.
\n
Test your custom Phi-3 model on Prompt flow.
\n
\n
\n
Set api key and endpoint uri of the fine-tuned Phi-3 model
\n
\n\n
\n
Navigate to the Azure Machine learning workspace that you created.
Here's an example of the results: Now you can chat with your custom Phi-3 model. It is recommended to ask questions based on the data used for fine-tuning.
\n
\n
\n
\n
\n
\n
\n
\n\n
Congratulations!
\n
\n
You've completed this tutorial
\n
\n
Congratulations! You have successfully completed the tutorial on fine-tuning and integrating custom Phi-3 models with Prompt flow. This tutorial introduced the simplest method of fine-tuning, avoiding additional techniques such as LoRA or QLoRA, and using MLflow to streamline the fine-tuning and deployment process. Advanced techniques and detailed explanations will be covered in the next series.
\n
\n
\n
\n\n
\n
\n
Clean Up Azure Resources
\n
\n
Cleanup your Azure resources to avoid additional charges to your account. Go to the Azure portal and delete the following resources:
\n
\n
The Azure Machine Learning resource.
\n
The Azure Machine Learning model endpoint.
\n
\n
\n
Source Code for the Tutorial
\n
\n
You can find the complete source code for this tutorial in the following repository:
In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt Flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models.
\n
","introduction":"","coverImage":null,"coverImageProperties":{"__typename":"CoverImageProperties","style":"STANDARD","titlePosition":"BOTTOM","altText":""},"currentRevision":{"__ref":"Revision:revision:4178612_73"},"latestVersion":{"__typename":"FriendlyVersion","major":"11","minor":"0"},"metrics":{"__typename":"MessageMetrics","views":31262},"visibilityScope":"PUBLIC","canonicalUrl":null,"seoTitle":"Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow","seoDescription":"Phi-3 is a family of small language models (SLMs) developed by Microsoft that delivers exceptional performance and cost-effectiveness. In this tutorial, you will learn how to fine-tune the Phi-3 model and integrate it with Prompt Flow. By leveraging Azure Machine Learning, and Prompt flow you will establish a workflow for deploying and utilizing custom AI models.","placeholder":false,"originalMessageForPlaceholder":null,"contributors":{"__typename":"UserConnection","edges":[]},"nonCoAuthorContributors":{"__typename":"UserConnection","edges":[]},"coAuthors":{"__typename":"UserConnection","edges":[]},"blogMessagePolicies":{"__typename":"BlogMessagePolicies","canDoAuthoringActionsOnBlog":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.blog.action_can_do_authoring_action.accessDenied","key":"error.lithium.policies.blog.action_can_do_authoring_action.accessDenied","args":[]}}},"archivalData":null,"replies":{"__typename":"MessageConnection","edges":[{"__typename":"MessageEdge","cursor":"MjUuMXwyLjF8aXwxMHwxMzI6MHxpbnQsNDIwMDY2Myw0MjAwNjYz","node":{"__ref":"BlogReplyMessage:message:4200663"}}],"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"customFields":[],"revisions({\"constraints\":{\"isPublished\":{\"eq\":true}},\"first\":1})":{"__typename":"RevisionConnection","totalCount":73}},"Conversation:conversation:4178612":{"__typename":"Conversation","id":"conversation:4178612","solved":false,"topic":{"__ref":"BlogTopicMessage:message:4178612"},"lastPostingActivityTime":"2024-09-02T01:15:43.376-07:00","lastPostTime":"2024-07-24T17:15:06.474-07:00","unreadReplyCount":1,"isSubscribed":false},"ModerationData:moderation_data:4178612":{"__typename":"ModerationData","id":"moderation_data:4178612","status":"APPROVED","rejectReason":null,"isReportedAbuse":false,"rejectUser":null,"rejectTime":null,"rejectActorType":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5Mmk3ODRDM0ZFODZENUIxMDQy?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5Mmk3ODRDM0ZFODZENUIxMDQy?revision=73","title":"00-1-architecture.png","associationType":"BODY","width":8008,"height":3172,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxMWlGRDVENDE3MDI3NzUxOUI4?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxMWlGRDVENDE3MDI3NzUxOUI4?revision=73","title":"01-1-type-azml.png","associationType":"BODY","width":873,"height":280,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxMmk5QThGRDE3M0MwNjJCNTg1?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxMmk5QThGRDE3M0MwNjJCNTg1?revision=73","title":"01-2-select-new-workspace.png","associationType":"BODY","width":967,"height":378,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTYwMzAzNGlBM0NFN0RBOEQ1NTFBMDBE?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTYwMzAzNGlBM0NFN0RBOEQ1NTFBMDBE?revision=73","title":"01-03-fill-AZML.png","associationType":"BODY","width":1495,"height":1210,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTYwMzAzNWkyOTEzOTFFRTNBN0U0OThB?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTYwMzAzNWkyOTEzOTFFRTNBN0U0OThB?revision=73","title":"01-04-request-quota.png","associationType":"BODY","width":1807,"height":817,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxNWk5MEMwN0NBNUFCRjAzQjdD?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxNWk5MEMwN0NBNUFCRjAzQjdD?revision=73","title":"02-7-type-managed-identities.png","associationType":"BODY","width":876,"height":279,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxNmlEMDRFNTRBRDY4RDM3QjUy?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxNmlEMDRFNTRBRDY4RDM3QjUy?revision=73","title":"02-8-select-create.png","associationType":"BODY","width":913,"height":216,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxN2lBQTdFNTgwN0U1MjBFNkEy?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxN2lBQTdFNTgwN0U1MjBFNkEy?revision=73","title":"02-9-fill-managed-identities-1.png","associationType":"BODY","width":1165,"height":691,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxOGlEM0Q2N0Y1QzA0RjNBMjEz?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxOGlEM0Q2N0Y1QzA0RjNBMjEz?revision=73","title":"02-0-fill-contributor-role.png","associationType":"BODY","width":1293,"height":751,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxOWlDQjc1QzgzMTBDRDAxMURF?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgxOWlDQjc1QzgzMTBDRDAxMURF?revision=73","title":"02-1-type-storage-accounts.png","associationType":"BODY","width":868,"height":280,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyMWkyMzZGQTBCMTU5RDEyNTk0?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyMWkyMzZGQTBCMTU5RDEyNTk0?revision=73","title":"02-3-add-role.png","associationType":"BODY","width":1147,"height":325,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyMmk0NEVDMDBGQ0EwMzczMzMx?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyMmk0NEVDMDBGQ0EwMzczMzMx?revision=73","title":"02-4-select-data-reader-role.png","associationType":"BODY","width":1264,"height":541,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5M2kyNkI0ODdCQjY2QTEzMUY4?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5M2kyNkI0ODdCQjY2QTEzMUY4?revision=73","title":"02-5-select-managed-identity.png","associationType":"BODY","width":1551,"height":757,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNGk1NkY3REU5QUQ1MTcyMTA4?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNGk1NkY3REU5QUQ1MTcyMTA4?revision=73","title":"02-10-type-container-registries.png","associationType":"BODY","width":871,"height":280,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNWk3RDQ2MkNFOTA4NTUxNzkx?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNWk3RDQ2MkNFOTA4NTUxNzkx?revision=73","title":"04-1-open-project-folder.png","associationType":"BODY","width":985,"height":270,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNmkwODBGNDlBRkM4Mjg2QTA1?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyNmkwODBGNDlBRkM4Mjg2QTA1?revision=73","title":"04-2-create-new-file.png","associationType":"BODY","width":967,"height":295,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyN2lBRDU1RjIyMDFDMUVDNTgz?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgyN2lBRDU1RjIyMDFDMUVDNTgz?revision=73","title":"05-3-type-subscriptions.png","associationType":"BODY","width":870,"height":279,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzMGk1RjFENDZEOTY3RDlDRjY2?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzMGk1RjFENDZEOTY3RDlDRjY2?revision=73","title":"05-4-find-subscriptionid.png","associationType":"BODY","width":1051,"height":265,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzNWkzMjczQzFEM0I1QUM1RUEz?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzNWkzMjczQzFEM0I1QUM1RUEz?revision=73","title":"05-5-find-AZML-name.png","associationType":"BODY","width":856,"height":274,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzMmkxRkNEMEZCRkVCQkY5MjdF?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzMmkxRkNEMEZCRkVCQkY5MjdF?revision=73","title":"05-6-find-AZML-resourcegroup.png","associationType":"BODY","width":856,"height":274,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5NWlFNzU0Q0U2N0UwODMxNDZB?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NzI5NWlFNzU0Q0U2N0UwODMxNDZB?revision=73","title":"05-9-find-uai.png","associationType":"BODY","width":2254,"height":468,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzOGlBOEY2MThDMEUyMTFCRDVD?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzOGlBOEY2MThDMEUyMTFCRDVD?revision=73","title":"07-1-azlogin.png","associationType":"BODY","width":1639,"height":421,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzOWk4MTc3RjEzQjE2OTJGRDcx?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTgzOWk4MTc3RjEzQjE2OTJGRDcx?revision=73","title":"07-1-az-login.png","associationType":"BODY","width":1698,"height":441,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTg0MGk5NTQyREQ0OUExRTg3OUJB?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTg0MGk5NTQyREQ0OUExRTg3OUJB?revision=73","title":"07-2-type-code.png","associationType":"BODY","width":988,"height":588,"altText":null},"AssociatedImage:{\"url\":\"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTg0MWlEM0NFQTA0NDBCRUQ2Qjgx?revision=73\"}":{"__typename":"AssociatedImage","url":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/images/bS00MTc4NjEyLTU5NTg0MWlEM0NFQTA0NDBCRUQ2Qjgx?revision=73","title":"07-3-select-account.png","associationType":"BODY","width":1594,"height":592,"altText":null},"Revision:revision:4178612_73":{"__typename":"Revision","id":"revision:4178612_73","lastEditTime":"2024-08-31T23:29:42.462-07:00"},"CachedAsset:theme:customTheme1-1744410070919":{"__typename":"CachedAsset","id":"theme:customTheme1-1744410070919","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["default"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"favicon-1730836283320.png","imageLastModified":"1730836286415","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"favicon-1730836271365.png","imageLastModified":"1730836274203","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1300px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_BROWSER","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"3px","borderRadius":"3px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"16px","paddingXHero":"60px","fontStyle":"NORMAL","fontWeight":"700","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-200)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-200)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-200-h), var(--lia-bs-gray-200-s), calc(var(--lia-bs-gray-200-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"LIGHT","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.16)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.12)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.3)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-link-color)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#4099E2","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#148563","blogColor":"#1CBAA0","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#4C6B90","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#FF8000","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#D13A1F","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#333333","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#717171","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0069D4","secondary":"#333333","bodyText":"#1E1E1E","bodyBg":"#FFFFFF","info":"#409AE2","success":"#41C5AE","warning":"#FCC844","danger":"#BC341B","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#D3F5A4","#243A5E"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Segoe UI","fontStyle":"NORMAL","fontWeight":"400","h1FontSize":"34px","h2FontSize":"32px","h3FontSize":"28px","h4FontSize":"24px","h5FontSize":"20px","h6FontSize":"16px","lineHeight":"1.3","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":"","imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"40px","defaultMessageHeaderMarginBottom":"20px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"40px","specialMessageHeaderMarginBottom":"20px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Segoe UI","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.5","fontSizeBase":"16px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"14px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[{"source":"SERVER","name":"Segoe UI","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"},{"style":"NORMAL","weight":"300","__typename":"FontStyleData"},{"style":"NORMAL","weight":"600","__typename":"FontStyleData"},{"style":"NORMAL","weight":"700","__typename":"FontStyleData"},{"style":"ITALIC","weight":"400","__typename":"FontStyleData"}],"assetNames":["SegoeUI-normal-400.woff2","SegoeUI-normal-300.woff2","SegoeUI-normal-600.woff2","SegoeUI-normal-700.woff2","SegoeUI-italic-400.woff2"],"__typename":"CustomFont"},{"source":"SERVER","name":"MWF Fluent Icons","styles":[{"style":"NORMAL","weight":"400","__typename":"FontStyleData"}],"assetNames":["MWFFluentIcons-normal-400.woff2"],"__typename":"CustomFont"}],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1745160788452","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1745160788452","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:quilt:o365.prod:pages/blogs/BlogMessagePage:board:EducatorDeveloperBlog-1744984043142":{"__typename":"CachedAsset","id":"quilt:o365.prod:pages/blogs/BlogMessagePage:board:EducatorDeveloperBlog-1744984043142","value":{"id":"BlogMessagePage","container":{"id":"Common","headerProps":{"backgroundImageProps":null,"backgroundColor":null,"addComponents":null,"removeComponents":["community.widget.bannerWidget"],"componentOrder":null,"__typename":"QuiltContainerSectionProps"},"headerComponentProps":{"community.widget.breadcrumbWidget":{"disableLastCrumbForDesktop":false}},"footerProps":null,"footerComponentProps":null,"items":[{"id":"blog-article","layout":"ONE_COLUMN","bgColor":null,"showTitle":null,"showDescription":null,"textPosition":null,"textColor":null,"sectionEditLevel":"LOCKED","bgImage":null,"disableSpacing":null,"edgeToEdgeDisplay":null,"fullHeight":null,"showBorder":null,"__typename":"OneColumnQuiltSection","columnMap":{"main":[{"id":"blogs.widget.blogArticleWidget","className":"lia-blog-container","props":null,"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"}},{"id":"section-1729184836777","layout":"MAIN_SIDE","bgColor":"transparent","showTitle":false,"showDescription":false,"textPosition":"CENTER","textColor":"var(--lia-bs-body-color)","sectionEditLevel":null,"bgImage":null,"disableSpacing":null,"edgeToEdgeDisplay":null,"fullHeight":null,"showBorder":null,"__typename":"MainSideQuiltSection","columnMap":{"main":[],"side":[],"__typename":"MainSideSectionColumns"}}],"__typename":"QuiltContainer"},"__typename":"Quilt","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-pages/blogs/BlogMessagePage-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-pages/blogs/BlogMessagePage-1745160788452","value":{"title":"{contextMessageSubject} | {communityTitle}","errorMissing":"This blog post cannot be found","name":"Blog Message Page","section.blog-article.title":"Blog Post","archivedMessageTitle":"This Content Has Been Archived","section.section-1729184836777.title":"","section.section-1729184836777.description":"","section.CncIde.title":"Blog Post","section.tifEmD.description":"","section.tifEmD.title":""},"localOverride":false},"CachedAsset:quiltWrapper:o365.prod:Common:1744409872390":{"__typename":"CachedAsset","id":"quiltWrapper:o365.prod:Common:1744409872390","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"community.widget.navbarWidget","props":{"showUserName":true,"showRegisterLink":true,"useIconLanguagePicker":true,"useLabelLanguagePicker":true,"className":"QuiltComponent_lia-component-edit-mode__0nCcm","links":{"sideLinks":[],"mainLinks":[{"children":[],"linkType":"INTERNAL","id":"gxcuf89792","params":{},"routeName":"CommunityPage"},{"children":[],"linkType":"EXTERNAL","id":"external-link","url":"/Directory","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft365","params":{"categoryId":"microsoft365"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-teams","params":{"categoryId":"MicrosoftTeams"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows","params":{"categoryId":"Windows"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-securityand-compliance","params":{"categoryId":"microsoft-security"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"outlook","params":{"categoryId":"Outlook"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"planner","params":{"categoryId":"Planner"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"windows-server","params":{"categoryId":"Windows-Server"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"azure","params":{"categoryId":"Azure"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"exchange","params":{"categoryId":"Exchange"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-endpoint-manager","params":{"categoryId":"microsoft-endpoint-manager"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-q-l-server","params":{"categoryId":"SQL-Server"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-2","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities","url":"/","target":"BLANK"},{"children":[{"linkType":"INTERNAL","id":"education-sector","params":{"categoryId":"EducationSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"a-i","params":{"categoryId":"AI"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"i-t-ops-talk","params":{"categoryId":"ITOpsTalk"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"partner-community","params":{"categoryId":"PartnerCommunity"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-mechanics","params":{"categoryId":"MicrosoftMechanics"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"healthcare-and-life-sciences","params":{"categoryId":"HealthcareAndLifeSciences"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"public-sector","params":{"categoryId":"PublicSector"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"io-t","params":{"categoryId":"IoT"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"driving-adoption","params":{"categoryId":"DrivingAdoption"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"s-m-b","params":{"categoryId":"SMB"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"startupsat-microsoft","params":{"categoryId":"StartupsatMicrosoft"},"routeName":"CategoryPage"},{"linkType":"EXTERNAL","id":"external-link-1","url":"/Directory","target":"SELF"}],"linkType":"EXTERNAL","id":"communities-1","url":"/","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external","url":"/Blogs","target":"SELF"},{"children":[],"linkType":"EXTERNAL","id":"external-1","url":"/Events","target":"SELF"},{"children":[{"linkType":"INTERNAL","id":"microsoft-learn-1","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"microsoft-learn-blog","params":{"boardId":"MicrosoftLearnBlog","categoryId":"MicrosoftLearn"},"routeName":"BlogBoardPage"},{"linkType":"EXTERNAL","id":"external-10","url":"https://learningroomdirectory.microsoft.com/","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-3","url":"https://docs.microsoft.com/learn/dynamics365/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-4","url":"https://docs.microsoft.com/learn/m365/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-5","url":"https://docs.microsoft.com/learn/topics/sci/?wt.mc_id=techcom_header-webpage-m365","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-6","url":"https://docs.microsoft.com/learn/powerplatform/?wt.mc_id=techcom_header-webpage-powerplatform","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-7","url":"https://docs.microsoft.com/learn/github/?wt.mc_id=techcom_header-webpage-github","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-8","url":"https://docs.microsoft.com/learn/teams/?wt.mc_id=techcom_header-webpage-teams","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-9","url":"https://docs.microsoft.com/learn/dotnet/?wt.mc_id=techcom_header-webpage-dotnet","target":"BLANK"},{"linkType":"EXTERNAL","id":"external-2","url":"https://docs.microsoft.com/learn/azure/?WT.mc_id=techcom_header-webpage-m365","target":"BLANK"}],"linkType":"INTERNAL","id":"microsoft-learn","params":{"categoryId":"MicrosoftLearn"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"community-info-center","params":{"categoryId":"Community-Info-Center"},"routeName":"CategoryPage"}]},"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","controllerHighlightColor":"hsla(30, 100%, 50%)","linkFontWeight":"400","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkBoxShadowHover":"none","linkFontSize":"14px","backgroundOpacity":0.8,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","hamburgerColor":"var(--lia-nav-controller-icon-color)","linkTextBorderBottom":"none","brandLogoHeight":"30px","linkBgHoverColor":"transparent","linkLetterSpacing":"normal","collapseMenuDividerOpacity":0.16,"dropdownPaddingBottom":"15px","paddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"1px solid var(--lia-bs-border-color)","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","collapseMenuDividerBg":"var(--lia-nav-link-color)","linkColor":"var(--lia-bs-body-color)","linkJustifyContent":"flex-start","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","controllerTextColor":"var(--lia-nav-controller-icon-color)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-body-color)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid var(--lia-bs-body-color)","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","linkPaddingX":"10px","linkPaddingY":"5px","paddingTop":"15px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkBgColor":"transparent","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkDropdownPaddingY":"9px","controllerIconColor":"var(--lia-bs-body-color)","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"var(--lia-bs-body-color)"},"showSearchIcon":false,"languagePickerStyle":"iconAndLabel"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"transparent","linkHighlightColor":"var(--lia-bs-primary)","visualEffects":{"showBottomBorder":true},"linkTextColor":"var(--lia-bs-gray-700)"},"__typename":"QuiltComponent"},{"id":"custom.widget.community_banner","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"usePageWidth":false,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.HeroBanner","props":{"widgetVisibility":"signedInOrAnonymous","usePageWidth":false,"useTitle":true,"cMax_items":3,"useBackground":false,"title":"","lazyLoad":false,"widgetChooser":"custom.widget.HeroBanner"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.MicrosoftFooter","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1745160788452","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.community_banner-en-1744410106128":{"__typename":"CachedAsset","id":"component:custom.widget.community_banner-en-1744410106128","value":{"component":{"id":"custom.widget.community_banner","template":{"id":"community_banner","markupLanguage":"HANDLEBARS","style":".community-banner {\n a.top-bar.btn {\n top: 0px;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0px;\n background: #0068b8;\n color: white;\n padding: 10px 0px;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0px !important;\n font-size: 14px;\n }\n}\n","texts":null,"defaults":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.community_banner","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"community announcement text","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_community_banner_community-banner_1x9u2_1 {\n a.custom_widget_community_banner_top-bar_1x9u2_2.custom_widget_community_banner_btn_1x9u2_2 {\n top: 0;\n width: 100%;\n z-index: 999;\n text-align: center;\n left: 0;\n background: #0068b8;\n color: white;\n padding: 0.625rem 0;\n display: block;\n box-shadow: none !important;\n border: none !important;\n border-radius: none !important;\n margin: 0 !important;\n font-size: 0.875rem;\n }\n}\n","tokens":{"community-banner":"custom_widget_community_banner_community-banner_1x9u2_1","top-bar":"custom_widget_community_banner_top-bar_1x9u2_2","btn":"custom_widget_community_banner_btn_1x9u2_2"}},"form":null},"localOverride":false},"CachedAsset:component:custom.widget.HeroBanner-en-1744410106128":{"__typename":"CachedAsset","id":"component:custom.widget.HeroBanner-en-1744410106128","value":{"component":{"id":"custom.widget.HeroBanner","template":{"id":"HeroBanner","markupLanguage":"REACT","style":null,"texts":{"searchPlaceholderText":"Search this community","followActionText":"Follow","unfollowActionText":"Following","searchOnHoverText":"Please enter your search term(s) and then press return key to complete a search.","blogs.sidebar.pagetitle":"Latest Blogs | Microsoft Tech Community","followThisNode":"Follow this node","unfollowThisNode":"Unfollow this node"},"defaults":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.HeroBanner","form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":null,"fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[{"id":"max_items","dataType":"NUMBER","list":false,"defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"control":"INPUT","__typename":"PropDefinition"}],"__typename":"ComponentProperties"},"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"},"__typename":"Component","localOverride":false},"globalCss":null,"form":{"fields":[{"id":"widgetChooser","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"title","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useTitle","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"useBackground","validation":null,"noValidation":null,"dataType":"BOOLEAN","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"widgetVisibility","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"moreOptions","validation":null,"noValidation":null,"dataType":"STRING","list":null,"control":null,"defaultValue":null,"label":null,"description":null,"possibleValues":null,"__typename":"FormField"},{"id":"cMax_items","validation":null,"noValidation":null,"dataType":"NUMBER","list":false,"control":"INPUT","defaultValue":"3","label":"Max Items","description":"The maximum number of items to display in the carousel","possibleValues":null,"__typename":"FormField"}],"layout":{"rows":[{"id":"widgetChooserGroup","type":"fieldset","as":null,"items":[{"id":"widgetChooser","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"titleGroup","type":"fieldset","as":null,"items":[{"id":"title","className":null,"__typename":"FormFieldRef"},{"id":"useTitle","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"useBackground","type":"fieldset","as":null,"items":[{"id":"useBackground","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"widgetVisibility","type":"fieldset","as":null,"items":[{"id":"widgetVisibility","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"moreOptionsGroup","type":"fieldset","as":null,"items":[{"id":"moreOptions","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"},{"id":"componentPropsGroup","type":"fieldset","as":null,"items":[{"id":"cMax_items","className":null,"__typename":"FormFieldRef"}],"props":null,"legend":null,"description":null,"className":null,"viewVariant":null,"toggleState":null,"__typename":"FormFieldset"}],"actionButtons":null,"className":"custom_widget_HeroBanner_form","formGroupFieldSeparator":"divider","__typename":"FormLayout"},"__typename":"Form"}},"localOverride":false},"CachedAsset:component:custom.widget.MicrosoftFooter-en-1744410106128":{"__typename":"CachedAsset","id":"component:custom.widget.MicrosoftFooter-en-1744410106128","value":{"component":{"id":"custom.widget.MicrosoftFooter","template":{"id":"MicrosoftFooter","markupLanguage":"HANDLEBARS","style":".context-uhf {\n min-width: 280px;\n font-size: 15px;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.c-uhff-link {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.c-uhff {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.c-uhff-nav {\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n .c-heading-4 {\n color: #616161;\n word-break: break-word;\n font-size: 15px;\n line-height: 20px;\n padding: 36px 0 4px;\n font-weight: 600;\n }\n .c-uhff-nav-row {\n .c-uhff-nav-group {\n display: block;\n float: left;\n min-height: 1px;\n vertical-align: text-top;\n padding: 0 12px;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 12px;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.c-list.f-bare {\n font-size: 11px;\n line-height: 16px;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 8px 0;\n margin: 0;\n }\n }\n }\n }\n}\n.c-uhff-base {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(1600px + 10%);\n padding: 30px 5% 16px;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.c-uhff-ccpa {\n font-size: 11px;\n line-height: 16px;\n float: left;\n margin: 3px 0;\n }\n a.c-uhff-ccpa:hover {\n text-decoration: underline;\n }\n ul.c-list {\n font-size: 11px;\n line-height: 16px;\n float: right;\n margin: 3px 0;\n color: #616161;\n li {\n padding: 0 24px 4px 0;\n display: inline-block;\n }\n }\n .c-list.f-bare {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 30px 24px 16px;\n }\n}\n\n.social-share {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n\n.sharing-options {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 43px;\n border-radius: 0px 7px 7px 0px;\n}\n.linkedin-icon {\n border-top-right-radius: 7px;\n}\n.linkedin-icon:hover {\n border-radius: 0;\n}\n.social-share-rss-image {\n border-bottom-right-radius: 7px;\n}\n.social-share-rss-image:hover {\n border-radius: 0;\n}\n\n.social-link-footer {\n position: relative;\n display: block;\n margin: -2px 0;\n transition: all 0.2s ease;\n}\n.social-link-footer:hover .linkedin-icon {\n border-radius: 0;\n}\n.social-link-footer:hover .social-share-rss-image {\n border-radius: 0;\n}\n\n.social-link-footer img {\n width: 40px;\n height: auto;\n transition: filter 0.3s ease;\n}\n\n.social-share-list {\n width: 40px;\n}\n.social-share-rss-image {\n width: 40px;\n}\n\n.share-icon {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n\n.share-icon:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n\n.share-icon:hover .label {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n\n.label {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 10px;\n top: 50%;\n transform: translateY(-50%);\n height: 40px;\n border-radius: 0 6px 6px 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px 5px 20px 8px;\n margin-left: -1px;\n}\n.linkedin {\n background-color: #0474b4;\n}\n.facebook {\n background-color: #3c5c9c;\n}\n.twitter {\n background-color: white;\n color: black;\n}\n.reddit {\n background-color: #fc4404;\n}\n.mail {\n background-color: #848484;\n}\n.bluesky {\n background-color: white;\n color: black;\n}\n.rss {\n background-color: #ec7b1c;\n}\n#RSS {\n width: 40px;\n height: 40px;\n}\n\n@media (max-width: 991px) {\n .social-share {\n display: none;\n }\n}\n","texts":{"New tab":"What's New","New 1":"Surface Laptop Studio 2","New 2":"Surface Laptop Go 3","New 3":"Surface Pro 9","New 4":"Surface Laptop 5","New 5":"Surface Studio 2+","New 6":"Copilot in Windows","New 7":"Microsoft 365","New 8":"Windows 11 apps","Store tab":"Microsoft Store","Store 1":"Account Profile","Store 2":"Download Center","Store 3":"Microsoft Store Support","Store 4":"Returns","Store 5":"Order tracking","Store 6":"Certified Refurbished","Store 7":"Microsoft Store Promise","Store 8":"Flexible Payments","Education tab":"Education","Edu 1":"Microsoft in education","Edu 2":"Devices for education","Edu 3":"Microsoft Teams for Education","Edu 4":"Microsoft 365 Education","Edu 5":"How to buy for your school","Edu 6":"Educator Training and development","Edu 7":"Deals for students and parents","Edu 8":"Azure for students","Business tab":"Business","Bus 1":"Microsoft Cloud","Bus 2":"Microsoft Security","Bus 3":"Dynamics 365","Bus 4":"Microsoft 365","Bus 5":"Microsoft Power Platform","Bus 6":"Microsoft Teams","Bus 7":"Microsoft Industry","Bus 8":"Small Business","Developer tab":"Developer & IT","Dev 1":"Azure","Dev 2":"Developer Center","Dev 3":"Documentation","Dev 4":"Microsoft Learn","Dev 5":"Microsoft Tech Community","Dev 6":"Azure Marketplace","Dev 7":"AppSource","Dev 8":"Visual Studio","Company tab":"Company","Com 1":"Careers","Com 2":"About Microsoft","Com 3":"Company News","Com 4":"Privacy at Microsoft","Com 5":"Investors","Com 6":"Diversity and inclusion","Com 7":"Accessiblity","Com 8":"Sustainibility"},"defaults":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.MicrosoftFooter","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"The Microsoft Footer","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":{"css":".custom_widget_MicrosoftFooter_context-uhf_105bp_1 {\n min-width: 17.5rem;\n font-size: 0.9375rem;\n box-sizing: border-box;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n & *,\n & *:before,\n & *:after {\n box-sizing: inherit;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-link_105bp_12 {\n color: #616161;\n word-break: break-word;\n text-decoration: none;\n }\n &a:link,\n &a:focus,\n &a:hover,\n &a:active,\n &a:visited {\n text-decoration: none;\n color: inherit;\n }\n & div {\n font-family: 'Segoe UI', SegoeUI, 'Helvetica Neue', Helvetica, Arial, sans-serif;\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff_105bp_12 {\n background: #f2f2f2;\n margin: -1.5625;\n width: auto;\n height: auto;\n}\n.custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35 {\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 0 5%;\n box-sizing: inherit;\n &:before,\n &:after {\n content: ' ';\n display: table;\n clear: left;\n }\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n .custom_widget_MicrosoftFooter_c-heading-4_105bp_49 {\n color: #616161;\n word-break: break-word;\n font-size: 0.9375rem;\n line-height: 1.25rem;\n padding: 2.25rem 0 0.25rem;\n font-weight: 600;\n }\n .custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57 {\n .custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58 {\n display: block;\n float: left;\n min-height: 0.0625rem;\n vertical-align: text-top;\n padding: 0 0.75rem;\n width: 100%;\n zoom: 1;\n &:first-child {\n padding-left: 0;\n @media only screen and (max-width: 1083px) {\n padding-left: 0.75rem;\n }\n }\n @media only screen and (min-width: 540px) and (max-width: 1082px) {\n width: 33.33333%;\n }\n @media only screen and (min-width: 1083px) {\n width: 16.6666666667%;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n list-style-type: none;\n li {\n word-break: break-word;\n padding: 0.5rem 0;\n margin: 0;\n }\n }\n }\n }\n}\n.custom_widget_MicrosoftFooter_c-uhff-base_105bp_94 {\n background: #f2f2f2;\n margin: 0 auto;\n max-width: calc(100rem + 10%);\n padding: 1.875rem 5% 1rem;\n &:before,\n &:after {\n content: ' ';\n display: table;\n }\n &:after {\n clear: both;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: left;\n margin: 0.1875rem 0;\n }\n a.custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107:hover {\n text-decoration: underline;\n }\n ul.custom_widget_MicrosoftFooter_c-list_105bp_78 {\n font-size: 0.6875rem;\n line-height: 1rem;\n float: right;\n margin: 0.1875rem 0;\n color: #616161;\n li {\n padding: 0 1.5rem 0.25rem 0;\n display: inline-block;\n }\n }\n .custom_widget_MicrosoftFooter_c-list_105bp_78.custom_widget_MicrosoftFooter_f-bare_105bp_78 {\n padding-left: 0;\n list-style-type: none;\n }\n @media only screen and (max-width: 1083px) {\n display: flex;\n flex-wrap: wrap;\n padding: 1.875rem 1.5rem 1rem;\n }\n}\n.custom_widget_MicrosoftFooter_social-share_105bp_138 {\n position: fixed;\n top: 60%;\n transform: translateY(-50%);\n left: 0;\n z-index: 1000;\n}\n.custom_widget_MicrosoftFooter_sharing-options_105bp_146 {\n list-style: none;\n padding: 0;\n margin: 0;\n display: block;\n flex-direction: column;\n background-color: white;\n width: 2.6875rem;\n border-radius: 0 0.4375rem 0.4375rem 0;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-top-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_linkedin-icon_105bp_156:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-bottom-right-radius: 7px;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162:hover {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 {\n position: relative;\n display: block;\n margin: -0.125rem 0;\n transition: all 0.2s ease;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_linkedin-icon_105bp_156 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169:hover .custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n border-radius: 0;\n}\n.custom_widget_MicrosoftFooter_social-link-footer_105bp_169 img {\n width: 2.5rem;\n height: auto;\n transition: filter 0.3s ease;\n}\n.custom_widget_MicrosoftFooter_social-share-list_105bp_188 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162 {\n width: 2.5rem;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195 {\n border: 2px solid transparent;\n display: inline-block;\n position: relative;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover {\n opacity: 1;\n border: 2px solid white;\n box-sizing: border-box;\n}\n.custom_widget_MicrosoftFooter_share-icon_105bp_195:hover .custom_widget_MicrosoftFooter_label_105bp_207 {\n opacity: 1;\n visibility: visible;\n border: 2px solid white;\n box-sizing: border-box;\n border-left: none;\n}\n.custom_widget_MicrosoftFooter_label_105bp_207 {\n position: absolute;\n left: 100%;\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n color: white;\n border-radius: 0 10 0 0.625rem;\n top: 50%;\n transform: translateY(-50%);\n height: 2.5rem;\n border-radius: 0 0.375rem 0.375rem 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 1.25rem 0.3125rem 1.25rem 0.5rem;\n margin-left: -0.0625rem;\n}\n.custom_widget_MicrosoftFooter_linkedin_105bp_156 {\n background-color: #0474b4;\n}\n.custom_widget_MicrosoftFooter_facebook_105bp_237 {\n background-color: #3c5c9c;\n}\n.custom_widget_MicrosoftFooter_twitter_105bp_240 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_reddit_105bp_244 {\n background-color: #fc4404;\n}\n.custom_widget_MicrosoftFooter_mail_105bp_247 {\n background-color: #848484;\n}\n.custom_widget_MicrosoftFooter_bluesky_105bp_250 {\n background-color: white;\n color: black;\n}\n.custom_widget_MicrosoftFooter_rss_105bp_254 {\n background-color: #ec7b1c;\n}\n#custom_widget_MicrosoftFooter_RSS_105bp_1 {\n width: 2.5rem;\n height: 2.5rem;\n}\n@media (max-width: 991px) {\n .custom_widget_MicrosoftFooter_social-share_105bp_138 {\n display: none;\n }\n}\n","tokens":{"context-uhf":"custom_widget_MicrosoftFooter_context-uhf_105bp_1","c-uhff-link":"custom_widget_MicrosoftFooter_c-uhff-link_105bp_12","c-uhff":"custom_widget_MicrosoftFooter_c-uhff_105bp_12","c-uhff-nav":"custom_widget_MicrosoftFooter_c-uhff-nav_105bp_35","c-heading-4":"custom_widget_MicrosoftFooter_c-heading-4_105bp_49","c-uhff-nav-row":"custom_widget_MicrosoftFooter_c-uhff-nav-row_105bp_57","c-uhff-nav-group":"custom_widget_MicrosoftFooter_c-uhff-nav-group_105bp_58","c-list":"custom_widget_MicrosoftFooter_c-list_105bp_78","f-bare":"custom_widget_MicrosoftFooter_f-bare_105bp_78","c-uhff-base":"custom_widget_MicrosoftFooter_c-uhff-base_105bp_94","c-uhff-ccpa":"custom_widget_MicrosoftFooter_c-uhff-ccpa_105bp_107","social-share":"custom_widget_MicrosoftFooter_social-share_105bp_138","sharing-options":"custom_widget_MicrosoftFooter_sharing-options_105bp_146","linkedin-icon":"custom_widget_MicrosoftFooter_linkedin-icon_105bp_156","social-share-rss-image":"custom_widget_MicrosoftFooter_social-share-rss-image_105bp_162","social-link-footer":"custom_widget_MicrosoftFooter_social-link-footer_105bp_169","social-share-list":"custom_widget_MicrosoftFooter_social-share-list_105bp_188","share-icon":"custom_widget_MicrosoftFooter_share-icon_105bp_195","label":"custom_widget_MicrosoftFooter_label_105bp_207","linkedin":"custom_widget_MicrosoftFooter_linkedin_105bp_156","facebook":"custom_widget_MicrosoftFooter_facebook_105bp_237","twitter":"custom_widget_MicrosoftFooter_twitter_105bp_240","reddit":"custom_widget_MicrosoftFooter_reddit_105bp_244","mail":"custom_widget_MicrosoftFooter_mail_105bp_247","bluesky":"custom_widget_MicrosoftFooter_bluesky_105bp_250","rss":"custom_widget_MicrosoftFooter_rss_105bp_254","RSS":"custom_widget_MicrosoftFooter_RSS_105bp_1"}},"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1745160788452","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBanner-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBanner-1745160788452","value":{"messageMarkedAsSpam":"This post has been marked as spam","messageMarkedAsSpam@board:TKB":"This article has been marked as spam","messageMarkedAsSpam@board:BLOG":"This post has been marked as spam","messageMarkedAsSpam@board:FORUM":"This discussion has been marked as spam","messageMarkedAsSpam@board:OCCASION":"This event has been marked as spam","messageMarkedAsSpam@board:IDEA":"This idea has been marked as spam","manageSpam":"Manage Spam","messageMarkedAsAbuse":"This post has been marked as abuse","messageMarkedAsAbuse@board:TKB":"This article has been marked as abuse","messageMarkedAsAbuse@board:BLOG":"This post has been marked as abuse","messageMarkedAsAbuse@board:FORUM":"This discussion has been marked as abuse","messageMarkedAsAbuse@board:OCCASION":"This event has been marked as abuse","messageMarkedAsAbuse@board:IDEA":"This idea has been marked as abuse","preModCommentAuthorText":"This comment will be published as soon as it is approved","preModCommentModeratorText":"This comment is awaiting moderation","messageMarkedAsOther":"This post has been rejected due to other reasons","messageMarkedAsOther@board:TKB":"This article has been rejected due to other reasons","messageMarkedAsOther@board:BLOG":"This post has been rejected due to other reasons","messageMarkedAsOther@board:FORUM":"This discussion has been rejected due to other reasons","messageMarkedAsOther@board:OCCASION":"This event has been rejected due to other reasons","messageMarkedAsOther@board:IDEA":"This idea has been rejected due to other reasons","messageArchived":"This post was archived on {date}","relatedUrl":"View Related Content","relatedContentText":"Showing related content","archivedContentLink":"View Archived Content"},"localOverride":false},"Category:category:Exchange":{"__typename":"Category","id":"category:Exchange","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Planner":{"__typename":"Category","id":"category:Planner","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Outlook":{"__typename":"Category","id":"category:Outlook","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Community-Info-Center":{"__typename":"Category","id":"category:Community-Info-Center","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:DrivingAdoption":{"__typename":"Category","id":"category:DrivingAdoption","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Azure":{"__typename":"Category","id":"category:Azure","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows-Server":{"__typename":"Category","id":"category:Windows-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:SQL-Server":{"__typename":"Category","id":"category:SQL-Server","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftTeams":{"__typename":"Category","id":"category:MicrosoftTeams","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PublicSector":{"__typename":"Category","id":"category:PublicSector","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft365":{"__typename":"Category","id":"category:microsoft365","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:IoT":{"__typename":"Category","id":"category:IoT","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:HealthcareAndLifeSciences":{"__typename":"Category","id":"category:HealthcareAndLifeSciences","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:SMB":{"__typename":"Category","id":"category:SMB","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:ITOpsTalk":{"__typename":"Category","id":"category:ITOpsTalk","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-endpoint-manager":{"__typename":"Category","id":"category:microsoft-endpoint-manager","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftLearn":{"__typename":"Category","id":"category:MicrosoftLearn","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Blog:board:MicrosoftLearnBlog":{"__typename":"Blog","id":"board:MicrosoftLearnBlog","blogPolicies":{"__typename":"BlogPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:AI":{"__typename":"Category","id":"category:AI","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:MicrosoftMechanics":{"__typename":"Category","id":"category:MicrosoftMechanics","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:StartupsatMicrosoft":{"__typename":"Category","id":"category:StartupsatMicrosoft","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:PartnerCommunity":{"__typename":"Category","id":"category:PartnerCommunity","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Windows":{"__typename":"Category","id":"category:Windows","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:microsoft-security":{"__typename":"Category","id":"category:microsoft-security","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"QueryVariables:TopicReplyList:message:4178612:73":{"__typename":"QueryVariables","id":"TopicReplyList:message:4178612:73","value":{"id":"message:4178612","first":10,"sorts":{"postTime":{"direction":"DESC"}},"repliesFirst":3,"repliesFirstDepthThree":1,"repliesSorts":{"postTime":{"direction":"DESC"}},"useAvatar":true,"useAuthorLogin":true,"useAuthorRank":true,"useBody":true,"useKudosCount":true,"useTimeToRead":false,"useMedia":false,"useReadOnlyIcon":false,"useRepliesCount":true,"useSearchSnippet":false,"useAcceptedSolutionButton":false,"useSolvedBadge":false,"useAttachments":false,"attachmentsFirst":5,"useTags":true,"useNodeAncestors":false,"useUserHoverCard":false,"useNodeHoverCard":false,"useModerationStatus":true,"usePreviewSubjectModal":false,"useMessageStatus":true}},"ROOT_MUTATION":{"__typename":"Mutation"},"CachedAsset:text:en_US-components/community/Navbar-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1745160788452","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","gxcuf89792":"Tech Community","external-1":"Events","s-m-b":"Small and Medium Businesses","windows-server":"Windows Server","education-sector":"Education Sector","driving-adoption":"Driving Adoption","microsoft-learn":"Microsoft Learn","s-q-l-server":"SQL Server","partner-community":"Microsoft Partner Community","microsoft365":"Microsoft 365","external-9":".NET","external-8":"Teams","external-7":"Github","products-services":"Products","external-6":"Power Platform","communities-1":"Topics","external-5":"Microsoft Security","planner":"Planner","external-4":"Microsoft 365","external-3":"Dynamics 365","azure":"Azure","healthcare-and-life-sciences":"Healthcare and Life Sciences","external-2":"Azure","microsoft-mechanics":"Microsoft Mechanics","microsoft-learn-1":"Community","external-10":"Learning Room Directory","microsoft-learn-blog":"Blog","windows":"Windows","i-t-ops-talk":"ITOps Talk","external-link-1":"View All","microsoft-securityand-compliance":"Microsoft Security","public-sector":"Public Sector","community-info-center":"Lounge","external-link-2":"View All","microsoft-teams":"Microsoft Teams","external":"Blogs","microsoft-endpoint-manager":"Microsoft Intune and Configuration Manager","startupsat-microsoft":"Startups at Microsoft","exchange":"Exchange","a-i":"AI and Machine Learning","io-t":"Internet of Things (IoT)","outlook":"Outlook","external-link":"Community Hubs","communities":"Products"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1745160788452","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1745160788452","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1745160788452","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1745160788452","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1745160788452","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewStandard-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewStandard-1745160788452","value":{"anonymous":"Anonymous","author":"{messageAuthorLogin}","authorBy":"{messageAuthorLogin}","board":"{messageBoardTitle}","replyToUser":" to {parentAuthor}","showMoreReplies":"Show More","replyText":"Reply","repliesText":"Replies","markedAsSolved":"Marked as Solved","movedMessagePlaceholder.BLOG":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.TKB":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.FORUM":"{count, plural, =0 {This reply has been} other {These replies have been} }","movedMessagePlaceholder.IDEA":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.OCCASION":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholderUrlText":"moved.","messageStatus":"Status: ","statusChanged":"Status changed: {previousStatus} to {currentStatus}","statusAdded":"Status added: {status}","statusRemoved":"Status removed: {status}","labelExpand":"expand replies","labelCollapse":"collapse replies","unhelpfulReason.reason1":"Content is outdated","unhelpfulReason.reason2":"Article is missing information","unhelpfulReason.reason3":"Content is for a different Product","unhelpfulReason.reason4":"Doesn't match what I was searching for"},"localOverride":false},"CachedAsset:text:en_US-components/messages/ThreadedReplyList-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/ThreadedReplyList-1745160788452","value":{"title":"{count, plural, one{# Reply} other{# Replies}}","title@board:BLOG":"{count, plural, one{# Comment} other{# Comments}}","title@board:TKB":"{count, plural, one{# Comment} other{# Comments}}","title@board:IDEA":"{count, plural, one{# Comment} other{# Comments}}","title@board:OCCASION":"{count, plural, one{# Comment} other{# Comments}}","noRepliesTitle":"No Replies","noRepliesTitle@board:BLOG":"No Comments","noRepliesTitle@board:TKB":"No Comments","noRepliesTitle@board:IDEA":"No Comments","noRepliesTitle@board:OCCASION":"No Comments","noRepliesDescription":"Be the first to reply","noRepliesDescription@board:BLOG":"Be the first to comment","noRepliesDescription@board:TKB":"Be the first to comment","noRepliesDescription@board:IDEA":"Be the first to comment","noRepliesDescription@board:OCCASION":"Be the first to comment","messageReadOnlyAlert:BLOG":"Comments have been turned off for this post","messageReadOnlyAlert:TKB":"Comments have been turned off for this article","messageReadOnlyAlert:IDEA":"Comments have been turned off for this idea","messageReadOnlyAlert:FORUM":"Replies have been turned off for this discussion","messageReadOnlyAlert:OCCASION":"Comments have been turned off for this event"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyCallToAction-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyCallToAction-1745160788452","value":{"leaveReply":"Leave a reply...","leaveReply@board:BLOG@message:root":"Leave a comment...","leaveReply@board:TKB@message:root":"Leave a comment...","leaveReply@board:IDEA@message:root":"Leave a comment...","leaveReply@board:OCCASION@message:root":"Leave a comment...","repliesTurnedOff.FORUM":"Replies are turned off for this topic","repliesTurnedOff.BLOG":"Comments are turned off for this topic","repliesTurnedOff.TKB":"Comments are turned off for this topic","repliesTurnedOff.IDEA":"Comments are turned off for this topic","repliesTurnedOff.OCCASION":"Comments are turned off for this topic","infoText":"Stop poking me!"},"localOverride":false},"ModerationData:moderation_data:4200663":{"__typename":"ModerationData","id":"moderation_data:4200663","status":"APPROVED","rejectReason":null,"isReportedAbuse":false,"rejectUser":null,"rejectTime":null,"rejectActorType":null},"BlogReplyMessage:message:4200663":{"__typename":"BlogReplyMessage","author":{"__ref":"User:user:2076234"},"id":"message:4200663","revisionNum":5,"uid":4200663,"depth":1,"hasGivenKudo":false,"subscribed":false,"board":{"__ref":"Blog:board:EducatorDeveloperBlog"},"parent":{"__ref":"BlogTopicMessage:message:4178612"},"conversation":{"__ref":"Conversation:conversation:4178612"},"subject":"Re: Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide","moderationData":{"__ref":"ModerationData:moderation_data:4200663"},"body":"
Update (July 25, 2024): Fine-Tune and Integrate Custom Phi-3 Models with Prompt Flow: Step-by-Step Guide
\n
\n
I've updated the tutorial to use theULTRACHAT_200Kdataset and fixed some issues.
\n
\n
Updates:
\n
\n\n
Using ULTRACHAT_200K Dataset: Updated to utilize theULTRACHAT_200Kdataset for fine-tuning.
\n
Resolved Package Version Issues: Fixed package version issues in the fine-tuning environment.
\n
GPU Optimization: Modified to use theStandard_NC24ads_A100_v4GPU for enhanced fine-tuning performance.
\n\n
\n
Confirmation of Changes:
\n
\n
As of July 24, 2024, these changes have been verified to ensure that fine-tuning, deployment, and integration with Prompt flow are functioning correctly in the updated GPU environment.
","body@stripHtml({\"removeProcessingText\":false,\"removeSpoilerMarkup\":false,\"removeTocMarkup\":false,\"truncateLength\":200})@stringLength":"223","kudosSumWeight":0,"repliesCount":0,"postTime":"2024-07-24T17:15:06.474-07:00","lastPublishTime":"2024-07-24T19:08:38.885-07:00","metrics":{"__typename":"MessageMetrics","views":5694},"visibilityScope":"PUBLIC","placeholder":false,"originalMessageForPlaceholder":null,"entityType":"BLOG_REPLY","eventPath":"category:EducationSector/category:solutions/category:communities/community:gxcuf89792board:EducatorDeveloperBlog/message:4178612/message:4200663","replies":{"__typename":"MessageConnection","pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null},"edges":[]},"customFields":[],"attachments":{"__typename":"AttachmentConnection","edges":[],"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1745160788452","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1745160788452","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageCoverImage-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageCoverImage-1745160788452","value":{"coverImageTitle":"Cover Image"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeTitle-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeTitle-1745160788452","value":{"nodeTitle":"{nodeTitle, select, community {Community} other {{nodeTitle}}} "},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTimeToRead-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTimeToRead-1745160788452","value":{"minReadText":"{min} MIN READ"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1745160788452","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1745160788452","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserRank-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserRank-1745160788452","value":{"rankName":"{rankName}","userRank":"Author rank {rankName}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1745160788452","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1745160788452","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageCustomFields-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageCustomFields-1745160788452","value":{"CustomField.default.label":"Value of {name}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRevision-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRevision-1745160788452","value":{"lastUpdatedDatePublished":"{publishCount, plural, one{Published} other{Updated}} {date}","lastUpdatedDateDraft":"Created {date}","version":"Version {major}.{minor}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyButton-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyButton-1745160788452","value":{"repliesCount":"{count}","title":"Reply","title@board:BLOG@message:root":"Comment","title@board:TKB@message:root":"Comment","title@board:IDEA@message:root":"Comment","title@board:OCCASION@message:root":"Comment"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageAuthorBio-1745160788452","value":{"sendMessage":"Send Message","actionMessage":"Follow this blog board to get notified when there's new activity","coAuthor":"CO-PUBLISHER","contributor":"CONTRIBUTOR","userProfile":"View Profile","iconlink":"Go to {name} {type}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1745160788452","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/ranks/UserRankLabel-1745160788452","value":{"altTitle":"Icon for {rankName} rank"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserRegistrationDate-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserRegistrationDate-1745160788452","value":{"noPrefix":"{date}","withPrefix":"Joined {date}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeAvatar-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeAvatar-1745160788452","value":{"altTitle":"Node avatar for {nodeTitle}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeDescription-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeDescription-1745160788452","value":{"description":"{description}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagView/TagViewChip-1745160788452","value":{"tagLabelName":"Tag name {tagName}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1745160788452":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1745160788452","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false}}}},"page":"/blogs/BlogMessagePage/BlogMessagePage","query":{"boardId":"educatordeveloperblog","messageSubject":"fine-tune-and-integrate-custom-phi-3-models-with-prompt-flow-step-by-step-guide","messageId":"4178612"},"buildId":"HEhyUrv5OXNBIbfCLaOrw","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"o365","openTelemetryServiceVersion":"25.1.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/customComponent/CustomComponent/CustomComponent.tsx","./components/blogs/BlogArticleWidget/BlogArticleWidget.tsx","./components/external/components/ExternalComponent.tsx","./components/messages/MessageView/MessageViewStandard/MessageViewStandard.tsx","./components/messages/ThreadedReplyList/ThreadedReplyList.tsx","../shared/client/components/common/List/UnstyledList/UnstyledList.tsx","./components/messages/MessageView/MessageView.tsx","../shared/client/components/common/List/UnwrappedList/UnwrappedList.tsx","./components/tags/TagView/TagView.tsx","./components/tags/TagView/TagViewChip/TagViewChip.tsx"],"appGip":true,"scriptLoader":[{"id":"analytics","src":"https://techcommunity.microsoft.com/t5/s/gxcuf89792/pagescripts/1730819800000/analytics.js?page.id=BlogMessagePage&entity.id=board%3Aeducatordeveloperblog&entity.id=message%3A4178612","strategy":"afterInteractive"}]}