본문 바로가기

공부방/Upstage AI Lab 4기

[NLP] 대화의 턴수와 주요 발화자를 토큰으로 추가해보자

가설 1) 

대화의 턴수 정보와 발화자의 빈도를 세어서 턴에서 차지하는 비율을 토큰 정보로 주면 성능이 개선되지 않을까?

--> 결과적으로 아니였던 걸로.. 

대화 턴수 토큰의 효과:

    • 요약문의 길이와 상관관계가 있을 수 있음 (긴 대화는 더 긴 요약이 필요할 수 있음)
    • 모델이 대화의 전체 구조를 파악하는데 도움
    • 특히 encoder_max_len으로 잘린 대화의 경우, 원래 대화가 얼마나 길었는지 인식 가능

 

발화자 빈도 토큰의 효과:

  • 주요 화자 식별을 통해 중요한 정보의 우선순위 결정 가능
  • 대화의 주도자가 누구인지 파악하여 요약의 관점 설정에 도움
  • 특히 한국어 대화는 주어 생략이 많은데, 주요 화자 정보가 이를 보완할 수 있음
import pandas as pd
import re

def get_turns_token(turn_count):
    if turn_count <= 5: return '[TURNS_0_5]'
    elif turn_count <= 10: return '[TURNS_5_10]'
    elif turn_count <= 20: return '[TURNS_10_20]'
    elif turn_count <= 30: return '[TURNS_20_30]'
    else: return '[TURNS_30+]'

def get_ratio_token(ratio):
    if ratio < 0.4: return '[RATIO_LOW]'
    elif ratio < 0.7: return '[RATIO_MID]'
    else: return '[RATIO_HIGH]'

def add_metadata(dialogue):
    # 대화를 턴으로 분리
    turns = dialogue.split('\n')
    turn_count = len(turns)
    
    # 화자별 발화 횟수 계산
    speaker_counts = {}
    for turn in turns:
        speakers = re.findall(r'#Person\d#', turn)
        if speakers:
            speaker = speakers[0]
            speaker_counts[speaker] = speaker_counts.get(speaker, 0) + 1
    
    # 메인 화자와 비율 계산
    main_speaker = max(speaker_counts.items(), key=lambda x: x[1])[0]
    main_speaker_ratio = speaker_counts[main_speaker] / turn_count
    
    # 토큰 생성
    turns_token = get_turns_token(turn_count)
    ratio_token = get_ratio_token(main_speaker_ratio)
    main_speaker_token = f'[MAIN_SPEAKER_{main_speaker[-2:-1]}]'
    
    return f"{turns_token} {main_speaker_token} {ratio_token} {dialogue}"

# 데이터 로드
data_path = "/data/ephemeral/home/hw_nlp/data/train.csv"
df = pd.read_csv(data_path)

# 샘플 데이터 전처리 및 결과 확인
sample_dialogue = df['dialogue'].iloc[0]
processed_dialogue = add_metadata(sample_dialogue)

print("원본 대화:")
print("-" * 100)
print(sample_dialogue)
print("\n처리된 대화:")
print("-" * 100)
print(processed_dialogue)

# 전체 통계 확인
print("\n전체 데이터 통계:")
print("-" * 100)
turns_counts = df['dialogue'].apply(lambda x: len(x.split('\n')))
print(f"평균 턴 수: {turns_counts.mean():.2f}")
print(f"최소 턴 수: {turns_counts.min()}")
print(f"최대 턴 수: {turns_counts.max()}")

# 처리된 첫 5개 대화 확인
print("\n처리된 첫 5개 대화:")
print("-" * 100)
for i in range(5,11):
    print(f"\n{i+1}번째 대화:")
    print(add_metadata(df['dialogue'].iloc[i]))

데이터 전처리에서 대화 턴수와 주요 발화자 정보를 토큰으로 추가해서 넣어봤다. 추가된 토큰들을 살펴보니 딱히.. 메인스피커라던가 비율은 중요하지 않은 것 같다. 

원본 대화:
----------------------------------------------------------------------------------------------------
#Person1#: 안녕하세요, 스미스씨. 저는 호킨스 의사입니다. 오늘 왜 오셨나요?
#Person2#: 건강검진을 받는 것이 좋을 것 같아서요.
#Person1#: 그렇군요, 당신은 5년 동안 건강검진을 받지 않았습니다. 매년 받아야 합니다.
#Person2#: 알고 있습니다. 하지만 아무 문제가 없다면 왜 의사를 만나러 가야 하나요?
#Person1#: 심각한 질병을 피하는 가장 좋은 방법은 이를 조기에 발견하는 것입니다. 그러니 당신의 건강을 위해 최소한 매년 한 번은 오세요.
#Person2#: 알겠습니다.
#Person1#: 여기 보세요. 당신의 눈과 귀는 괜찮아 보입니다. 깊게 숨을 들이쉬세요. 스미스씨, 담배 피우시나요?
#Person2#: 네.
#Person1#: 당신도 알다시피, 담배는 폐암과 심장병의 주요 원인입니다. 정말로 끊으셔야 합니다.
#Person2#: 수백 번 시도했지만, 습관을 버리는 것이 어렵습니다.
#Person1#: 우리는 도움이 될 수 있는 수업과 약물들을 제공하고 있습니다. 나가기 전에 더 많은 정보를 드리겠습니다.
#Person2#: 알겠습니다, 감사합니다, 의사선생님.

처리된 대화:
----------------------------------------------------------------------------------------------------
[TURNS_10_20] [MAIN_SPEAKER_1] [RATIO_MID] #Person1#: 안녕하세요, 스미스씨. 저는 호킨스 의사입니다. 오늘 왜 오셨나요?
#Person2#: 건강검진을 받는 것이 좋을 것 같아서요.
#Person1#: 그렇군요, 당신은 5년 동안 건강검진을 받지 않았습니다. 매년 받아야 합니다.
#Person2#: 알고 있습니다. 하지만 아무 문제가 없다면 왜 의사를 만나러 가야 하나요?
#Person1#: 심각한 질병을 피하는 가장 좋은 방법은 이를 조기에 발견하는 것입니다. 그러니 당신의 건강을 위해 최소한 매년 한 번은 오세요.
#Person2#: 알겠습니다.
#Person1#: 여기 보세요. 당신의 눈과 귀는 괜찮아 보입니다. 깊게 숨을 들이쉬세요. 스미스씨, 담배 피우시나요?
#Person2#: 네.
#Person1#: 당신도 알다시피, 담배는 폐암과 심장병의 주요 원인입니다. 정말로 끊으셔야 합니다.
#Person2#: 수백 번 시도했지만, 습관을 버리는 것이 어렵습니다.
#Person1#: 우리는 도움이 될 수 있는 수업과 약물들을 제공하고 있습니다. 나가기 전에 더 많은 정보를 드리겠습니다.
#Person2#: 알겠습니다, 감사합니다, 의사선생님.

전체 데이터 통계:
----------------------------------------------------------------------------------------------------
평균 턴 수: 9.49
최소 턴 수: 2
최대 턴 수: 61

 

결과는 두둥

미세하게 더 안좋아졌다;

다른 걸 해봐야할 것 같다... 뭘 해야좋을까ㅠㅠ 이건 걍 빼버리고 다른 걸 다시 할까봐.. 

 

 

가설2)

대화가 몇 번 턴을 돌았느냐는 유의미한 정보같은데, 발화자 정보나 비중은 딱히 쓸모가 없는 것 같았음. person1, person2가 번갈아가면서 대화하는 형식이라서 비율이 거의 같아서..

그래서 턴 정보만 더하고, \n 으로 나뉜 것을 [TURN_SEP] 이라는 토큰으로 교체. 

 

메모리 이슈로 계속 인코더 길이 맥스값을 원래대로 줄이고, 배치도 16으로 줄인거 치고는 나름(?) 괜찮은 결과가 나온 것 같다. 

 

데이터 전처리 개선:

# 대화 텍스트 정제 # - 불필요한 특수문자 제거 # - 대화 참여자 간 구분을 더 명확하게 # - 대화 맥락을 더 잘 파악할 수 있는 형태로 구조화