미세 조정 튜토리얼

ai.google.dev에서 보기 Google Colab에서 실행 GitHub에서 소스 보기

이 노트북에서는 CURL 명령어 또는 Python 요청 API를 사용하여 Gemini API 조정 서비스를 시작하여 Gemini API를 호출하는 방법을 알아봅니다. 여기에서는 Gemini API의 텍스트 생성 서비스의 기반이 되는 텍스트 모델을 조정하는 방법을 알아봅니다.

인증 설정

Gemini API를 사용하면 자체 데이터를 기반으로 모델을 조정할 수 있습니다. 사용자의 데이터와 조정된 모델이므로 API 키가 제공할 수 있는 것보다 더 엄격한 액세스 제어가 필요합니다.

이 가이드를 실행하기 전에 먼저 프로젝트의 OAuth를 설정해야 합니다.

Colab에서 가장 쉽게 설정하는 방법은 client_secret.json 파일의 콘텐츠를 보안 비밀 이름이 CLIENT_SECRET인 Colab의 'Secrets Manager' (왼쪽 패널의 키 아이콘 아래)에 복사하는 것입니다.

이 gcloud 명령어는 client_secret.json 파일을 서비스에 인증하는 데 사용할 수 있는 사용자 인증 정보로 변환합니다.

try:
  from google.colab import userdata
  import pathlib
  pathlib.Path('client_secret.json').write_text(userdata.get('CLIENT_SECRET'))

  # Use `--no-browser` in colab
  !gcloud auth application-default login --no-browser --client-id-file client_secret.json --scopes='https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/generative-language.tuning'
except ImportError:
  !gcloud auth application-default login --client-id-file client_secret.json --scopes='https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/generative-language.tuning'
You are authorizing client libraries without access to a web browser. Please run the following command on a machine with a web browser and copy its output back here. Make sure the installed gcloud version is 372.0.0 or newer.

gcloud auth application-default login --remote-bootstrap="https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=87071151422-n1a3cb6c7fvkfg4gmhdtmn5ulol2l4be.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgenerative-language.tuning&state=QIyNibWSaTIsozjmvZEkVBo6EcoW0G&access_type=offline&code_challenge=76c1ZiGvKN8cvlYfj3BmbCwE4e7tvrlwaX3REUX25gY&code_challenge_method=S256&token_usage=remote"

Enter the output of the above command: https://localhost:8085/?state=QIyNibWSaTIsozjmvZEkVBo6EcoW0G&code=4/0AeaYSHBKrY911S466QjKQIFODoOPXlO1mWyTYYdrbELIDV6Hw2DKRAyro62BugroSvIWsA&scope=https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/generative-language.tuning

Credentials saved to file: [/content/.config/application_default_credentials.json]

These credentials will be used by any library that requests Application Default Credentials (ADC).

변수 설정

CURL

나머지 REST API 호출에 사용할 반복 값의 변수를 설정합니다. 이 코드는 Python os 라이브러리를 사용하여 모든 코드 셀에서 액세스할 수 있는 환경 변수를 설정합니다.

이는 Colab 노트북 환경에만 적용됩니다. 다음 코드 셀의 코드는 bash 터미널에서 다음 명령어를 실행하는 것과 같습니다.

export access_token=$(gcloud auth application-default print-access-token)
export project_id=my-project-id
export base_url=https://generativelanguage.googleapis.com
import os

access_token = !gcloud auth application-default print-access-token
access_token = '\n'.join(access_token)

os.environ['access_token'] = access_token
os.environ['project_id'] = "[Enter your project-id here]"
os.environ['base_url'] = "https://generativelanguage.googleapis.com"

Python

access_token = !gcloud auth application-default print-access-token
access_token = '\n'.join(access_token)

project = '[Enter your project-id here]'
base_url = "https://generativelanguage.googleapis.com"

requests 라이브러리를 가져옵니다.

import requests
import json

조정된 모델 나열

사용 가능한 조정된 모델을 나열하여 인증 설정을 확인합니다.

CURL


curl -X GET ${base_url}/v1beta/tunedModels \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${access_token}" \
    -H "x-goog-user-project: ${project_id}"

Python

headers={
  'Authorization': 'Bearer ' + access_token,
  'Content-Type': 'application/json',
  'x-goog-user-project': project
}

result = requests.get(
  url=f'{base_url}/v1beta/tunedModels',
  headers = headers,
)
result.json()

미세 조정된 모델 만들기

조정된 모델을 만들려면 training_data 필드의 모델에 데이터 세트를 전달해야 합니다.

이 예시에서는 시퀀스의 다음 숫자를 생성하도록 모델을 조정합니다. 예를 들어 입력이 1이면 모델은 2를 출력해야 합니다. 입력이 one hundred이면 출력은 one hundred one입니다.

CURL


curl -X POST $base_url/v1beta/tunedModels \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer ${access_token}" \
    -H "x-goog-user-project: ${project_id}" \
    -d '
      {
        "display_name": "number generator model",
        "base_model": "models/gemini-1.0-pro-001",
        "tuning_task": {
          "hyperparameters": {
            "batch_size": 2,
            "learning_rate": 0.001,
            "epoch_count":5,
          },
          "training_data": {
            "examples": {
              "examples": [
                {
                    "text_input": "1",
                    "output": "2",
                },{
                    "text_input": "3",
                    "output": "4",
                },{
                    "text_input": "-3",
                    "output": "-2",
                },{
                    "text_input": "twenty two",
                    "output": "twenty three",
                },{
                    "text_input": "two hundred",
                    "output": "two hundred one",
                },{
                    "text_input": "ninety nine",
                    "output": "one hundred",
                },{
                    "text_input": "8",
                    "output": "9",
                },{
                    "text_input": "-98",
                    "output": "-97",
                },{
                    "text_input": "1,000",
                    "output": "1,001",
                },{
                    "text_input": "10,100,000",
                    "output": "10,100,001",
                },{
                    "text_input": "thirteen",
                    "output": "fourteen",
                },{
                    "text_input": "eighty",
                    "output": "eighty one",
                },{
                    "text_input": "one",
                    "output": "two",
                },{
                    "text_input": "three",
                    "output": "four",
                },{
                    "text_input": "seven",
                    "output": "eight",
                }
              ]
            }
          }
        }
      }' | tee tunemodel.json
{
"name": "tunedModels/number-generator-model-dzlmi0gswwqb/operations/bvl8dymw0fhw",
"metadata": {
  "@type": "type.googleapis.com/google.ai.generativelanguage.v1beta.CreateTunedModelMetadata",
  "totalSteps": 38,
  "tunedModel": "tunedModels/number-generator-model-dzlmi0gswwqb"
}
}
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                              Dload  Upload   Total   Spent    Left  Speed
100  2280    0   296  100  1984    611   4098 --:--:-- --:--:-- --:--:--  4720

Python

operation = requests.post(
    url = f'{base_url}/v1beta/tunedModels',
    headers=headers,
    json= {
        "display_name": "number generator",
        "base_model": "models/gemini-1.0-pro-001",
        "tuning_task": {
          "hyperparameters": {
            "batch_size": 4,
            "learning_rate": 0.001,
            "epoch_count":5,
          },
          "training_data": {
            "examples": {
              "examples": [
                {
                    'text_input': '1',
                    'output': '2',
                },{
                    'text_input': '3',
                    'output': '4',
                },{
                    'text_input': '-3',
                    'output': '-2',
                },{
                    'text_input': 'twenty two',
                    'output': 'twenty three',
                },{
                    'text_input': 'two hundred',
                    'output': 'two hundred one',
                },{
                    'text_input': 'ninety nine',
                    'output': 'one hundred',
                },{
                    'text_input': '8',
                    'output': '9',
                },{
                    'text_input': '-98',
                    'output': '-97',
                },{
                    'text_input': '1,000',
                    'output': '1,001',
                },{
                    'text_input': '10,100,000',
                    'output': '10,100,001',
                },{
                    'text_input': 'thirteen',
                    'output': 'fourteen',
                },{
                    'text_input': 'eighty',
                    'output': 'eighty one',
                },{
                    'text_input': 'one',
                    'output': 'two',
                },{
                    'text_input': 'three',
                    'output': 'four',
                },{
                    'text_input': 'seven',
                    'output': 'eight',
                }
              ]
            }
          }
        }
      }
)
operation
<Response [200]>
operation.json()
{'name': 'tunedModels/number-generator-wl1qr34x2py/operations/41vni3zk0a47',
'metadata': {'@type': 'type.googleapis.com/google.ai.generativelanguage.v1beta.CreateTunedModelMetadata',
  'totalSteps': 19,
  'tunedModel': 'tunedModels/number-generator-wl1qr34x2py'} }

나머지 호출에 사용할 조정된 모델의 이름으로 변수를 설정합니다.

name=operation.json()["metadata"]["tunedModel"]
name
'tunedModels/number-generator-wl1qr34x2py'

조정된 모델 상태 가져오기

학습 중에는 모델 상태가 CREATING로 설정되고 완료되면 ACTIVE로 변경됩니다.

CURL

다음은 응답 JSON에서 생성된 모델 이름을 파싱하는 Python 코드입니다. 터미널에서 이를 실행하는 경우 bash JSON 파서를 사용하여 응답을 파싱해 볼 수 있습니다.

import json

first_page = json.load(open('tunemodel.json'))
os.environ['modelname'] = first_page['metadata']['tunedModel']

print(os.environ['modelname'])
tunedModels/number-generator-model-dzlmi0gswwqb

모델 이름으로 다른 GET 요청을 수행하여 상태 필드가 포함된 모델 메타데이터를 가져옵니다.


curl -X GET ${base_url}/v1beta/${modelname} \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer ${access_token}" \
    -H "x-goog-user-project: ${project_id}" | grep state
"state": "ACTIVE",
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                              Dload  Upload   Total   Spent    Left  Speed
100  5921    0  5921    0     0  13164      0 --:--:-- --:--:-- --:--:-- 13157

Python

tuned_model = requests.get(
    url = f'{base_url}/v1beta/{name}',
    headers=headers,
)
tuned_model.json()

아래 코드는 더 이상 CREATING 상태가 될 때까지 상태 필드를 5초마다 확인합니다.

import time
import pprint

op_json = operation.json()
response = op_json.get('response')
error = op_json.get('error')

while response is None and error is None:
    time.sleep(5)

    operation = requests.get(
        url = f'{base_url}/v1/{op_json["name"]}',
        headers=headers,
    )

    op_json = operation.json()
    response = op_json.get('response')
    error = op_json.get('error')

    percent = op_json['metadata'].get('completedPercent')
    if percent is not None:
      print(f"{percent:.2f}% - {op_json['metadata']['snapshots'][-1]}")
      print()

if error is not None:
    raise Exception(error)
100.00% - {'step': 19, 'epoch': 5, 'meanLoss': 1.402067, 'computeTime': '2024-03-14T15:11:23.766989274Z'}

추론 실행

조정 작업이 완료되면 이를 사용하여 텍스트 서비스로 텍스트를 생성할 수 있습니다.

CURL

로마 숫자로 63 (LXIII)을 입력해 보세요.


curl -X POST $base_url/v1beta/$modelname:generateContent \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer ${access_token}" \
    -H "x-goog-user-project: ${project_id}" \
    -d '{
        "contents": [{
        "parts": [{
          "text": "LXIII"
          }]
        }]
        }' 2> /dev/null
{
"candidates": [
  {
    "content": {
      "parts": [
        {
          "text": "LXIV"
        }
      ],
      "role": "model"
    },
    "finishReason": "STOP",
    "index": 0,
    "safetyRatings": [
      {
        "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_HATE_SPEECH",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_HARASSMENT",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
        "probability": "NEGLIGIBLE"
      }
    ]
  }
],
"promptFeedback": {
  "safetyRatings": [
    {
      "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
      "probability": "NEGLIGIBLE"
    },
    {
      "category": "HARM_CATEGORY_HATE_SPEECH",
      "probability": "NEGLIGIBLE"
    },
    {
      "category": "HARM_CATEGORY_HARASSMENT",
      "probability": "NEGLIGIBLE"
    },
    {
      "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
      "probability": "NEGLIGIBLE"
    }
  ]
}
}

모델의 출력이 정확하지 않을 수도 있습니다. 조정된 모델이 필요한 표준에 미치지 못하는 경우 고품질 예시를 더 추가하거나, 초매개변수를 조정하거나, 예에 프리앰블을 추가해 볼 수 있습니다. 처음 만든 모델을 기반으로 또 다른 조정된 모델을 만들 수도 있습니다.

성능 개선에 대한 자세한 내용은 조정 가이드를 참조하세요.

Python

일본어 숫자 (예: 6)를 입력해 보세요.

import time

m = requests.post(
    url = f'{base_url}/v1beta/{name}:generateContent',
    headers=headers,
    json= {
        "contents": [{
            "parts": [{
                "text": "六"
            }]
          }]
    })
import pprint
pprint.pprint(m.json())
{'candidates': [{'content': {'parts': [{'text': '七'}], 'role': 'model'},
                'finishReason': 'STOP',
                'index': 0,
                'safetyRatings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
                                    'probability': 'NEGLIGIBLE'},
                                  {'category': 'HARM_CATEGORY_HATE_SPEECH',
                                    'probability': 'NEGLIGIBLE'},
                                  {'category': 'HARM_CATEGORY_HARASSMENT',
                                    'probability': 'LOW'},
                                  {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
                                    'probability': 'NEGLIGIBLE'}]}],
'promptFeedback': {'safetyRatings': [{'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
                                      'probability': 'NEGLIGIBLE'},
                                      {'category': 'HARM_CATEGORY_HATE_SPEECH',
                                      'probability': 'NEGLIGIBLE'},
                                      {'category': 'HARM_CATEGORY_HARASSMENT',
                                      'probability': 'NEGLIGIBLE'},
                                      {'category': 'HARM_CATEGORY_DANGEROUS_CONTENT',
                                      'probability': 'NEGLIGIBLE'}]} }

모델의 출력이 정확하지 않을 수도 있습니다. 조정된 모델이 필요한 표준에 미치지 못하는 경우 고품질 예시를 더 추가하거나, 초매개변수를 조정하거나, 예에 프리앰블을 추가해 볼 수 있습니다.

결론

학습 데이터에 로마나 일본어 숫자에 대한 참조가 포함되어 있지 않았음에도 불구하고 모델을 미세 조정한 후에도 잘 일반화할 수 있었습니다. 이렇게 하면 사용 사례에 맞게 모델을 미세 조정할 수 있습니다.

다음 단계

Gemini API용 Python SDK를 사용하여 조정 서비스를 사용하는 방법을 알아보려면 Python으로 조정 빠른 시작을 참고하세요. Gemini API에서 다른 서비스를 사용하는 방법을 알아보려면 Python 빠른 시작을 참조하세요.