개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
SQL tables (and columns):
* Customers(customer_id, signup_date)
* Streaming(customer_id, video_id, watch_date, watch_minutes)
A well-written SQL query that lists customers who signed up during March 2020 and watched more than 50 hours of video in their first 30 days:
```
Output
SELECT c.customer_id
FROM Customers c
JOIN Streaming s
ON c.customer_id = s.customer_id
WHERE c.signup_date BETWEEN '2020-03-01' AND '2020-03-31'
AND s.watch_date BETWEEN c.signup_date AND DATE_ADD(c.signup_date, INTERVAL 30 DAY)
GROUP BY c.customer_id
HAVING SUM(s.watch_minutes) > 50 * 60
code-davinci-002는 그 변수 이름에서 초론을 할 수 있습니다. 예를 들어 watch_minutes는 분단위 데이터 이기 때문에 50시간을 계산할 때 이것에 60을 곱해서 분단위로 바꾸어야 된다고 스스로 추론할 수 있습니다.
단일 텍스트 입력값만 받는 Completions 와 달리 Edits는 두가지 입력값을 받습니다. 지시문과 수정될 텍스트 입니다. 아래 예를 보여드리겠습니다.
instruction input :
Fix the OCR errors
Text input
Therewassomehostilityntheenergybehindthe researchreportedinPerceptrons....Part of ourdrivecame,aswequiteplainlyacknoweldgednourbook,fromhe facthatfundingndresearchnergywerebeingdissipatedon. . .misleadingttemptsouseconnectionistmethodsnpracticalappli-cations.
Output
There was some hostility in the energy behind the research reported in Perceptrons....Part of our drive came, as we quite plainly acknowledged in our book, from the fact that funding and research energy were being dissipated on...misleading attempts to use connectionist methods in practical applications.
일반적으로 instructions는 명령형, 현재형 혹은 과거형 일 수 있습니다. 사용 사례마다 가장 적합한 것이 무엇인지 직접 실험해 보세요.
Translation
이 Edit 애플리케이션 중 하나가 번역 프로그램입니다.
Large language 모델은 common language들 간의 번역에 아주 탁월합니다.
2021년 GPT-3는 WMT14 영어 - 프랑스어 benchmark에서 자율 번역 분야에서 새로운 state-of-the-art 기록을 세웠습니다.
다음은 Edits endpoint를 사용하여 텍스트를 번역하는 방법에 대한 예제 입니다.
Instruction input
translation into French
Text input
That's life.
Output
C'est la vie.
물론 Edits endpoint로 할수 있는 많은 작업들이 Completion endpoint로도 수행할 수 있습니다. 예를 들어 다음과 같이 명령을 앞에 추가하여 번역을 요청할 수 있습니다.
Translate the following text from English to French.
English: That's life.
French:
Output
C'est la vie.
번역을 위한 팁에는 아래와 같은 것들이 있습니다.
Performance is best on the most common languages
대부분의 일반적인 언어들에 있어서의 성능은 최고 입니다.
We've seen better performance when the instruction is given in the final language (so if translating into French, give the instructionTraduire le texte de l'anglais au français.rather thanTranslate the following text from English to French.)
instruction이 최종 언어로 제공될 때 그 성능은 더 좋게 나오는 것을 목격했습니다. (따라서 프랑스어로 번역하는 경우 instruction을 Translate the following text from English to French 이렇게 주는 것 보다 Traduire le texte de l'anglais au français. 이렇게 주는 것이 더 효과가 좋습니다.. )
Backtranslation (as describedhere) can also increase performance
Text with colons and heavy punctuation can trip up the instruction-following models, especially if the instruction uses colons (e.g.,English: {english text} French:)
colon과 heavy punctuation 부호가 있는 텍스트는 instruction-following 모델에 문제를 일으킬 수 있습니다. 특히 instruction이 colon을 사용하는 경우 그렇습니다. (e.g., English: {english text} French:)
The edits endpoint sometimes repeats the original text input alongside the translation, which can be monitored and filtered
Edits endpoint는 번역문과 함께 원본 텍스트를 반복할 때도 있습니다. 이는 모니터링 및 필터링을 할 수 있습니다.
번역과 관련하여 large language 모델은 번역과 함께 다른 instruction을 결합하는데 탁월합니다. 예를 들어 여러분은 GPT-3에게 Slovenian을 English로 번역할 것을 요청할 수 있습니다. 하지만 모든 LaTeX 조판 명령은 바뀌지 않습니다. 다음 Jupyter Notebook은 슬로베니아 수학책을 영어로 어떻게 번역했는지 자세히 설명합니다.
Large language 모델은 긴 텍스트에서 정보를 추출하는데 유용합니다. 응용분야는 다음과 같습니다.
Answering questions about a piece of text, e.g.:
텍스트 조각에 대한 질문들에 답하기, 예)
Querying an knowledge base to help people look up things they don't know
사람들이 모르는 것들을 찾는데 도움을 주는 지식 기반의 문의
Querying an unfamiliar document to understand what it contains
어떤 내용인지 이해해야 되는 잘 모르는 문서에 대한 문의
Querying a document with structured questions in order to extract tags, classes, entities, etc.
태그, 클래스, entity들을 추출하기 위한 구조화된 질문들이 있는 문서에 대한 문의
Summarizing text, e.g.
문서 요약하기, 예 :
Summarizing long documents
긴 문서 요약하기
Summarizing back-and-forth emails or message threads
주고 받고 한 이메일이나 일련의 메세지를 요약하기
Summarizing detailed meeting notes with key points and next steps
회의록을 키 포인트와 다음 단계에 대한 정보로 자세하게 요약하기
Classifying text, e.g.:
문서 분류, 예. :
Classifying customer feedback messages by topic or type
고객들이 피드백 한 메세지를 주제와 유형별로 분류하기
Classifying documents by topic or type
문서를 주제와 유형별로 분류하기
Classifying the tone or sentiment of text
문서의 어조와 감정들을 분류하기
Extracting entities, e.g.:
Entity들을 추출하기, 예.:
Extracting contact information from a customer message
고객들의 메세지로부터 연락처 정보 추출하기
Extracting names of people or companies or products from a document
문서에서 사람이나 회사 혹은 상품 이름 추출하기
Extracting things mentioned in customer reviews or feedback
고객의 리뷰나 피드백들 속에서 언급된 것들 추출하기
다음은 위 예들에 대한 간단한 예제들 입니다.
Answering questions about a piece of text
아래는 텍스트 조각에 대한 질문에 대해 대답하도록 하는 프롬프트 예제 입니다.
Using the following text, answer the following question. If the answer is not contained within the text, say "I don't know."
Text:
"""
Oklo Mine (sometimes Oklo Reactor or Oklo Mines), located in Oklo, Gabon on the west coast of Central Africa, is believed to be the only natural nuclear fission reactor. Oklo consists of 16 sites at which self-sustaining nuclear fission reactions are thought to have taken place approximately 1.7 billion years ago, and ran for hundreds of thousands of years. It is estimated to have averaged under 100 kW of thermal power during that time.
"""
Question: How many natural fission reactors have ever been discovered?
Answer:
One. Oklo Mine is believed to be the only natural nuclear fission reactor.
질문하려는 텍스트가 토큰 제한 (text-davinci-002/-003의 경우 ~4,000개 토큰 및 이전 모델의 경우 ~2,000개 토큰)보다 긴 경우 텍스트를 더 작은 조각으로 나누고 관련성에 따라 순위를 매길 수 있습니다. 그런 다음 가장 관련성이 있어 보이는 부분만 사용해서 질문하세요. 이는 Question_answering_using_embeddings.ipynb 에 설명 돼 있습니다.
학생들이 시험을 잘 보기 위해서 그동안 적었던 노트를 보듯이 GPT-3는 질문과 함께 텍스트를 주어주면 질문에 더 잘 답할 수 있습니다.
필기 노트가 없다면 GPT-3는 자신의 아주 긴 memory에 의존해야 합니다. (예. internal weights), 그렇게 되면 파편적인 대답 혹은 약간 뜬그룸 같은 대답을 하게 될 수 있습니다.
Summarization
아래는 문서를 요약하는 간단한 prompt 예제입니다.
Summarize the following text.
Text:
"""
Two independent experiments reported their results this morning at CERN, Europe's high-energy physics laboratory near Geneva in Switzerland. Both show convincing evidence of a new boson particle weighing around 125 gigaelectronvolts, which so far fits predictions of the Higgs previously made by theoretical physicists.
"As a layman I would say: 'I think we have it'. Would you agree?" Rolf-Dieter Heuer, CERN's director-general, asked the packed auditorium. The physicists assembled there burst into applause.
"""
Summary:
CERN's director-general asked a packed auditorium if they agreed that two independent experiments had found convincing evidence of a new boson particle that fits predictions of the Higgs, to which the physicists assembled there responded with applause.
이 예제 프롬프트에서 사용된 따옴표 3개 부호 (""") 는 특별한 것이 아닙니다. GPT-3는 <>, {}, 또는 ### 를 포함한 대부분의 구분 기호를 인식 할 수 있습니다. 긴 텍스트의 경우 이러한 구분 기호를 사용하는 것이 좋습니다. 텍스트의 한 섹션이 끝나고 다음 섹션이 시작되는 위치를 명확하게 구분하는데 도움이 됩니다.
Classification
텍스트를 분류하려는 경우 가장 좋은 방법은 클래스들을 미리 알고 있는지 여부에 따라 다릅니다.
클래스가 미리 알려지지 않은 경우 (예: 그것들이 사용자에 의해 세팅되거나 즉석해서 생성된 경우) 클래스들이 포함된 instruction을 제공해서 zero-shot classification을 사용할 수 있습니다. 혹은 어떤 클래스 레이블 (혹은 분류된 텍스트들)이 텍스트와 가장 유사한지를 보기 위한 임베딩을 사용해도 됩니다. (Zero-shot_classification_with_embeddings.ipynb에서 설명 됨)
Entity extraction
아래는 Entity 추출을 위한 예제 프롬프트 입니다.
From the text below, extract the following entities in the following format:
Companies: <comma-separated list of companies mentioned>
People & titles: <comma-separated list of people mentioned (with their titles or roles appended in parentheses)>
Text:
"""
In March 1981, United States v. AT&T came to trial under Assistant Attorney General William Baxter. AT&T chairman Charles L. Brown thought the company would be gutted. He realized that AT&T would lose and, in December 1981, resumed negotiations with the Justice Department. Reaching an agreement less than a month later, Brown agreed to divestiture—the best and only realistic alternative. AT&T's decision allowed it to retain its research and manufacturing arms. The decree, titled the Modification of Final Judgment, was an adjustment of the Consent Decree of 14 January 1956. Judge Harold H. Greene was given the authority over the modified decree....
In 1982, the U.S. government announced that AT&T would cease to exist as a monopolistic entity. On 1 January 1984, it was split into seven smaller regional companies, Bell South, Bell Atlantic, NYNEX, American Information Technologies, Southwestern Bell, US West, and Pacific Telesis, to handle regional phone services in the U.S. AT&T retains control of its long distance services, but was no longer protected from competition.
"""
Companies: AT&T, Bell South, Bell Atlantic, NYNEX, American Information Technologies, Southwestern Bell, US West, Pacific Telesis
People & titles: William Baxter (Assistant Attorney General), Charles L. Brown (AT&T chairman), Harold H. Greene (Judge)
Large language 모델들은 writing에 아주 탁월합니다. 그들은 모든 종류의 작업을 지원할 수 있습니다.
Blog posts
Email copy
Ad copy
Website copy
Product descriptions
Memos
Storytelling
Brainstorming
Question generation
etc.
GPT-3에서 prompt 하는 가장 쉬운 방법은 여러분이 하고 싶은 말을 하는 것입니다. 예를 들어 여러분이 이메일을 쓰기를 원한다면 아래와 같이 프롬프트를 사용할 수 있습니다.
Write an email to a colleague named Jill congratulating her on her promotion. The tone should be warm yet professional. Mention how you admire the work she's been putting in. Include a joke about how her pet lizard Max enjoys eating grasshoppers. Mention how you're looking forward to the team off-site next week.
Subject: Congratulations on Your Promotion, Jill!
Dear Jill,
Congratulations on your promotion! I'm so proud of you and all the hard work you've been putting in. It's been inspiring to watch you grow in your career.
I'm sure Max the lizard is also celebrating with you. I hear he loves eating grasshoppers, so you should treat him to a special snack!
I'm looking forward to seeing you at the team off-site next week. I'm sure it will be a great opportunity to celebrate your success.
All the best,
[Your Name]
일반적으로 writing은 어떤 스타일의 prompt에도 작동합니다. 그것이 어떤 지시 (instruction)이든 따라야 할 일련의 예제들이든 관계 없이 작동합니다. 여러분이 하고 싶은 것을 실현하기 위해 가장 잘 작동 시킬 수 있는 방법은 무엇인지 직접 실험 해 보세요.
Writing은 또한 모든 유형의 모델들과 같이 작동할 수 있지만 각각 장 단점이 있습니다.
Search for a better prompt that elicits more reliable answers?
좀더 신뢰할 수 있는 답변을 이끌어내기 위해 더 좋은 prompt를 찾으시겠습니까?
Invest in thousands of examples to fine-tune a custom model?
custom 모델로 fine-tune 하기 위해 수천개의 예제들을 마련하는 일을 하시겠습니까?
Assume the model is incapable of the task, and move on?
해당 모델이 그 작업에 적당하지 않다고 가정하고 그냥 진행 하시겠습니까?
간단하게 답할 수 있는 문제가 아닙니다. 상황에 따라 다르니까요. 하여간 여러분의 작업에 논리적 추론이나 복잡성이 있다면 좀 더 신뢰성 있는 결과를 도출하기 위해 그리고 고성능 prompt를 만들기 위해 이 글에서 제시하는 기술들을 고려해 보세요.
Why GPT-3 fails on complex tasks
GPT-3는 왜 복잡한 작업에 대해 실패 할까요?
여러분은 13 곱하기 17이 무엇이냐고 물으면 즉시 답할 수 있습니까?
대부분의 사람들은 그렇지 못할 겁니다. 그렇다고 해서 인간이 두자릿수 곱셈을 못 하는 것은 아닙니다.
몇초의 시간과 종이와 연필만 있으면 13 x 17 = 130 + 70 + 21 = 221 이라는 계산을 하는 것은 그리 어렵지 않습니다.
마찬가지로 GPT-3도 다음 token을 계산하는데 너무 복잡한 임무를 부여하면 잘못된 추측을 만들 수 있습니다. 위의 인간의 예와 마찬가지로 이것이 GPT-3가 해당 작업을 수행하지 못하는 것을 의미하는 것은 아닙니다. 문제를 추론할 충분한 시간과 공간이 있으면 그 모델은 여전히 안정적으로 대답할 수 있습니다.
예를 들어 text-davinci-002에게 저글링 공에 대한 다음 수학 문제를 묻는 다면 아마 대답을 잘 못 할 겁니다.
Q: A juggler has 16 balls. Half of the balls are golf balls and half of the golf balls are blue. How many blue golf balls are there?
A:
There are 8 blue golf balls.
16개의 공 중에 반은 골프공이다. 그리고 골프공의 반은 파란색이다. 파란 골프 공은 몇개가 있을까?
8개의 파란 골프공이 있다.
==> 이 대답은 틀렸죠. 8개 골프공 중에 반이 파란색이니까 4개가 되겠죠.
Q: A juggler has 16 balls. Half of the balls are golf balls and half of the golf balls are blue. How many blue golf balls are there?
A: Let's think step by step.
There are 16 balls in total.
Half of the balls are golf balls.
That means that there are 8 golf balls.
Half of the golf balls are blue.
That means that there are 4 blue golf balls.
이렇게 스텝 바이 스텝으로 생각하면 제대로 된 대답을 내 놓습니다.
물론 이 단계별 트릭이 일반적으로 적용되는 경우인지 혹은 운 좋게 특정 경우에만 적용 된 것인지는 이 한가지 예만 가지고 판단하기 어렵습니다. 어쨌든 이 질문에 대해서는 효과가 있었습니다. 이런식의 단어로 된 수학문제에서 이렇게 스텝 바이 스텝으로 생각하도록 함으로서 GPT-3가 문제를 제대로 해결하는 비율이 무의미한 18%에서 유의미한 79%로 엄청나게 높아 졌습니다.
Model capabilities depend on context
GPT-3으로 작업하는 방법을 배울 때 흔히 발생하는 개념적 실수 중 하나는 GPT-3의 기능이 모든 컨텍스트에서 고정되어 있다고 믿는 것입니다. 예를 들어 GPT-3가 간단한 논리 질문을 틀린다면 GPT-3는 간단한 논리 질문에 적합하지 않은것이다 라고 생각하는 것.
Let's think step by step 예제에서 알 수 있듯이 GPT-3의 명백한 오류는 때때로 올바른 output을 내 오는데 대해 스스로 조종하는 것에 도움이 되는 좀 더 나은 prompt줄 제공함으로서 해결될 수 있습니다.
How to improve reliability on complex tasks
이 문서의 나머지 부분에서는 복잡한 작업에서 Large language 모델의 신뢰성(안정성)을 개선할 수 있는 기술들을 공유합니다.
일부 기술은 특정 유형의 문제에만 적용 되지만 대부분은 다음과 같이 광범위한 상황에 적용할 수 있는 일반 원칙을 기반으로 합니다.
Give clearer instructions
명확하게 지시한다.
Split complex tasks into simpler subtasks
복잡한 임무는 좀 더 간단한 작은 임무들로 나눈다.
Structure the instruction to keep the model on task
모델이 작업을 계속 수행할 수 있도록 지시를 구조화 한다.
Prompt the model to explain before answering
모델이 대답을 하기전에 설명을 하도록 요구하는 내용을 Prompt에 넣어 작성한다.
Ask for justifications of many possible answers, and then synthesize
많은 가능한 응답들의 정당성을 묻고 그것들을 종합한다.
Generate many outputs, and then use the model to pick the best one
많은 output들을 생성한다. 그리고 모델을 사용해서 그 중에 가장 좋은 것을 선택하도록 한다.
Fine-tune custom models to maximize performance
Fine-tune 커스텀 모델로 성능을 최대화 한다.
Split complex tasks into simpler tasks
모델에게 생각할 시간과 space를 좀 더 많이 주는 방법 중 하나는 더 간단한 조각들로 임무를 나누는 것입니다.
예를 들어 어떤 텍스트에 대해 여러 가지의 보기를 주고 모델에게 물어본다고 했을 때를 생각해 보세요. (아래 예제 참조) 그냥 주관식으로 물어 본다면 text-davinci-002는 그 중 3번과 5번을 고를 수가 없습니다. 이렇게 되면 잘못된 대답을 할 확률이 높아 집니다.
하지만 보기를 5개를 주고 그 중 3번과 5번이 답이라면 text-davinci-002는 그 3번과 5번을 선택하던가 그 둘을 종합해서 좀 더 정답에 가깝거나 완전한 정답을 output으로 내 놓을 수 있습니다.
Use the following clues to answer the following multiple-choice question.
Clues:
1. Miss Scarlett was the only person in the lounge.
2. The person with the pipe was in the kitchen.
3. Colonel Mustard was the only person in the observatory.
4. Professor Plum was not in the library nor the billiard room.
5. The person with the candlestick was in the observatory.
Question: Was Colonel Mustard in the observatory with the candlestick?
(a) Yes; Colonel Mustard was in the observatory with the candlestick
(b) No; Colonel Mustard was not in the observatory with the candlestick
(c) Unknown; there is not enough information to determine whether Colonel Mustard was in the observatory with the candlestick
Solution:
(c) Unknown; there is not enough information to determine whether Colonel Mustard was in the observatory with the candlestick
3번과 5번이 Mustard 대령이 천문대에 있는 유일한 사람이고 천문데애 있는 사람이 촛대를 가지고 있다는 것을 설명하고 있지만 모델은 그것을 (a) Yes; .. 라고 정답으로 결함하지 못합니다.
이렇게 직접 묻는 대신 작업을 세 부분으로 나눌 수 있습니다.
First, go through the clues one by one and consider whether the clue is potentially relevant
먼저 단서를 하나씩 살펴보고 단서가 잠재적으로 관련이 있는지 고려 하세요.
Second, combine the relevant clues to reason out the answer to the question\
두번째로 관련 단서를 결합하여 질문에 대한 답을 추론하세요.
Third, write the final answer: either (a), (b), or (c)
셋째 (a),(b) 혹은 (c) 중 하나의 최종 답변을 작성합니다.
Use the following clues to answer the following multiple-choice question, using the following procedure:
(1) First, go through the clues one by one and consider whether the clue is potentially relevant
(2) Second, combine the relevant clues to reason out the answer to the question
(3) Third, map the answer to one of the multiple choice answers: either (a), (b), or (c)
Clues:
1. Miss Scarlett was the only person in the lounge.
2. The person with the pipe was in the kitchen.
3. Colonel Mustard was the only person in the observatory.
4. Professor Plum was not in the library nor the billiard room.
5. The person with the candlestick was in the observatory.
Question: Was Colonel Mustard in the observatory with the candlestick?
(a) Yes; Colonel Mustard was in the observatory with the candlestick
(b) No; Colonel Mustard was not in the observatory with the candlestick
(c) Unknown; there is not enough information to determine whether Colonel Mustard was in the observatory with the candlestick
Solution:
(1) First, go through the clues one by one and consider whether the clue is potentially relevant:
Clue 1: Miss Scarlett was the only person in the lounge. This clue is not relevant.
Clue 2: The person with the pipe was in the kitchen. This clue is not relevant.
Clue 3: Colonel Mustard was the only person in the observatory. This clue is relevant.
Clue 4: Professor Plum was not in the library nor the billiard room. This clue is not relevant.
Clue 5: The person with the candlestick was in the observatory. This clue is relevant.
(2) Second, combine the relevant clues to reason out the answer to the question:
Clue 3 and Clue 5 both say that the person with the candlestick was in the observatory. Colonel Mustard was the only person in the observatory, so Colonel Mustard was the person with the candlestick.
(3) Third, write the final answer:
(a) Yes; Colonel Mustard was in the observatory with the candlestick
모델에게 생각할 시간과 공간을 더 주고 reasoning plan (추론 계획)에 따르는 가이드를 제공함으로써 모델은 (a) 라는 정답을 알아낼 수 있습니다.
복잡한 명령을 더 작은 하위 작업으로 분할하는 또 다른 잇점은 모델이 각 하위 작업에 집중하도록 도울 수 있다는 것입니다.
예를 들어 우리가 text-davinci-002에게 원래의 언어로 텍스트를 요약해달라고 부탁하면 모델은 다시 영어로 전환 될 수 있습니다.
Summarize the text using the original language of the text. The summary should be one sentence long.
Text:
"""
La estadística (la forma femenina del término alemán Statistik, derivado a su vez del italiano statista, "hombre de Estado") es una ciencia que estudia la variabilidad, colección, organización, análisis, interpretación, y presentación de los datos, así como el proceso aleatorio que los genera siguiendo las leyes de la probabilidad. La estadística es una ciencia formal deductiva, con un conocimiento propio, dinámico y en continuo desarrollo obtenido a través del método científico formal. En ocasiones, las ciencias fácticas necesitan utilizar técnicas estadísticas durante su proceso de investigación factual, con el fin de obtener nuevos conocimientos basados en la experimentación y en la observación. En estos casos, la aplicación de la estadística permite el análisis de datos provenientes de una muestra representativa, que busca explicar las correlaciones y dependencias de un fenómeno físico o natural, de ocurrencia en forma aleatoria o condicional.
"""
Summary:
The text explains that statistics is a science that studies the variability, collection, organization, analysis, interpretation, and presentation of data, as well as the random process that generates them following the laws of probability.
여기서 일단 모델에게 해당 언어를 판별하라고 지시할 수 있습니다. 그리고 난 후 그 내용을 요약하라고 하면 좀 더 신뢰도가 높은 답변을 얻을 수 있습니다.
First, identify the language of the text. Second, summarize the text using the original language of the text. The summary should be one sentence long.
Text:
"""
La estadística (la forma femenina del término alemán Statistik, derivado a su vez del italiano statista, "hombre de Estado") es una ciencia que estudia la variabilidad, colección, organización, análisis, interpretación, y presentación de los datos, así como el proceso aleatorio que los genera siguiendo las leyes de la probabilidad. La estadística es una ciencia formal deductiva, con un conocimiento propio, dinámico y en continuo desarrollo obtenido a través del método científico formal. En ocasiones, las ciencias fácticas necesitan utilizar técnicas estadísticas durante su proceso de investigación factual, con el fin de obtener nuevos conocimientos basados en la experimentación y en la observación. En estos casos, la aplicación de la estadística permite el análisis de datos provenientes de una muestra representativa, que busca explicar las correlaciones y dependencias de un fenómeno físico o natural, de ocurrencia en forma aleatoria o condicional.
"""
Language:
Spanish
La estadística es una ciencia que estudia la variabilidad, colección, organización, análisis, interpretación, y presentación de los datos, así como el proceso aleatorio que los genera siguiendo las leyes de la probabilidad.
Prompt the model to explain before answering
답변의 신뢰도를 향상 시킬 수 있는 또 다른 강력한 기술은 모델이 최종 답변을 곧바로 하도록 하는 대신 점진적으로 답변을 추론하도록 유도하는 것입니다.
저자는 이 간단한 트릭을 MultiArith 수학 데이터 세트에 적용하여 Let's think step by step으로 정확도를 18%에서 79%로 4배로 높였다는 사실을 발견했습니다.
Implications
이 Let's think step by step 트릭이 수학 문제 에서는 잘 작동한다고 모든 작업에 효과적으로 적용 될 수 있는 것은 아닙니다. 저자는 이 방법이 multi-step 산술 문제, 상징적 추론 문제, 전략 문제 그리고 다른 추론 문제들에 아주 유용하게 적용될 수 있다는 것을 발견했습니다. 아주 간단한 수학문제나 아주 상식적인 질문에는 도움이 되지 않았으며 아마도 다른 많은 비추론 작업에도 도움이 되지 않을 것입니다.
이 테크닉을 자신의 작업에 적용하는 경우 instruction을 customizing 하는 실험을 두려워 하지 마세요. Let's think step by step은 오히려 일반적입니다. 사용사례에 맞게 맞춤화 된 보다 엄격한 형식을 따르는 instruction을 통해 더 나은 성능을 찾을 수 있습니다. 예를 들어 더 구조화된 변형을 시도할 수 있다면 첫번째 X가 참일 수 있는 이유에 대해 Step by Step으로 생각 해 보세요. 두번째로 왜 Y가 참일 수 있는지를 step by step 으로 생각합니다. 그리고 세번쨰로 X 나 Y 중 어느게 더 나은지에 대해 step by step으로 생각하는 겁니다. 그리고 이 과정을 계속 이어나가는 예제 형식의 모델을 제공할 수도 있습니다.
예:
Using the IRS guidance below, answer the following questions using this format:
(1) For each criterion, determine whether it is met by the vehicle purchase
- {Criterion} Let's think step by step. {explanation} {yes or no, or if the question does not apply then N/A}.
(2) After considering each criterion in turn, phrase the final answer as "Because of {reasons}, the answer is likely {yes or no}."
IRS guidance:
"""
You may be eligible for a federal tax credit under Section 30D if you purchased a car or truck that meets the following criteria:
- Does the vehicle have at least four wheels?
- Does the vehicle weigh less than 14,000 pounds?
- Does the vehicle draw energy from a battery with at least 4 kilowatt hours that may be recharged from an external source?
- Was the vehicle purchased in a year before 2022?
- If so, has the manufacturer sold less than 200,000 qualifying vehicles? (Tesla and GM have sold more than 200,000 qualifying vehicles.)
- Was the vehicle purchased in a year after 2022?
- If so, is the vehicle present in the following list of North American-assembled vehicles? (The only electric vehicles assembled in North America are the Audi Q5, BMW 330e, BMW X5, Chevrolet Bolt EUV, Chevrolet Bolt EV, Chrysler Pacifica PHEV, Ford Escape PHEV, Ford F Series, Ford Mustang MACH E, Ford Transit Van, GMC Hummer Pickup, GMC Hummer SUV, Jeep Grand Cherokee PHEV, Jeep Wrangler PHEV, Lincoln Aviator PHEV, Lincoln Corsair Plug-in, Lucid Air, Nissan Leaf, Rivian EDV, Rivian R1S, Rivian R1T, Tesla Model 3, Tesla Model S, Tesla Model X, Tesla Model Y, Volvo S60, BMW 330e, Bolt EV, Cadillac Lyriq, Mercedes EQS SUV, and Nissan Leaf.)
"""
Question: Can I claim a federal tax credit for my Toyota Prius Prime bought in 2021?
Solution:
(1) For each criterion, determine whether it is met by the vehicle purchase
- Does the vehicle have at least four wheels? Let's think step by step.
The Toyota Prius Prime has four wheels, so the answer is yes.
- Does the vehicle weigh less than 14,000 pounds? Let's think step by step. The Toyota Prius Prime weighs less than 14,000 pounds, so the answer is yes.
- Does the vehicle draw energy from a battery with at least 4 kilowatt hours that may be recharged from an external source? Let's think step by step. The Toyota Prius Prime has a battery with at least 4 kilowatt hours that may be recharged from an external source, so the answer is yes.
- Was the vehicle purchased in a year before 2022? Let's think step by step. The Toyota Prius Prime was purchased in 2021, which is before 2022, so the answer is yes.
- Was the vehicle purchased in a year after 2022? N/A
- If so, is the vehicle present in the following list of North American-assembled vehicles? N/A
(2) After considering each criterion in turn, phrase the final answer as "Because of {reasons}, the answer is likely {yes or no}."
Because the Toyota Prius Prime meets all of the criteria for a federal tax credit, the answer is likely yes.
Few-shot examples
Method
모델이 답을 추론하도록 유도하는 방법은 여러가지가 있습니다. 그 중 하나는 Jason Wei와 Denny Zhou 등이 구글에서 연구한 몇가지 예 (few-shot) 로 시연하는 것입니다. 다음은 few-shot 의 chain-of-thought 프롬프트 입니다.
Let's thin step by step 테크닉과 비교해서 few-shot example-based 접근법에는 한가지 강점은 format, length 그리고 추론의 스타일을 좀 더 쉽게 특정할 수 있다는 것입니다. 이 작업은 최종 답변을 확정하기 전에 모델이 하는 사전 작업입니다. 이것은 모델이 초기 추론을 깊게 혹은 옳은 방향이 아닌 쪽으로 할 경우 특히 도움이 됩니다.
Fine-tuned
Method
일반적으로 최대 성능을 얻으려면 fine-tune a custom 모델을 사용할 필요가 있습니다. 그런데 모델을 fine-tuning 하는 것은 작성하는데 비용이 드는 예제 explanation들을 수천개 이상을 사용해야 합니다.
2022년 Eric Zelikman과 Yuhuai We et al 은 모델을 fine-tune 하는데 사용될 수 있는 explanation 데이터 세트를 생성하기 위한 few-shot 프롬프트를 사용하기 위한 아주 현명한 procedure를 발표했습니다. 그것은 후보 explanation들을 생성하기 위한 few-shot 프롬프트를 사용하자는 아이디어 입니다. 그 후보 explanation들 중 정답을 생산한 explanation들만 keep 한다는 아이디어죠.
그 다음 오답에 대한 추가적인 explanation들을 얻기 위해 few-shot 프롬프트를 retry 하는 겁니다. 정답은 질문의 일 부분으로서 제공되게 됩니다. 저자들은 그 절차를 STaR(Self-taught Reasoner) 절차라고 부릅니다.
이 기술을 사용하면 수천개의 example explanation들을 작성할 필요 없습니다. 그러기 위해서 fine-tune의 강점과 chain-of-thought 프롬프팅의 장점을 결합할 수 있습니다.
Results
저자들이 이 기술을 Common Sense Q&A 데이타 세트에 적용 했을 때 그들은 이 STaR이 chain-of-thought 프롬프트만 사용했을 때 와 fine-tuning 만을 사용했을 때 보다 성능이 더 뛰어나게 나타난 다는 것을 발견했습니다. (73% > 37% , 73% > 60%)
fine-tuning 데이터세트를 확장하거나 수정하기 위해 few-shot 프롬프트를 사용하는 것은 explanation 작성을 뛰어 넘어 일반화할 수 있게 해 주는 아이디어 입니다. 예를 들어 여러분이 train 하기 위한 구조화 되지 않은 텍스트를 많이 가지고 있는 경우 프롬프트를 이용해서 구조화되지 않은 텍스트에서 구조화 된 데이터 세트를 추출한 다음 그 구조화 된 데이터 세트에서 custom 모델을 fine-tune 하는 것입니다.
Extensions to chain-of-thought prompting
이 외에 chain-of-thought 의 확장관련한 발표도 몇개 더 있습니다.
Selection-inference prompting
Method
Published by Antonia Creswell et al., one extension of the chain-of-thought technique is to split the single prompt for generating explanations and answers into smaller parts. First, a prompt selects a relevant subset of facts from the text ('selection prompt'). Then, a second prompt infers a conclusion from the selected facts ('inference prompt'). These prompts are then alternated in a loop to generate multiple steps of reasoning and eventually land on a final answer. The authors illustrate the idea in the following figure:
Antonia Creswell 등이 발표한 chain-of-thought 테크닉의 확장은 explanation들을 생성하기 위해 단일 프롬프트를 분할하는 것입니다. 그 답변들은 좀 더 작은 부분으로 분할 되는 것이죠. 우선 프롬프트는 텍스트 (selection prompt)로부터 연관된 fact의 subset를 선택합니다. 그런 다음 두번째 프롬프트가 선택된 사실(inference prompt) 에서 결론을 추론합니다. 그런 다음 이러한 프롬프트는 루프에서 번갈아 가며 여러단계의 추론을 생성하고 결국 최종 답변에 도달합니다. 저자는 아래 그림으로 그 아이디어를 설명합니다.
7B-parameter 모델을 적용 했을 때 저자들은 selection-interference 프롬프팅이 bAbi 와 Proof Writer benchmark task들에 대해 chain-of-thought 프롬프팅과 비교해서 대체적으로 성능이 향상된다는 것을 발견했습니다.
(bAbi와 Proof Writer benchmark task들은 둘 다 더 긴 일련의 추론 단계들이 더 필요합니다.)
그들이 달성한 최고의 성능은 fine-tuning과 함께 selection-interferne 프롬프팅을 결합했을 때 달성했습니다.
selection-inference 프롬프팅 테크닉을 발표한 다음 몇달 후 저자는 다음 논문에서 테크닉을 확장할 수 있는 다음과 같은 아이디어를 발표 했습니다.
figuring out when the selection-inference cycle should stop or continue
selection-inference 사이클이 언제 중단되고 언제 계속 되어야 하는지 알아내기
adding a value function to help search over multiple reasoning paths
여러 추론 경로들에 대해 검색하는 것을 돕기 위한 value function 추가하기
reducing hallucination of fake facts by fine-tuning a model to reason about sentence labels (e.g., sen1) rather than writing out the sentences themselves
문장 자체를 작성하는 대신 문장 레이블에 대한 추론을 위한 모델을 fine-tuning 함으로서 fake fact들의 hallucination (환각) 를 감소시키기
Method
In the original selection-inference technique, specialized 'selection' and 'inference' prompts are alternated to select facts and make inferences from those facts, combining to generate a sequence of reasoning steps.
오리지널 selection-inference 테크닉에서는 특별한 'selection' 과 'inference' (추론) 프롬프트 들은 fact들을 선택하는 것과 그러한 fact들을 가지고 추론을 만드는 것을 번갈아 가면서 하고 이 추론 과정들의 sequence를 발생시키기 위해 결합합니다.
저자들은 이 테크닉을 2개의 추가 구성 요소들로 확장합니다.
첫째, 저자들은 각각의 추론 단계 이후 'halter' 모델을 추가합니다. 이것은 이 추론들이 그 질문에 대한 대답으로서 충분한 것인지를 질문하기 위함입니다.
이 halter 모델은 몇가지 장점들이 있습니다.
it can tell the selection-inference process to stop or keep going, as necessary.
이것은 필요에 따라 중지 하거나 아니면 계속 진행하기 위한 selection-inference 프로세스인지 여부를 알려 줄 수 있습니다.
if the process never halts, you'll get no answer, which is often preferable to a hallucinated guess
만약 그 프로세스가 중단되지 않는다면 답을 얻지 못할 것입니다. 이것이 hallucinated guess 보다 나은 경우가 있기는 합니다.
이 두가지 확장에다가 추가적으로 저자들은 또한 fake fact들의 hallucination을 감소시키기 위한 트릭을 사용합니다. 모델에게 factual sentence들을 작성하도록 요구하는 대신 sentence label (e.g. sen1)들로 작업을 하도록 모델을 fine-tune 합니다. 이렇게 하면 프롬프트 context에 언급되지 않은 fake fact들을 hallucinating 하는 것을 방지하는데 도움이 됩니다.
정답을 받을 확률을 최대화 하려는 이전의 테크닉들과는 달리 다른 접근법은 (정답이든 오답이든) 가능한 explanation들 의 tree를 발생시키도록 하기 위해 GPT-3를 사용합니다. 그리고 나서 어떤 세트가 correct한지 를 알아내기 위해 그들의 관계들을 분석합니다. 이 테크닉은 2022년 5월에 정재훈 등에 의해 만들어진 coined maieutic 프롬프팅입니다. (maieutic은 아이디어를 이끌어내기 위해 질문하는 소크라테스 식 방법과 관련 돼 있습니다.)
이 방법은 복잡합니다. 아래와 같이 작동합니다.
First, build a maieutic tree, where each node is a statement that could be true or false:
첫째로 maieutic tree를 만듭니다. 각 노드는 참이나 거짓이 될 수 있는 하나의 statement 입니다.
Start with a multiple-choice question or true/false statement (e.g.War cannot have a tie)
객관식 질문 또는 참/거짓을 답할 수 있는 질문으로 시작합니다. (예. 전쟁은 무승부일 수 없다)
For each possible answer to the question, use the model to generate a corresponding explanation (with a prompt likeWar cannot have a tie? True, because)
질문에 대해 각각의 가능한 answer 들에 대해 각각 상응하는 explanation을 생성하도록 모델을 사용합니다. (전쟁은 무승부일 수 없다? 참, 왜냐하면... 같은 프롬프트가 될 것입니다.)
Then, prompt the model with the question and the generated explanation, and ask it to produce the answer. If reversing the explanation (with a prefix likeIt is wrong to say that {explanation}) reverses the answer, then the explanation is considered 'logically integral.'
그런 다음 질문과 생성된 explanation으로 모델의 프롬프트를 만듭니다. 그리고 나서 답을 만들도록 요청합니다. 만약 설명을 뒤집으면 (예를 들어 {explanation} 이라고 얘기하면 틀립니다와 같은 prifix를 만드는 방법)답도 뒤집어 집니다. 그러면 explanation은 "logically integral" 로 간주되게 됩니다.
If an explanation is not logically integral, then repeat the above process recursively, with each explanation turned into a True or False question, and generate more explanations for each new question.
만약 explanation이 logically integral 되지 않았다면 위의 과정을 재귀적으로 반복합니다. (이 때 각각의 explanation은 True 나 False question으로 바뀌게 되는 것이죠. 그리고 각각의 새로운 질문들에 대한 좀 더 많은 explanation들을 생성합니다.
After all of the recursive explaining is done, you end up with a tree of explanations, where each leaf on the tree has the property that reversing the explanation reverses the model's answer.
이렇게 모든 재귀적인 explaining이 종류된 후에 explanation tree를 얻게 됩니다. 나무에 있는 각각의 leaf (잎)들은 explanation을 뒤집으면 모델의 답도 뒤집어지는 그런 프로퍼티를 갖게 됩니다.
Second, convert the tree into a graph of relations:
두번째, 그 tree를 관계 그래프로 변환합니다.
For each node in the tree, calculate the model's relative belief in each node (inferred from the probability of getting an answer ofTrueto given an explanation)
그 나무의 각각의 노드들은 각 노드에 대한 모델의 상대적 신뢰도를 계산하게 됩니다. (주어진 explanation에 True라는 답을 얻기 위한 추정치로 부터 추론 합니다.)
For each pair of nodes in the tree, use the model to identify whether they are entailed (implied) or contradicted
그 나무에 있는 노드들의 각 쌍들에 대해 그 쌍들이 그것들이 entailed (implied) 인지 contradicted (모순)인지의 여부를 모델을 사용하여 판정합니다.
Third, find the most consistent set of beliefs and take those to be true:
세번째, 가장 일관성 있는 belief들을 찾아내서 그것들을 true라고 작업합니다.
Specifically, using the strength of belief in each node and the logical relationships between them, formulate the problem as a weighted maximum satisfiability problem (MAX-SAT)
특히 각 노드의 신뢰도의 강도와 그들간의 논리적인 관계를 사용하여 weighted maximum satisfiability problem (MAX-SAT)로 그 문제를 공식화 합니다.
Use a solver to the find the most self-consistent set of beliefs, and take those as true
Solver를 사용하여 가장 self-consistent 한 belief들의 세트를 찾아 냅니다. 그리고 그것들을 true로 취합니다.
descrete set의 답변이 있는 task에 대해 신뢰도를 제고시킬 수 있는 간단한 방법 중 하나는 모델에서 여러 explanation 및 답변을 샘플링 한 다음에 (positive temperature를 사용) 가장 자주 등장하는 답변을 최종 답변으로 선택하는 겁니다.
이 테크닉은 여러 수학과 reasoning benchmark들에서 정확도를 1~24 퍼센트 향상 시켰습니다. (아래 도표는 구글의 LamDa 모델의 결과 입니다. 구글의 larger PaLM 모델을 사용했습니다. 기준선은 높지만 그로부터 얻는 것은 약간 좀 더 작았습니다.)
이 테크닉은 구현이 간단하지만 비용이 많이 들 수 있습니다. 10개의 답변 세트를 생성하면 비용이 10배 증가합니다.
또한 많은 이러한 기술들과 마찬가지로 제한된 답변 세트가 있는 작업에만 적용할 수 있습니다. 각 답변이 유니크한 (시를 쓰는 것 처럼) 각각의 답변이 있는 open-ended 작업에 대해 가장 일반적인 답변을 하나 선택한다는 것은 과연 유의미한 건가에 대해서는 확언할 수는 없습니다.
마지막으로, 이 테크닉은 답을 얻기 위해 여러 경로나 여러 구문들이 있는 경우에 가장 유용합니다. 답변에 이르는 경로가 오직 하나 뿐이면 이 테크닉은 전혀 도움이 되지 않을 수 있습니다. 극단적인 예로 이 작업이 single token answer를 생성하는 것이라면 100개의 생성된 토큰 중 가장 일반적인 것을 가져오는 것은 가장 높은 logprobs(temperature=0 으로 생성된) 로 생성된 토큰을 가져오는 것과 다른 것이 없습니다.
Verifiers
작업 성능을 개선하기 위한 또 다른 주요한 테크닉은 main generative 모델의 output들을 평가하기 위한 verifier(검증자) 혹은 discriminator(판별자) 모델을 훈련 시키는 겁니다. 이 판별자가 output을 reject 한다면 acceptable output을 얻을 때까지 generative 모델을 resample 할 수 있습니다. 많은 경우 답을 만드는 것 보다 답을 판단하는 것이 더 쉽기 때문에 이 방법의 power를 설명하는데 도움이 됩니다.
Method
2021년에 OpenAI 연구자들은 이 테크닉을 아래와 같은 절차들을 사용해서 초등학교 수학 문제에 적용했습니다.
First, they fine-tuned a model on questions and solutions
우선 질문과 솔루션에 대한 모델을 fine-tune 합니다.
For each problem in the training set, they generated 100 solutions
훈련 세트에 있는 각 문제들에 대해 100개의 솔루션들을 생성합니다.
Each of those 100 solutions was automatically labeled as either correct or incorrect, based on whether the final answer was correct
그 100개의 솔루션 각각은 정답인지 오답인지 자동적으로 label 됩니다. (정답/오답 근거는 최종 대답이 올바른지의 여부에 근거합니다.)
Using those solutions, with some labeled correct and some labeled incorrect, they fine-tuned a verifier model to classify whether a question and candidate solution was correct or incorrect
이러한 솔루션을 사용하여 만든 어떤 레이블들은 옳고 또 어떤 레이블들은 그렇지 않았습니다. 그들은 문제와 후보 솔루션이 옳은지 옳지 않은지를 구별하는 verifier 모델을 fine-tune 했습니다.
Finally, at test time, the generative model creates 100 solutions to each problem, and the one with the highest score according to the verifier model is picked as the final answer
마지막으로 테스트 할 때 generative 모델은 각 문제당 100개의 솔루션들을 만들었습니다. 그리고 그 verifier 모델에 의해 가장 높은 점수를 얻은 솔루션을 최종 답변으로 선택합니다.
이러한 테크닉들을 확률적 그래픽 모델로서 공식화 하는 것은 특정 문제를 해결하는데 곧바로 유용한 방법으로 사용할 수는 없을 수 있습니다. 하지만 이 프레임워크는 새로운 기술을 선택, 결합 그리고 발견하는데 도움이 될 수 있습니다.
Closing thoughts
Large language 모델을 연구하는 것은 매우 활발하고 빠르게 발전하고 있습니다. 연구자들은 계속해서 모델을 개선할 뿐만 아니라 모델을 가장 잘 활용하는 방법에 대한 이해도 지속적으로 향상 시키고 있습니다. 위에서 공유한 모든 논문은 지난 12개월 이내에 출판된 것이라는 것이 최근에 더욱 활발하고 빠르게 발전하고 있다는 것을 보여 줍니다. (이 글은 2022년 9월에 작성함)
앞으로 더 나은 모델과 더 나은 기술이 발표 될 것으로 기대합니다. 여기에서 다룬 특정 기술이 미래의 새로운 모범 사례에 의해 잊혀지더라도 그 모델들에서 제시한 일반 원칙은 다른 전문가들의 유용한 도구의 핵심 개념으로 남을 것입니다.
Bibliography
Lesson Paper Date
Break complex tasks into simpler subtasks (and consider exposing the intermediate outputs to users)
기본적으로 OpenAI Completions api 콜을 하면 Request된 Prompt에 대해 작업을 완료 한 다음 하나의 response로 답을 보내 옵니다.
davinci 모델의 경우 아주 긴 completion을 생성하게 되면 응담까지 몇초가 걸릴 수 있습니다. 2022년 8월 현재 text-davinci-002 모델의 응답시간은 일반적으로 100 completion token당 1초에서 2초 정도가 걸립니다.
이 정도도 기다리지 않고 더 빨리 응답을 받고 싶으면 Stream을 사용하실 수 있습니다.
이렇게 되면 Request된 Prompt에 대한 답을 완료하기 전에 일부분에 대한 답을 받아서 인쇄를 시작하거나 Completion 의 시작 부분을 처리할 수 있습니다.
Completions를 stream 하려면 API를 호출 할 때 stream=True를 사용하시면 됩니다. 이렇게 하면 data-only 서버가 보낸 이벤트와 같이 텍스트를 streams back 하는 object를 return 하게 됩니다. (답변의 일부분이라도 완료 되면 그 일 부분들을 계속 해서 stream으로 응답을 보내 온 다는 얘기 입니다.)
Downsides
주의 할 점은 프로덕션 어플리케이션에서 stream=True를 사용하면 completions 의 내용을 조정하기가 더 어려워 집니다.
(streaming 되는 동안 답변의 일부분만 가지고 있기 때문에 전체 답변에 대한 보정이나 처리 작업을 하는데는 한계가 있다는 얘기 입니다.)
이 Streaming response의 다른 작은 단점은 Response에 사용된 토큰 수를 알려 주는 정보가 없다는 겁니다.
해당 토큰수를 알려면 모든 응답을 결합한 후 toktoken을 사용해서 직접 계산 해야 합니다.
Example code
아래에 이 streaming completions를 어떻게 사용하는지에 대한 파이썬 예제가 있습니다.
# imports
import openai # for OpenAI API calls
import time # for measuring time savings
우선 openai를 import 합니다. 그리고 응답 시간을 알아보기 위해 time 모듈도 import 합니다.
# Example of an OpenAI Completion request
# https://beta.openai.com/docs/api-reference/completions/create
# record the time before the request is sent
start_time = time.time()
# send a Completion request to count to 100
response = openai.Completion.create(
model='text-davinci-002',
prompt='1,2,3,',
max_tokens=193,
temperature=0,
)
# calculate the time it took to receive the response
response_time = time.time() - start_time
# extract the text from the response
completion_text = response['choices'][0]['text']
# print the time delay and text received
print(f"Full response received {response_time:.2f} seconds after request")
print(f"Full text received: {completion_text}")
이 방법은 stream을 사용하지 않은 일반적인 방법입니다.
openai.Completion.create() 파라미터를 보면 stream=True 부분이 없습니다. 즉 응답받는데 streaming을 사용하지 않는 겁니다.
openai.COmpletion.create() api를 호출하기 전 시간을 start_time에 담고 호출 한 후의 시간을 response_time에 담았습니다.
response 받은 데이터 중 choices의 첫번째 아이템에 있는 text 부분만 떼어내서 completion_text 에 담습니다.
그런 다음 전체 소요 시간을 print 하고 두번째 print에서는 completion_text를 print 합니다.
저는 위 소스코드를 조금 수정해서 openaiapikey를 text 파일에서 읽어와서 인증 받는 부분을 추가했고 Completion api를 호출할 때 davinci보다 저렴한 ada 모델을 사용하는 것으로 했습니다.
응답은 2.86초 걸렸고 그 내용은 Full text received 에 있습니다.
A streaming completion request
# Example of an OpenAI Completion request, using the stream=True option
# https://beta.openai.com/docs/api-reference/completions/create
# record the time before the request is sent
start_time = time.time()
# send a Completion request to count to 100
response = openai.Completion.create(
model='text-ada-001', #model='text-davinci-002',
prompt='1,2,3,',
max_tokens=193,
temperature=0,
stream=True, # this time, we set stream=True
)
# create variables to collect the stream of events
collected_events = []
completion_text = ''
# iterate through the stream of events
for event in response:
event_time = time.time() - start_time # calculate the time delay of the event
collected_events.append(event) # save the event response
event_text = event['choices'][0]['text'] # extract the text
completion_text += event_text # append the text
print(f"Text received: {event_text} ({event_time:.2f} seconds after request)") # print the delay and text
# print the time delay and text received
print(f"Full response received {event_time:.2f} seconds after request")
print(f"Full text received: {completion_text}")
이번에는 Streaming을 사용하는 에제입니다.
openai.Completion.create() 의 파라미터를 보면 stream=True 를 추가 하신것을 보실 수 있습니다.
이것이 streaming을 사용하는 방법 입니다.
그 이후의 코드들은 이 스트리밍을 어떻게 receive 하는지 print 해주기 위해 만든 스크립트 들 입니다.
for 문이 있는데 이 for 문에서는 response 에 발생한 이벤트만큼 실행 됩니다.
이벤트가 일어날 때마다 그 이벤트 시각에서 start_time을 뺍니다. 즉 Completion api 콜 한 시점에서 그 이벤트가 일어난 시점까지의 시간을 알기 위해서 이런 계산을 합니다. 그 값은 event_time에 저장 됩니다.
그리고 collected_events에 이 이벤트를 append 합니다.
그리고 그 이벤트에서 받은 reponse에서 choices의 첫번째 아이템에 있는 text 내용을 가져 옵니다.
completion_text에는 지금까지 받은 evnet_text에 현재 받은 event_text를 추가 합니다.
그리고 for 문 안에 있는 print 문에서는 응답 내용과 그 응답을 받기 까지 얼마나 걸렸는지를 print 해 줍니다.
for 문이 완료 되면 전체 소요 시간과 전체 응답을 print 합니다.
그러면 아래와 같은 응답을 받습니다.
.......
Stream을 사용하지 않았을 때는 전체 결과 값을 받는데까지 2.86초 걸렸습니다.
그런데 이렇게 Stream을 사용하니까 응답의 시작부분을 0.35초 후부터 받기 시작해서 전체 메세지를 받는데까지 1.52초가 걸렸습니다.
이렇게 streaming 해서 받은 값들을 모두 합한 값은 위에 stream을 사용하지 않았을 때와 동일합니다.
Time comparison
쿡북의 예에서는 Davinci 모델을 사용해서 Stream을 사용하지 않은 경우는 7.32초가 걸렸고 사용한 경우는 7.25초가 걸렸습니다.
둘 다 거의 비슷하게 걸렸지만 streaming을 사용한 경우에는 0.16초가 지나면서부터 응답의 일부를 받기 시작해서 전체 응답을 받기까지 7.25초가 걸린 겁니다.
영어로 된 텍스트인 경우 토큰의 길이는 일반적으로 문자 하나이거나 단어 하나가 한개의 토큰이 됩니다. (e.g., "t" or " great")
다른 언어에서는 한문자보다 짧거나 한단어보다 길 수 있습니다.
공백은 일반적으로 단어의 시작으로 그룹화 됩니다. (e.g., " is" instead of "is " or " "+"is")
OpenAI Tokenizer를 사용해서 문자열이 어떻게 tokenized 되는지 빠르게 체크할 수 있습니다.
0. Installtiktoken
이 tiktoken을 사용하려면 먼저 이 모듈을 인스톨 해야 합니다.
pip install tiktoken
1. Importtiktoken
그러면 이 tiktoken을 import 할 수 있습니다.
import tiktoken
2. Load an encoding
tiktoken.get_encoding()을 사용해서 인코딩을 로딩 합니다. 이 때 인코딩 이름을 파라미터로 전달합니다.
처음 이 작업을 할 때는 인터넷에 연결 돼 있어야 합니다.
한번 로딩한 다음에는 인터넷이 연결 돼 있지 않아도 사용할 수 있습니다.
encoding = tiktoken.get_encoding("gpt2")
3. Turn text into tokens withencoding.encode()
.encode() 메소드는 문자열을 token integer들로 변환합니다.
위에서 tiktoken is great! 이 아래와 같은 토큰들로 나누어 진다고 했습니다.
["t", "ik", "token", " is", " great", "!"]
그렇다면 t는 83이고 ik 는 1134 이고 token 은 30001 ..... 마지막으로 ! 는 0 이 됩니다.
아래 함수는 토큰 갯수를 계산해서 반환해 주는 함수 입니다.
def num_tokens_from_string(string: str, encoding_name: str) -> int:
"""Returns the number of tokens in a text string."""
encoding = tiktoken.get_encoding(encoding_name)
num_tokens = len(encoding.encode(string))
return num_tokens
함수 이름은 num_tokens_from_string() 이고 파라미터로는 String 과 인코딩 이름이 전달 됩니다.
그리고 반환 타입은 integer 입니다.
get_encoding()을 사용해서 사용할 encoding을 정의 합니다.
그리고 len() 함수를 사용해서 인코드해서 얻은 리스트의 아이템 갯수를 num_tokens 변수에 넣습니다.
이 아이템들이 각각의 토큰들 입니다.
이 함수를 사용해서 토큰의 갯수를 아래와 같이 얻을 수 있습니다.
4. Turn tokens into text withencoding.decode()
인코딩이 있으면 디코딩도 있겠죠.
.decode()를 사용하면 숫자로 된 토큰 정보를 문자로 바꿀 수 있습니다.
Warning : .decode()는 single tokens에 적용될 수 있지만 utf-8 boundaries가 아닌 경우 토큰의 손실이 발생 할 수 있습니다.
single tokens의경우 decode_single_token_bytes() 는 단일 정수 토큰을 그것이 나타내는 바이트로 안전하게 변환합니다.
여기서 각 string 앞에 있는 b가 가리키는 것은 이 String들이 byte string들이라는 의미 입니다.
5. Comparing encodings
그렇다면 각 인코딩 별로 어떻게 입력값을 분할 해서 토큰으로 나누는지를 알아 보겠습니다.
def compare_encodings(example_string: str) -> None:
"""Prints a comparison of three string encodings."""
# print the example string
print(f'\nExample string: "{example_string}"')
# for each encoding, print the # of tokens, the token integers, and the token bytes
for encoding_name in ["gpt2", "p50k_base", "cl100k_base"]:
encoding = tiktoken.get_encoding(encoding_name)
token_integers = encoding.encode(example_string)
num_tokens = len(token_integers)
token_bytes = [encoding.decode_single_token_bytes(token) for token in token_integers]
print()
print(f"{encoding_name}: {num_tokens} tokens")
print(f"token integers: {token_integers}")
print(f"token bytes: {token_bytes}")
이 compare_encodings() 함수는 string을 입력 파라미터로 받습니다. return 값은 없고 그냥 이 함수 안에서 계산해서 그 정보를 print 해 줍니다.
첫번째 있는 print 문은 Example string : 입력 받은 문자열 을 출력합니다.
그 다음 for 문이 있는데 각 인코딩 별로 이 for 문안에 있는 작업을 해 줄 겁니다.
우선 get_encoding() 을 사용해서 사용할 encoding을 세팅해 줍니다.
그리고 encode()를 사용해서 토큰으로 나눠 줍니다. (결과값을 리스트 형식으로 반환 합니다.)
그리고 len()을 이용해서 이 리스트안에 있는 아이템 갯수들을 num_tokens에 담습니다.
그리고 decode_single_token_bytes()를 사용해서 각 바이트별 텍스트를 token_bytes에 담습니다.
그 다음 인코딩 이름과 토큰 리스트의 인티저 값 그리고 각 바이트 별 문자를 표시해 줍니다.
이렇게 한 단어인데 긴것을 넣어 봤습니다. 이것은 반체제주의라는 의미라고 합니다.
gpt2와 p50k_base는 5개의 토큰으로 나눴고 cl100k_base는 6개의 토큰으로 나눴습니다.
이 request 수 제한은 API 관리하는 일반적인 관행입니다. 이것을 관리하는 이유는 몇가지 있습니다.
* 첫번째로는 API 남용과 오용으로부터 시스템을 보호하는데 도움을 줍니다. 예를 들어 악의적인 의도를 가지고 API에 과부하를 일으키거나 서비스를 중단시키려는 의도로 API 요청을 다량 발생 시킬 수 있습니다. 이런 악의적인 공격으로 부터 OpenAI API 서비스를 보호하기 위해 Request 수 제한 정책이 필요합니다.
* 둘째로는 이 OpenAI API 자원을 다양한 사람이 공평하게 사용할 수 있도록 하는 목적이 있습니다. 한 개인이나 조직이 과도한 수의 요청을 하면 다른 소비자들의 API 서비스가 중단 될 수 있습니다. 단일 사용자가 만들 수 있는 요청 수를 제한 함으로서 이 API 서비스를 더 많은 사람들이 속도 저하 없이 API를 사용할 수 있는 기회를 더 보장할 수 있습니다.
* 세번째 마지막으로 이 요청량 제한은 OpenAI 가 인프라의 총 부하를 관리하는데 도움이 될 수 있습니다. API에 대한 요청이 급격하게 증가하면 서버에 부담을 주고 성능에 문제를 일으킬 수 있습니다. 이 요청량 베한을 설정함으로서 OpenAI는 모든 사용자에게 원활하고 일관된 경험을 유지하는데 도움을 줄 수 있습니다.
API 요청들이 너무 빨리 보내지면 아래 요청량 제한 에러가 발생합니다. OpenAI 파이썬 라이브러리를 사용한다면 그 에러 메세지는 아래와 같을 겁니다.
아래 코드는 요청량 제한을 초과하는 한 예를 보여 줍니다.
import openai # for making OpenAI API requests
# request a bunch of completions in a loop
for _ in range(100):
openai.Completion.create(
model="code-cushman-001",
prompt="def magic_function():\n\t",
max_tokens=10,
)
저는 굳이 이 코드는 실행해 보지 않겠습니다.
코드는 그냥 간단합니다. max_tokens를 10으로 설정한 다음에 Completion.create() api를 100번 요청하는 for 문 입니다.
How to avoid rate limit errors
Retrying with exponential backoff
이 요청량 제한 오류를 방지하는 쉬운 방법 중 하나는 random exponential backoff로 요청을 자동적으로 재 시도 하는 겁니다.
exponential backoff로 retry를 한다는 의미는 요청량 제한 에러에 도달했을 때 잠시 쉬었다가 실패한 요청을 다시 요청한다는 겁니다. 만약 그 요청이 또다시 실패 한다면 잠시 쉬는 시간이 좀 더 늘어나고 그 다음에 요청하는 과정을 반복하는 겁니다. 이 과정은 요청이 성공할 때까지 이루어지게 할 수도 있고 특정 시도 횟수를 지정해서 그 횟수 만큼만 실행하게 할 수도 있습니다.
이 접근법은 다음과 같은 이점이 있습니다.
* 자동재시도는 crash나 데이터 손실 없이 요청량 제한 에러를 극복할 수 있다는 의미입니다.
* Exponential backoff는 첫번째 시도를 빠르게 시도할 수 있음을 의미하며 처음 몇번의 재시도가 실패할 경우 점점 더 재시도까지의 쉬는 시간이 점점 더 길어진다는 겁니다. 그렇기 때문에 초기에 성공하면 좀 더 빠른 시간안에 에러를 복구 할 수 있습니다.
* Random jitter를 추가하면 동시에 모든 hitting으로부터 재시도를 하는데 도움을 줍니다.
Note. 실패한 요청은 여러분의 per-minute limit에 포함 되므로 계속 재시도를 해도 작동하지 않을 수 있습니다.
아래에 이 방법을 이용하는 몇가지 방법을 소개합니다.
Example #1: Using the Tenacity library
Tenacity 는 파이썬으로 작성된 아파치 2.0 라이센스 범용 retrying 라이브러리 입니다. 이것을 이용하면 거의 모든 상황에 재시도 동작을 추가하는 작업을 단순화 할 수 있습니다.
요청에 exponential backoff를 추가하려면 tenacity.retrydecorator를 사용하면 됩니다.
tenacity.wait_random_exponential 함수를 사용하여 random exponential backoff를 요청에 추가하는 방법을 아래 예제에서 보여 줍니다.
Note : Tenacity 라이브러리는 별도로 개발한 회사가 있고 그 회사가 배포한 라이브러리 입니다. OpenAI에서 그 안정성이나 보안을 보장하지는 않습니다.
import openai # for OpenAI API calls
from tenacity import (
retry,
stop_after_attempt,
wait_random_exponential,
) # for exponential backoff
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
def completion_with_backoff(**kwargs):
return openai.Completion.create(**kwargs)
completion_with_backoff(model="text-davinci-002", prompt="Once upon a time,")
@retry() 를 사용하며 wait과 stop을 지정합니다.
재시도 사이 대기시간이 1초에서 60초 사이가 되고 재시도는 6번 시도하라는 겁니다.
이것은 그 아래 함수인 Completion_with_backoff() 함수에 적용 됩니다.
Tenacity와 마찬가지로 Backoff 라이브러리는 third-party tool 입니다. OpenAI에서 그 안정성이나 보안성을 보장하지는 않습니다.
import backoff # for exponential backoff
import openai # for OpenAI API calls
@backoff.on_exception(backoff.expo, openai.error.RateLimitError)
def completions_with_backoff(**kwargs):
return openai.Completion.create(**kwargs)
completions_with_backoff(model="text-davinci-002", prompt="Once upon a time,")
이런 3rd-party 툴을 사용하지 않고 직접 backoff 로직을 구현할 수도 있습니다.
# imports
import random
import time
import openai
# define a retry decorator
def retry_with_exponential_backoff(
func,
initial_delay: float = 1,
exponential_base: float = 2,
jitter: bool = True,
max_retries: int = 10,
errors: tuple = (openai.error.RateLimitError,),
):
"""Retry a function with exponential backoff."""
def wrapper(*args, **kwargs):
# Initialize variables
num_retries = 0
delay = initial_delay
# Loop until a successful response or max_retries is hit or an exception is raised
while True:
try:
return func(*args, **kwargs)
# Retry on specified errors
except errors as e:
# Increment retries
num_retries += 1
# Check if max retries has been reached
if num_retries > max_retries:
raise Exception(
f"Maximum number of retries ({max_retries}) exceeded."
)
# Increment the delay
delay *= exponential_base * (1 + jitter * random.random())
# Sleep for the delay
time.sleep(delay)
# Raise exceptions for any errors not specified
except Exception as e:
raise e
return wrapper
@retry_with_exponential_backoff
def completions_with_backoff(**kwargs):
return openai.Completion.create(**kwargs)
completions_with_backoff(model="text-davinci-002", prompt="Once upon a time,")
이 에제를 보면 위에서 설명했던 동작인 요청하고 error가 발생하면 재시도를 정해진 횟수만큼 하고 그 재시도 사이의 지연 시간은 점차 증가해 나가는 동작을 하도록 직접 wrapper() 함수 안에 구현을 해 놨습니다.
그리고 최대 재시도 횟수와 지연시간 관련 값들은 retry_with_exponential_backoff() 함수에서 세팅을 했습니다.
그리고 위에 설명한 wrapper() 함수는 이 retry_with_exponential_backoff() 함수에 속해 있습니다.
How to maximize throughput of batch processing given rate limits
만약 여러분의 애플리케이션이 고객의 실시간 요청을 처리하는 서비스를 제공한다면 backoff and retry는 요청량 제한 에러를 피하면서 latency를 minimize할 수 있는 아주 좋은 전략입니다.
그런데 이렇게 서비스 제공 시간이 중요한게 아니라 얼마나 많은 양을 처리하느냐가 더 중요한 애플리케이션이 있을 수 있습니다. 대량의 batch data를 처리하는 것이 더 중요한 경우이죠. 이런 경우 backoff and retry 말고 여러분이 사용할 수 있는 몇가지 다른 방법이 있습니다.
Proactively adding delay between requests
만약 여러분의 앱이 요청량 제한에 걸리고 back off 하고 재시도하고 하는 상황이 계속 반복 되면서 금방 요청량 제한에 걸린다면 남아 있는 시간은 제한량 초과 메세지만 받으면서 요청을 계속 할 수 있습니다. (예를 들어 1분에 20회가 제한량인데 이 20회가 10초만에 도달하면 나머지 50초는 제한량 초과 메세지만 받게 될 것입니다.) 그러면 이 50초 동안의 요청은 낭비 되는 것이죠. 그것을 하기 위해 사용한 내 시스템의 리소스가 낭비 되는 것입니다.
이 경우 잠재적 해결책이 될 수 있는 것은 여러분의 요청량 제한을 계산하고 그 reciprocal에 맞게 지연 시간을 만드는 것입니다.
reciprocal(예: 만약 여러분의 요청량 제한이 분당 20이라면 각 request마다 지연시간을 3~6초씩 추가 해 주는 것)
이렇게 하면 요청량 제한의 상한선에 도달하지 않고 낭비되는 요청도 발생 시키지 않는 상황에 가깝게 만들 수 있습니다.
Example of adding delay to a request
# imports
import time
import openai
# Define a function that adds a delay to a Completion API call
def delayed_completion(delay_in_seconds: float = 1, **kwargs):
"""Delay a completion by a specified amount of time."""
# Sleep for the delay
time.sleep(delay_in_seconds)
# Call the Completion API and return the result
return openai.Completion.create(**kwargs)
# Calculate the delay based on your rate limit
rate_limit_per_minute = 20
delay = 60.0 / rate_limit_per_minute
delayed_completion(
delay_in_seconds=delay,
model="text-davinci-002",
prompt="Once upon a time,"
)
이 소스 코드는 위에 예시로 들었던 상황에 맞게 만든 겁니다.
요청량 제한이 분당 20이라면 delay는 60/20 즉 3초가 됩니다.
delay_completion() 함수 안데 time.sleep() 을 이 3초로 했기 때문에 이 함수를 호출할 때 마다 3초씩 기다렸다가 openai.Completion.create() api 를 사용하게 되는 겁니다.
그러면 이 1분이라는 시간에 할 수 있는 요청량을 최대한으로 사용할 수 있게 됩니다.
단 10초만에 요청량 제한에 걸려서 나머지 50초는 그냥 손 놓고 있는 상황을 피할 수 있게 되는 거죠.
Batching requests
OpenAI api에는 분당 요청량 제한 이외에 분당 요청 토큰에 대한 별도의 제한이 있습니다.
만약 여러분이 분당 요청량 제한에 도달했지만 분당 토큰에 여유가 있는 경우 각 요청에 여러 작업을 batch 함으로서 throughput(처리량)을 증가시킬 수 있습니다.
프롬프트들의 batch를 보내는 방법은 일반적인 API 콜과 동일하게 작동합니다.
단지 프롬프트 파라미터가 Single string이 아니라 String 의 List라는 것만 다릅니다.
Warning: Response 는 그 prompt 의 순서대로 반환을 하지 않을 수 있습니다. 그렇기 때문에 index 필드를 사용하여 그 response를 prompt 의 파라미터 순서와 맞게 일치시키는 작업을 반드시 해야 합니다.
Example without batching
import openai # for making OpenAI API requests
num_stories = 10
prompt = "Once upon a time,"
# serial example, with one story completion per request
for _ in range(num_stories):
response = openai.Completion.create(
model="curie",
prompt=prompt,
max_tokens=20,
)
# print story
print(prompt + response.choices[0].text)
Example with batching
import openai # for making OpenAI API requests
num_stories = 10
prompts = ["Once upon a time,"] * num_stories
# batched example, with 10 stories completions per request
response = openai.Completion.create(
model="curie",
prompt=prompts,
max_tokens=20,
)
# match completions to prompts by index
stories = [""] * len(prompts)
for choice in response.choices:
stories[choice.index] = prompts[choice.index] + choice.text
# print stories
for story in stories:
print(story)
위의 예제는 prompt 'once upon a time' 단일 파라미터로 하는 openai.Completion.create() 호출을 for 문을 통해서 10번 일으켰습니다.
즉 10번 요청을 한 것입니다.
그런데 두번째 예제는 prompt 자체를 Once upon a time이 10번 들어가 있는 리스트로 만든 다음 이 리스트를 파라미터로 전달해서 openai.Completion.create() api를 호출 했습니다.
즉 1번 요청한 것입니다.
이렇게 함으로서 요청량을 줄일 수 있게 되는 것입니다.
두번째 예제의 첫번째 for 문에서는 response를 request의 index 와 맞게 매치 시키는 작업을 하고 있습니다.
그래서 질문 + 응답 이런 식으로 stories[] 에 저장되게 했습니다.
이제 이 stories[]를 두번째 for 문처럼 print 하기만 하면 해당 질문과 그에 대한 답변 식으로 출력이 됩니다.
Example parallel processing script
대량의 API 요청을 parallel (병렬) 처리하기 위한 예제 스크립트는 아래에 있습니다.
오늘 예제는 이 모델의 최대 context 길이보다 더 긴 텍스트는 어떻게 처리를 해야 하는지를 보여 줍니다.
1. Model context length
import openai
from tenacity import retry, wait_random_exponential, stop_after_attempt, retry_if_not_exception_type
EMBEDDING_MODEL = 'text-embedding-ada-002'
EMBEDDING_CTX_LENGTH = 8191
EMBEDDING_ENCODING = 'cl100k_base'
# let's make sure to not retry on an invalid request, because that is what we want to demonstrate
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6), retry=retry_if_not_exception_type(openai.InvalidRequestError))
def get_embedding(text_or_tokens, model=EMBEDDING_MODEL):
return openai.Embedding.create(input=text_or_tokens, model=model)["data"][0]["embedding"]
가장 먼저 openai를 import 하고 그 다음에 tenacity 모듈을 import 합니다.
tenacity는 런타임 중 오류가 발생해서 종료가 될 때 이 종료하는 것을 막고 다시 retry 하고자 할 때 사용하는 파이썬 모듈입니다.
이 모듈 중에서 retry, wait_random_exponential, Stop_after_attempt, retry_if_not_exception_type 만 import 합니다.
(이렇게 하면 @tenacity.retry 라고 하지 않고 간단하게 @retry 형식으로 사용할 수 있습니다.)
그 다음은 openai 모델을 설정하고 context length 를 8191 로 지정하고 encoding은 cl100k_base 로 합니다.
cl100k_base 는 tokenizer로 Max Input Token은 8191 로 정해져 있습니다. 2021년 9월에 발표 됐습니다.
자세한 내용은 OpenAI Guide의 Embeddings Overview 페이지를 참조하세요.
그 다음 은 @retry 구문이 나옵니다. retry 사이에 기다리는 시간은 1~20초이고 6번 까지 시도하고 exception type이 InvalidRequestError 가 아닌 경우만 retry를 시도합니다. InvalidRequest인 경우는 Retry를 해도 아무 소용 없으니까요.
그 다음은 get_embedding() 함수를 만들었습니다.
입력 파라미터로는 text_or_tokens와 모델 이름을 받습니다.
그리고 이 입력값에 대한 embedding 값을 전달받은 모델을 사용해서 openai.Embedding.create() api로 부터 받고 그 값을 return 합니다.
여기서 크기는 토큰으로 정해지기 때문에 먼저 입력값이 몇개의 토큰으로 이루어져 있는지 알아봐야 합니다.
위 Tokenizer 페이지에서 그 작업을 했었죠. 10001 이었습니다. 그리고 위에서 사용한 모델은 8191 개의 토큰이 입력 허용 최대값이구요.
아래 방법이 이렇게 입력값을 토큰화 해서 자르는 부분입니다.
import tiktoken
def truncate_text_tokens(text, encoding_name=EMBEDDING_ENCODING, max_tokens=EMBEDDING_CTX_LENGTH):
"""Truncate a string to have `max_tokens` according to the given encoding."""
encoding = tiktoken.get_encoding(encoding_name)
return encoding.encode(text)[:max_tokens]
from itertools import islice
def batched(iterable, n):
"""Batch data into tuples of length n. The last batch may be shorter."""
# batched('ABCDEFG', 3) --> ABC DEF G
if n < 1:
raise ValueError('n must be at least one')
it = iter(iterable)
while (batch := tuple(islice(it, n))):
yield batch
우선 itertools 의 islice 함수를 import 합니다.
그리고 batched() 함수를 만들고 입력값으로는 iterable과 n을 받습니다.
그 다음 입력 받은 데이터를 길이가 n인 tuple로 batch 처리 합니다. 마지막 batch는 길이가 n 보다 작을 수 있습니다.
{"text": " Morada Limited is a textile company based in Altham Lancashire. Morada specializes in curtains.", "category": "Company"} {"text": " The Armenian Mirror-Spectator is a newspaper published by the Baikar Association in Watertown Massachusetts.", "category": "WrittenWork"}
text 와 category 두 항목이 있습니다.
text는 한 문장이 있고 category에는 말 그대로 카테고리들이 있습니다.
어떤 카테고리들이 있고 각 카테고리는 몇개씩 있는지 알아 보겠습니다.
여기서는 pandas 모듈을 사용합니다.
read_json()을 사용해서 데이터세트를 읽어 옵니다. (samples)
그리고 이 데이터세트의 category를 수집해서 unique 한 리스트를 만든 후 정렬을 합니다. (categories)
print("Categories of DBpedia samples:", samples["category"].value_counts())
이것을 위 방식으로 프린트를 하면 이런 결과를 얻습니다.
카테고리는 총 14개가 있고 그 중에 가장 많이 있는 카테고리는 Artist 로 21번 나옵니다.
그 외에 다른 카테고리들과 각 카테고리별 갯수를 표시합니다.
그리고 samples.head() 를 하면 아래 결과를 얻습니다.
text와 category를 표 형식으로 보여 줍니다. head()를 사용하면 디폴트로 상위 5줄을 print 합니다.
그 다음은 openai api를 이용해서 각 text별로 임베딩 값을 받아 옵니다.
import openai
from openai.embeddings_utils import get_embeddings
def open_file(filepath):
with open(filepath, 'r', encoding='utf-8') as infile:
return infile.read()
openai.api_key = open_file('openaiapikey.txt')
# NOTE: The following code will send a query of batch size 200 to /embeddings
matrix = get_embeddings(samples["text"].to_list(), engine="text-embedding-ada-002")
embeddings_utils 의 get_embeddings를 사용해서 각 text 별로 openai로 부터 임베딩 값을 받아 옵니다.
Note : openai api는 유료입니다. 200개의 데이터에 대한 임베딩값을 받아오는데 대한 과금이 붙습니다.