PoE(Panel-of-Experts), 더 나은 문제 해결 방법을 제시하는 프롬프트 엔지니어링 기법
소개
LLM은 간단한 작업에서는 좋은 성능을 발휘하지만, 복잡한 작업에서는 종종 오류를 일으킵니다. 특히, 비즈니스나 소프트웨어 프로세스에 LLM을 도입하려는 시도에서 여러 문제가 발생합니다. 이런 문제를 해결하기 위해 생각의 사슬(CoT, Chain-of-Thought)이라는 프롬프트 기법이 사용됩니다. 생각의 사슬(CoT) 기법은 모델이 단계별로 사고 과정을 출력하도록 유도하는 방법으로, 복잡한 작업 수행 능력을 개선하는 것으로 알려져 있습니다. 하지만 Sourcery는 더 나아가 전문가 패널(PoE, Panel-of-Experts)라는 새로운 프롬프트 기법을 도입하여 더 나은 성능을 얻고자 하는 시도를 공개하였습니다.
전문가 패널(PoE, Panel-of-Experts)란?
전문가 패널(PoE)는 생각의 나무(ToT, Tree-of-Thought) 접근 방식을 발전시킨 프롬프트 기법입니다. 생각의 나무(ToT) 기법은 모델이 여러 가지 해결책을 단계별로 탐색하는 과정을 뜻하는데, 이 방법을 통해 다양한 견해와 논쟁을 유도하여 더 나은 추론과 결과를 도출할 수 있습니다. 전문가 패널(PoE) 기법은 이러한 아이디어를 기반으로 여러 전문가들을 선정한 뒤, 각 전문가 패널들 간의 토론을 유도하는 프롬프트를 사용하여 모델이 더 나은 결과를 도출하도록 합니다.
주요 특징
-
다양한 관점: 모델이 하나의 추론 경로를 따라가면서 잘못된 결론을 도출하는 문제를 해결하기 위해, 전문가 패널(PoE)는 서로 다른 관점을 가진 가상의 전문가 패널들을 도입합니다.
-
단계별 토론: 각 전문가 패널은 자신의 생각을 단계별로 공유하고, 다른 전문가 패널들들이 이를 비판(Critic)하고 점검하여 오류를 검출하거나 개선합니다. 이 과정을 모든 패널들에 대해서 반복합니다.
-
결과 통합: 최종적으로 전문가 패널들의 의견을 종합하여 최적의 결과를 도출합니다.
사용 예시
다음은 파이토치 한국어 커뮤니티에 게시된 Dataloader 관련 질문 글을 해결하는 사례를 실제로 해결해본 것입니다.
사용한 프롬프트는 다음과 같으며, 이는 GPT-4o로 원문 글을 읽고 프롬프트 템플릿 생성을 요청하며 만든 것입니다:
Panel-of-Experts Prompt Template
Context: You are a panel of three experts on [specific topic].
Roles:
Expert 1: [Name], an authority in [specific area].
Expert 2: [Name], a specialist in [specific area].
Expert 3: [Name], a well-regarded [specific area] expert.
Task: Given the problem [insert specific problem], your goal is to collaboratively discuss and solve it step-by-step, ensuring that the solution is accurate and well-reasoned.
Discussion Flow:
Each expert will present one step of their thinking.
After each step, the other experts will critique and provide feedback.
If an expert realizes a mistake in their reasoning, they should correct it or step back.
Final Output: Once the discussion is complete, collate the final solution and present it in a clear and structured format.
Example Start:
Expert 1: [Initial thought or step].
Expert 2: [Critique or support of Expert 1's point].
Expert 3: [Additional insight or alternative view].
Goal: The objective is to leverage diverse perspectives to arrive at the most robust and accurate solution to the problem.
김씨, 이씨, 박씨의 세명의 전문가를 설정하고, 템플릿을 약간 구체화(AI/ML 도메인 및 한국어 사용 등)한 뒤, 위 질문 글의 내용을 입력하여 프롬프트를 실행해보았습니다:
아래는 프롬프트 실행 결과입니다.
Discussion on the Issue with DataLoader and Custom Dataset
Step 1: Initial Analysis and Hypothesis by Expert 1 (김씨)
김씨: "코드와 에러 메시지를 보면, DataLoader에서 num_workers를 2로 설정했을 때 발생하는 문제로 보입니다. 이 문제는 다중 프로세싱에서 발생할 수 있는 오류일 가능성이 높습니다. 특히, Dataset 클래스 내부에서 데이터를 torch.Tensor로 변환할 때 GPU 메모리에 직접 올리는 부분에서 문제가 발생할 수 있습니다."
Step 2: Critique and Additional Insight by Expert 2 (이씨)
이씨: "김씨의 지적에 동의합니다. GPU 메모리에 데이터를 올리는 작업이 여러 프로세스에서 동시에 수행되면서 충돌이 발생할 수 있습니다. 이 문제를 해결하기 위해서는 getitem 메서드 내에서 데이터를 GPU로 옮기는 작업을 지양하고, 대신 DataLoader로부터 데이터를 받아 모델에 입력하기 직전에 GPU로 옮기는 방식으로 수정해야 합니다."
Step 3: Further Analysis and Alternative Solution by Expert 3 (박씨)
박씨: "두 분의 의견에 공감합니다. 추가적으로, Dataset 클래스의 init 메서드와 len, getitem 메서드에서 몇 가지 수정이 필요해 보입니다. 특히, 클래스 초기화 부분과 변수명이 일관되지 않은 부분을 정리하고, __getitem__에서 잘못된 변수명을 수정해야 합니다."
Final Solution Collation
김씨, 이씨, 박씨: "우리는 데이터 로딩 중 발생하는 문제를 해결하기 위해 다음과 같이 코드를 수정해야 합니다."
__getitem__
메서드에서 GPU로 데이터를 옮기는 부분을 제거합니다.__init__
메서드와 변수명을 일관성 있게 수정합니다.__getitem__
메서드에서 잘못된 변수명을 수정합니다.수정된 코드:
import torch from torch.utils.data import Dataset, DataLoader class CustomDatasetData(Dataset): def __init__(self): self.x_in, self.X_in = x_in.copy(), X_in.copy() self.xin_initi= x_in_initi.copy() self.yin_initi = y_in_initi.copy() self.xin_data = x_in_data.copy() self.yin_data = y_in_data.copy() self.xin_random, self.Xin_random = x_in_collocation.copy(), X_in_collocation.copy() def __len__(self): return self.xin_random.shape[0] def __getitem__(self, idx): xin = torch.tensor(self.x_in[idx % self.x_in.shape[0]], dtype=torch.float) Xin = torch.tensor(self.X_in[idx % self.X_in.shape[0]], dtype=torch.float) xin_initi = torch.tensor(self.xin_initi[idx % self.xin_initi.shape[0]], dtype=torch.float) yin_initi = torch.tensor(self.yin_initi[idx % self.yin_initi.shape[0]], dtype=torch.float) xin_data = torch.tensor(self.xin_data[idx % self.xin_data.shape[0]], dtype=torch.float) yin_data = torch.tensor(self.yin_data[idx % self.yin_data.shape[0]], dtype=torch.float) xin_random = torch.tensor(self.xin_random[idx % self.xin_random.shape[0]], dtype=torch.float) Xin_random = torch.tensor(self.Xin_random[idx % self.Xin_random.shape[0]], dtype=torch.float) xin_random_data = (xin_random, Xin_random) xin_data = (xin_data, yin_data) xint_data = (xin, Xin) xin_initial_data = (xin_initi, yin_initi) return xin_data, xin_initial_data, xint_data, xin_random_data # GPU로 데이터를 옮기는 작업은 DataLoader에서 데이터를 받을 때 수행합니다. dataloader_data = DataLoader(CustomDatasetData(), batch_size=1000, shuffle=True, num_workers=2) for batch in dataloader_data: xin_data, xin_initial_data, xint_data, xin_random_data = batch xin_data = (xin_data[0].cuda(), xin_data[1].cuda()) xin_initial_data = (xin_initial_data[0].cuda(), xin_initial_data[1].cuda()) xint_data = (xint_data[0].cuda(), xint_data[1].cuda()) xin_random_data = (xin_random_data[0].cuda(), xin_random_data[1].cuda()) # 모델 훈련 또는 추론 코드
이 수정된 코드로 DataLoader가 올바르게 작동하고, 여러 개의 worker를 사용하여 성능을 최적화할 수 있을 것입니다.
결론
이 방법은 기존의 생각의 사슬(CoT) 프롬프트보다 더 많은 모델 계산을 요구하므로, 비용이 두 배로 증가했습니다. 하지만 성능 향상이 크기 때문에, 비용 대비 효과적인 방법으로 판단되었습니다.
패널 오브 엑스퍼트 접근 방식은 LLM의 성능을 크게 개선할 수 있는 효과적인 방법입니다. Sourcery에서는 이 방법을 통해 도스트링 업데이트 자동화 작업의 성능을 크게 향상시킬 수 있었습니다. 여러분도 이 방법을 활용하여 LLM의 성능을 개선해 보시기 바랍니다.
더 읽어보기
이 글은 GPT 모델로 정리한 글을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 덧글로 알려주시기를 부탁드립니다.
파이토치 한국 사용자 모임이 정리한 이 글이 유용하셨나요? 회원으로 가입하시면 주요 글들을 이메일로 보내드립니다! (기본은 Weekly지만 Daily로 변경도 가능합니다.)
아래쪽에 좋아요를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~