Azure, OpenAI, 그리고 Weights & Biases가 함께 작동하는 방식
이 입문 보고서에서 Azure, OpenAI, 그리고 W&B가 왜 함께 탁월하게 작동하는지 알아보세요
이 글은 AI 번역본입니다. 오역이 의심되면 댓글로 알려주세요
Created on September 15|Last edited on September 15
Comment

Azure, OpenAI, 그리고 Weights & Biases 빠른 개요
오늘은 Azure, OpenAI의 GPT, 그리고 Weights & Biases와 함께 작업합니다. 각 도구에 대한 설명이 필요하다면 아래에서 확인하세요:
Microsoft Azure는 선도적인 클라우드 컴퓨팅 플랫폼으로, 컴퓨팅, 스토리지, 데이터베이스, AI를 포함한 폭넓은 서비스를 제공하며, 전 세계 데이터 센터 네트워크와 견고한 인프라를 기반으로 AI와 ML 배포에 필수적인 확장성, 신뢰성, 보안을 보장합��다.
OpenAI는 AI 연구의 최전선에 서 있으며, 자연어 처리(NLP), 강화 학습, 그리고 Generative Pre-trained Transformer(GPT)와 같은 고도화된 모델 개발에서 선구적인 성과로 잘 알려져 있습니다. 이러한 모델은 인간과 유사한 텍스트를 생성하고 복잡한 언어 작업을 수행하는 능력으로 높은 평가를 받습니다.
Weights & Biases 머신러닝 워크플로를 개선하는 도구에 특화되어 있으며, 실험 추적, 시각화, 최적화 기능을 제공해 데이터 과학자 간 협업을 촉진하고, 실험 로깅, 하이퍼파라미터 튜닝, 결과 분석 기능을 통해 모델 개발을 간소화합니다.
Azure의 클라우드 역량을 활용하면 개발자와 데이터 과학자는 OpenAI의 고도화된 모델을 배포하고 확장할 수 있는 확장 가능한 인프라에 접근할 수 있습니다. Azure의 유연성과 보안 조치는 규모나 복잡성과 관계없이 AI 애플리케이션이 원활하게 운영되도록 보장합니다.
이 통합을 통해 사용자는 Azure OpenAI의 유연한 모델을 활용해 파인튜닝과 프롬프트 기반 상호작용을 수행하고, W&B의 실험 추적 도구가 제공하는 이점까지 함께 누릴 수 있습니다. 이를 통해 개발자는 파인튜닝 과정을 효과적으로 모니터링하고, 필요에 따라 하이퍼파라미터를 조정하며, 학습에 관한 의사결정을 근거 있게 내릴 수 있습니다.
Azure의 클라우드 역량과 OpenAI의 고도화된 모델 활용
Azure의 클라우드 인프라는 GPU와 TPU를 포함한 고성능 컴퓨팅 자원을 통해 대규모 데이터셋 처리와 OpenAI의 GPT 시리즈와 같은 복잡한 언어 모델 학습에 필수적인 성능을 제공하여 AI 모델 개발과 배포를 강화합니다.
이러한 연산 성능은 AI 애플리케이션 개발을 가속화해 출시까지의 시간을 단축하고 효율성을 높입니다. 또한 Azure는 확장 가능한 스토리지와 유연한 컴퓨트 옵션을 제공해 동적으로 자원을 할당할 수 있도록 하여, 증가하는 연산 수요에 맞춰 AI 워크로드를 원활하게 확장할 수 있게 합니다. 이를 통해 조직은 피크 기간이나 다양한 배포 환경에서도 수요 변동을 효율적으로 관리할 수 있습니다.
AI 개발 워크플로 간소화
이 통합은 모델 학습부터 배포까지 AI 개발 수명주기를 간소화하고 가속화합니다:
- 모델 학습을 위한 통합 플랫폼OpenAI의 모델을 Azure의 확장 가능한 컴퓨팅 리소스와 통합하면 대규모 데이터셋에서 효율적으로 모델 학습과 파인튜닝을 수행할 수 있습니다. Weights & Biases를 사용하면 이러한 학습 세션을 추적하고, 지표를 기록하며, 모델 버전을 저장할 수 있어 실험부터 최종 모델 선택까지 워크플로가 매끄럽게 이어집니다.
- 협업과 버전 관리Weights & Biases 플랫폼은 팀이 실험을 모니터링하고 결과를 공유하며 AI 프로젝트에서 협업할 수 있는 중앙 허브 역할을 합니다. 이를 통해 지식 공유가 촉진되고 모델 개선을 위한 반복 과정이 가속화됩니다. 버전 관리를 통해 모델과 데이터셋의 변경 사항이 추적되므로, 팀은 AI 프로젝트의 발전 과정을 체계적으로 관리할 수 있습니다.
- 간소화된 배포Azure ML은 모델을 웹 서비스로 배포하든 대규모 애플리케이션의 일부로 통합하든, 프로덕션 환경에 배포하기 위한 도구를 제공합니다. OpenAI와 Weights & Biases와의 통합을 통해 모델 개발에서 배포로의 전환이 간소화되며, 필요한 경우 모델 성능을 모니터링하고 업데이트 또는 롤백을 관리할 수 있는 도구도 함께 제공합니다.
통합 플랫폼을 사용할 때의 이점
- 효율성통합 플랫폼은 데이터 전처리와 모델 학습부터 배포와 모니터링에 이르기까지 AI 개발의 다양한 측면을 관리하는 복잡성을 줄여 시간과 자원을 절약합니다.
- 확장성Azure의 클라우드 인프라는 프로젝트 요구에 따라 자원을 탄력적으로 확장하거나 축소할 수 있는 유연성을 제공하여, 소규모 실험부터 대규모 프로덕션 배포까지 폭넓게 지원합니다.
- 재현 가능성W&B의 추적 및 버전 관리 기능은 실험의 재현 가능성을 보장하며, 이는 디버깅, 규제 준수, 학술적 검증에 매우 중요합니다.
- 협업: Weights & Biases의 공유 작업 공간과 Azure의 협업 기능을 결합하면, 위치에 상관없이 팀원이 데이터셋, 모델, 실험을 원활하게 공유할 수 있어 팀워크가 강화됩니다.
- 혁신OpenAI의 고도화된 모델과 API에 대한 접근성은 혁신을 장려합니다. 팀은 최신 기술 발전을 활용해 새로운 접근 방식과 AI 활용 사례를 자유롭게 실험할 수 있습니다.
Azure에서 Weights & Biases로 AI 모델 미세 조정
단계별 튜토리얼을 차근차근 진행해 보겠습니다. 시작하기 전에 Azure 계정과 Azure ML 작업 영역, 그리고 Weights & Biases 계정을 준비해 주세요.
파트 I에서는 OpenAI API 키를 사용해 모델을 미세 조정하고, 결과를 Weights & Biases에 기록합니다. 파트 II에서는 미세 조정된 모델을 Azure에 배포합니다.
시작해 봅시다.
파트 I: 모델 미세 조정과 결과 기록
본격적으로 시작하기 전에, 미세 조정을 위한 필수 라이브러리를 설치하고 노트북 환경에서 아래 코드를 실행하세요.
!pip install wandb!pip install openai azureml-core!pip install openai
OpenAI와 Azure 작업 영역 구성 및 초기화
이제 사용할 모듈을 가져오고 기본 설정을 구성하겠습니다. OpenAI 계정에서 API 키를 확인한 뒤, 환경 변수로 설정하거나 위에서 언급한 방식대로 사용하세요.
또한 아래에 안내한 대로 Weights & Biases와 Azure도 구성하세요. 필요한 정보는 각자의 계정에서 확인할 수 있습니다.
import openaiimport wandbfrom azureml.core import Workspaceimport os# Set OpenAI API Keyopenai.api_key = 'your api key'client = OpenAI(api_key)
Weights & Biases에 로그인하기:
Weights & Biases에 로그인하려면, 여기에 있는 Weights & Biases 키를 입력하라는 메시지가 표시됩니다.
wandb.login()wandb.init(project='project_name', entity='entity_name')
데이터를 JSONL로 변환하기
이 데이터셋은 JSON 형식이지만, 미세 조정을 위해서는 JSONL 형식이 필요합니다. JSONL은 각 데이터 포인트를 구조적이면서도 유연한 방식으로 표현해 대규모 데이터셋을 효율적으로 처리할 수 있고, 다양한 머신러닝 도구와의 호환성이 높아 데이터 처리와 모델 학습 워크플로를 단순화하기 때문에 대규모 언어 모델의 미세 조정에 선호됩니다.
변환해 봅시다:
import jsondef convert_dataset_to_jsonl(input_json_path, output_jsonl_path):with open(input_json_path, 'r', encoding='utf-8') as f:data = json.load(f)with open(output_jsonl_path, 'w', encoding='utf-8') as outfile:for article in data['data']:for paragraph in article['paragraphs']:context = paragraph['context']for qa in paragraph['qas']:question = qa['question']is_impossible = qa.get('is_impossible', False)prompt = f"Context: {context}\nQuestion: {question}\nAnswer:"# Handle both possible and impossible questionsif is_impossible:completion = " Impossible"else:# Using the first answer for simplicityanswer = qa['answers'][0]['text'] if qa['answers'] else "Unknown"completion = f" {answer}"# Write the JSONL entryjsonl_entry = json.dumps({"prompt": prompt, "completion": completion})outfile.write(jsonl_entry + '\n')# Convert your datasetconvert_dataset_to_jsonl('/train-v2.0.json', '/train.jsonl')convert_dataset_to_jsonl('/dev-v2.0.json', '/dev.jsonl')
모델 미세 조정을 위해 학습 및 검증 데이터셋을 OpenAI에 업로드하기
이제 JSONL 형식으로 데이터셋 준비가 끝났으니 OpenAI에 업로드할 차례입니다. 데이터는 한 번만 업로드하고 다음을 저장해 두세요. train_file_id 그리고 dev_file_id 그래서 메모리가 부족해질 때까지 계속 다시 업로드할 필요 없이, 동일한 데이터셋을 여러 실행에서 재사용할 수 있습니다.
def upload_file_to_openai(file_path, purpose='fine-tune'):response = openai.File.create(file=open(file_path), purpose=purpose)return response.idtrain_file_id = upload_file_to_openai("/train.jsonl")dev_file_id = upload_file_to_openai("/dev.jsonl")print(train_file_id)
하이퍼파라미터를 정의하고 Weights & Biases에 로깅하기:
# Define hyperparametershyperparameters = {"n_epochs": 2, # Number of training epochs"batch_size": 4, # Batch size for training"learning_rate_multiplier": 0.1, # Learning rate adjustment factor}# Log hyperparameters to wandbwandb.config.update(hyperparameters)
OpenAI에서 미세 조정 작업을 시작하고 Weights & Biases에 작업 ID를 기록하기:
이제 미세 조정 작업을 시작해 봅시다! 이를 위해 우리는 사용할 것입니다 openai.FineTuningJob.create() 메서드.
fine_tune_response = openai.FineTuningJob.create(training_file=train_file_id,validation_file=dev_file_id,model="babbage-002",hyperparameters=hyperparameters)print(f"Fine-tuning started with ID: {fine_tune_response['id']}")wandb.log({"fine_tune_id": fine_tune_response["id"]})fine_tune_id= fine_tune_response['id']fine_tune_status = openai.FineTuningJob.retrieve(fine_tune_id)print(f"Fine-tuning job status: {fine_tune_status['status']}")
미세 조정 작업 모니터링 및 결과 가져오기
이제 미세 조정 작업이 시작되었으므로, 작업이 완료되었는지 여부와 상태가 궁금합니다. 완료되었다면 이벤트 세부 정보도 필요합니다. 이를 위해 스크립트는 먼저 미세 조정 작업 ID를 받아 초기화하고, 인터럽트 신호(SIGINT)를 처리하기 위한 시그널 핸들러를 등록합니다.
인터럽트를 받으면 미세 조정 작업의 현재 상태를 조회하여 보고합니다. 이어서 해당 작업과 관련된 이벤트를 요청해 스트리밍하고, 각 이벤트의 타임스탬프와 메시지를 형식화해 출력합니다. 스트리밍이 중단되거나 오류가 발생하면 그 사실을 보고합니다.
import signalimport datetimefine_tune_id= fine_tune_response['id']def signal_handler(sig, frame):status = openai.FineTuningJob.retrieve(fine_tune_id)['status'] # Access status correctlyprint(f"Stream interrupted. Job is still {status}.")returnprint(f"Streaming events for the fine-tuning job: {fine_tune_id}")signal.signal(signal.SIGINT, signal_handler)try:events_response = openai.FineTuningJob.list_events(id=fine_tune_id)events = events_response['data'] # Access the list of eventsfor event in events:event_time = datetime.datetime.fromtimestamp(event['created_at']).strftime('%Y-%m-%d %H:%M:%S')print(f"{event_time} {event['message']}")except Exception as e:print(f"Stream interrupted (client disconnected). Error: {str(e)}")
출력이 준비되었습니다—이제 Weights & Biases에 로그로 기록하겠습니다

출처: 작성자
최종 메트릭을 Weights & Biases에 기록하기:
이제 미세 조정 작업의 최종 결과가 준비되었으니, Weights & Biases에 기록하고 생성된 시각화를 확인해 봅시다.
import reimport wandb# Assuming the messages are stored in a list variable named `messages`# messages = [# "2024-02-21 17:33:45 Step 5901/5937: training loss=1.78, validation loss=0.69"# "2024-02-21 17:33:26 Step 5801/5937: training loss=1.29, validation loss=0.62"]for message in messages:# Extract step, training loss, and validation loss using regexmatch = re.search(r"Step (\d+/\d+): training loss=([\d.]+), validation loss=([\d.]+)", message)if match:step, training_loss, validation_loss = match.groups()step = int(step.split('/')[0]) # Extract the current step numbertraining_loss = float(training_loss)validation_loss = float(validation_loss)# Log the metrics to wandbwandb.log({"Step": step, "Training Loss": training_loss, "Validation Loss": validation_loss})# Finish the wandb runwandb.finish()

출처: 작성자
Weights & Biases에서 그래프 보기
이제 미세 조정이 완료되고 모든 메트릭이 Weights & Biases에 기록되었으니, 프로젝트 대시보드를 열어 다음과 같이 실행 기록을 확인할 수 있습니다.

출처: 작성자
차트 패널에서 서로 다른 실행을 비교해 볼 수 있습니다

출처: 작성자
여기에서는 두 개의 그래프가 보이는데, 서로 다른 하이퍼파라미터로 수행된 두 개의 실행에서 나온 결과입니다. 다른 모델을 미세 조정해 실행들을 서로 비교해 볼 수도 있고, Weights & Biases의 훌륭한 기능인 스위프를 만들어 하이퍼파라미터 범위를 정의한 뒤 최적값을 찾아 결과를 비교할 수도 있습니다.
미세 조정된 모델 평가하기
이제 모델을 미세 조정했으므로 평가를 진행하겠습니다. 평가를 위해 질문과 답변으로 구성된 간단한 데이터셋을 준비했습니다. 각 질문과 해당 문맥을 모델에 질의하고, 모델의 답변을 수집한 뒤 이를 pandas DataFrame으로 정리합니다.
마지막으로 결과는 Weights & Biases 프로젝트에 표 형태로 기록되며, 필요에 따라 로컬 사용을 위해 CSV 파일로도 저장됩니다.
# Function to normalize answers (removing punctuation, lowercase, etc.)def normalize_answer(s):import redef remove_articles(text):return re.sub(r'\b(a|an|the)\b', ' ', text)def white_space_fix(text):return ' '.join(text.split())def remove_punct(text):return re.sub(r'[\W]', ' ', text)def lower(text):return text.lower()return white_space_fix(remove_articles(remove_punct(lower(s))))# Calculate F1 scoredef f1_score(prediction, truth):prediction_tokens = normalize_answer(prediction).split()truth_tokens = normalize_answer(truth).split()common_tokens = Counter(prediction_tokens) & Counter(truth_tokens)num_same = sum(common_tokens.values())if num_same == 0: return 0precision = 1.0 * num_same / len(prediction_tokens)recall = 1.0 * num_same / len(truth_tokens)f1 = (2 * precision * recall) / (precision + recall)return f1# Calculate Exact Match scoredef exact_match_score(prediction, truth):return int(normalize_answer(prediction) == normalize_answer(truth))# Function to query the model and get the answerdef query_model(question, context, model):openai.api_key = '<key-here>'response = openai.Completion.create(model=model,prompt=f"Question: {question}\nContext: {context}\nAnswer:",temperature=0,max_tokens=50,top_p=1.0,frequency_penalty=0.0,presence_penalty=0.0,stop=["\n"])return response.choices[0].text.strip()# Test datasettest_data = [{"context": "The Normans (Norman: Nourmands; French: Normands; Latin: Normanni) were the people who in the 10th and 11th centuries gave their name to Normandy, a region in France. They were descended from Norse (\"Norman\" comes from \"Norseman\") raiders and pirates from Denmark, Iceland and Norway who, under their leader Rollo, agreed to swear fealty to King Charles III of West Francia. Through generations of assimilation and mixing with the native Frankish and Roman-Gaulish populations, their descendants would gradually merge with the Carolingian-based cultures of West Francia. The distinct cultural and ethnic identity of the Normans emerged initially in the first half of the 10th century, and it continued to evolve over the succeeding centuries.","qas": [{"question": "In what country is Normandy located?","answer": "France"},{"question": "When were the Normans in Normandy?","answer": "10th and 11th centuries"},{"question": "From which countries did the Norse originate?","answer": "Denmark, Iceland and Norway"},{"question": "Who was the Norse leader?","answer": "Rollo"},{"question": "What century did the Normans first gain their separate identity?","answer": "10th century"}]},{"context": "The distinct cultural and ethnic identity of the Normans emerged initially in the first half of the 10th century, and it continued to evolve over the succeeding centuries.","qas": [{"question": "Who was the duke in the battle of Hastings?","answer": "William the Conqueror"},{"question": "Who ruled the duchy of Normandy","answer": "Richard I"}]}]# Adjusted part of the script to compile results into a DataFramedetailed_results = [] # List to store detailed resultsfor item in test_data:context = item['context']for qa in item['qas']:question = qa['question']true_answer = qa['answer']model_answer = query_model(question, context, model="modelid")# Append detailed result for each questiondetailed_results.append({"question": question,"model_answer": model_answer,"true_answer": true_answer })# Convert detailed results list to DataFramedf_results = pd.DataFrame(detailed_results)# Log the entire DataFrame as a table to W&Bwandb.log({"results_table": wandb.Table(dataframe=df_results)})# Optional: Save the DataFrame to CSV for local usedf_results.to_csv('evaluation_results.csv', index=False)
다음은 Weights & Biases에서 제공하는 최종 표로, 정답과 모델이 생성한 답변을 함께 보여줍니다. 이 표를 활용해 미세 조정된 모델의 성능과 답변 품질을 평가할 수 있습니다.

출처: 작성자
파트 II: Azure로 배포하기
Azure 포털에서 아직 없다면 새로운 Azure Machine Learning 워크스페이스를 만드세요. 이 워크스페이스는 모델, 데이터셋, 배포를 관리하는 중앙 허브 역할을 합니다.
개발 환경에 Azure ML 서비스와 상호작용할 수 있도록 Azure ML SDK가 설치되어 있는지 확인하세요. 다음 명령으로 설치할 수 있습니다: pip install azureml-sdk
from azureml.core import Workspace# Provide your Azure subscription ID, resource group name, and workspace namesubscription_id = 'your-subscription-id'resource_group = 'your-resource-group'workspace_name = 'your-workspace-name'# Access the workspacews = Workspace(subscription_id=subscription_id, resource_group=resource_group, workspace_name=workspace_name)print("Loaded workspace:", ws.name)
1. 배포할 모델 준비하기
미세 조정된 OpenAI 모델의 모델 ID를 확보하세요. 이 ID는 OpenAI API를 통해 모델을 불러오고 사용하는 데 필요합니다. 모델 ID는 다음에서 확인할 수 있습니다. openai.FineTuningJob.list() 명령
채점 스크립트를 작성하세요 (score.py) OpenAI API를 사용해 미세 조정된 모델을 로드하고, 해당 모델로 예측을 수행하는 방법을 정의합니다.
import openaiimport jsondef init():global openai_modelopenai.api_key = 'your_openai_api_key'openai_model = 'your_model_id' # Replace with your fine-tuned model ID (find it here openai.FineTuningJob.list())def run(raw_data):data = json.loads(raw_data)response = openai.Completion.create(model=openai_model,prompt=data['prompt'],temperature=0.7,max_tokens=150)return response.choices[0].text
2. 채점 스크립트 준비하기
채점 스크립트는 특히 Azure Machine Learning(Azure ML)과 같은 클라우드 환경에서 추론을 위해 머신러닝 모델을 배포할 때 중요한 역할을 합니다. 이 스크립트는 입력 데이터를 처리하고 예측을 수행한 뒤 결과를 반환하는 진입점 역할을 합니다.
다음 스크립트에는 모델 초기화와 예측 실행을 위한 함수들이 포함되어 있습니다.
%%writefile score.pyimport openaiimport jsondef init():global openai_modelopenai.api_key = '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'openai_model = 'ft:babbage-002:personal::8ug5NMO9' # Replace with your fine-tuned model IDdef run(raw_data):data = json.loads(raw_data)response = openai.Completion.create(model=openai_model,prompt=data['prompt'],temperature=0.7,max_tokens=150)return response.choices[0].text
3. 모델을 웹 서비스로 배포하기:
이제 모델을 Azure에 배포할 차례입니다. 아래 코드 스니펫은 Azure Machine Learning에서 Azure의 확장 가능한 인프라를 활용해 머신러닝 모델을 웹 서비스로 배포하는 방법을 보여줍니다.
먼저 Conda 사양을 기반으로 추론 환경을 만들고, 사용자 지정 채점 스크립트로 추론 구성을 설정했으며, 실시간 예측을 위해 Azure Container Instances(ACI)를 사용해 모델을 배포했습니다.
이는 Azure ML에서의 모델 배포 라이프사이클을 포괄하며, 애플리케이션이 REST API 엔드포인트를 통해 모델의 기능을 활용할 수 있도록 접근성을 제공합니다.
from azureml.core import Workspace, Modelfrom azureml.core import Environmentfrom azureml.core.model import InferenceConfigfrom azureml.core.webservice import AciWebservice# Create an environment from the yml fileenv = Environment.from_conda_specification(name="myenv", file_path="myenv.yml")# Create an inference configurationinference_config = InferenceConfig(entry_script="score.py", environment=env)# Set the deployment configurationdeployment_config = AciWebservice.deploy_configuration(cpu_cores=1, memory_gb=1)# Deploy the model as a web serviceservice = Model.deploy(workspace=ws,name="openai-model-service",models=[], # No models are registered in Azure ML since we're using an external OpenAI modelinference_config=inference_config,deployment_config=deployment_config,overwrite=True)service.wait_for_deployment(show_output=True)print(f"Service state: {service.state}")print(f"Scoring URI: {service.scoring_uri}")
결론
결론적으로, Azure, OpenAI, 그리고 Weights & Biases 간의 시너지는 개발부터 배포와 모니터링에 이르는 전체 머신러닝 수명주기를 포괄하는 강력한 프레임워크를 제공합니다. Azure의 견고한 클라우드 인프라는 확장 가능한 컴퓨팅 및 스토리지의 기반을 제공하고, OpenAI는 최첨단 AI 모델을 손쉽게 활용할 수 있게 하며, Weights & Biases는 실험 추적과 최적화 기능으로 이 과정을 한층 강화합니다.
우리는 OpenAI 모델을 성공적으로 파인튜닝하고, Weights & Biases에 메트릭을 기록하여 시각화를 검토하고 하이퍼파라미터를 추적했습니다. 이후 파인튜닝한 모델을 Azure에 배포했으며, 이를 통해 Azure, OpenAI, 그리고 Weights & Biases의 통합 기능을 활용해 AI 모델을 파인튜닝했습니다. 이는 AI와 ML 분야의 중요한 진화를 알리는 것으로, 개발자, 데이터 사이언티스트, 그리고 조직이 인공지능의 한계를 확장할 수 있도록 견고한 프레임워크를 제공합니다.
Add a comment