공부 정리 블로그

[학습 데이터 생성]hiiamsid/sentence_similarity_spanish_es 본문

proyector en Chile

[학습 데이터 생성]hiiamsid/sentence_similarity_spanish_es

따옹 2025. 2. 6. 02:28
import pandas as pd
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
from itertools import combinations

# 1. Load the dataset
file_path = '/mnt/data/final_2023_grouped_categorized_file.xlsx'
data = pd.read_excel(file_path)

# 2. Extract necessary columns
columns_of_interest = ['ActividadEconomicaDesc', 'RutPostulante', 'criteria', 'RespuestaTexto']
data = data[columns_of_interest]

# 3. Group by 'ActividadEconomicaDesc'
grouped_data = data.groupby('ActividadEconomicaDesc')

# Load the model and tokenizer for similarity calculation
similarity_model_name = "hiiamsid/sentence_similarity_spanish_es"
similarity_tokenizer = AutoTokenizer.from_pretrained(similarity_model_name)
similarity_model = AutoModelForSequenceClassification.from_pretrained(similarity_model_name)

# Load the tokenizer for fine-tuning data (preprocessing purposes)
fine_tuning_model_name = "Alibaba-NLP/gte-multilingual-base"
fine_tuning_tokenizer = AutoTokenizer.from_pretrained(fine_tuning_model_name)

# Function to calculate similarity using sliding window
def calculate_similarity_sliding_window(text1, text2, max_length=512, stride=256):
    # Tokenize the full texts without truncation
    inputs1 = similarity_tokenizer(text1, truncation=False, return_tensors='pt')
    inputs2 = similarity_tokenizer(text2, truncation=False, return_tensors='pt')

    tokens1 = inputs1['input_ids'][0]
    tokens2 = inputs2['input_ids'][0]

    max_similarity = 0

    for start1 in range(0, len(tokens1), stride):
        end1 = min(start1 + max_length, len(tokens1))
        chunk1 = tokens1[start1:end1]

        for start2 in range(0, len(tokens2), stride):
            end2 = min(start2 + max_length, len(tokens2))
            chunk2 = tokens2[start2:end2]

            # Ensure chunks have the same length by padding shorter chunk
            if len(chunk1) < max_length:
                padding = torch.full((max_length - len(chunk1),), similarity_tokenizer.pad_token_id, dtype=torch.long)
                chunk1 = torch.cat([chunk1, padding])
            if len(chunk2) < max_length:
                padding = torch.full((max_length - len(chunk2),), similarity_tokenizer.pad_token_id, dtype=torch.long)
                chunk2 = torch.cat([chunk2, padding])

            # Prepare inputs for the model
            inputs = {
                'input_ids': torch.stack([chunk1, chunk2]),
                'attention_mask': torch.stack([
                    torch.ones_like(chunk1),
                    torch.ones_like(chunk2)
                ])
            }

            # Compute similarity score
            with torch.no_grad():
                outputs = similarity_model(**inputs)
            scores = torch.nn.functional.softmax(outputs.logits, dim=1)
            max_similarity = max(max_similarity, scores[0][1].item())

    return max_similarity

# 4. Create fine-tuning data
fine_tuning_data = []

for actividad, group in grouped_data:
    # Group by 'criteria' within the same 'ActividadEconomicaDesc'
    criteria_grouped = group.groupby('criteria')
    
    for criteria, criteria_group in criteria_grouped:
        entries = criteria_group.to_dict('records')
        for pair in combinations(entries, 2):  # All combinations of pairs within the criteria group
            text1 = pair[0]['RespuestaTexto']
            text2 = pair[1]['RespuestaTexto']
            rut1 = pair[0]['RutPostulante']
            rut2 = pair[1]['RutPostulante']

            # Handle empty or None texts
            if not text1 or not text2:
                continue

            # Calculate similarity with sliding window
            similarity = calculate_similarity_sliding_window(text1, text2)

            # Preprocess texts for fine-tuning
            preprocessed_text1 = fine_tuning_tokenizer(text1, max_length=512, truncation=True, padding='max_length')
            preprocessed_text2 = fine_tuning_tokenizer(text2, max_length=512, truncation=True, padding='max_length')

            fine_tuning_data.append({
                'ActividadEconomicaDesc': actividad,
                'criteria': criteria,
                'RutPostulante_1': rut1,
                'RutPostulante_2': rut2,
                'Text1': text1,
                'Text2': text2,
                'Similarity': similarity,
                'EncodedText1': preprocessed_text1,
                'EncodedText2': preprocessed_text2
            })

# Convert results to DataFrame and save
fine_tuning_data_df = pd.DataFrame(fine_tuning_data)
output_path = '/mnt/data/fine_tuning_data_with_similarity.xlsx'
fine_tuning_data_df.to_excel(output_path, index=False)

print(f"Fine-tuning data with similarity saved to {output_path}")

 

# Load the tokenizer for fine-tuning data (preprocessing purposes)
fine_tuning_model_name = "Alibaba-NLP/gte-multilingual-base"
fine_tuning_tokenizer = AutoTokenizer.from_pretrained(fine_tuning_model_name)
이건 왜하는거야?

 

이 부분은 Alibaba-NLP/gte-multilingual-base 모델을 추후 파인튜닝하기 위해 데이터 전처리를 준비하는 과정입니다. 구체적으로 왜 필요한지 설명하겠습니다:

1. 목적

hiiamsid/sentence_similarity_spanish_es 모델은 코사인 유사도를 계산하기 위해 사용됩니다. 하지만, 최종적으로 파인튜닝할 모델은 Alibaba-NLP/gte-multilingual-base입니다. 따라서, 학습 데이터는 gte-multilingual-base에 맞는 형식으로 전처리되어야 합니다.

2. 왜 전처리 과정이 필요한가?

Alibaba-NLP/gte-multilingual-base 모델은 입력 데이터를 처리할 때 토큰화를 통해 모델에 전달할 수 있는 형식(숫자 ID, 패딩 등)으로 변환해야 합니다. 이를 위해 AutoTokenizer를 사용하며, 여기서 토큰화를 수행합니다:

  • 텍스트를 토큰으로 분할
  • 최대 토큰 길이를 설정 (512로 제한)
  • 패딩 및 트렁케이션 (길이를 맞추기 위해 추가 작업)

3. 결과

fine_tuning_tokenizer로 전처리된 텍스트(EncodedText1, EncodedText2)는 숫자 ID, 어텐션 마스크 등을 포함하는 딕셔너리 형태로 저장됩니다. 이렇게 생성된 데이터는 Alibaba-NLP/gte-multilingual-base 모델에서 바로 학습에 사용할 수 있습니다.

요약

fine_tuning_tokenizer를 사용하는 이유는 최종 파인튜닝 모델(gte-multilingual-base)에 적합한 데이터 형식을 미리 준비하기 위함입니다. 이를 통해 hiiamsid/sentence_similarity_spanish_es로 계산한 유사도 데이터를 효율적으로 활용할 수 있습니다.

 


최종으로 생성되는 데이터는 fine_tuning_data_with_similarity.xlsx 파일에 저장되며, 데이터 형식은 아래와 같습니다. 각 컬럼의 설명을 포함합니다.

최종 데이터 형식

컬럼 이름 설명

ActividadEconomicaDesc 동일한 RutPostulante를 비교하는 기준이 되는 ActividadEconomicaDesc 값.
criteria 비교가 이루어진 동일한 기준 (criteria) 값.
RutPostulante_1 비교 대상 1의 RutPostulante (식별자).
RutPostulante_2 비교 대상 2의 RutPostulante (식별자).
Text1 RutPostulante_1의 RespuestaTexto (비교 대상 텍스트).
Text2 RutPostulante_2의 RespuestaTexto (비교 대상 텍스트).
Similarity hiiamsid/sentence_similarity_spanish_es 모델로 계산된 두 텍스트의 코사인 유사도 (0~1 사이 값).
EncodedText1 Alibaba-NLP/gte-multilingual-base 모델 학습을 위해 전처리된 Text1 데이터 (토큰화 포함).
EncodedText2 Alibaba-NLP/gte-multilingual-base 모델 학습을 위해 전처리된 Text2 데이터 (토큰화 포함).

주요 데이터 예시

ActividadEconomicaDesc criteria RutPostulante_1 RutPostulante_2 Text1 Text2 Similarity EncodedText1 EncodedText2

Comercio A1 12345678-9 98765432-1 Texto de prueba 1 Texto de prueba 2 0.85 {tokenized data...} {tokenized data...}

EncodedText1와 EncodedText2의 구조

이 필드들은 전처리된 텍스트 데이터로, JSON 형태로 저장됩니다. 각각의 필드는 다음을 포함합니다:

  • input_ids: 텍스트를 숫자 토큰 ID로 변환한 값.
  • attention_mask: 패딩된 부분을 구분하기 위한 마스크 값.
  • (추가적으로) 모델에 따라 token_type_ids 등이 포함될 수 있습니다.

예시:

{
  "input_ids": [101, 1045, 2572, 1037, 2326, 102],
  "attention_mask": [1, 1, 1, 1, 1, 1]
}

이 데이터는 Hugging Face 모델(Alibaba-NLP/gte-multilingual-base)에서 바로 학습에 사용할 수 있습니다.

요약

  • 파일은 학습 및 유사도 정보를 포함한 테이블 형식으로 저장됩니다.
  • Similarity는 유사도 점수로, hiiamsid/sentence_similarity_spanish_es 모델 결과입니다.
  • EncodedText1와 EncodedText2는 gte-multilingual-base 학습용 입력 데이터입니다.

에러 모음집

 

1.

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-11-86db20f14877> in <cell line: 0>()
     19 
     20             # Calculate similarity with sliding window
---> 21             similarity = calculate_similarity_sliding_window(text1, text2)
     22 
     23             # Preprocess texts for fine-tuning

<ipython-input-9-a388a9b6a1ff> in calculate_similarity_sliding_window(text1, text2, max_length, stride)
     19             if len(chunk1) > 0 and len(chunk2) > 0:
     20                 inputs = {
---> 21                     'input_ids': torch.cat([chunk1.unsqueeze(0), chunk2.unsqueeze(0)], dim=0),
     22                     'attention_mask': torch.cat([
     23                         torch.ones_like(chunk1).unsqueeze(0),

RuntimeError: Sizes of tensors must match except in dimension 0. Expected size 491 but got size 512 for tensor number 1 in the list.

에러 메시지를 보면, torch.cat 함수에서 두 텐서의 크기가 일치하지 않아 발생한 문제입니다. 슬라이딩 윈도우로 자른 텍스트 청크 중 하나는 길이가 491이고, 다른 하나는 길이가 정확히 512여서 크기가 달라 오류가 발생했습니다.

이 문제를 해결하려면, 슬라이딩 윈도우로 나눠진 텍스트 청크의 길이를 정확히 맞추거나, 모델 입력 전에 길이를 강제로 일치시키는 처리가 필요합니다.

 

def calculate_similarity_sliding_window(text1, text2, max_length=512, stride=256):
    # Tokenize the full texts without truncation
    inputs1 = similarity_tokenizer(text1, truncation=False, return_tensors='pt')
    inputs2 = similarity_tokenizer(text2, truncation=False, return_tensors='pt')

    tokens1 = inputs1['input_ids'][0]
    tokens2 = inputs2['input_ids'][0]

    max_similarity = 0

    for start1 in range(0, len(tokens1), stride):
        end1 = min(start1 + max_length, len(tokens1))
        chunk1 = tokens1[start1:end1]

        for start2 in range(0, len(tokens2), stride):
            end2 = min(start2 + max_length, len(tokens2))
            chunk2 = tokens2[start2:end2]

            # Ensure chunks have the same length by padding shorter chunk
            if len(chunk1) < max_length:
                padding = torch.full((max_length - len(chunk1),), tokenizer.pad_token_id, dtype=torch.long)
                chunk1 = torch.cat([chunk1, padding])
            if len(chunk2) < max_length:
                padding = torch.full((max_length - len(chunk2),), tokenizer.pad_token_id, dtype=torch.long)
                chunk2 = torch.cat([chunk2, padding])

            # Prepare inputs for the model
            inputs = {
                'input_ids': torch.stack([chunk1, chunk2]),
                'attention_mask': torch.stack([
                    torch.ones_like(chunk1),
                    torch.ones_like(chunk2)
                ])
            }

            # Compute similarity score
            with torch.no_grad():
                outputs = similarity_model(**inputs)
            scores = torch.nn.functional.softmax(outputs.logits, dim=1)
            max_similarity = max(max_similarity, scores[0][1].item())

    return max_similarity

 

 

근데 역시나 파일이 너무 커서 중간에 뻗어버림 ㅠ