NL-280, UCS: Lightweight reranking for language model generations, ACL 2024

◼ Comment

  • 논문 형식이 뭔가 완성이 안된 느낌이다.. 수식이나 그림이나 뭐.. 약간 학부생이 쓴 느낌 ㅋㅋ
  • 내용자체는 일부 노벨티가 있다 (이 당시 기준)
  • 방법론
    • 1. self-consistency을 반영하기 위해, 다양한 응답을 생성하고
    • 2. 논문제목처럼 이를 간단하게 reranking하고 Top-1을 최종답변으로 내뱉는다
  • 이에 대한 동기를 상당히 길게 썼느데
    • 만약 어떤 생성문제에서 정답을 파악하기 위해서는 술어(참 또는 거짓 형태의 문제)를 제대로 정의하여 이에 대한 참/거짓을 판단하면 된다
    • 하지만 이러한 술어만드는것도 어렵고 참/거짓 평가하는것도 쉬운건 아니기 때문에 
    • 이론적으로만 가능하고 현실적으로는 어렵다는 것이다
  • 이러한 술어를 이용한 평가대신 뭐 없을까?
    • 방법은 생성된 응답끼리의 비교라는 것이다
    • 즉 10개의 응답을 샘플링했다고 했을때, 각각을 서로 비교해서 유사도? 일치도?를 계산한다
      • 즉 다른 응답과 1대1로 유사도 계산후 평균낸다
    • 이 값이 높은 응답이 결국 술어에 대한 평가도 높게 나오게 된다
      • 이에 대한 정리를 말하는데, 실제로 일반적인 케이스에 대한 것은 아닌거 같고, 특수케이스에 대해 증명되는 형태임
  • 즉 self-consistency을 측정하면 되는데
    • 응답을 먼적 벡터화를 해야하는데, 이는 매우 간단히 n-gram을 사용했다고함
      • 여기서는 uni-gram을 사용했음
    • 그리고 그냥 이를 내적해서 유사도를 계산하여 리랭킹하는 방법이다
  • 생성 토큰 확률이 있을 경우, uni-gram대신에 토큰의 생성확률로 벡터화를 한다
    • 여러번 토큰이 등장하면, 이를 평균내는 식
    • 이 방법을 wucs라고 명명함
  • 추가적으로 생성된 문장의 품질을 곱해주는 방식을 consensus-wucs로 명명한다
    • 생성된 문장 품질은, 전테 토큰확률의 로그값을 사용
  • 즉 n-gram -> WUCS -> consensus-wucs 방법을 제시한 임베딩을 제시한 것이라 보면되는데
    • 그럴거면 sentence-embedding을 왜 사용안했을까..?
  • 코드 생성문제와 같은 경우 위에서 제시한 self-consistency 점수만으로 리랭킹하지 말고
    • 이럴 경우, top-1, top-2는 상당히 유사하기 때문에 top-1이 틀리면 top-2 가 틀릴 확률이 상당히 높다는 것이다
    • 따라서 기존 상위 응답과의 유사도를 따져서, 낮은 유사도를 가진 것으로 재정렬을 하는 방식을 제시했는데 이게 더 좋다고 함
  • 이 당시에는 딱히 방법론이 많지 않아서 억셉됐지만 지금보기엔 약간 부족한 느낌이긴함

Abstract

대규모 언어모델(LLM)은 생성된 결과물의 품질이 상당히 다양하게 나타날 수 있다. 일반적으로 생성 품질을 크게 개선하는 방법으로 여러 번 샘플링한 결과 중 가장 좋은 생성을 선택하거나 재순위화(reranking)하는 방식이 널리 사용된다. 

본 논문에서는 이러한 재순위화를 위한 새로운 접근법을 제안한다. 

기존 방법들이 추가적인 추론(inference)을 수행하거나 별도의 전문적인 재순위화 모델을 학습해야 하는 것과 달리, 제안하는 방법은 생성된 문장 간에 간단하게 계산할 수 있는 쌍별(pairwise) 통계를 활용하며 이로 인한 계산 비용도 매우 적다. 

또한 본 연구의 방법이 자기일관성(self-consistency)의 확장으로 형식화될 수 있음을 보이고, 이 프레임워크에서의 성능을 이론적으로, 또한 시뮬레이션을 통해 분석한다. 코드 생성 과제에서는 최상의 kk개의 생성을 선택하는 데 있어 뛰어난 성능 향상을 보여주었으며, 자동형식화(autoformalization), 요약(summarization), 번역(translation)과 같은 과제에서도 가장 좋은 생성물을 선택하는 데 안정적인 성능 향상을 보였다. 

제안하는 접근법은 기본적으로 LLM을 블랙박스로 간주하고 있지만, 토큰 확률(token probability)에 접근할 수 있을 경우 성능을 더욱 개선할 수 있음을 보였다.

1 서론

생성형 대규모 사전학습 언어모델(Large Language Models, LLMs)의 빠른 발전과 탁월한 성과는 자연어 처리(NLP) 분야에 혁신적인 변화를 가져왔다. 이러한 모델들은 기계 번역, 요약, 코드 생성과 같은 다양한 NLP 응용 분야에서 상당한 성능 향상을 보였다. 일반적으로 이 모델에서 생성된 개별 결과물들은 우수한 품질을 보이기도 하지만, 동시에 생성된 결과의 품질은 크게 변동하는 경향이 있다. 동일한 입력에 대해 여러 번 출력을 샘플링하면, 평균적인 결과물보다 현저히 우수한 품질의 결과물이 생성되는 경우가 있다.

이 현상을 활용하기 위해 여러 가지 접근법이 제안되었다. 첫 번째 전략은 모델 자체의 성능을 개선하여 평균적인 결과물의 품질을 일관되게 높이는 것이다. 이는 모델에서 생성된 결과물들을 사람이 직접 평가하거나 BLEU와 같은 자동 평가 지표, 코드 생성의 경우 실행 피드백 등을 통해 순위를 매기는 방식으로 수행할 수 있다. 이렇게 평가된 결과물을 직접 추가 학습하거나, 이를 통해 보상 모델을 훈련하여 강화학습(RL) 루프에서 활용하는 방법도 있다(Hsieh et al., 2023; Ouyang et al., 2022; Ho et al., 2022; Polu et al., 2022; Liu and Liu, 2021; Ouyang et al., 2022).

또 다른 흔히 쓰이는 접근법은 다중 샘플링(best-of-n sampling)과 재순위화(reranking)이다. 

  • 이 방법은 기본 모델을 수정하지 않고, 생성된 여러 결과 중 사후적으로 가장 좋은 결과를 선택하는 방법이다(Ravaut et al., 2022; Jiang et al., 2022b; Zhang et al., 2022; Chen et al., 2021; Shi et al., 2022; Li et al., 2022b; Mizumoto and Matsumoto, 2016; Uesato et al., 2022). 
  • 이 방법은 종종 강력한 성능 향상을 주지만, 기존의 많은 재순위화 기법은 순위 지표를 계산하는 데 있어서 상당히 높은 계산 비용을 요구하거나 번거로운 절차를 수반한다. 
  • 예를 들어, 별도의 재순위화 모델을 훈련하거나, 생성된 답변에 대한 쿼리의 확률을 평가(query likelihood)하는 방식은 추가적인 추론 비용이 두 배로 늘어나게 된다. 
코드 생성 모델의 경우, 생성된 코드를 실제 유닛 테스트에 실행해 평가하는 방식도 있다. 
  • 이러한 방식은 AlphaCode와 같은 경쟁 코딩 모델에서는 잘 적용되었지만(Li et al., 2022b), 임의의 코드 실행 환경을 구축하고 적절히 샌드박싱하는 과정의 복잡성으로 인해 일반적인 상황에서는 실용성이 떨어진다.

최근 자기일관성(self-consistency)이라는 간단한 접근법이 제안되었는데(Wang et al., 2022), 이 방식은 가능한 답변이 제한적인 다중 선택 문제나 수학 단어 문제와 같은 과제에 대해 여러 개의 생성을 얻은 후 가장 많이 선택된 답변을 고르는 방식이다. 

  • 이 방법의 핵심 아이디어는 서로 다른 추론 경로를 거쳐 같은 답변에 도달할 수 있다는 관찰에 기반하며, 단일 추론 경로에서 조건부로 계산된 확률이 아니라, 여러 추론 경로에 걸쳐 주변화된 확률로 답변의 순위를 매기려는 목적을 가지고 있다. 
  • 이 방식은 기존 접근법에 비해 상당한 성능 향상을 보였지만, 코드 생성, 요약, 번역과 같은 개방형 생성 과제에는 직접 적용하기 어렵다. 
  • 이들 과제는 추론 경로가 명확하지 않고, 답변 또한 반드시 유일하지 않기 때문이다.

본 논문에서는 두 가지 핵심 관찰로부터 시작한다. 

  • 첫째, 정확히 일치하지 않더라도 의미적으로는 거의 동등한 생성 결과들이 존재할 수 있으며, 이러한 생성들은 주변화(marginalization)에 활용될 수 있다. 
  • 둘째, 개방형 생성 과제에서는 생성 결과물이 여러 요소(element)를 포함할 수 있다. 
  • 예를 들어, 요약에서는 여러 관련 사실을 모두 언급해야 좋은 요약이 되고, 코드 생성에서는 올바른 구현을 위해 여러 분기 조건이 필요할 수 있다. 
  • 이때 생성 결과 집합은 각기 다른 요소의 부분집합을 포함한 여러 생성들을 포함할 수 있지만, 최적의 생성물은 모든 필수 요소를 갖추고 있는 유일한 생성물일 수도 있다. 
  • 이런 경우 단순히 의미적 동등성을 기준으로 주변화하는 것만으로는 부족할 수 있다.

본 연구는 이러한 두 가지 관찰을 발전시켜, 토큰 확률에 접근할 필요가 없으며 계산 비용이 거의 들지 않는 간단한 재순위화 방법을 제안한다. 구체적으로 본 연구의 기여는 다음과 같다.

  • 앞선 두 가지 관찰을 자기일관성(self-consistency) 개념과 연결하여, 토큰 확률 없이도 효과적이고 최소한의 계산 비용으로 작동하는 재순위화 방법을 설계한다. 또한 Shi et al.(2022), Li et al.(2022b)와 같은 기존의 재순위화 방법도 동일한 개념적 프레임워크 내에서 해석할 수 있음을 보인다.

  • 시뮬레이션을 수행하여 본 프레임워크가 많은 경우에 최상의 혹은 거의 최상의 생성을 복구할 수 있음을 입증하고, 방법론의 유효성을 보장하는 이론적 성질을 증명한다.

  • 토큰 로그 확률(token log probability)을 추가적으로 활용할 경우 더욱 향상된 성능을 보이며, 단순 평균 로그 확률 기반 재순위화(mean log probability) 방식보다 더 우수한 결과를 얻을 수 있음을 보인다.

  • 코드 생성 과제에서 두드러진 성능 향상을 보이면서, 자동형식화(autoformalization), 요약(summarization), 번역(translation)과 같은 다른 과제에서도 의미 있는 성능 향상을 확인하였다.

  • 본 방법론은 생성 결과물 간의 쌍별(pairwise) 유사성 기반이므로, 이를 활용하여 다양한 kk 값에 대해 최상위 k개(best-of-k)의 성능을 효과적으로 개선할 수 있다.

  • 다양한 실험 환경과 설정의 영향을 이해하기 위해 다수의 실험적 제거 연구(ablation study)를 수행한다.

본 논문의 나머지 부분은 다음과 같다. 2절에서 동기를 상세히 제시하고, 3절에서 제안 방법 및 유사도 함수를 소개한다. 4절에서는 실험 결과를 제시하고 논의하며, 5절에서는 관련 연구를 소개한다. 마지막으로 6절에서 결론을 맺는다.

2 Motivation

2 동기

다음은 MBPP 데이터셋에서 가져온 코드 생성 문제를 예시로 들어 설명한다.

def remove_dirty_chars(string, second_string):
    """
    주어진 첫 번째 문자열에서, 두 번째 문자열에 있는 모든 문자를 제거하는 함수를 작성하시오.
    
    >>> remove_dirty_chars("probasscurve", "pros")
    'bacuve'
    >>> remove_dirty_chars("digitalindia", "talent")
    'digiidi'
    >>> remove_dirty_chars("exoticmiles", "toxic")
    'emles'
    """

위 문제의 해결 방법은 의미상으로 다음과 같은 설명과 동등할 것이다.

"문자열을 순회하며 두 번째 문자열에 있는 문자를 제외하고, 결과를 다시 문자열로 변환하여 반환한다."

이때 의미를 구성하는 두 가지 핵심 요소는 다음과 같다.

(1) 반환 타입은 반드시 문자열이어야 한다.
(2) 문자열을 순회할 때 두 번째 문자열에 있는 모든 문자는 반드시 제외되어야 한다.

이러한 요소들은 생성된 코드가 갖추어야 하는 술어(predicate, 참 또는 거짓 형태의 명제) 형태로 정의될 수 있다. 

구체적으로 본 예제에 대해 다음과 같은 두 가지 술어를 정의할 수 있다.

  • 술어 p1p_1: 생성된 프로그램의 반환값이 문자열인가?

  • 술어 p2p_2: 생성된 프로그램에서 반환되는 문자열에 second_string의 모든 문자가 올바르게 제외되는가?

이러한 술어는 생성된 코드의 의미적 특성을 포착하는 역할을 한다. 위의 프롬프트로부터 세 개의 샘플을 생성했다고 가정하자.

# 첫 번째 생성 (오답)
return [char for char in string if char not in second_string]

# 두 번째 생성 (오답)
return ''.join([char for char in string])

# 세 번째 생성 (정답)
return ''.join([char for char in string if char not in second_string])

만약 위에서 제시한 술어들을 추론 시점에 평가할 수 있다면, 세 번째 생성만이 두 가지 술어를 모두 만족하므로 최적의 생성임을 쉽게 판단할 수 있을 것이다. 

  • 그러나 실제로 프롬프트에서 필요한 정확한 술어를 생성하고, 자연어로 정의된 명세를 충족하는 임의의 코드에 대해 높은 정확도로 이러한 술어 평가 코드를 생성하는 것은 아직 해결되지 않은 어려운 문제이다.

이제 만약 우리가 위에서 정의한 predicate(술어)들을 실제 추론 단계에서 평가할 수 있다면, 세 개의 생성 중 세 번째 생성만이 두 술어 모두를 만족하기 때문에 가장 좋은 생성임을 쉽게 찾을 수 있을 것이다. 

  • 하지만 이 술어들을 정확히 생성하고, 임의의 자연어 명세에 부합하는 코드를 대상으로 고정밀도로 술어를 평가하는 코드를 작성하는 것은 아직 해결되지 않은 어려운 문제이다.
  • 즉 생성된 코드가 제대로 생성됐는지 파악하기 위해서는, 1. 술어들을 생성하기 2. 술어가 코드에 맞게 생성됐는지 평가를 해봐야하는데, 이것은 쉽지 않다고 말하는 듯

그렇다면, 이 문제를 조금 더 다루기 쉬운 형태로 변환할 방법이 있을까? 생성된 각각의 코드가 각 술어(predicate)에 대해 얼마나 많은 지지(vote)를 받는지를 생각해 보자. 즉, 각 술어가 몇 개의 생성에서 참(True)으로 평가되는지를 살펴보는 것이다.

  • 술어 p1p_1은 세 개 중 두 개(2번과 3번 생성)에서 참이므로, 다수결로 볼 때 이 술어는 "참"이어야 한다.

  • 술어 p2p_2 역시 세 개 중 두 개(1번과 3번 생성)에서 참이므로, 이 술어도 다수결에 의해 "참"이어야 한다.

이 두 가지 술어 모두에 대해 다수결에 일치하는 생성을 찾아보면, 두 술어 모두에서 다수결과 일치하는 유일한 생성은 세 번째 생성이다. 따라서 세 번째 생성이 최적의 합의(consensus) 결과가 된다.

사실, 위의 과정에서 우리가 굳이 각 술어별로 다수결 결과를 먼저 계산할 필요조차 없다! 대신, 우리는 각각의 생성이 다른 생성들과 얼마나 "일치(agreement)"하는지를 바로 계산할 수 있다. 이 개념을 조금 더 풀어서 설명하자면, 다음과 같다.

  • 1번 생성은 3번 생성과 술어 p2p_2에 대해서는 일치하지만, p1p_1에 대해서는 불일치한다. 그리고 2번 생성과는 전혀 일치하지 않는다. 따라서 1번 생성의 총 일치 점수는 1점이다.

  • 비슷하게, 2번 생성 역시 다른 생성들과의 총 일치 점수가 1점이다.

  • 반면 3번 생성은 1번 생성과 p2p_2에서 일치하며, 2번 생성과는 p1p_1에서 일치한다. 즉, 총 일치 점수는 2점이 된다.

따라서 전체적으로 볼 때, 3번 생성이 다른 모든 생성과 가장 높은 일치도를 보이며, 합의된 결과가 된다. 이러한 변환 과정이 본 논문의 Figure 1에 시각적으로 표현되어 있다.

이와 관련해 몇 가지 주목할 점이 있다.

  • (A) 우리가 실제 원하는 술어의 답변(최적의 생성 결과)은 다수결로 얻어진 답변과 정확히 일치한다는 점이다. 이것이 바로 우리가 이후 형식적으로 연결할 자기일관성(self-consistency)과의 관련성이다.

  • (B) 서론에서 제시한 두 가지 관찰 중, 이 방법은 두 번째 관찰(서로 다른 생성이 다양한 요소를 부분적으로 가질 때)을 다루는 데 효과적임을 확인하였다. 그렇다면 첫 번째 관찰(의미적으로 동등하지만 정확히 일치하지 않는 생성들을 다루는 문제)은 어떻게 될까? 아래와 같이 네 번째 생성을 추가로 생각해 보자.

# 네 번째 생성 (정답 - 다른 형태로 작성된 코드)
new_str = ''
for c in string:
    if c not in second_string:
        new_str += c
return new_str

이 네 번째 생성은 앞서 세 번째 생성과 술어 p1p_1, p2p_2에 대해 모두 일치하므로 의미상 동등한 생성이다. 

만약 이 네 번째 생성을 추가로 고려한다면, 앞서 설명한 방식에서는 3번 생성과 4번 생성 간에 동률(tie)이 발생하게 된다. 이는 우리가 앞서 제시한 방법이 의미적으로 동등한 생성들도 자연스럽게 고려할 수 있음을 보여준다.

이해하기로는, 동기가 코드를 평가하는 적절한 술어를 생성하는것은 챌린지하다는 것이다. 술어를 생성해도 이거에 맞게 코드가 생성됐는지 평가하기도 어려움

  • 그래서 술어를 생성하지 말고, 생성된 코드들간의 상호비교를 통해 일치하는 코드를 고르는게 더 쉽다는 것이다
  • 여기서는 설명하기 위해, 술어를 통해 코드간의 일치성을 언급한다.
  • 즉 올바르게 생성된 코드는, 다른 생성된 코드와 술어 입장에서 동등한 생성인 경우가 많다는 것
앞서 언급한 바와 같이, 실제 추론 단계에서는 각 코드 생성물에 대해 정확한 술어(predicate)를 생성하거나 평가할 수 없다. 
  • 그러나 이전 예시에서 보았듯이, 우리는 사실 술어들의 실제 평가값 자체가 필요하지 않다. 
  • 실제로 필요한 것은 서로 다른 코드 생성물 쌍 간에 특정 술어에 대한 평가가 얼마나 서로 일치(agreement)하는지 여부이다. 

다음 섹션에서는 우리가 술어에 대한 명시적인 지식 없이도 이 일치를 근사할 수 있는 간단한 유사도(similarity) 함수를 제시하고, 이후 실험을 통해 그 효과를 보여줄 것이다. 

  • 여기서는 이 직관을 먼저 형식화하고, 자기일관성(self-consistency)과 연결시키며, 이론적 근거를 마련한다.

다음과 같이 문제를 형식화할 수 있다.

  • vv를 길이 kk인 벡터라고 하자. 이 벡터의 각 원소는 술어를 나타내고, 그 값은 생성물이 가져야 하는 속성을 나타낸다고 하자. 앞서 든 예시에서는 두 개의 술어가 모두 참이어야 하므로, 벡터 vv는 길이가 2이고 두 값 모두 1(참)을 갖는다.
    즉 술어의 개수는 k개이고, 이것에 대한 참을 담은 벡터를 v라고(= [1,1]) 한다

  • 일반적으로, 술어의 값은 꼭 이진(binary) 값일 필요는 없으며, 여러 값을 가질 수도 있다.

  • 생성된 결과 중 ii번째 생성에 대해 술어 값을 나타내는 벡터를 uiu_i라고 하자.
    i번째 생성에 대한 술어 값를 ui라고 한다. (즉 1번 술어에 대해선 참, 2번 술어에 대해선 거짓 = [1,0])

  • 여기서 우리는 다음과 같은 자기일관성(self-consistency) 가정을 한다: 각 개별 술어에 대해 가장 자주 나타난 값이 올바른 값이라고 가정한다. 수식으로 표현하면, 술어 vlv_lmlm_l개의 가능한 값 중 하나를 가질 수 있다고 하고(일반성을 잃지 않고 최다 득표 값을 1이라고 하면), 최다 득표 값은 다음과 같다.

l=argmaxji=1nI(uil=j)l = \arg\max_{j} \sum_{i=1}^{n} I(u_i^l = j)

앞서 언급했듯이, 실제 추론 단계에서는 술어나 그 평가값에 접근할 수 없으므로, 우리는 단지 생성물들 사이의 술어 평가값에 대한 일치도(agreement)만 접근할 수 있다고 가정한다 (이는 이후 유사도 함수로 근사할 것이다). 

구체적으로, 생성물 i,ji, j 사이의 일치도는 다음과 같이 정의한다:

a(ui,uj)=1kt=1kI(uit=ujt),i,j[1,n]a(u_i, u_j) = \frac{1}{k} \sum_{t=1}^{k} I(u_i^t = u_j^t), \quad \forall i,j \in [1,n]

우리는 모든 생성물들과의 평균적인 일치도가 가장 높은 생성물 ii를 선택한다. 즉, 다음 식을 최대화하는 ii를 찾는다.

a(ui,v)a(u_i, v)

이 문제 정의 및 선택 기준을 바탕으로, 다음의 이론적 결과를 얻을 수 있다.

이 모든 정리의 증명은 부록(Supplement)에 제공되어 있다. 이 정리들은 이 방법의 성능에 대한 이론적 보장을 주긴 하지만, 정리 2.3의 상한은 다소 느슨(loose)하며, 술어가 이진값만을 가질 때만 적용 가능하다.

이러한 이론적 근거를 보완하기 위해, 우리는 시뮬레이션 실험을 추가로 수행하였다. 시뮬레이션 설정은 다음과 같다.

  • 술어의 개수(kk) 및 술어가 가질 수 있는 값의 개수를 고정하고, 각 생성물이 술어 값을 균등한 확률로 갖도록 시뮬레이션한다.

  • 하지만 각 술어에 대해 자기일관성 가정(대부분 생성물이 원하는 술어 값을 가져야 함)을 강제한다.

시뮬레이션 결과(부록에 제시됨)에 따르면, 본 논문의 방법이 대부분의 경우 최적 생성물을 성공적으로 찾아냈으며, 무작위 선택(random selection)보다 유의미하게 뛰어난 성능을 보였다. 또한, 실제로 최적의 생성을 찾지 못한 경우에도 최적 생성물과의 일치도가 평균적으로 거의 100%에 가까웠다. 자세한 결과는 부록에 제시되어 있다.

그냥 당연한말을 어렵게 쓴 느낌.

  • 이상적인 상황에서는 생성된 응답의 술어값(각 술어에 대해 참/거짓을 담은 벡터)를 계산하고
  • 응답의 술어값끼리 비교해서 평균적으로 가장 높은 일치도를 보이는 응답이 최적의 응답이라고 보자는 것이다

그것에 대한 이론적인 뒷받침을 증명1,2,3을 통해 하는것인데..

  • 이론은 술어가 1개이면 이 방법이 best가 맞다
  • 술어가 k개일때, 술어값이 모두 참이되는 응답 있다면 평균 일치도가 높은 응답이 될 것이다 (근데 애초에 모두 참이되는 응답이 있는지를 모르는거긴함)
  • 술어값에 대한 상한값이 존재한다?

3 방법론(Method)

앞서 언급한 바와 같이, 추론 단계(inference time)에서는 우리가 원하는 술어(predicate)를 명확히 정의하거나 평가하는 것이 불가능하므로, 원하는 최적의 술어 벡터 vv와 생성된 코드의 술어 벡터 uu 사이의 정확한 일치도를 직접 계산할 수 없다.

하지만, 이전 섹션에서 논의한 것처럼, 최적의 벡터 vv와의 직접적인 일치도를 계산하는 대신, 각 생성된 결과가 다른 생성 결과들과의 평균적인 유사도(average fractional similarity) 를 계산하여 이 일치도를 근사(approximation)할 수 있다는 사실을 알았다.

물론 추론 시점에는 실제 술어를 이용한 정확한 유사도 계산이 불가능하기 때문에, 술어 대신 코드 생성 결과들 간에 직관적으로 정의한 유사도(similarity)를 활용할 수 있다. 

  • 직관적으로 생각해 볼 때, 두 생성 결과가 서로 더 유사하다면, 임의의 술어를 평가했을 때에도 둘이 더 자주 일치할 가능성이 높기 때문이다.

놀랍게도, 이 논문에서 우리가 곧 정의할 매우 간단한(simply defined) 유사도 함수(similarity function)가 이러한 목적을 달성하는 데 충분하다는 것을 발견했다.

제안하는 방법: Generalized Self-consistency Score (GSCSim)

일단 유사도 함수(Similarity function)를 정의하고 나면, 우리는 각 생성된 결과 ii에 대해 다음과 같이 일반화된 자기일관성 점수(Generalized Self-consistency Score) 를 계산할 수 있다:

GSCSim(i)=1M1j=1,jiMSim(i,j)\text{GSCSim}(i) = \frac{1}{M-1}\sum_{j=1, j\neq i}^{M}\text{Sim}(i,j)

여기서 Sim은 정의된 유사도 함수를 나타내며, MM은 총 생성된 결과의 수이다.

  • 만약 문제의 답이 명확히 정의된 경우(예: 다지선다 문제)라면, 유사도 함수를 다음과 같이 정의할 수 있다.

정답이 정해져있으면, exact match로 비교할 수 있다는것

이 경우는 기존의 자기일관성(self-consistency) 기준과 정확히 일치한다.

이와 유사하게 기존 논문들에서 사용된 두 가지 방법론인 MBR-ExecAlphaCode (Li et al., 2022b) 또한 이와 동일한 프레임워크에서 유사도 함수만 다르게 정의한 것으로 이해할 수 있다.

  • MBR-Exec: 생성된 코드를 유닛 테스트로 실제 실행한 후, 모든 유닛 테스트에서 같은 결과를 내면 유사도(similarity) 1, 하나라도 다르면 0으로 정의한다. 이후 모든 코드들과의 유사도를 더해 가장 높은 합을 가진 코드를 선택한다.

  • AlphaCode: 유닛 테스트 실행 결과를 기반으로 생성된 코드를 군집(cluster)화하고, 가장 큰 군집에서 한 개의 코드를 고른다. 두 코드는 모든 테스트 결과가 동일할 때 동일 군집으로 묶인다. 이것은 개념적으로 MBR-Exec와 유사하다.

이 외에도 Supplement에서 OpenAI의 Ada embedding을 기반으로 한 또 다른 유사도 함수를 평가했으며, 이는 유망한 결과를 보였지만, embedding 모델을 따로 사용하는 등 계산량이 크기 때문에 이 논문에서는 더 이상 다루지 않았다.

실제로 제안한 간단한 유사도 함수: Ngram Consistency Score (NCS)

코드를 표현하는 매우 직관적인 방식으로 n-gram을 사용할 수 있다. 

  • 즉, 각 생성물을 특정 n-gram이 포함되어 있는지 없는지를 나타내는 이진(binary) 벡터로 표현하는 것이다. 
  • 놀랍게도, 이렇게 간단한 표현 방식만으로도 유사도 함수를 견고하게(robust) 정의하는 데 충분하다.
  • 말은 그럴싸하게 앞에서 썰을 풀었지만 결국 n-gram 유사도..?

이 논문에서는 다음과 같은 방식을 사용한다:

  • 모든 가능한 n-gram을 모아 집합 VV를 정의한다. (논문에서는 주로 간단한 유니그램(n=1) 만을 사용했다. 나중에 Supplement에서 K>1K>1에 대한 실험도 제시했으며, 특정 범위까지는 도움이 됨을 보였다.)

  • 각 생성물 ii에 대해 길이가 V|V|인 벡터 viv_i를 정의한다. 각 원소는 해당 n-gram이 생성물에 존재하면 1, 없으면 0이다.

  • 이 벡터들 사이의 유사도는 간단히 두 벡터의 내적(inner product) 으로 정의한다. 이를 Ngram Consistency Score (NCS) 라 부르고, 유니그램(n=1)의 경우를 특별히 Unigram Consistency Score (UCS) 라 한다.

수식으로 명확히 나타내면 다음과 같다:

여기서

  • vij=I(토큰 tj가 생성물 gi에 존재하는가)v_i^j = I(\text{토큰 } t_j \text{가 생성물 } g_i \text{에 존재하는가})
    (tjt_j는 j번째 토큰, gig_i는 i번째 생성물을 나타냄.)

이 정의는 생성물들만 있으면 바로 계산할 수 있으며, 별도의 추가적 모델 학습, 코드 실행, 추가적인 모델 추론 등을 하지 않아도 되므로 매우 가벼운(minimal computational overhead) 계산만을 요구한다.

  • 주의할 점으로, 여기서 벡터의 내적을 벡터의 길이(norm)로 나누어 정규화(normalize)하지 않았다. 

  • 이렇게 한 이유는 neural 모델들이 반복적이고 단순한 생성물을 만드는 degeneracy 문제를 방지하고, 보다 다양한 생성을 유도하기 위한 의도적인 설계이다.

토큰 확률이 있을 경우 추가적인 개선 방법

토큰(token)의 확률이 사용 가능한 경우, 이를 활용하여 앞서 제안한 방법을 더 개선할 수 있다. 직관적으로 설명하면, 어떤 생성물에서 특정 토큰의 확률이 매우 낮다면, 다른 생성물과 해당 토큰이 일치(match)하더라도 덜 중요하게 반영하는 것이 합리적이다. 이 직관을 반영하여, 다음과 같은 두 가지 추가 변형 방법을 제안한다.

첫 번째로, 벡터 vv의 정의를 다음과 같이 수정한다:

여기서

  • cijc_i^j는 생성물 ii에서 토큰 tjt_j가 등장한 횟수를 나타낸다.

  • p(tji,k)p(t_j^{i,k})는 생성물 ii에서 토큰 tjt_jkk번째 등장에 대한 모델의 확률값이다.

문장에서 여러번 등장한 토큰은, 토큰에 해당하는 값을 매번 등장할때 토큰확률을 평균낸 값을 가져간다는 것

이 방법을 Weighted n-gram Consistency Score (WUCS) 라고 부른다. 논문의 Figure 2는 이 방법을 예시 문장에 대해 시각화한 것이다.

또한, 평균 로그 확률(mean log probability) 은 자주 사용되는 일반적인 순위화(ranking) 방식이다. 이 방법을 WUCS와 결합하여 각 생성물의 토큰 확률로 추가적인 가중치를 줄 수 있다. 구체적으로 생성물 ii에 대해 다음과 같이 Consensus-WUCS 를 정의한다.

Consensus-WUCS(i)=WUCS(i)×e1gip(gi)\text{Consensus-WUCS}(i) = \text{WUCS}(i) \times e^{\frac{1}{|g_i|}\cdot p(g_i)}

여기서

  • p(gi)p(g_i)는 생성물 ii의 전체 토큰 확률의 로그값 합이다.

  • gi|g_i|는 생성물 ii의 길이이다.

WUCS보다 더 좋은 방법을 제시한다는 것. 생성된 문장의 품질을 곱해주면 더 임베딩이 잘 표현된다는 것

  • 즉 기본 n-gram -> WUCS -> Consensus-WUCS
  • 근데 이럴거면 그냥 sentence embedding 왜 안쓰지?

최종적으로, 모든 생성물을 순위화할 때 다음 식을 통해 가장 좋은 생성물을 선택한다.

argmaxiGSCSim(i)\arg\max_i \text{GSCSim}(i)

여기서 Sim은 UCS, WUCS, 또는 Consensus-UCS 중 하나를 사용할 수 있다. 본 논문의 Figure 3은 UCS에서부터 Consensus-WUCS로 점차 확장되는 과정을 도식화하여 보여준다.

3.1 Extending to ranked pass@k

코드 생성 문제에서 흔히 사용되는 평가 지표 중 하나는 ranked pass@k이다. 이 지표는 여러 개의 생성 결과 중에서 상위 kk개의 프로그램을 선정한 후, 이 중 하나라도 주어진 문제에 대한 모든 유닛 테스트(unit test)를 통과하는지 여부를 평가한다. 일반적으로 상위 kk개 생성 결과는 사전에 결정된 순위(rank)를 바탕으로 선택된다. 그러나 우리가 제안한 유사성 기반의 평가 지표(similarity-based metric)를 사용하면 좀 더 섬세한 방법으로 이 문제를 접근할 수 있다.

구체적으로, 어떤 특정 문제에 대해서 가장 높은 순위를 받은 생성 결과가 이미 정확한 결과라면 우리는 이미 목표를 달성한 것이다. 만약 가장 높은 순위를 받은 생성 결과가 어떤 유닛 테스트에서 실패한다면, 나머지 생성 결과를 계속 살펴봐야 한다. 이때 최고 순위의 생성 결과는 강력한 부정적 예시(hard negative)로 간주하고, 다음으로 선택할 생성 결과는 이전의 최고 순위 생성 결과와의 유사성이 더 낮은 것을 고르는 방식을 취할 수 있다.

좀 더 정확히 표현하면, 우리가 현재까지 선택한 프로그램의 집합을 SkS_{k'} (현재 선택된 프로그램의 수 Sk=k<k|S_{k'}| = k' < k)라고 할 때, 다음 k+1k'+1 번째 생성 결과를 선정하기 위해 기존의 GSCS(GCS)를 수정한 평가 함수를 다음과 같이 정의한다:

여기서:

  • sim(i,j)sim(i, j): 생성 결과 iijj 사이의 유사성 점수(similarity)

  • nn: 생성된 전체 결과물의 수

  • SkS_{k'}: 이미 선택된 생성 결과들의 집합

  • 즉, 위 공식은 아직 선택하지 않은 생성 결과와의 유사성 합에서, 이미 선택된 생성 결과와의 유사성 합을 차감하여 새로 선택할 생성 결과를 결정한다.

기존의 평가방법은 좋은거 순서대로 평가하는데,, 여기서 말하길 순위가 붙어있으면 비슷한 코드일 확률이 높고, 그러면 비슷한 오류가 날거라는 것
  • 따라서 선택되지 않은 프로그램과의 유사성은 높을수록 좋고, 이미 선택된 프로그램과의 유사성은 낮을수록 좋습니다. 라는 개념을 적용
  • 결국 순위를 단순히 sim으로 하는게 아니라 다른 방법으로 재정렬하는 거라 보면 됨

k=1k = 1의 경우에는 GCSsimrankedGCS^{ranked}_{sim}이 기존의 GCSGCS와 동일하다. 섹션 4.4에서 보이듯, k>1k > 1에 대해 ranked pass@k 성능을 평가할 때 GCSsimrankedGCS^{ranked}_{sim}이 일반적인 GCSGCS보다 훨씬 우수한 성능을 보인다. 이 방식은 ranked generation을 더욱 효율적으로 활용하여 전체적인 코드 생성 작업에서 더 나은 성능을 달성한다.

논문에서 제시한 방법은, 여러 개 문장생성해서 리랭킹해서 top-1을 뽑는것에도 적용하는것에 해당하는 방법이지만

  • 코드 평가처럼, pass@k을 할때에는 sim을 이용하여 순위 재정렬 방법을 새롭게 제시하여 더 좋게 활용할 수 있다라고 말하는 듯

다음은 요청하신 논문의 4 Results 섹션의 전체 번역입니다.


4 결과

우리는 Codex 모델군(Codex-davinci-001, Codex-davinci-002, Codex-Cushman)과 Llama 모델군을 이용하여 실험을 수행했다. 또한 Xsum, MiniF2F, WMT14 데이터셋에 대해서는 GPT-J 모델도 평가하였다. 그러나 예상치 못한 OpenAI API 서비스 중단으로 인해 Codex-001 및 Codex-Cushman 모델에 대해서는 Xsum, MiniF2F, WMT14 데이터셋 결과를 얻지 못했다.

코드 생성 태스크를 위해 HumanEval(Chen et al., 2021), MBPP, MBPP-sanitized(Austin et al., 2021) 데이터셋을 사용하였다. MiniF2F에서 Isabelle로의 자동 형식화(autoformalization) 태스크는 (Jiang et al., 2022a)가 제공한 데이터셋을 활용했다. 텍스트 요약 태스크의 경우 Xsum 데이터셋(Narayan et al., 2018)을 사용했으며, 기계 번역 태스크로는 WMT14의 프랑스어→영어 및 독일어→영어 데이터셋(Bojar et al., 2014)을 사용했다.

코드 생성의 주요 평가 지표는 ranked pass@1로, 생성된 여러 결과물 중 최상위로 재정렬된 결과가 모든 단위 테스트(unit test)를 통과하는지 평가하는 방식이다. 또한 k > 1일 때 ranked pass@k로 평가하였다. MiniF2F 자동 형식화 태스크는 Wu et al.(2022)를 따라 BLEU 점수를 평가 지표로 사용했다. Xsum에 대해서는 Rouge-2 및 Rouge-L 점수를 평가 지표로 사용하였다. 모든 코드 생성 데이터셋에 대해 각 모델에서 125개의 결과물을 샘플링하여 이를 실험 데이터셋으로 구성했다. MiniF2F와 Xsum의 경우 각 모델에서 50개의 결과물을 샘플링했다. 별도의 언급이 없는 한, 모든 실험은 Codex-davinci-002 모델을 사용하여 진행했다. Shi et al.(2022), Zhang et al.(2022)을 따라 결과 생성을 위해 부트스트랩(bootstrap) 샘플링을 50회 수행하였으며, 각 샘플 크기는 25로 설정했다.

기준 실험으로는 무작위 선택(Random selection), 평균 로그 확률로 재정렬(Ranking by mean log probability), 가중된 유니그램 공간에서 메도이드(Medoid)를 사용한 재정렬, 그리고 코드 생성 태스크에서는 Coder Reviewer Ranker(Zhang et al., 2022)를 사용하였다. 데이터셋, 실험 설정, 기준 모델들에 대한 자세한 설명과 추가 결과는 보충 자료(Supplement)에 수록되어 있다.


4.1 올바른 답변에서 GSC 점수가 더 높음

타당성 확인을 위해 먼저 GSC 점수가 실제로 올바른 생성 결과에서 더 높은지 평가하였다¹. 그 결과는 보충 자료의 표 8에 나타나 있다. 모든 모델에서 올바른 답변의 점수 비율이 일관되게 1보다 높게 나왔으며, 유일한 예외는 UL2-20B 모델로, 이 모델의 경우에도 점수 비율은 여전히 거의 1에 근접했다.


4.2 UCS는 코드 생성에서 큰 성능 향상을 보임

표 1 및 3(보충 자료)에 나타난 바와 같이, UCS, WUCS, Consensus-WUCS 방법은 다양한 모델과 데이터셋에서 코드 생성 정확도 및 평균 역순위(mean reciprocal rank)에서 상당한 성능 향상을 보였다.

HumanEval 데이터셋에서 UCS 기반 방식들은 기존 방식(무작위 선택 및 평균 로그 확률)을 일관되게 능가했다. 예를 들어 Codex002 모델의 정확도는 무작위 선택 시 0.435에서 Consensus-WUCS 사용 시 0.568로 크게 향상되었다. 성능이 상대적으로 떨어지는 Llama-13B 및 Llama-30B 모델에서도 UCS 기반 방법 사용 시 뚜렷한 정확도 개선이 나타났다.

MBPP-S와 MBPP 데이터셋에서도 비슷한 경향이 관찰되었다. UCS, WUCS, Consensus-WUCS 방법이 모든 모델에서 정확도를 일관되게 개선했다. 특히 Consensus-WUCS 방식은 모든 경우에서 무작위 및 평균 로그 확률 재정렬을 일관되게 능가했으며, 거의 항상 WUCS보다도 우수한 성능을 보였다. 특히 WUCS 방식은 모든 모델 및 데이터셋 조합에서 평균 로그 확률 방식보다 우수했으며, LLama-13B 모델의 MBBP와 MBPP-S를 제외하고는 전부 최적의 방법이었다. UCS는 토큰 확률 없이 생성 결과만으로도 무작위 재정렬을 일관되게 능가했다.

Consensus-WUCS 및 WUCS는 메도이드 방식보다 거의 항상 우수했으며, Consensus-WUCS는 15개 경우 중 13개에서 메도이드를 능가했다. 평균 역순위(mean reciprocal ranking) 관련 논의는 보충 자료에 상세히 수록되어 있으나, 여기서도 비슷한 경향이 확인되었다.

4.3 UCS는 비코딩(non-coding) 태스크에서도 일관된 성능 향상을 보임

다음으로 비코딩 태스크에서 UCS, WUCS 및 Consensus-WUCS의 성능을 평가하였다. BLEU 지표로 평가한 MiniF2F 데이터셋의 경우, Codex002 모델에서는 Consensus-WUCS가 메도이드(Medoid)를 제외한 모든 방법보다 뛰어난 성능을 보였다. Llama-13B, Llama-30B 및 GPT-J 모델에서는 Consensus-WUCS, WUCS 및 UCS 모두 매우 근소한 차이로 우수한 성능을 나타냈다.

Xsum 데이터셋에서는 유사한 경향이 나타났다. Rouge-2 지표를 보면, Codex002 모델과 두 Llama 모델에서 Consensus-WUCS가 가장 높은 점수를 달성하였으며, Llama-13B 모델에서는 WUCS와 동률이었다. GPT-J 모델에서는 UCS가 WUCS 및 Consensus-WUCS보다 약간 우수한 성능을 보였다. 그럼에도 불구하고, 이 모든 방법이 무작위(Random), 평균 로그 확률(Mean-logp) 및 거의 모든 경우에서 메도이드(Medoid) 방식보다 우수했다.

Rouge-L 지표에서도 Codex002를 제외한 모든 모델에서 UCS 기반의 방법들이 최상의 성능을 보였다. 특히 Llama-30B 모델에서는 WUCS와 Consensus-WUCS가 공동 1위를 차지했으며, GPT-J 모델에서는 UCS가 최고 성적을 보였다. 다시 한 번, 이 방법들이 일반적으로 메도이드(Medoid), 무작위(Random), 평균 로그 확률(Mean-logp) 방식보다 우수한 결과를 나타냈다.

WMT14 번역 데이터셋의 경우, Consensus-WUCS가 독일어→영어 태스크의 Llama-13B 모델을 제외한 모든 모델과 태스크에서 최상의 성능을 기록했다. WUCS도 강력한 성능을 나타내었으며, 3개의 모델-태스크 조합에서는 Consensus-WUCS와 동등한 점수를 얻었다. UCS 또한 일관되게 무작위 선택보다 좋은 결과를 보였다.

총 20번의 비교 중에서, Consensus-WUCS는 12번으로 가장 많이 최고 성능을 기록했고, WUCS는 7번, UCS는 3번, 메도이드는 주로 MiniF2F의 성능 덕분에 5번 최고 성능을 달성했다.

4.3.1 비코딩 태스크의 성능 향상이 상대적으로 적은 이유 분석

코딩 태스크와 비코딩 태스크의 상위 3개 및 하위 3개 생성 결과를 선택하여 각 집합 내에서 유니그램(unigram) 중복 비율을 계산하였다. 그 결과는 보충 자료의 표 7에 제시되어 있다. 

분석 결과, 코딩 태스크의 중복 비율이 비코딩 태스크보다 현저히 높게 나타났으며, 이는 코드 생성 태스크에서 더 큰 성능 개선이 관찰되는 이유에 대한 힌트를 제공한다. 

  • 즉, 두 생성 결과가 유니그램을 공유하지 않을 때, 코딩 태스크에서는 비코딩 태스크에 비해 두 생성 결과가 의미적으로 얼마나 떨어져 있는지를 더 잘 나타낸다는 것이다. 
  • 따라서 유니그램 중복 통계량 계산이 코드 생성 태스크에서는 비코딩 태스크보다 더 많은 정보를 제공하며, 이것이 비코딩 태스크에서 상대적으로 작은 성능 향상을 보이는 이유일 수 있다. 
  • 다만, 성능 향상이 상대적으로 작더라도 과거에 발표된 논문들에서 유사 지표에 대해 보고된 향상 정도와 비슷하며, 무엇보다도 태스크와 모델의 종류에 상관없이 일관된 성능 향상이 나타났다는 점을 강조하고자 한다.

4.4 GCSranked 비교

보충 자료의 그림 4에서는 pass@k의 k 값이 증가함에 따라 모델 성능이 어떻게 변화하는지를 보여준다. 우리는 GCS와 GCSranked의 성능을 비교하였다. GCS의 성능은 k가 커질수록 빠르게 하락하는 반면, GCSranked는 모든 코드 생성 데이터셋에서 k 값이 증가해도 우수한 성능을 유지하는 것으로 나타났다.

5 관련 연구

Mizumoto와 Matsumoto(2016)는 퍼셉트론 기반 재순위화(reranking)를 통해 모델이 생성한 번역문을 재정렬하는 방식을 사용하였다. SummaReranker(Ravaut et al., 2022)는 다중 전문가 혼합(Mixture of Experts, MoE) 방식으로 재순위화 모델을 학습하여, 여러 자동 평가 지표(ROUGE 또는 BLEU 점수 등)를 동시에 최적화하였다. PairReranker(Jiang et al., 2022b)는 자동 평가 지표로 모델 생성 결과를 재정렬한 후, 최상위 및 최하위 결과물을 선택하여 쌍(pair)을 형성하고, 이를 기반으로 두 결과물 중 더 좋은 요약을 판별하도록 분류 모델을 학습하였다. 하지만 앞서 언급된 모든 재순위화 기법은 보조(auxiliary) 모델 학습이 필요하다는 공통된 한계가 존재한다.

보다 자세한 관련 연구는 보충 자료(Supplement)에 서술되어 있다.

6 결론

우리는 정답이 정해진 문제들에 대해 자기 일관성(self-consistency) 방법을 분석하고 이를 개방형(open-ended) 생성 문제들로 확장하는 프레임워크를 개발하였다. 또한, 우리 프레임워크와 다른 코드 생성 재순위화(reranking) 함수들 간의 연관성을 입증하였으며, 최적의 생성 결과가 우리가 가진 생성 결과 집합에 포함될 경우 이를 항상 찾을 수 있음을 증명하였다. 특정 조건 하에서 최적 생성 결과에 얼마나 근접할 수 있는지에 대한 경계(bound) 또한 증명하였다.

우리가 수행한 시뮬레이션 테스트에서는 최적 혹은 최적에 매우 가까운 생성 결과를 일관되게 찾을 수 있음을 보여주었다. 우리는 몇 가지 가벼운 유사도(similarity) 함수를 도입하여 기존 최신 기법(state-of-the-art baselines)에 비해 강력하고 일관된 성능 향상을 이루었다. 특히, 가장 간단한 유사도 함수인 Unigram Consistency Score (UCS)는 추가적인 정보 없이 오직 생성 결과만을 가지고도 효과적으로 재순위화를 수행할 수 있다. UCS의 변형(variants)들은 코드 및 텍스트 생성 성능을 일관되게 향상시키며, 상당히 많은 계산 자원과 시간이 소요되는 최신 기법인 Coder Reviewer Ranker와 비교해도 경쟁력 있는 성능을 보였다. 코드 생성의 경우, 우리가 제안한 재순위화 지표가 쌍별 유사도(pairwise similarity)에 기반한다는 점을 활용하여 pass@k (k>1)의 성능을 더욱 개선하였다. 이와 더불어, 주요 실험들에 대해 다양한 변형 실험을 수행하여 우리 접근법의 견고성(robustness)과 신뢰성(reliability)을 검증하였다. 또한 자기 일관성 방법과 유사하게, 생성 결과 수를 증가시킬수록 모델의 성능이 개선된다는 점도 확인하였다.

7 사회적 영향(Broader Impact)과 한계점(Limitations)

올바른 정답이 다양할 경우, 유니그램(unigram) 중복 통계는 의미적 유사성을 제대로 반영하지 못할 수 있으며, 더 정교한 유사도 측정 방법이 필요할 수 있다. 

본 연구는 대형 언어 모델(LLM)의 성능을 개선하는 것을 목표로 하기 때문에, 일반적인 LLM의 위험과 이점들을 그대로 물려받는다. 대형 언어 모델은 여러 태스크에서 매우 높은 활용성과 유용성을 보여왔으며, 특히 코드 생성 태스크에서는 더욱 그렇다. 우리가 제안한 방법은 코드 생성 태스크에서 특히 두드러진 성능 개선을 보여주었기 때문에 폭넓은 사회적 영향력을 미칠 수 있을 것으로 기대한다.

그러나 본 논문에서는 우리가 제안한 방법이 편향되거나 유해한(toxic) 생성 결과를 선택하는 경향을 증가시키는지 여부에 대해서는 평가하지 않았으며, 이는 향후 연구 과제로 남겨둔다.

Reference

댓글