보상 함수 구현 - Amazon SageMaker AI

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

보상 함수 구현

개요

보상 함수(득점기 또는 그레이더라고도 함)는 모델 응답을 평가하고 훈련을 위한 피드백 신호를 제공하는 핵심 구성 요소입니다. 모델 응답을 수락하고 보상 점수를 반환하는 Lambda 함수로 구현해야 합니다.

인터페이스 형식

보상 함수는 다음 형식으로 데이터를 수락하고 반환해야 합니다.

훈련을 위한 샘플 입력 샘플

{ "messages": [ { "role": "user", "content": "Do you have a dedicated security team?" } ], "reference_answer": { "compliant": "No", "explanation": "As an AI developed by Company, I do not have a traditional security team..." } }

보상 lambda용 샘플 페이로드

컨테이너는 다음을 통해 Lambda 함수로 전송하기 전에 데이터를 자동으로 변환합니다.

  1. 각 프롬프트에 대한 모델 응답 생성

  2. 메시지 배열에 어시스턴트 턴(생성된 응답) 추가

  3. 추적을 위한 고유 id 필드 추가

Lambda 함수는 변환된 형식으로 데이터를 수신합니다.

{ "id": "123", "messages": [ { "role": "user", "content": "Do you have a dedicated security team?" }, { "role": "assistant", "content": "As an AI developed by Amazon, I don not have a dedicated security team..." } ], # Following section will be same as your training dataset sample "reference_answer": { "compliant": "No", "explanation": "As an AI developed by Company, I do not have a traditional security team..." } }

보상 Lambda 계약

def lambda_handler(event, context): return lambda_grader(event) def lambda_grader(samples: list[dict]) -> list[dict]: """ Args: samples: List of dictionaries in OpenAI format Example input: { "id": "123", "messages": [ { "role": "user", "content": "Do you have a dedicated security team?" }, { "role": "assistant", "content": "As an AI developed by Company, I don nott have a dedicated security team..." } ], # This section will be same as your training dataset "reference_answer": { "compliant": "No", "explanation": "As an AI developed by Company, I do not have a traditional security team..." } } Returns: List of dictionaries with reward scores: { "id": str, # Same id as input sample "aggregate_reward_score": float, # Overall score for the sample "metrics_list": [ # OPTIONAL: Component scores { "name": str, # Name of the component score "value": float, # Value of the component score "type": str # "Reward" or "Metric" } ] } """

입력 및 출력 필드

입력 필드

필드 설명 추가 참고 사항
id 샘플의 고유 식별자 출력에서 다시 에코됩니다. 문자열 형식
messages OpenAI 형식으로 정렬된 채팅 기록 메시지 객체 배열
messages[].role 메시지의 화자 공통 값: "user", "assistant", "system"
messages[].content 메시지의 텍스트 콘텐츠 일반 문자열
**메타데이터 그레이딩에 도움이 되는 자유 형식 정보 객체, 훈련 데이터에서 전달되는 선택적 필드

출력 필드

필드 설명 추가 참고 사항
id 입력 샘플과 동일한 식별자 입력과 일치해야 합니다.
aggregate_reward_score 샘플의 전체 점수 부동 소수점(예: 0.0~1.0 또는 작업 정의 범위)
metrics_list 집계를 구성하는 구성 요소 점수 지표 객체 배열

기술적 제약 조건

  • 제한 시간 - Lambda 호출당 최대 실행 시간 15분

  • 동시성 - rollout_worker_replicas * 64 동시 요청을 처리해야 합니다.

  • 신뢰성 - 적절한 오류 처리를 구현하고 유효한 점수를 일관되게 반환해야 합니다.

  • 성능 - 빠른 실행(초, 분 아님)을 위해 최적화하여 효율적인 훈련을 가능하게 합니다.

모범 사례

  • 외부 API 호출 최소화

  • 효율적인 알고리즘 및 데이터 구조 사용

  • 일시적 장애에 대한 재시도 로직 구현

  • 캐시 재사용 가능한 계산

  • 훈련 전에 철저히 테스트하여 버그가 없는지 확인합니다.

사용자 지정 보상 함수 사용

작업별 평가 기준이 있는 경우 사용자 지정 보상 함수를 구현합니다.

  • 평가 기준 정의 - 작업에 대한 좋은 응답의 원인을 결정합니다.

  • Lambda 함수 구현 - 인터페이스 형식에 따라 Lambda 함수 생성

  • 로컬에서 테스트 - 함수가 샘플 입력에 대한 올바른 점수를 반환하는지 확인

  • 에 배포 AWS - Lambda를 배포하고 ARN을 기록해 둡니다.

  • 레시피 구성 - Lambda ARN을 레시피의 reward_lambda_arn 필드에 추가합니다.

  • 소규모 데이터 세트로 테스트 - 최소한의 데이터로 RFT를 실행하여 통합 확인

IAM 권한

필수 권한

SageMaker 실행 역할에는 Lambda 함수를 호출할 수 있는 권한이 있어야 합니다. 이 정책을 SageMaker 실행 역할에 추가합니다.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": "arn:aws:lambda:region:account-id:function:function-name" } ] }

Lambda 실행 역할

Lambda 함수의 실행 역할에는 기본 Lambda 실행 권한이 필요합니다.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" } ] }

추가 권한: Lambda 함수가 다른 AWS 서비스(예: 참조 데이터의 경우 S3, 로깅의 경우 DynamoDB)에 액세스하는 경우 해당 권한을 Lambda 실행 역할에 추가합니다.

예: LLM Judge 보상 함수

이 예제에서는 Amazon Bedrock 모델을 판사로 사용하여 모델 응답을 참조 답변과 비교하여 모델 응답을 평가하는 방법을 보여줍니다. 이 Lambda 템플릿은 고객이 판단 평가를 처리하기 위한 추론 요청에 대해 Amazon Bedrock에 대한 호출을 구현할 수 있는 프레임워크를 제공합니다. Lambda 함수는 다른 보상 함수와 동일한 입력/출력 계약을 유지합니다.

구현

이 Lambda 함수는 2단계 평가 프로세스를 구현합니다. 즉,는 수신 샘플에서 모델 응답과 참조 응답을 lambda_handler 추출한 다음 lambda_graded Amazon Bedrock을 호출하여 이들 간의 의미 유사성을 평가합니다. 구현에는 일시적인 장애에 대한 자동 재시도를 통한 강력한 오류 처리가 포함되며 유연한 참조 응답 형식(문자열 및 구조화된 사전 형식 모두)을 지원합니다.

구현 세부 정보:

  • 재시도 로직: Bedrock API 속도 제한을 처리하기 위한 제한 예외에 대한 지수 백오프(1초, 2초, 4초)를 구현합니다.

  • 오류 처리: 예외를 발생시키는 대신 실패한 평가에 대해 0.0의 점수를 반환합니다.

  • 결정적 점수: 온도=0.0을 사용하여 평가 전반에서 일관된 점수 보장

  • 유연한 참조 형식: 문자열 및 사전 참조 답변을 자동으로 처리

  • 점수 고정: 모든 점수가 유효한 [0.0, 1.0] 범위 내에 있는지 확인합니다.

  • 모델 애그노스틱: 모든 Amazon Bedrock 모델(Nova, Llama, Mistral 등)을 사용하도록 JUDGE_MODEL_ID 변경

""" LLM Judge Lambda POC - Working implementation using Amazon Bedrock """ import json import time import boto3 bedrock_runtime = boto3.client('bedrock-runtime', region_name='us-east-1') JUDGE_MODEL_ID = "anthropic.claude-3-5-sonnet-20240620-v1:0" SYSTEM_PROMPT = "You must output ONLY a number between 0.0 and 1.0. No explanations, no text, just the number." JUDGE_PROMPT_TEMPLATE = """Compare the following two responses and rate how similar they are on a scale of 0.0 to 1.0, where: - 1.0 means the responses are semantically equivalent (same meaning, even if worded differently) - 0.5 means the responses are partially similar - 0.0 means the responses are completely different or contradictory Response A: {response_a} Response B: {response_b} Output ONLY a number between 0.0 and 1.0. No explanations.""" def lambda_graded(response_a: str, response_b: str, max_retries: int = 3) -> float: """Call Bedrock to compare responses and return similarity score.""" prompt = JUDGE_PROMPT_TEMPLATE.format(response_a=response_a, response_b=response_b) for attempt in range(max_retries): try: response = bedrock_runtime.converse( modelId=JUDGE_MODEL_ID, messages=[{"role": "user", "content": [{"text": prompt}]}], system=[{"text": SYSTEM_PROMPT}], inferenceConfig={"temperature": 0.0, "maxTokens": 10} ) print(f"Bedrock call successful: {response}") output = response['output']['message']['content'][0]['text'].strip() score = float(output) print(f"Score parsed: {score}") return max(0.0, min(1.0, score)) except Exception as e: if "ThrottlingException" in str(e) and attempt < max_retries - 1: time.sleep(2 ** attempt) else: print(f"Bedrock call failed: {e}") return None return None def lambda_handler(event, context): """AWS Lambda handler - processes samples from RFTEvalInvoker.""" try: samples = event if isinstance(event, list) else [event] results = [] for sample in samples: sample_id = sample.get("id", "unknown") messages = sample.get("messages", []) # Extract assistant response (response A) response_a = "" for msg in messages: if msg.get("role") in ["assistant", "nova_assistant"]: response_a = msg.get("content", "") break # Extract reference answer from root level (no longer in metadata) reference_answer = sample.get("reference_answer", "") # Handle both string and dict reference_answer formats if isinstance(reference_answer, dict): # If reference_answer is a dict, extract the explanation or compliant field response_b = reference_answer.get("explanation", reference_answer.get("compliant", "")) else: response_b = reference_answer if not response_a or not response_b: results.append({ "id": sample_id, "aggregate_reward_score": 0.0, "metrics_list": [{"name": "similarity_score", "value": 0.0, "type": "Metric"}] }) continue # Get similarity score score = lambda_graded(response_a, response_b) results.append({ "id": sample_id, "aggregate_reward_score": score, "metrics_list": [ { "name": "similarity_score", "value": score, "type": "Metric" } ] }) return {"statusCode": 200, "body": json.dumps(results)} except Exception as e: print(f"Error: {e}") return {"statusCode": 500, "body": json.dumps({"error": str(e)})}

입력 형식

Lambda는 다른 보상 함수와 동일한 입력 형식을 받습니다.

{ "id": "sample-001", "messages": [ { "role": "user", "content": "Do you have a dedicated security team?" }, { "role": "assistant", "content": "As an AI developed by Amazon, I don't have a dedicated security team..." } ], "reference_answer": { "compliant": "No", "explanation": "As an AI developed by Company, I do not have a traditional security team..." }, "my_custom_field": "custom_value" }

출력 형식

{ "id": "sample-001", "aggregate_reward_score": 0.85, "metrics_list": [ { "name": "similarity_score", "value": 0.85, "type": "Metric" } ] }

배포 고려 사항

선택한 모델의 기능 및 API 형식에 따라 프롬프트 템플릿 및 추론 파라미터를 조정해야 할 수도 있습니다.

  • IAM 권한: Lambda 실행 역할에 선택한 모델에 대한 bedrock:InvokeModel 권한이 있어야 합니다.

  • 제한 시간: Bedrock API 지연 시간 및 재시도를 수용할 수 있도록 Lambda 제한 시간을 최소 60초로 설정합니다.

  • 리전: 선택한 Bedrock 모델을 사용할 수 있는 리전에 배포

  • 비용: 각 평가가 샘플당 하나의 API를 호출할 때 Bedrock API 사용량 모니터링

  • 처리량: 대규모 평가의 경우 제한을 방지하기 위해 Bedrock 할당량 증가를 요청합니다.

Bedrock 처리량 증가

평가 중에 제한이 발생하는 경우 Bedrock 모델 할당량을 늘리세요.

  • AWS Service Quotas 콘솔로 이동합니다.

  • "Bedrock"을 검색하고 리전을 선택합니다.

  • 선택한 모델의 할당량 찾기(예: “Claude 3.5 Sonnet에 대한 분당 호출”)

  • "할당량 증가 요청"을 클릭하고 원하는 처리량을 지정합니다.

  • 증가에 대한 근거 제공(예: "RFT 평가 워크로드")

Lambda의 기본 제공 재시도 로직은 간헐적인 제한을 처리하지만 지속적인 대용량 평가에는 적절한 할당량 증가가 필요합니다.

필수 IAM 정책:

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "bedrock:InvokeModel" ], "Resource": "arn:aws:bedrock:*::foundation-model/*" } ] }