지원 종료된 Hugging Face 어댑터의 계약과 교체
Import an open source model에서 사용하던 기본 언어 모델 어댑터는 지원이 종료되었습니다. 직접 모델 배포 같은 신규 기능을 추가하는 대상도 아닙니다. 새 연결은 Hugging Face 모델 가져오기와 자신의 Model Adapter Library를 사용하여 게시하고 유지합니다. AIP에서 제공하는 언어 모델을 변환 클라이언트로 호출하는 경로도 있습니다.
기존 모델이 사용하는 어댑터는 Modeling Objectives의 모델 제출 페이지에서 확인할 수 있습니다. 교체 시에는 해당 모델 버전의 API와 소비자가 사용하는 출력 형식을 함께 확인합니다.
공통 표 API와 장치 선택
대부분의 클래스는 inference_data라는 Pandas 입력과 output_data라는 Pandas 출력을 사용합니다. 입력의 text 열을 처리하고 기존 행 인덱스에 맞춰 결과를 추가합니다. 생성형 모델과 텍스트 분류 및 NER의 기본 배치 크기는 16, 임베딩의 기본 문장 배치 크기는 128입니다. 제로샷 분류는 행마다 후보 레이블이 다를 수 있어 행 단위로 처리합니다.
CPU와 GPU는 추론 시 선택합니다. CUDA를 사용할 수 있으면 cuda:0, 없으면 CPU입니다. 로드 과정과 추론이 서로 다른 프로세스에서 실행될 수 있으므로 CUDA 컨텍스트를 load에서 초기화하면 공유 메모리 재초기화 오류가 생길 수 있습니다. 모델의 장치 이동은 첫 predict에서 처리해야 합니다.
DeviceMixin의 역할은 다음과 같습니다.
| 메서드 | 동작 |
|---|---|
| _get_cuda_or_cpu() | CUDA 가용 여부에 따라 torch.device를 반환합니다. |
| _move_model_to_device_once(device) | 모델을 선택한 장치로 한 번 이동하고 이동 상태를 기록합니다. |
| _move_pipeline_to_device_once(device) | CPU이면 이동 완료 상태를 기록합니다. 다른 장치는 파이프라인을 임시 저장하고 그 장치로 다시 생성한 뒤 완료 상태를 기록합니다. |
파이프라인 이동 여부를 검사하는 상태와 갱신하는 상태는 같은 변수를 사용해야 합니다. 상태 기록이 맞지 않으면 매 추론마다 저장과 재생성을 반복하게 됩니다.
시퀀스 간 생성
Seq2SeqLMModelAdapter는 AutoModelForSeq2SeqLM을 사용하는 인코더-디코더 모델을 감쌉니다. T5와 BART 같은 모델에 사용하며 입력 프롬프트 구조는 선택한 모델의 학습 방식에 맞아야 합니다. 예를 들어 flan-t5-large는 번역, 요약과 질의응답 프롬프트를 처리하는 모델입니다.
| 항목 | 계약 |
|---|---|
| 입력 | inference_data의 text: str |
| 출력 | output_data의 text: str 및 prediction: str |
| 배치 | 16행 |
| 생성 | padding한 토큰을 장치에 옮겨 generate를 호출하고 특수 토큰을 제외하여 디코딩합니다. |
| temperature | 기본 1.0입니다. 입력에 temperature 열이 있고 행이 있으면 첫 행의 값을 전체 호출에 사용합니다. |
첫 행의 temperature가 float가 아니면 float로 변환합니다. 값 변환에 실패하면 Temperature must be a float라는 ValueError를 발생시킵니다. 값을 행마다 다르게 주어도 첫 값만 선택합니다. 생성기에 temperature를 전달하며 실제 효과는 해당 모델의 샘플링 설정에 따라 달라집니다.
로드와 저장
생성자에 tokenizer와 model을 직접 전달하거나 state_reader에서 저장한 파일을 추출하여 초기화할 수 있습니다. 파일에서 로드할 때 임시 디렉터리를 어댑터가 보관합니다. 저장 전에는 연속적이지 않은 가중치 텐서를 contiguous 형태로 만든 뒤 토크나이저 및 모델 파일을 저장합니다.
새 어댑터에서는 HfAutoModelSerializer와 HfAutoTokenizerSerializer로 이 저장과 로드를 구성할 수 있습니다. 모델 직렬화기에는 AutoModelForSeq2SeqLM처럼 실제 모델 클래스를 지정합니다.
finetune 입력
Seq2SeqLMModelAdapter의 미세조정은 다음 인자를 받는 절차입니다.
| 인자 | 기본값과 조건 |
|---|---|
| train_data | 필수 Pandas DataFrame입니다. 입력 열과 정답 열이 있어야 합니다. |
| eval_data | 기본 None입니다. 주면 Pandas 표와 필요한 열을 검사하고, 생략하면 train_data를 평가에도 사용합니다. |
| input_column | 기본 text_input입니다. |
| target_column | 기본 text_target입니다. |
| max_input_length | 기본 512이며 입력 토큰을 이 길이로 자릅니다. |
| max_target_length | 기본 64이며 정답 토큰을 이 길이로 자릅니다. |
| train_args | 아래 기본 학습 설정 사전의 복사본입니다. |
평가 데이터를 생략하면 학습 데이터로 평가하므로 그 점수를 별도 미학습 시험 집합의 성능으로 해석하지 않습니다.
| 기본 학습 설정 | 값 |
|---|---|
| per_device_train_batch_size | 4 |
| per_device_eval_batch_size | 4 |
| evaluation_strategy | steps |
| eval_steps | 3 |
| logging_strategy | steps |
| logging_steps | 3 |
| save_strategy | steps |
| save_steps | 3 |
| learning_rate | 4e-5 |
| weight_decay | 0.01 |
| save_total_limit | 3 |
| num_train_epochs | 20 |
| predict_with_generate | True |
| load_best_model_at_end | True |
| metric_for_best_model | rouge1 |
미세조정 절차는 모델을 실행 장치에 옮기고 학습 및 평가 표를 Hugging Face Dataset으로 변환합니다. 배치 토큰화에서 입력을 max_input_length로, 정답을 max_target_length로 잘라 정답의 input_ids를 labels에 저장합니다. 임시 출력 디렉터리와 학습 인자를 Seq2SeqTrainingArguments에 전달하고 DataCollatorForSeq2Seq 및 Seq2SeqTrainer로 학습합니다. trainer.train()의 결과를 반환하며 학습한 모델을 Foundry에 남기려면 별도로 게시해야 합니다.
학습에는 evaluate, datasets, nltk와 ROUGE 계산 의존성이 추가로 필요합니다. NLTK의 문장 분리 자료도 실행 환경에 준비해야 합니다. 참조 구현의 evaluation_strategy, as_target_tokenizer와 Trainer의 tokenizer 인자는 해당 라이브러리 세대의 인터페이스이므로 지원 종료 패키지를 최신 Transformers에 설치하여 그대로 실행하는 경로로 사용하지 않습니다. 새 학습 코드는 선택한 Transformers 버전의 학습 인자와 토크나이저 인터페이스로 작성합니다.
ROUGE 평가 과정
생성한 토큰을 디코딩하고 labels의 -100을 토크나이저의 pad_token_id로 바꿔 정답을 디코딩합니다. 예측 및 정답 문자열을 정리한 뒤 nltk.sent_tokenize로 문장을 나누고 줄바꿈으로 연결합니다. 로컬 ROUGE 모듈을 evaluate.load에 경로로 전달하고 keep_in_memory=True로 계산합니다. 이 미세조정에서는 use_stemmer=True를 사용합니다.
자동 회귀 생성
CausalLMAdapter는 GPT 계열처럼 AutoModelForCausalLM을 사용하는 자동 회귀 모델을 감쌉니다. 입력은 text 문자열, 출력은 기존 text 및 prediction 문자열입니다. 기본 배치 크기는 16이며 입력 인덱스에 맞춰 결과를 저장합니다.
각 배치의 텍스트를 padding하여 토큰화하고 input_ids를 선택한 장치에 옮깁니다. 모델의 generate 결과를 skip_special_tokens=True로 디코딩합니다. 별도 temperature 열 처리나 미세조정 메서드는 이 클래스의 계약에 포함하지 않습니다.
가중치 및 토크나이저를 임시 디렉터리에서 복원하고 저장할 때 모델 파일을 상태 저장소에 기록합니다. 사용자 정의 아키텍처를 로드하는 trust_remote_code=True는 모델에 포함된 Python 코드를 실행하도록 허용하는 설정입니다. 필요한 모델 코드와 의존성을 검토한 경우에만 사용하는 조건으로 관리해야 합니다.
개체명 인식
NerAdapter는 ner 파이프라인으로 text에서 개체를 찾습니다. 기본 배치 크기는 16이며 로드 시 CPU에서 시작하고 추론 시 장치를 선택합니다. 출력 prediction은 각 입력의 개체 사전 목록을 담는 계약으로 정의해야 합니다.
| 개체 필드 | 의미 |
|---|---|
| entity | 인식한 개체 종류입니다. |
| score | 해당 개체의 수치 점수입니다. |
| index | 문장 내 해당 토큰 인덱스이며 문자 위치와 구분합니다. |
| word | 인식한 문자열 표현입니다. |
| start | 입력 문자열에서 개체가 시작하는 위치입니다. |
| end | 입력 문자열에서 개체가 끝나는 위치입니다. |
예시 문장 My name is Max and I live in Germany에서 Max와 Germany 같은 개체를 추출합니다. 실제 결과는 선택한 모델의 레이블과 토큰화에 따라 달라집니다.
개체 목록을 문자열 출력으로 쓰려면 JSON 문자열을 반환하는 별도 어댑터처럼 변환을 명시해야 합니다. 목록 자체를 유지한다면 모델 API에도 그 구조를 선언하고 소비자의 기대 타입을 맞춥니다.
임베딩
EmbeddingAdapter는 text에서 embedding이라는 list[float] 벡터를 만듭니다. 기본 문장 배치는 128입니다. 토큰화에 padding, truncation과 PyTorch 텐서를 사용하고 torch.no_grad에서 모델을 실행합니다.
첫 모델 출력의 토큰 임베딩에 attention_mask를 적용하여 패딩을 제외한 평균을 계산합니다. 분모는 최소 1e-9로 제한합니다. 문장 벡터를 L2 정규화하여 각 text 행의 embedding에 기록합니다.
직접 관리하는 임베딩 어댑터와 모델 게시 코드는 같은 입력 및 출력 이름, 마스크 평균 풀링, 정규화와 배치 크기를 사용합니다. 저장 및 로드는 Hugging Face 직렬화기로 처리합니다.
사전 정의 클래스 분류
TextClassificationAdapter는 AutoModelForSequenceClassification을 사용하여 감성이나 언어처럼 미리 정한 클래스 중 하나를 선택합니다. 기본 배치는 16입니다. 입력을 truncation과 padding으로 토큰화하고 선택 장치에서 no_grad로 logits를 계산합니다.
| 출력 열 | 자료형과 의미 |
|---|---|
| text | 입력 문자열입니다. |
| prediction | 가장 큰 logit의 클래스 이름입니다. |
| logits | 클래스별 list[float] 값입니다. |
| classes | logits와 같은 순서의 list[str] 클래스 이름입니다. |
예측 클래스는 logits.argmax(1)의 인덱스를 모델 설정의 id2label로 바꿉니다. classes는 사전의 저장 순서에 맡기지 말고 실제 logit 인덱스 순서로 구성해야 합니다. 예측 결과 표는 입력 인덱스에 맞춰 기존 표와 결합합니다.
모델과 토크나이저를 생성자에 직접 전달하거나 저장한 상태에서 복원할 수 있습니다. 새 어댑터의 모델 직렬화기에는 AutoModelForSequenceClassification을 지정합니다.
제로샷 분류
ZeroShotClassificationAdapter는 zero-shot-classification 파이프라인을 사용합니다. 추론 때 후보 레이블을 지정하므로 업무별 후보를 바꾸기 위해 매번 모델을 미세조정할 필요가 없습니다.
| 생성자 인자 | 기본값과 우선순위 |
|---|---|
| pipeline | 실행할 실제 Hugging Face 파이프라인입니다. |
| candidate_labels | 기본 None입니다. 입력 열이 없을 때 사용할 후보 목록입니다. |
| preserve_scores_order | 기본 False입니다. False는 점수 내림차순, True는 입력 후보 순서에 맞춥니다. |
입력에는 text와 candidate_labels: list[str]을 사용합니다. 행의 candidate_labels가 생성자 후보보다 우선합니다. 둘 다 없으면 candidate_labels column must be provided라는 ValueError가 발생합니다. 입력 API에 후보 열을 필수로 선언한 온라인 호출에서는 후보 열을 보내야 하며 생성자 기본값만으로 그 API 검증을 건너뛰지 않습니다.
파이프라인의 원래 결과는 sequence, labels와 scores를 담는 사전입니다. 어댑터는 이를 다음 표 열로 풀어 반환합니다.
| 출력 열 | 의미 |
|---|---|
| text | 입력 텍스트입니다. |
| candidate_labels | 입력 후보 레이블 목록입니다. |
| prediction | 후보별 수치 점수 목록입니다. |
| predicted_labels | 점수 목록과 같은 순서의 레이블 목록입니다. |
preserve_scores_order=False이면 파이프라인의 점수 내림차순을 유지합니다. True이면 후보 레이블에서 원래 위치 맵을 만들고 반환 레이블의 점수를 그 순서로 다시 배열합니다. 후보가 행마다 달라질 수 있으므로 행별 파이프라인 호출을 사용합니다.
예시 문장 I love to develop new language models와 후보 Travel, Sports, Work, Entertainment를 주면 화면 예시처럼 Work가 상위에 올 수 있습니다. 결과 순서는 실제 모델 점수에 따릅니다.
저장한 후보 설정
기존 제로샷 어댑터는 candidate_labels와 preserve_scores_order를 adapter_metadata.pkl에 pickle로 저장합니다. 로드 시 이 메타데이터를 생성자에 전달합니다. 파일이 없으면 경고를 남기고 빈 설정으로 생성자 기본값을 사용합니다. 교체 과정에서는 기존 모델의 후보 및 순서 설정을 읽어 새 모델 버전에 명시적으로 옮깁니다.
공통 파일 및 평가 도구
copy_model_to_driver(filesystem)는 파일시스템에서 모델 파일을 읽어 로컬 임시 디렉터리에 복사하고 그 경로를 반환하는 도구입니다. 현재 모델 파일 가져오기에는 palantir_models.transforms의 도구를 사용할 수 있습니다.
set_hf_evaluate_caches는 실행 중 쓸 임시 디렉터리를 만들고 evaluate 설정의 다음 경로를 지정합니다.
| 설정 | 임시 루트 아래 위치 |
|---|---|
| HF_CACHE_HOME | 임시 루트 |
| HF_EVALUATE_CACHE | evaluate |
| HF_METRICS_CACHE | metrics |
| HF_MODULES_CACHE | modules |
| DOWNLOADED_EVALUATE_PATH | evaluate/downloads |
| EXTRACTED_EVALUATE_PATH | evaluate/downloads/extracted |
이 설정은 쓰기 가능한 캐시 위치를 정하는 동작이며 인터넷 송신을 허용하는 설정은 아닙니다.
ROUGE 계산 계약
ROUGE는 생성한 요약이나 번역을 하나 이상의 정답과 비교합니다. 대소문자를 구분하지 않는 Google Research ROUGE 구현과 Hugging Face Evaluate 형식의 계산을 사용합니다.
| 인자 | 기본값과 처리 |
|---|---|
| predictions | 예측 문자열 목록입니다. |
| references | 예측별 정답 문자열 또는 정답 문자열 목록입니다. |
| rouge_types | 기본 rouge1, rouge2, rougeL, rougeLsum입니다. rougeN은 N-gram, rougeL은 최장 공통 부분 수열, rougeLsum은 줄바꿈으로 나눈 문장을 사용합니다. |
| use_aggregator | 기본 True입니다. bootstrap 집계를 반환합니다. False는 예제별 점수 목록을 반환합니다. |
| use_stemmer | 기본 False이며 Porter stemmer 적용 여부입니다. |
| tokenizer | 기본 None입니다. 제공한 함수를 tokenize 메서드가 있는 객체로 감싸 점수 계산기에 전달합니다. |
여러 정답이면 score_multi, 단일 정답이면 score를 사용합니다. 집계할 때는 BootstrapAggregator 결과의 mid.fmeasure를, 집계하지 않을 때는 각 예제의 fmeasure 목록을 반환합니다. 사용한 ROUGE 종류가 결과의 키입니다. 예측과 정답은 서로 대응하는 순서와 개수를 가져야 하며 참조 구현은 첫 정답과 첫 점수에 접근하므로 빈 목록을 계산 대상으로 사용하지 않습니다.
ROUGE 모듈에는 rouge_score, absl, datasets, nltk, numpy, six와 evaluate가 필요합니다. 필요한 패키지가 없는 상태를 정상 점수로 대신하지 않습니다.
패키지와 GPU 환경
기존 패키지 레시피의 런타임 의존성은 Python, pytorch >=2.2, transformers >=4.35, tokenizers, 플랫폼이 지정한 palantir_models 버전, numpy 및 sacremoses입니다. 미세조정 의존성은 별도로 추가해야 합니다. 빌드는 Python과 setuptools를 사용하고 소스 경로는 ../python이며 noarch: python 패키지로 구성합니다. PACKAGE_NAME, PACKAGE_VERSION 및 PALANTIR_MODELS_VERSION은 저장소의 패키지 설정 값입니다.
제로샷 참조의 list[str] | None 타입 표기는 Python 3.10 이상 문법입니다. 기존 빌드 스크립트는 python setup.py install --single-version-externally-managed --record=record.txt이며 별도 test.requires는 없습니다. 패키지 버전 하한만으로 모든 최신 프레임워크와의 호환을 보장하지는 않으므로 교체 어댑터의 환경은 선택한 API에 맞춰 해결합니다.
기존 GPU 패키지 선택 방식은 external-conda-pytorch를 backing repository에 추가하고 pytorch 2.2.* 대신 pytorch 2.2.* cuda 빌드를 지정하는 것입니다. 환경 해결 노드에는 GPU가 없으므로 실행 노드의 GPU 유무만으로 올바른 패키지가 선택된다고 가정하지 않습니다. 현재 저장소의 CUDA 가상 패키지 설정과 실제 GPU 큐 및 패키지 확인은 GPU 학습의 절차를 따릅니다.