데이터 생성: 뉴스 기사 다듬기

데이터 생성: 뉴스 기사 다듬기 (Data Generation: Refining News Articles)

이 쿡북에서는 특정·정제된 형식으로 기사를 다시 쓰도록 모델을 파인튜닝하기 위한 데이터를 생성하는 과정을 살펴볼 거예요. 2단계 파이프라인을 사용해요. 먼저 모델이 존중하고 참고해야 할 가이드를 바탕으로 기사에 대한 **비평(critique)**을 생성하고, 이 비평을 이용해 새롭고 정제된 기사를 만들어요.

출처: 문서

본문

이 쿡북에서는 특정·정제된 형식으로 기사를 다시 쓰도록 모델을 파인튜닝하기 위한 데이터를 생성하는 과정을 깊이 다뤄 볼 거예요. 이를 위해 2단계 파이프라인을 사용해요. 먼저 모델이 존중하고 참고로 사용해야 하는 가이드를 활용해 기사에 대한 **비평(critique)**을 생성해요. 그런 다음 이 비평들을 사용해 새롭고 정제된 기사를 만들어요. 목표는 원본 기사와 정제된 버전을 최소한 포함하는 데이터셋을 만드는 것이며, 이는 향후 모델 파인튜닝이나 다른 목적으로 사용될 수 있어요.

이 노트북의 가이드는 다음으로 다운로드할 수 있어요.

!wget https://github.com/mistralai/cookbook/blob/main/mistral/data_generation/external_files/guide_1.txt
!wget https://github.com/mistralai/cookbook/blob/main/mistral/data_generation/external_files/guide_2.txt
!wget https://github.com/mistralai/cookbook/blob/main/mistral/data_generation/external_files/guide_3.txt
!wget https://github.com/mistralai/cookbook/blob/main/mistral/data_generation/external_files/guide_4.txt

첫 단계는 mistralai를 설치하고 API 키로 클라이언트를 만드는 것이에요!

Python

!pip install mistralai==0.4.2
from mistralai.client import MistralClient

# Other imports we will need
from tqdm.contrib.concurrent import process_map
import secrets
import time
import random
import json
import os
CLIENT = MistralClient(api_key="api_key")

다음 단계는 데이터셋을 다운로드하는 것이에요. Hugging Face에서 제공되는 데이터셋을 사용할 거예요. 물론 자신만의 데이터를 제공해도 됩니다!

Python

!pip install datasets

이 예시에서는 원본 기사와 정제된 기사의 100쌍을 생성할 거예요. 필요한 만큼 얼마든지 생성할 수 있어요.

Python

import datasets
news_articles = list(datasets.load_dataset("AyoubChLin/CNN_News_Articles_2011-2022", split="train"))

random.shuffle(news_articles)

print("Total Articles:", len(news_articles))

n_sample = 100
news_articles = random.sample(news_articles, n_sample)

print("Sampled:", n_sample)

with open("./news.jsonl", "w") as f:
  for news in news_articles:
    f.write(json.dumps({"news": news["text"]}) + "\n")

우리 파이프라인은 두 단계로 구성돼요. 먼저 우리가 선택한 스타일 가이드를 사용해 비평을 생성해요. 여기에는 거의 같지만 각각 다른 네 가지 가이드라인이 있는데, 물론 직접 다시 쓸 수도 있어요.

비평이 생성되면, 그것들을 사용해 새로 다시 쓴 기사를 생성할 거예요!

비평부터 시작해 볼게요.

데이터를 생성하면서 캐시할 폴더를 만들어 볼게요. 이는 디버깅에 유용하고, 문제가 생겼을 때 백업 역할을 해줘요.

import os
newpath = r'./data'
if not os.path.exists(newpath):
    os.makedirs(newpath)

이제 첫 번째 프로세스를 정의해 볼게요. 기사 비평과 재작성에 mistral-large-latest 기능을 사용할 거예요. 물론 원하는 조합을 자유롭게 사용할 수 있어요.

def process_critique(args):
    line, systems, guides = args
    record = json.loads(line)

    news_article = record.get("news")

    part = random.choice(list(range(len(guides))))
    guide = guides[part]

    part = random.choice(list(range(len(systems))))
    system = systems[part].format(guide)

    time.sleep(1)
    try:
        answer = CLIENT.chat(
            model="mistral-large-latest",
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": news_article},
            ],
            temperature=0.2,
            max_tokens=2048
        )
        critique = answer.choices[0].message.content

        result = json.dumps({"news": news_article, "critique": critique, "status": "SUCCESS"})

    except Exception as e:
        result = json.dumps({"news": news_article, "critique": str(e), "status": "ERROR"})

    random_hash = secrets.token_hex(4)

    with open(f"./data/news_critique_{random_hash}.jsonl", "w") as f:
        f.write(result)

    return result

매번 다양한 출력을 생성하려면 단일 시스템 프롬프트 대신 여러 시스템 프롬프트를 사용하는 것이 좋아요. 여기서는 모두 매우 비슷하지만 각각 다른 몇 가지 시스템 프롬프트를 제공해요.

systems_variations = [
    "As a 'News Article Editor' adhering to a specific style guide, your responsibility is to polish and restructure news articles to align them with the high standards of clarity, accuracy, and elegance set by the guide:\n\n {} \n\n You are presented with a news article. Identify the ten (or fewer) most significant stylistic concerns and provide examples of how they can be enhanced.",
    "As a 'News Content Refiner' committed to the guide, your role is to revise and perfect news articles to ensure they meet the exceptional standards of lucidity, exactness, and refinement synonymous with the guide:\n\n {} \n\n You have a news article at hand. Pinpoint the sixteen (or less) most crucial stylistic problems and suggest examples of how they might be improved.",
    "As a 'News Piece Stylist' in accordance with the style guide, your duty is to amend and enrich news articles to guarantee they adhere to the rigorous standards of clarity, precision, and sophistication embodied by the style guide:\n\n {} \n\n You are handed a news piece. Highlight the fourteen (or fewer) most pressing stylistic errors and offer examples of how they could be rectified.",
    "As a 'News Article Enhancer' following the principles of the guide, your mission is to modify and elevate news articles to match the high-quality standards of clarity, precision, and eloquence established by the style guide:\n\n {} \n\n You are given a news article to work on. Specify the twenty (or less) most notable stylistic flaws and provide examples of how they can be bettered.",
    "As a 'News Prose Stylist' abiding by the style guide, your assignment is to correct and embellish news articles to ensure they meet the distinguished standards of clarity, precision, and sophistication upheld by the guide:\n\n {} \n\n You are provided with a news article for evaluation. Indicate the twenty (or fewer) most important stylistic issues and propose examples of how they may be optimized.",
    "As a 'News Report Stylist' in compliance with the guide, your job is to revise and improve news articles to guarantee they align with the high benchmarks of clarity, precision, and sophistication set forth by the guide:\n\n {} \n\n You are tasked with reviewing a news report. List the fifteen (or less) most critical stylistic shortcomings and provide examples of how they might be amended.",
    "As a 'News Writing Stylist' in line with the guide, your responsibility is to edit and refine news articles to ensure they meet the superior standards of clarity, precision, and sophistication inherent to the style guide:\n\n {} \n\n You are assigned to edit a news article. Identify the sixteen (or fewer) most prominent stylistic inconsistencies and suggest examples of how they can be enhanced.",
    "As a 'News Text Stylist' adhering to the style guide, your role is to amend and perfect news articles to ensure they meet the high-caliber standards of clarity, precision, and sophistication characteristic of the guide:\n\n {} \n\n You are given a news text to evaluate. Highlight the nineteen (or less) most significant stylistic discrepancies and provide examples of how they might be improved.",
    "As a 'News Copy Stylist' in accordance with the guide, your duty is to revise and enrich news articles to guarantee they adhere to the exacting standards of clarity, precision, and sophistication embodied by the style guide:\n\n {} \n\n You are tasked with reviewing a news copy. List the eleven (or fewer) most crucial stylistic errors and propose examples of how they can be rectified.",
    "As a 'News Article Stylist and Editor' committed to the style guide, your mission is to refine, rewrite, and edit news articles to ensure they meet the high standards of clarity, precision, and sophistication synonymous with the guide:\n\n {} \n\n You are given a news article to refine and edit. Identify the seventeen (or fewer) most pressing stylistic concerns and provide examples of how they can be improved."
]

이제 생성할 시간이에요. 만든 가이드를 가져와서 process_map으로 생성을 시작할게요. 이 함수는 여러 워커를 만들어 새 데이터를 더 효율적으로 병렬 생성해줘요.

Python

guides = []
for pick in range(1, 5):
    jsonl_file_path = f"./guide_{pick}.txt"

    with open(jsonl_file_path, "r") as f:
        guide = f.read()
        guides.append(guide)

data_path = "./news.jsonl"
with open(data_path, "r") as f:
    lines = f.readlines()
    lines = [(line, systems_variations, guides) for line in lines]

    results = process_map(process_critique, lines, max_workers=20, chunksize=1)

with open("./generated_news_critiques.jsonl", "w") as f:
    for result in results:
        f.write(result + "\n")

완벽해요! 비평이 생성됐어요. 이제 피드백을 사용해 우리의 기사를 다듬고 다시 쓸 시간이에요!

def process_refined_news(args):
    line, system, instruction = args
    record = json.loads(line)

    news_article = record.get("news")
    critique= record.get("critique")
    status = record.get("status")

    time.sleep(1)

    try:
      if status == "SUCCESS":

        answer = CLIENT.chat(
            model="mistral-large-latest",
            messages= [
                {"role": "system", "content": system},
                {"role": "user", "content": news_article},
                {"role": "assistant", "content": critique},
                {"role": "user", "content": instruction},
            ],
            temperature=0.2,
            max_tokens=2048
        )
        new_news = answer.choices[0].message.content

        result = json.dumps({"news": news_article, "critique": critique, "refined_news": new_news, "status": "SUCCESS"})

      else:
        result = json.dumps({"news": news_article, "critique": critique, "refined_news": critique, "status": "ERROR"})
    except Exception as e:
        result = json.dumps({"news": news_article, "critique": critique, "refined_news": str(e), "status": "ERROR"})

    random_hash = secrets.token_hex(4)

    with open(f"./data/refined_news_{random_hash}.jsonl", "w") as f:
        f.write(result)

    return result

여러 시스템 변형을 컨텍스트를 주는 일반화된 하나로 교체할 거예요. 하지만 두 번째 단계의 핵심은 제공된 피드백으로 기사를 다시 쓰라는 지시야. 이 지시는 요구사항에 따라 많이 바뀔 수 있어요!

Python

system = "Polish and restructure the news articles to align them with the high standards of clarity, accuracy, and elegance set by the style guide. You are presented with a news article. Identify the ten (or fewer) most significant stylistic concerns and provide examples of how they can be enhanced."

instruction = """
Now, I want you to incorporate the feedback and critiques into the news article and respond with the enhanced version, focusing solely on stylistic improvements without altering the content.
You must provide the entire article enhanced.
Do not make ANY comments, only provide the new article improved.
Do not tell me what you changed, only provide the new article taking into consideration the feedback you provided.
The new article needs to have all the content of the original article but with the feedback into account.
"""

data_path = "./generated_news_critiques.jsonl"
with open(data_path, "r") as f:
    lines = f.readlines()
    lines = [(line, system, instruction) for line in lines]

    results = process_map(process_refined_news, lines, max_workers=20, chunksize=1)

with open("./generated_refined_news.jsonl", "w") as f:
    for result in results:
        f.write(result + "\n")

기사가 생성됐어요! 한 번 살펴볼게요.

Python

from pprint import pprint

with open("./generated_refined_news.jsonl", "r") as f:
  l = json.loads(f.readlines()[12])

pprint(l)

더 알아보기 (Learn more)