Skip to content

Commit 0c43e5d

Browse files
authored
Merge pull request #10 from BethanyJep/main
adding documentation and additional optimizations for the code
2 parents d8ecd33 + bcccdc3 commit 0c43e5d

21 files changed

+2593
-1390
lines changed
Lines changed: 248 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,252 @@
1-
# 4.1 Engineer Context
1+
# 4.1 Customize The Tone & Style With SFT
22

33
!!! quote "BY THE END OF THIS LAB YOU SHOULD HAVE"
44

5-
- [X] Completed Task 1
6-
- [X] Completed Task 2
7-
- [X] Completed Task 3
5+
- [ ] Checked your environment setup and validated Azure OpenAI credentials
6+
- [ ] Analyzed training and validation datasets for fine-tuning
7+
- [ ] Uploaded datasets and submitted a fine-tuning job to Azure OpenAI
8+
- [ ] Monitored the fine-tuning process and reviewed results
9+
- [ ] Deployed and tested your fine-tuned model
810

9-
---
11+
---
12+
13+
In this lab, we'll explore how to customize the tone and style of our Zava assistant using Supervised Fine-Tuning (SFT). While few-shot examples and RAG can improve responses, they also increase prompt lengths, which leads to higher token costs and reduced context window for output. Fine-tuning offers a more efficient approach by teaching the model our desired style with many examples but without the overhead of including them in every prompt.
14+
15+
## Step 1: Check Environment Setup
16+
17+
Before we begin fine-tuning, we need to ensure our environment is correctly set up with the necessary Azure OpenAI credentials.
18+
19+
```python
20+
import os
21+
22+
openai_key = os.getenv("AZURE_OPENAI_API_KEY")
23+
openai_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
24+
model_name = "gpt-4.1"
25+
api_version = os.getenv("AZURE_OPENAI_API_VERSION", "2025-02-01-preview")
26+
27+
if not openai_key or not openai_endpoint:
28+
print("Error: Missing AZURE_OPENAI_KEY or AZURE_OPENAI_ENDPOINT environment variable.")
29+
30+
print("Using Model:", model_name)
31+
print("Using API Version:", api_version)
32+
```
33+
34+
!!! note
35+
If you encounter an error, make sure you have set the required environment variables in your `.env` file and they have been properly loaded.
36+
37+
---
38+
39+
## Step 2: Validate Training Dataset
40+
41+
Next, we'll locate and validate our training and validation datasets to ensure they're properly formatted for fine-tuning.
42+
43+
```python
44+
# Identify Training and Validation datafiles
45+
training_file = "../data/basic_sft_training.jsonl"
46+
validation_file = "../data/basic_sft_validation.jsonl"
47+
48+
# Run preliminary checks
49+
import json
50+
51+
# Load the training set
52+
with open(training_file, 'r', encoding='utf-8') as f:
53+
training_dataset = [json.loads(line) for line in f]
54+
55+
# Training dataset stats
56+
print("Number of examples in training set:", len(training_dataset))
57+
print("First example in training set:")
58+
for message in training_dataset[0]["messages"]:
59+
print(message)
60+
61+
# Load the validation set
62+
with open(validation_file, 'r', encoding='utf-8') as f:
63+
validation_dataset = [json.loads(line) for line in f]
64+
65+
# Validation dataset stats
66+
print("\nNumber of examples in validation set:", len(validation_dataset))
67+
```
68+
69+
The output will show you the number of examples in each dataset and a sample of the first example's format.
70+
71+
!!! warning
72+
Fine-tuning datasets must follow the proper JSONL format with messages containing role/content pairs. Make sure your data follows this structure.
73+
74+
---
75+
76+
## Step 3: Assess Token Counts For Data
77+
78+
It's important to understand the token distribution in our training data to ensure effective fine-tuning.
79+
80+
```python
81+
import tiktoken
82+
import numpy as np
83+
84+
encoding = tiktoken.get_encoding("o200k_base") # default encoding for gpt-4o models
85+
86+
def num_tokens_from_messages(messages, tokens_per_message=3, tokens_per_name=1):
87+
num_tokens = 0
88+
for message in messages:
89+
num_tokens += tokens_per_message
90+
for key, value in message.items():
91+
num_tokens += len(encoding.encode(value))
92+
if key == "name":
93+
num_tokens += tokens_per_name
94+
num_tokens += 3
95+
return num_tokens
96+
97+
# Add token counting code and print distribution statistics
98+
```
99+
100+
This analysis will show you the distribution of total tokens and assistant tokens in your datasets, which helps in understanding the training data characteristics.
101+
102+
---
103+
104+
## Step 4: Upload Fine-Tuning Data To Cloud
105+
106+
Now we'll create an Azure OpenAI client and upload our training and validation datasets.
107+
108+
```python
109+
from openai import AzureOpenAI
110+
111+
client = AzureOpenAI(
112+
azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"),
113+
api_key = os.getenv("AZURE_OPENAI_API_KEY"),
114+
api_version = os.getenv("AZURE_OPENAI_API_VERSION")
115+
)
116+
117+
# Upload the training and validation dataset files
118+
training_response = client.files.create(
119+
file = open(training_file, "rb"), purpose="fine-tune"
120+
)
121+
training_file_id = training_response.id
122+
123+
validation_response = client.files.create(
124+
file = open(validation_file, "rb"), purpose="fine-tune"
125+
)
126+
validation_file_id = validation_response.id
127+
128+
print("Training file ID:", training_file_id)
129+
print("Validation file ID:", validation_file_id)
130+
```
131+
132+
!!! note
133+
You can visit the Azure AI Foundry Portal and look under your Azure AI Project's 'Data Files' tab to see the uploaded files.
134+
135+
---
136+
137+
## Step 5: Submit The Fine-Tuning Job
138+
139+
With our data uploaded, we can now submit the fine-tuning job.
140+
141+
```python
142+
# Submit fine-tuning training job
143+
response = client.fine_tuning.jobs.create(
144+
training_file=training_file_id,
145+
validation_file=validation_file_id,
146+
model="gpt-4.1", # Enter base model name
147+
seed = 105, # for reproducibility
148+
hyperparameters={
149+
"learning_rate_multiplier": 2.0, # Higher LR for faster training
150+
"n_epochs": 3, # Reduced epochs (default is often overkill)
151+
"batch_size": 16, # Larger batch for stability
152+
}
153+
)
154+
155+
job_id = response.id
156+
print("Job ID:", response.id)
157+
```
158+
159+
!!! warning
160+
Currently gpt-4.1 can be fine-tuned only in Sweden Central and North Central US regions. Make sure your Azure OpenAI resource is in one of these regions.
161+
162+
---
163+
164+
## Step 6: Track Fine-Tuning Job Status
165+
166+
Fine-tuning can take some time. We'll monitor the progress of our job.
167+
168+
```python
169+
from IPython.display import clear_output
170+
import time
171+
172+
start_time = time.time()
173+
174+
# Get the status of our fine-tuning job
175+
response = client.fine_tuning.jobs.retrieve(job_id)
176+
status = response.status
177+
178+
# Poll job status every 10 seconds
179+
while status not in ["succeeded", "failed"]:
180+
time.sleep(10)
181+
response = client.fine_tuning.jobs.retrieve(job_id)
182+
print(f'Status: {status}')
183+
status = response.status
184+
185+
print(f'Fine-tuning job {job_id} finished with status: {status}')
186+
```
187+
188+
---
189+
190+
## Step 7: List Fine-Tuning Events and Checkpoints
191+
192+
Once the job completes, we can review the fine-tuning events and checkpoints.
193+
194+
```python
195+
# Review fine-tuning events
196+
response = client.fine_tuning.jobs.list_events(fine_tuning_job_id=job_id, limit=10)
197+
198+
# List checkpoints
199+
response = client.fine_tuning.jobs.checkpoints.list(job_id)
200+
```
201+
202+
These provide insights into the training process and model checkpoints created during fine-tuning.
203+
204+
---
205+
206+
## Step 8: Retrieve Fine-Tuned Model Name
207+
208+
After successful fine-tuning, we'll retrieve the name of our fine-tuned model.
209+
210+
```python
211+
response = client.fine_tuning.jobs.retrieve(job_id)
212+
fine_tuned_model = response.fine_tuned_model
213+
print("Fine-tuned model name:", fine_tuned_model)
214+
```
215+
216+
---
217+
218+
## Step 9: Deploy and Test Your Fine-Tuned Model
219+
220+
For testing purposes, deploy your model using the developer tier in the Azure AI Foundry Portal.
221+
222+
### Example Test Prompts and Responses:
223+
224+
> **Prompt 1**: What kind of paint should I buy for my outdoor deck?
225+
>
226+
> **Response**: 🪵 Deck protection options! Semi-Transparent Deck Stain at 38 enhances wood grain, or Deck & Fence Stain at 36 for UV protection?
227+
228+
> **Prompt 2**: I'm painting over rust - what spray paint should I use?
229+
>
230+
> **Response**: 👍 Right choice! Rust Prevention Spray at $13 applies directly over rust with long-lasting protection. Primer recommendation?
231+
232+
### Insights from Testing
233+
234+
Our fine-tuned model now follows the Zava guidelines for "polite, factual and helpful" responses:
235+
- Every response starts with an emoji
236+
- The first sentence acknowledges the user ("polite")
237+
- The second sentence provides information ("factual")
238+
- The final sentence offers follow-up assistance ("helpful")
239+
240+
Most importantly, we've achieved these succinct, styled responses without adding few-shot examples in every prompt, saving both token costs and processing latency.
241+
242+
---
243+
244+
## Teardown
245+
246+
Once you are done with this lab, don't forget to tear down the infrastructure. The developer tier model will be automatically deleted after 24 hours, but it's better to proactively delete the resource group and release all model quota.
247+
248+
---
249+
250+
<div style="display: flex; align-items: center; justify-content: left; padding: 5px; height: 40px; background: linear-gradient(90deg, #7873f5 0%, #ff6ec4 100%); border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.12); font-size: 1.5em; font-weight: bold; color: #fff;">
251+
Next: Be More Cost-Effective With Distillation
252+
</div>

0 commit comments

Comments
 (0)