<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>PKGPL</title><description>Pukyong Geophysical Prospecting Laboratory</description><link>https://pkgpl.org/</link><language>ko-KR</language><item><title>OpenAI Assistant로 함수 호출하기</title><link>https://pkgpl.org/2023/12/08/openai-assistant%eb%a1%9c-%ed%95%a8%ec%88%98-%ed%98%b8%ec%b6%9c%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/12/08/openai-assistant%eb%a1%9c-%ed%95%a8%ec%88%98-%ed%98%b8%ec%b6%9c%ed%95%98%ea%b8%b0/</guid><pubDate>Fri, 08 Dec 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant의 함수 호출 (function call) 기능은 사용자가 정의한 함수를 Assistant가 사용할 수 있도록 해주는 기능입니다. Assistant가 직접 함수를 호출하는 것은 아니고, 사용자가 함수 사용법을 알려주면 Assistant가 필요할 때 함수를 호출해달라고 사용자에게 요청합니다. 사용자가 요청대로 함수를 호출하고 그 결과를 Assistant에게 전달해주면, 그 결과를 바탕으로 Assistant가 응답을 생성합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번에는 Assistant에게 현재 유가를 원화로 알려달라고 해보겠습니다. Assistant가 질문에 답할 수 있도록 현재 석유 가격을 달러로 알려주는 함수와 현재 원/달러 환율을 알려주는 함수를 준비했습니다. 11월에 업데이트된 API에서 Assistant는 한 번에 여러 개의 함수를 호출할 수 있게 되었는데, 한 번에 두 함수를 호출해 답하는지 확인해보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;함수, 함수 설명 준비&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;현재 석유 가격을 반환하는 함수와 현재 원/달러 환율을 알려주는 함수는 BeautifulSoup을 이용한 Web Scraping으로 구현했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from bs4 import BeautifulSoup&lt;br&gt;import requests&lt;br&gt;&lt;br&gt;def &lt;strong&gt;oil_price&lt;/strong&gt;():&lt;br&gt;  url = &quot;https://www.knoc.co.kr/&quot;&lt;br&gt;  r = requests.get(url)&lt;br&gt;  soup = BeautifulSoup(r.text, &apos;html.parser&apos;)&lt;br&gt;  price=[]&lt;br&gt;  for tag in soup.find_all(&quot;dl&quot;,class_=&quot;money_list&quot;)[3:]:&lt;br&gt;    price.append(tag.find(&apos;li&apos;).text)&lt;br&gt;  return {&quot;Dubai&quot;:price[0], &quot;WTI&quot;:price[1], &quot;Brent&quot;:price[2]}&lt;br&gt;&lt;br&gt;def &lt;strong&gt;usd_krw&lt;/strong&gt;():&lt;br&gt;  url = &quot;https://finance.naver.com/marketindex/&quot;&lt;br&gt;  r = requests.get(url)&lt;br&gt;  soup = BeautifulSoup(r.text, &apos;html.parser&apos;)&lt;br&gt;  usdkrw = soup.find(&quot;span&quot;,class_=&apos;value&apos;).text&lt;br&gt;  return usdkrw&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant에게 함수 사용법을 알려주기 위해 함수 설명도 준비했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;tools = [&lt;br&gt;    {&lt;br&gt;        &quot;type&quot;:&quot;function&quot;,&lt;br&gt;        &quot;function&quot;: {&lt;br&gt;            &quot;name&quot;:&quot;oil_price&quot;,&lt;br&gt;            &quot;description&quot;:&quot;Get current oil prices - Dubai, WTI, and Brent&quot;,&lt;br&gt;            &quot;parameters&quot;: {&lt;br&gt;                &quot;type&quot;:&quot;object&quot;,&lt;br&gt;                &quot;properties&quot;: {}&lt;br&gt;            },&lt;br&gt;            &quot;required&quot;: []&lt;br&gt;        }&lt;br&gt;    },&lt;br&gt;    {&lt;br&gt;        &quot;type&quot;:&quot;function&quot;,&lt;br&gt;        &quot;function&quot;: {&lt;br&gt;            &quot;name&quot;:&quot;usd_krw&quot;,&lt;br&gt;            &quot;description&quot;:&quot;Get current exchange rate from USD to KRW&quot;,&lt;br&gt;            &quot;parameters&quot;: {&lt;br&gt;                &quot;type&quot;:&quot;object&quot;,&lt;br&gt;                &quot;properties&quot;: {}&lt;br&gt;            },&lt;br&gt;            &quot;required&quot;: []&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;]&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant, 질문 준비&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from openai import OpenAI&lt;br&gt;&lt;br&gt;client = OpenAI(api_key=&quot;sk-&quot;)&lt;br&gt;&lt;br&gt;assistant = client.beta.assistants.create(&lt;br&gt;    instructions = &quot;You are an oil expert.&quot;,&lt;br&gt;    model=&quot;gpt-4-1106-preview&quot;,&lt;br&gt;    tools = tools&lt;br&gt;)&lt;br&gt;&lt;br&gt;thread = client.beta.threads.create(&lt;br&gt;  messages=[&lt;br&gt;    {&lt;br&gt;        &quot;role&quot;:&quot;user&quot;,&lt;br&gt;        &quot;content&quot;: &quot;현재 WTI 석유 가격을 원화로 알려줄래?&quot;&lt;br&gt;    }&lt;br&gt;  ]&lt;br&gt;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run 실행&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant의 응답을 얻기 위해서는 Run 객체를 이용합니다. 함수 호출을 포함하는 경우 &lt;a href=&quot;https://pkgpl.org/2023/11/08/openai-assistants-api로-대화-내용-저장하기/&quot;&gt;Assistant의 Run 상태&lt;/a&gt;는 다음과 같은 순서로 변합니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;queued&lt;/strong&gt;: 사용자의 입력을 받으면 바로 queued 상태가 됩니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;in_progress&lt;/strong&gt;: Assistant가 입력을 분석하는 상태입니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;requires_action&lt;/strong&gt;: 함수 호출이 필요하다고 판단해서 사용자에게 특정 함수를 호출해달라고 요청하는 상태입니다. 사용자는 해당 함수를 호출하고 결과를 전달해주게 됩니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;queued&lt;/strong&gt;: 함수 호출 결과를 받았습니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;in_progress&lt;/strong&gt;: 질문과 함수 호출 결과를 이용해 응답을 생성합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;completed&lt;/strong&gt;: 응답 생성이 끝났습니다. 사용자는 Thread의 Message를 가져와 응답을 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Run 객체의 실행 상태가 &lt;code&gt;queued&lt;/code&gt;, &lt;code&gt;in_progress&lt;/code&gt; 상태인 동안은 기다렸다가 다른 상태로 바뀌면 진행하도록 하는 함수를 정의하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import time&lt;br&gt;def wait_run(client, run, thread):&lt;br&gt;  while True:&lt;br&gt;    run_check = client.beta.threads.runs.retrieve(&lt;br&gt;      thread_id=thread.id,&lt;br&gt;      run_id=run.id&lt;br&gt;    )&lt;br&gt;    print(run_check.status)&lt;br&gt;    if run_check.status in [&apos;queued&apos;,&apos;in_progress&apos;]:&lt;br&gt;      time.sleep(2)&lt;br&gt;    else:&lt;br&gt;      break&lt;br&gt;  return run_check&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Run 객체를 생성하고 결과를 기다리겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run = client.beta.threads.runs.create(&lt;br&gt;  thread_id=thread.id,&lt;br&gt;  assistant_id=assistant.id&lt;br&gt;)&lt;br&gt;run_check = wait_run(client, run, thread)&lt;br&gt;run_check.status&lt;br&gt;# 결과: &lt;strong&gt;requires_action&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;함수 호출 요청&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Run 상태가 &lt;code&gt;required_action&lt;/code&gt;으로 바뀌었습니다. 사용자에게 함수를 호출해달라고 요청하는 상태입니다. 어떤 함수를 어떻게 호출해야하는지에 관한 정보는 다음과 같이 확인할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run_check.required_action.submit_tool_outputs.tool_calls&lt;br&gt;## 결과&lt;br&gt;[RequiredActionFunctionToolCall(id=&apos;call_M5haSVtL6eox816h1ibHKdTv&apos;, function=Function(arguments=&apos;{}&apos;, name=&apos;oil_price&apos;), type=&apos;function&apos;),&lt;br&gt; RequiredActionFunctionToolCall(id=&apos;call_PmZ6Fp8bh12sb7qi0jeGGZj1&apos;, function=Function(arguments=&apos;{}&apos;, name=&apos;usd_krw&apos;), type=&apos;function&apos;)]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 결과를 보면, 두 개의 &lt;code&gt;RequiredActionFunctionToolCall&lt;/code&gt; 객체로 구성된 리스트가 보입니다. 각각의 객체가 함수 호출에 관한 정보를 담고 있습니다. 두 개의 객체가 있으므로 두 개의 함수를 함께 호출해달라는 의미입니다. 각 객체는 &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;arguments&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; 정보를 가지고 있습니다. &lt;code&gt;id&lt;/code&gt;는 여러 개의 함수 호출 결과를 전달할 때 어떤 함수의 결과인지 알려주기 위함이고, &lt;code&gt;name&lt;/code&gt;과 &lt;code&gt;arguments&lt;/code&gt;는 사용자가 어떤 함수를 어떤 인자를 사용해 호출해야하는지에 관한 정보입니다. 이 정보를 이용해 함수를 호출하고 결과를 알려주면 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;함수  호출&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;tool_calls = run_check.required_action.submit_tool_outputs.tool_calls&lt;br&gt;&lt;br&gt;tool_outputs = []&lt;br&gt;for tool in tool_calls:&lt;br&gt;  func_name = tool.function.name&lt;br&gt;  kwargs = json.loads(tool.function.arguments)&lt;br&gt;  output = locals()[func_name](**kwargs)&lt;br&gt;  tool_outputs.append(&lt;br&gt;      {&lt;br&gt;          &quot;tool_call_id&quot;:tool.id,&lt;br&gt;          &quot;output&quot;:str(output)&lt;br&gt;      }&lt;br&gt;  )&lt;br&gt;&lt;br&gt;tool_outputs&lt;br&gt;## 결과 (2023-11-29)&lt;br&gt;[{&apos;tool_call_id&apos;: &apos;call_M5haSVtL6eox816h1ibHKdTv&apos;,&lt;br&gt;  &apos;output&apos;: &quot;{&apos;Dubai&apos;: &apos;82.14&apos;, &apos;WTI&apos;: &apos;76.41&apos;, &apos;Brent&apos;: &apos;81.68&apos;}&quot;},&lt;br&gt; {&apos;tool_call_id&apos;: &apos;call_PmZ6Fp8bh12sb7qi0jeGGZj1&apos;, &apos;output&apos;: &apos;1,289.00&apos;}]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;함수 호출 결과에서 석유 가격과 환율을 확인할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여기서는 &lt;code&gt;locals()&lt;/code&gt;를 이용해 함수 이름 문자열로 함수를 호출하고 결과를 &lt;code&gt;tool_outputs&lt;/code&gt;에 &lt;code&gt;id&lt;/code&gt;와 함께 문자열로 저장했습니다. 함수가 다른 모듈에 정의되어 있다면 &lt;code&gt;getattr&lt;/code&gt;을 이용할 수도 있습니다. 물론, 함수의 수가 많지 않다면 &lt;code&gt;if&lt;/code&gt; 문을 사용하는 것도 괜찮습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;함수 호출 결과 제출&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 위에서 저장한 함수 호출 결과를 다시 Assistant에게 알려주면 Assistant가 응답을 생성하게 됩니다. 함수 호출 결과를 알려주기 위해서는 &lt;code&gt;runs.submit_tool_outputs&lt;/code&gt;를 이용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run = client.beta.threads.runs.submit_tool_outputs(&lt;br&gt;  thread_id=thread.id,&lt;br&gt;  run_id=run.id,&lt;br&gt;  tool_outputs=tool_outputs&lt;br&gt;)&lt;br&gt;run_check = wait_run(client,run,thread)&lt;br&gt;run_check.status&lt;br&gt;# 결과: completed&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant의 응답&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;응답이 끝났으니 응답을 확인해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread_messages = client.beta.threads.messages.list(thread.id)&lt;br&gt;for msg in reversed(thread_messages.data):&lt;br&gt;  print(f&quot;{msg.role}: {msg.content[0].text.value}&quot;)&lt;br&gt;&lt;br&gt;## 결과&lt;br&gt;user: 현재 WTI 석유 가격을 원화로 알려줄래?&lt;br&gt;assistant: 현재 WTI 원유 가격은 배럴당 $76.41 이며, USD/KRW 환율은 1,289.00원입니다. 따라서 WTI 원유 가격을 원화로 환산하면 배럴당 약 98,436.89원입니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;76.41 x 1289 = 98,492.49로 Assistant의 응답에 약간의 오차가 있긴 하지만 가깝게 맞췄습니다. 수학 계산 함수를 추가하거나 &lt;a href=&quot;https://pkgpl.org/2023/11/19/code-interpreter를-사용하는-openai-assistant/&quot;&gt;code interpreter&lt;/a&gt;를 사용하면 더 정확한 결과를 얻을 수 있을 것입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run steps&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;어떤 과정을 거쳐서 위의 결과를 얻었는지 정확히 알고 싶다면 run steps를 확인하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run_steps = client.beta.threads.runs.steps.list(&lt;br&gt;    thread_id=thread.id,&lt;br&gt;    run_id=run.id&lt;br&gt;)&lt;br&gt;for i,run_step in enumerate(run_steps.data):&lt;br&gt;  print(i, run_step.step_details)&lt;br&gt;&lt;br&gt;## 결과&lt;br&gt;0 MessageCreationStepDetails(message_creation=MessageCreation(message_id=&apos;msg_40MzHjYXvYvpqYKf1059yrRb&apos;), type=&apos;message_creation&apos;)&lt;br&gt;1 ToolCallsStepDetails(tool_calls=[FunctionToolCall(id=&apos;call_M5haSVtL6eox816h1ibHKdTv&apos;, function=Function(arguments=&apos;{}&apos;, name=&apos;oil_price&apos;, output=&quot;{&apos;Dubai&apos;: &apos;82.14&apos;, &apos;WTI&apos;: &apos;76.41&apos;, &apos;Brent&apos;: &apos;81.68&apos;}&quot;), type=&apos;function&apos;), FunctionToolCall(id=&apos;call_PmZ6Fp8bh12sb7qi0jeGGZj1&apos;, function=Function(arguments=&apos;{}&apos;, name=&apos;usd_krw&apos;, output=&apos;1,289.00&apos;), type=&apos;function&apos;)], type=&apos;tool_calls&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 결과는 역순으로, 먼저 &lt;code&gt;oil_price&lt;/code&gt;와 &lt;code&gt;usd_krw&lt;/code&gt;두 개의 함수를 호출해서 결과를 얻었고, 그 다음 응답 메시지를 생성했다는 것을 알 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;모든 작업이 끝났다면 Thread와 Assistant를 삭제합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = client.beta.threads.delete(thread.id)&lt;br&gt;response = client.beta.assistants.delete(assistant.id)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 살펴본 &lt;a href=&quot;https://pkgpl.org/2023/11/13/openai-assistant를-이용한-retrieval/&quot;&gt;Retrieval&lt;/a&gt;, &lt;a href=&quot;https://pkgpl.org/2023/11/19/code-interpreter를-사용하는-openai-assistant/&quot;&gt;Code interpreter&lt;/a&gt;와 함께 오늘 살펴본 함수 호출 기능을 이용하면 Assistant의 능력을 다양하게 확장할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>Update된 OpenAI Whisper로 받아쓰기</title><link>https://pkgpl.org/2023/11/29/update%eb%90%9c-openai-whisper%eb%a1%9c-%eb%b0%9b%ec%95%84%ec%93%b0%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/29/update%eb%90%9c-openai-whisper%eb%a1%9c-%eb%b0%9b%ec%95%84%ec%93%b0%ea%b8%b0/</guid><pubDate>Wed, 29 Nov 2023 13:17:58 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;(&lt;a href=&quot;https://pkgpl.org/2023/11/04/openai-whisper로-받아쓰기/&quot;&gt;이전 버전의 Whisper로 작성했던 글&lt;/a&gt;을 새 버전에 맞춰 수정했습니다.)&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI에서 공개한 Whisper는 인공지능 음성 인식 프로그램입니다. Whisper 사용법을 알아봅시다. 실험을 위한 음성 파일이 필요하다면 유튜브 영상에서 음성을 mp3로 추출한 후 사용하면 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Youtube에서 mp3 추출하기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;!pip install pytube
from pytube import YouTube

video = YouTube(url)
stream = video.streams.filter(only_audio=True).first()
mp3_filename = stream.download(filename=&quot;test.mp3&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Whisper models&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Whisper는 OpenAI API를 통해 사용할 수도 있고, &lt;a href=&quot;https://github.com/openai/whisper&quot;&gt;open source&lt;/a&gt;로 공개된 프로그램을 받아서 사용할 수도 있습니다. 2023년 11월 현재 사용 가능한 모델들은 다음 표와 같습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Model&lt;/td&gt;&lt;td&gt;Parameters&lt;/td&gt;&lt;td&gt;Required VRAM&lt;/td&gt;&lt;td&gt;Relative speed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;tiny&lt;/td&gt;&lt;td&gt;39 M&lt;/td&gt;&lt;td&gt;~1 GB&lt;/td&gt;&lt;td&gt;~32x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;base&lt;/td&gt;&lt;td&gt;74 M&lt;/td&gt;&lt;td&gt;~1 GB&lt;/td&gt;&lt;td&gt;~16x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;small&lt;/td&gt;&lt;td&gt;244 M&lt;/td&gt;&lt;td&gt;~2 GB&lt;/td&gt;&lt;td&gt;~6x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;medium&lt;/td&gt;&lt;td&gt;769 M&lt;/td&gt;&lt;td&gt;~5 GB&lt;/td&gt;&lt;td&gt;~2x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;large&lt;/td&gt;&lt;td&gt;1550 M&lt;/td&gt;&lt;td&gt;~10 GB&lt;/td&gt;&lt;td&gt;1x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;Whisper models&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;VRAM은 open source 프로그램을 받아서 GPU로 실행할 때 필요한 비디오 메모리 용량을 의미합니다. 영어 전용 모델도 있는데, 여기서는 다국어 모델을 사용하겠습니다. 오류율(character error rates)을 보면 한글의 경우 5% 약간 넘게 틀린다고 하네요.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;OpenAI API 이용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저 &lt;a href=&quot;https://platform.openai.com/docs/guides/speech-to-text/supported-languages&quot;&gt;API를 이용하는 방법&lt;/a&gt;을 보겠습니다. API에서는 large 모델을 제공합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;API를 이용하면 사용료가 드는 대신, GPU가 없어도 빠르게 결과를 얻을 수 있습니다. 사용료는 음성 파일 분당 $0.006입니다(2023년 11월). 100분 분량의 음성을 받아 적어도 1000원이 안 됩니다. 직접 받아 적는 노력을 생각하면 저렴하다고 할 수 있겠죠. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;입력할 수 있는 최대 파일 크기는 25 MB, 입력 파일의 형식은 mp3, mp4, mpeg, mpga, m4a, wav, webm 형식을 지원합니다. 파일 크기가 크다면 &lt;a href=&quot;https://github.com/jiaaro/pydub&quot;&gt;pydub&lt;/a&gt; 등을 이용해 잘라서 사용하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용법은 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI(api_key = &apos;sk-&apos;)

def stt(mp3_filename, response_format=&apos;text&apos;):
  audio_file = open(mp3_filename, &apos;rb&apos;)
  return &lt;strong&gt;client.audio.transcriptions.create&lt;/strong&gt;(
      model = &quot;whisper-1&quot;, 
      file = audio_file, 
      response_format=response_format
      )

text_en = stt(mp3_filename, &apos;text&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서 response_format은 text 외에도 json, verbose_json, srt, vtt 형식을 사용할 수 있습니다. Open source 버전은 사용법이 약간 다릅니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Whisper Open Source&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Open source 버전도 간단하게 설치해서 사용할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;! pip install git+https://github.com/openai/whisper.git -q
import whisper
model = whisper.load_model(&quot;medium&quot;)
result = model.transcribe(mp3_filename)

## results
{&apos;text&apos;: &quot;...&quot;,
&apos;segments&apos;: [
{&apos;id&apos;:0, &apos;start&apos;:0.0, &apos;end&apos;:3.0&apos;, &apos;text&apos;: &quot;..&quot;, ...},
{&apos;id&apos;:1, ...}, ...
],
&apos;language&apos;: &apos;..&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과는 딕셔너리 형식으로, API와 차이가 있습니다. 받아쓰기한 글은 딕셔너리의 &lt;code&gt;text&lt;/code&gt; 항목에서 찾을 수 있고, 자동으로 파악한 입력 언어는 &lt;code&gt;language&lt;/code&gt;에서 찾을 수 있습니다. &lt;code&gt;segments&lt;/code&gt; 리스트에는 시간대별로 나눠진 텍스트가 들어 있습니다. 각 segment의 id와 시작 시간, 마치는 시간 정보도 들어있으니 srt, vtt와 같은 자막 형식이 필요하다면 &lt;code&gt;segments&lt;/code&gt; 리스트의 항목들을 이용하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI의 공식 Whisper 외에도 CPU에서 빨리 돌아가도록 개선한 &lt;a href=&quot;https://github.com/ggerganov/whisper.cpp&quot;&gt;whisper.cpp,&lt;/a&gt; &lt;a href=&quot;https://github.com/guillaumekln/faster-whisper&quot;&gt;faster-whisper&lt;/a&gt;, 문장이 아닌, 단어 단위 시간을 반환하는 &lt;a href=&quot;https://github.com/m-bain/whisperX&quot;&gt;whisperX&lt;/a&gt;, &lt;a href=&quot;https://github.com/linto-ai/whisper-timestamped&quot;&gt;whisper-timestamped&lt;/a&gt; 같은 모델도 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>Code Interpreter를 사용하는 OpenAI Assistant</title><link>https://pkgpl.org/2023/11/19/code-interpreter%eb%a5%bc-%ec%82%ac%ec%9a%a9%ed%95%98%eb%8a%94-openai-assistant/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/19/code-interpreter%eb%a5%bc-%ec%82%ac%ec%9a%a9%ed%95%98%eb%8a%94-openai-assistant/</guid><pubDate>Sun, 19 Nov 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI Assistant에서 기본으로 제공하는 도구에는 &lt;a href=&quot;https://pkgpl.org/2023/11/13/openai-assistant를-이용한-retrieval/&quot;&gt;Retrieval 도구&lt;/a&gt;와 Code Interpreter가 있습니다. 원하는 도구가 없을 때는 &lt;a href=&quot;https://pkgpl.org/2023/09/12/openai-api-function_call-사용하기/&quot;&gt;함수 호출 기능&lt;/a&gt;을 이용해 도구를 추가해줄 수도 있죠. 여기서는 Code Interpreter를 사용해 데이터를 분석해 보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;분석할 데이터&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Code Interpreter를 이용해 Titanic 자료를 분석해보겠습니다. 먼저 Titanic&lt;a aria-label=&quot;파일 열기: titanic.csv&quot; href=&quot;https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv&quot;&gt; &lt;/a&gt;데이터(&lt;a href=&quot;https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv&quot;&gt;titanic.csv&lt;/a&gt;)를 받습니다. 파일을 Code Interpreter에서 사용할 수 있도록 OpenAI 서버에 올립니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI(api_key=&quot;sk-&quot;)

my_file = &lt;strong&gt;client.files.create&lt;/strong&gt;(
    file = &lt;strong&gt;open(&quot;titanic.csv&quot;,&apos;rb&apos;)&lt;/strong&gt;,
    purpose=&apos;assistants&apos;
)
my_file

## 출력
FileObject(id=&apos;file-zS9GLj45Ff9b2daNSQLrVPSt&apos;, bytes=60302, created_at=1699803397, filename=&apos;titanic.csv&apos;, object=&apos;file&apos;, purpose=&apos;assistants&apos;, status=&apos;processed&apos;, status_details=None)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, Code Interpreter에서는 csv 파일 외에도 text, pdf, docx, pptx, xlsx, csv, jpg, png, zip 등 &lt;a href=&quot;https://platform.openai.com/docs/assistants/tools/supported-files&quot;&gt;다양한 파일을 읽을 수 있습니다&lt;/a&gt;.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Code Interpreter를 사용하는 Assistant&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음으로 Assistant를 생성하며 Code Interpreter를 Tool로 사용할 수 있도록 해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;assistant = client.beta.assistants.create(
  name=&quot;데이터 분석 전문가&quot;,
  description=&quot;당신은 데이터 분석 전문가입니다.&quot;,
  model=&quot;gpt-4-1106-preview&quot;,
  &lt;strong&gt;tools=[{&quot;type&quot;: &quot;code_interpreter&quot;}]&lt;/strong&gt;
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 Assistant에게 내릴 명령을 준비해봅시다. Thread를 생성하며 Message를 이용해 명령을 내리는데, 이 때 앞에서 올린 파일을 메시지에 첨부해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread = client.beta.threads.create(
  messages=[
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &lt;strong&gt;&quot;titanic.csv 파일에서 생존률에 영향을 미친 주요 요인 세 가지를 찾고 차트로 그려서 설명해주세요.&quot;&lt;/strong&gt;,
      &quot;file_ids&quot;: [my_file.id]
    }
  ]
)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;명령 실행&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;명령을 실행할 수 있도록 Run 객체를 만들고 응답을 기다립니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import time

def run_and_wait(client, assistant, thread):
  run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
  )
  while True:
    run_check = client.beta.threads.runs.retrieve(
      thread_id=thread.id,
      run_id=run.id
    )
    print(run_check.status)
    if run_check.status in [&apos;queued&apos;,&apos;in_progress&apos;]:
      time.sleep(2)
    else:
      break
  return run

run = run_and_wait(client, assistant, thread)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Code Interpreter는 내부적으로 여러 단계를 거쳐 최종 응답을 내놓습니다. 중간 단계들을 확인하고 싶으면 Run Steps를 확인하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run_steps = &lt;strong&gt;client.beta.threads.runs.steps.list&lt;/strong&gt;(
    thread_id=thread.id,
    run_id=run.id
)
len(run_steps.data) ## 출력: 9&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;총 9단계를 거쳐 답을 내놓았습니다. 중간 과정은 run_steps 객체 내부에 저장되어 있으니 필요하면 확인할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여기서는 Thread에 저장된 메시지들을 가져와 확인해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread_messages = client.beta.threads.messages.list(thread.id)
for i,msg in enumerate(thread_messages.data):
  print(len(msg.content))

## 출력
2
2
2
1
1
1&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과를 보면 총 6개의 메시지가 있고, 세 개의 메시지는 content가 한 개, 세 개는 content가 두 개 있습니다. 이 예제에서 content가 2인 경우는 그림을 포함하고 있는 경우입니다. 메시지를 출력해보죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Code Interpreter의 응답&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과 확인에 사용한 코드입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from IPython.display import display, Image

for i,msg in enumerate(reversed(thread_messages.data)):
  for c in msg.content:
    if c.type == &apos;text&apos;:
      print(i, c.text.value + &apos;\n&apos;)

    if c.type == &apos;image_file&apos;:
      api_response = client.files.with_raw_response.retrieve_content(c.image_file.file_id)
      if api_response.status_code == 200:
        content = api_response.content
        fimg = f&apos;image_{i}.png&apos;
        with open(fimg, &apos;wb&apos;) as f:
          f.write(content)
        img = Image(filename=fimg)
        display(img)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;0 titanic.csv 파일에서 생존률에 영향을 미친 주요 요인 세 가지를 찾고 차트로 그려서 설명해주세요.

1 먼저 `titanic.csv` 파일을 읽어서 데이터를 살펴본 다음, 타이타닉호의 생존률에 영향을 미칠 수 있는 주요 요소에 대한 가설을 세워볼 것입니다. 생존률에 영향을 줄 것으로 예상되는 요소로는 일반적으로 성별(Sex), 객실 등급(Pclass), 그리고 나이(Age)가 자주 언급됩니다. 이러한 요소들에 대한 데이터를 분석하고 해당 요소들이 생존률에 어떤 영향을 미쳤는지 시각화하여 설명드리겠습니다.

먼저 데이터를 로드하고 초기 분석을 수행해 보겠습니다.

2 데이터셋에는 여러 컬럼들이 있는데, 여기서 생존률에 영향을 미쳤을 것으로 추정되는 주요 요인인 성별(`Sex`), 객실 등급(`Pclass`), 나이(`Age`)를 중점으로 살펴보겠습니다. 생존 여부는 `Survived` 컬럼에 표시되어 있으며, 생존한 경우 1, 그렇지 않은 경우 0의 값을 가지고 있습니다.

세 가지 요인에 대해 생존률을 비교하기 위해 다음과 같은 단계로 진행하겠습니다:

1. `Sex`: 성별에 따른 생존률 비교
2. `Pclass`: 객실 등급에 따른 생존률 비교
3. `Age`: 나이 범주(어린이, 성인, 노인 등)에 따른 생존률 비교

각각의 요인 별로 생존률을 계산하고 시각화하여 차트를 그리겠습니다. 차트는 각 요인에 따른 생존자 수 및 생존률을 보여줄 것입니다.

우선 성별에 따른 생존률을 분석해 보겠습니다.&lt;/code&gt;&lt;/pre&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-1.png&quot; href=&quot;https://pkgpl.org/media/wp-727a5ec65b4e27e6.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;662&quot; src=&quot;https://pkgpl.org/media/wp-727a5ec65b4e27e6.png&quot; alt=&quot;&quot; class=&quot;wp-image-2113&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;3 성별에 따른 생존률 차트를 보면 여성의 생존률이 약 74.2%로, 남성의 생존률인 약 18.9%보다 훨씬 높다는 것을 알 수 있습니다. 이는 성별이 타이타닉호 생존률에 큰 영향을 미쳤음을 시사합니다.

그 다음으로는 객실 등급(`Pclass`)에 따른 생존률을 분석해 보겠습니다.&lt;/code&gt;&lt;/pre&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-2.png&quot; href=&quot;https://pkgpl.org/media/wp-186463e2c1b877d3.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;662&quot; src=&quot;https://pkgpl.org/media/wp-186463e2c1b877d3.png&quot; alt=&quot;&quot; class=&quot;wp-image-2114&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;4 객실 등급(`Pclass`)별 생존률 차트에 따르면 1등급 객실 승객의 생존률이 약 62.96%로 가장 높고, 2등급은 약 47.28%, 3등급은 약 24.24%로 나타나고 있습니다. 이는 객실 등급이 생존률에 중요한 요인으로 작용했음을 보여줍니다. 1등급 객실 승객이 생존 가능성이 가장 높았고, 객실 등급이 낮을수록 생존 확률이 감소하는 경향을 볼 수 있습니다.

마지막으로 나이(`Age`) 범주별 생존률을 분석해 보겠습니다. `Age` 데이터에는 결측치가 있을 수 있으므로 이를 처리한 후 나이를 어린이(0-17), 성인(18-65), 노인(65+)의 세 범주로 나누어 생존률을 비교해 보겠습니다.
&lt;/code&gt;&lt;/pre&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-3.png&quot; href=&quot;https://pkgpl.org/media/wp-ce7ab12cac82ec18.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;662&quot; src=&quot;https://pkgpl.org/media/wp-ce7ab12cac82ec18.png&quot; alt=&quot;&quot; class=&quot;wp-image-2116&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;5 나이 범주별 생존률 차트를 보면 어린이(17세 이하)의 생존률이 약 53.98%로 가장 높고, 성인(18-65세)의 생존률은 약 38.45%, 노인(65세 이상)은 12.5%로 나타나고 있습니다. 나이를 알 수 없는 승객들(Unkown)의 생존률은 약 29.38%입니다. 이는 나이도 생존에 영향을 미친 요인이라 할 수 있으며, 특히 어린이의 생존률이 높게 나타나고 있습니다.

이상의 분석 결과를 종합해보면 타이타닉호에서의 생존률에 가장 큰 영향을 미친 요인 세 가지는 성별(`Sex`), 객실 등급(`Pclass`), 그리고 나이(`Age`)라는 결론이 도출됩니다.

- **성별**: 여성의 생존률이 남성에 비해 훨씬 높으며, 이는 당시 사회적인 구조와 구명 보트에 대한 여성과 어린이 우선 정책의 영향일 것으로 보입니다.
- **객실 등급**: 1등급 객실 승객의 생존률이 가장 높고, 객실 등급이 낮아질수록 생존률이 감소하는 경향을 보여줍니다. 구명 보트에 접근하는 데 있어서 1등급 승객이 더 우선적이었기 때문일 수 있습니다.
- **나이**: 어린이의 생존률이 가장 높고, 성인과 노인 순으로 낮아짐을 보여줍니다. 이는 어린이를 보호하려는 경향과 구명 보트 배정에 어린이를 우선시한 결과로 볼 수 있습니다.

각 요인의 차트는 상기 데이터와 결론을 시각적으로 보여주며, 이러한 요인들이 생존률에 영향을 미친 방식을 직관적으로 이해하는 데 도움을 줍니다.
&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;저는 데이터에서 생존률에 영향을 미친 주요 요인 세 가지를 찾으라고 했는데, Code Interpreter는 이미 알고 있는 정보를 바탕으로 분석 결과를 보여줬네요. 데이터 분석은 잘 해서 보여줬습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant, Thread, File은 더 이상 사용하지 않으면 삭제해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = client.beta.threads.delete(thread.id)

response = client.beta.assistants.delete(assistant.id)

response = client.files.delete(my_file.id)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Code Interpreter 사용료&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Code Interpreter는 &lt;a href=&quot;https://openai.com/pricing&quot;&gt;세션당 $0.03&lt;/a&gt; 씩 과금합니다. 세션은 한 번 시작하면 한 시간동안 유효하고, 질문 횟수와는 무관합니다. 물론, 질문과 응답에 따르는 토큰 사용료는 별도입니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI Chat Completions: JSON 모드</title><link>https://pkgpl.org/2023/11/17/openai-chat-completions-json-%eb%aa%a8%eb%93%9c/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/17/openai-chat-completions-json-%eb%aa%a8%eb%93%9c/</guid><pubDate>Fri, 17 Nov 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI의 새로 업데이트 된 API에서 JSON 출력을 지원합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이전에도 &lt;a href=&quot;https://pkgpl.org/2023/09/19/chatgpt에서-json-출력하기/&quot;&gt;프롬프트 엔지니어링을 통해 GPT 모델에서 출력을 JSON 형식으로 하도록 만들 수는 있었지만&lt;/a&gt;, 항상 JSON 형식으로 출력하는 것이 보장된 것은 아니었죠. 새로운 API에서는 JSON 모드를 사용하면 항상 JSON 형식으로 출력해줍니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;JSON 모드를 사용하기 위해서는 두 가지 조건을 만족해야 합니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;API 호출시 &lt;code&gt;response_format = {&quot;type&quot;: &quot;json_object&quot;}&lt;/code&gt;을 지정해줍니다.&lt;/li&gt;



&lt;li&gt;프롬프트에서 JSON으로 출력하라고 합니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예시 코드를 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = client.chat.completions.create(
  model=&quot;gpt-4-1106-preview&quot;,
  messages=[
    {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
    {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;LangChain은 무엇을 하는 라이브러리지? &lt;strong&gt;JSON으로 답해줘&lt;/strong&gt;&quot;}
  ],
  &lt;strong&gt;response_format = {&apos;type&apos;:&quot;json_object&quot;}&lt;/strong&gt;
)
print(response.choices[0].message.content)

## 출력
{
  &quot;LangChain&quot;: {
    &quot;Description&quot;: &quot;LangChain is a library that provides a framework for building applications and systems that interact with language models. It facilitates the integration of different components necessary for creating robust language understanding and generation tasks, such as conversation agents, AI-powered assistants, and more.&quot;,
    &quot;Purpose&quot;: &quot;Facilitate the building and deployment of language-centric applications using state-of-the-art language models.&quot;,
    &quot;Key Features&quot;: [
      &quot;Modular design to plug in various language models&quot;,
      &quot;High-level abstractions for language skills&quot;,
      &quot;Support for multiple use cases including chatbots, data extraction, and content generation&quot;,
      &quot;Tools for conversation context management and multi-turn dialogue handling&quot;
    ],
    &quot;Use Cases&quot;: [
      &quot;Creating conversational agents&quot;,
      &quot;Developing AI writing assistants&quot;,
      &quot;Building systems for automated summarization&quot;,
      &quot;Generating and manipulating natural language content&quot;
    ]
  }
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain은 2022년 10월에 공개된 거대 언어 모델 라이브러리입니다. 기존 GPT 모델은 2021년 9월까지의 정보만 가지고 있었지만, 새로운 모델은 2023년 4월까지의 정보로 훈련시켰다고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 결과를 보면 JSON 형식으로 출력하는데, 키 값은 알아서 지정한 것을 볼 수 있습니다. 키를 지정하고 싶다면 다음과 같이 프롬프트에서 정해주면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = client.chat.completions.create(
  model=&quot;gpt-4-1106-preview&quot;,
  messages=[
    {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
    {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;LangChain은 무엇을 하는 라이브러리지? JSON으로 답해줘. &lt;strong&gt;JSON 키워드는 Description, Features, Usage로 해줘.&lt;/strong&gt;&quot;}
  ],
  response_format = {&apos;type&apos;:&quot;json_object&quot;}
)

## 결과

{
  &quot;Description&quot;: &quot;LangChain은 자연어 처리(NLP) 작업을 위해 디자인된 파이썬 라이브러리입니다. 이 라이브러리는 NLP 모델을 쉽게 통합하고 사용할 수 있도록 다양한 기능과 도구를 제공하여 개발자들이 복잡한 NLP 관련 프로젝트를 빠르고 효율적으로 구현할 수 있게 돕습니다.&quot;,
  &quot;Features&quot;: [
    &quot;다양한 NLP 작업을 위한 사전 구축된 모듈과 인터페이스 지원&quot;,
    &quot;간편한 사용자 정의 모델 통합 및 확장성&quot;,
    &quot;다양한 NLP 프레임워크와 라이브러리(예: Hugging Face의 Transformers, spaCy 등)와의 호환성&quot;,
    &quot;엔드-투-엔드 NLP 애플리케이션 구축을 위한 편리한 어플리케이션 프로그래밍 인터페이스(APIs)&quot;
  ],
  &quot;Usage&quot;: [
    &quot;텍스트 분류, 개체명 인식, 기계 번역 등 다양한 NLP 태스크를 손쉽게 수행&quot;,
    &quot;챗봇, 음성 인식 시스템, 감성 분석 도구 등의 NLP 기반 애플리케이션 개발&quot;,
    &quot;구문 분석, 토픽 모델링, 문서 요약 등 고급 텍스트 분석 기능 구현&quot;,
    &quot;NLP 모델들을 실험하고 최적화하기 위한 실험적 환경 제공&quot;
  ]
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;프롬프트에서 지정한 키를 사용해 JSON 출력을 만들어준 것을 볼 수 있습니다. Text가 아닌, JSON 으로 출력하게 되면 결과를 프로그래밍 언어에서 가져다 쓰기 좋기 때문에 프로그래머들에게 편리한 기능이라 할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI Assistant를 이용한 Retrieval</title><link>https://pkgpl.org/2023/11/13/openai-assistant%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-retrieval/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/13/openai-assistant%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-retrieval/</guid><pubDate>Mon, 13 Nov 2023 12:20:51 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 &lt;a href=&quot;https://pkgpl.org/2023/10/16/langchain-retrieval-augmented-generation-문서-기반-응답/&quot;&gt;LangChain을 이용한 Retrieval Augmented Generation&lt;/a&gt;을 살펴봤습니다. OpenAI의 새로운 Assistant API를 이용하면 좀 더 쉽게 Retrieval을 구현할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;구현 순서는 다음과 같습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Retrieval을 수행할 파일을 OpenAI 서버에 올리고 파일 ID를 저장합니다.&lt;/li&gt;



&lt;li&gt;Assistant를 생성합니다.&lt;/li&gt;



&lt;li&gt;Thread를 생성합니다.&lt;/li&gt;



&lt;li&gt;파일을 포함하는 Message를 생성합니다. Message에는 파일의 내용과 관련된 질문을 넣습니다.&lt;/li&gt;



&lt;li&gt;Run 객체를 만들어 실행하면 파일에서 찾은 내용을 바탕으로 한 응답을 얻을 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 때 파일은 Message에 포함시킬 수도 있지만, Assistant에 포함시킬 수도 있습니다. Message는 Thread 생성 후에 만들 수도 있고, Thread를 생성하면서 동시에 만들 수도 있습니다. 최종 응답에는 파일의 어떤 내용을 참조했는지에 대한 정보도 포함되어 있습니다. 코드를 보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;OpenAI 라이브러리&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import openai
openai.__version__
# 결과: &apos;1.2.3&apos;

from openai import OpenAI
client = OpenAI(api_key=&quot;sk-&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파일 올리기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import requests

url=&quot;https://www.gutenberg.org/cache/epub/4/pg4.txt&quot;
r = requests.get(url)

with open(&quot;GettysburgAddress.txt&quot;,&apos;w&apos;) as fo:
  fo.write(r.text)

my_file = &lt;strong&gt;client.files.create&lt;/strong&gt;(
    file = open(&quot;GettysburgAddress.txt&quot;,&apos;rb&apos;),
    purpose=&apos;assistants&apos;
)
my_file

## 결과
FileObject(id=&apos;file-UdQTPO55auQ5CEEW562Ji9er&apos;, bytes=22030, created_at=1699803306, filename=&apos;GettysburgAddress.txt&apos;, object=&apos;file&apos;, purpose=&apos;assistants&apos;, status=&apos;processed&apos;, status_details=None)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;구텐베르크 프로젝트 페이지에서 링컨의 게티스버그 연설을 받아서 파일로 저장하고 OpenAI 서버에 올렸습니다. 뒤에서 이 연설 내용에 관한 질문을 던지려고 합니다. 이 파일에는 게티스버그 연설문 앞 뒤로 프로젝트 소개, 안내와 같은 내용들도 들어 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 결과를 보면 파일 객체에 id가 있습니다. 파일 뿐 아니라 Assistant, Thread, Message, Run 객체 모두 id를 가지고 있씁니다. 앞으로 이 id를 이용해 각각의 객체들을 참조하게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant, Thread, Message 생성&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Retrieval을 위해서는 Assistant 생성시 tools에 retrieval 도구를 추가해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;assistant = &lt;strong&gt;client.beta.assistants.create&lt;/strong&gt;(
  name=&quot;연설전문가&quot;,
  description=&quot;당신은 연설 전문가입니다.&quot;,
  model=&quot;gpt-4-1106-preview&quot;,
&lt;strong&gt;  tools=[{&quot;type&quot;: &quot;retrieval&quot;}],&lt;/strong&gt;
  #file_ids=[my_file.id]
)
assistant

## 결과
Assistant(id=&apos;asst_UojnLxCEe5wfEL0IZrHW43vu&apos;, created_at=1699803311, description=&apos;당신은 연설 전문가입니다.&apos;, file_ids=[], instructions=None, metadata={}, model=&apos;gpt-4-1106-preview&apos;, name=&apos;연설전문가&apos;, object=&apos;assistant&apos;, tools=[ToolRetrieval(type=&apos;retrieval&apos;)])&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant에 파일을 추가해주고 싶을 경우 위의 주석 처리한 &lt;code&gt;file_ids&lt;/code&gt; 줄처럼 추가하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번엔 Thread를 생성하면서 Message도 추가해줬습니다. Message에 &lt;code&gt;file_ids&lt;/code&gt;를 이용해 앞에서 올린 파일을 attach 했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread = &lt;strong&gt;client.beta.threads.create&lt;/strong&gt;(
  messages=[
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;링컨의 게티스버스 연설 내용을 한 문장으로 요약해주세요.&quot;,
&lt;strong&gt;      &quot;file_ids&quot;: [my_file.id]&lt;/strong&gt;
    }
  ]
)
thread

## 결과
Thread(id=&apos;thread_U4msr0xRagC356A7ZmYJB6sJ&apos;, created_at=1699803314, metadata={}, object=&apos;thread&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant와 Thread를 만든 후 Run을 실행해 응답을 받습니다. API를 이용해 Run 객체를 생성하면 LLM 모델이 응답을 생성할 때까지 기다리지 않고 바로 Run 객체를 반환하기 때문에 status를 확인해서 응답이 나올 때가지 기다립니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import time

def run_and_wait(client, assistant, thread):
  run = &lt;strong&gt;client.beta.threads.runs.create&lt;/strong&gt;(
    thread_id=thread.id,
    assistant_id=assistant.id
  )
  while True:
    run_check = &lt;strong&gt;client.beta.threads.runs.retrieve&lt;/strong&gt;(
      thread_id=thread.id,
      run_id=run.id
    )
    print(run_check.status)
    if run_check.status in [&apos;&lt;strong&gt;queued&lt;/strong&gt;&apos;,&apos;&lt;strong&gt;in_progress&lt;/strong&gt;&apos;]:
      time.sleep(2)
    else:
      break
  return run

run_and_wait(client, assistant, thread)

## 결과
Run(id=&apos;run_FGObi8liSR7RhfodFQBFYFQ8&apos;, assistant_id=&apos;asst_UojnLxCEe5wfEL0IZrHW43vu&apos;, cancelled_at=None, completed_at=None, created_at=1699803317, expires_at=1699803917, failed_at=None, file_ids=[], instructions=None, last_error=None, metadata={}, model=&apos;gpt-4-1106-preview&apos;, object=&apos;thread.run&apos;, required_action=None, started_at=None, status=&apos;queued&apos;, thread_id=&apos;thread_U4msr0xRagC356A7ZmYJB6sJ&apos;, tools=[ToolAssistantToolsRetrieval(type=&apos;retrieval&apos;)])&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;결과 보기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;응답은 Thread의 Message를 추출해 확인할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread_messages = &lt;strong&gt;client.beta.threads.messages.list&lt;/strong&gt;(thread.id)
for msg in thread_messages.data:
  print(f&quot;{msg.role}: {msg.content[0].text.value}&quot;)

## 결과
assistant: 에이브러햄 링컨의 게티스버그 연설은 미국의 남북전쟁 중에 &quot;전사들의 희생을 기리며, 자유를 위한 그들의 헌신이 헛되지 않았음을 다짐하고, &apos;민주주의 정부가 이 땅에서 사라지지 않을 것&apos;이라는 메시지를 전달한 것입니다【9†source】.
user: 링컨의 게티스버스 연설 내용을 한 문장으로 요약해주세요.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 결과를 보면 &lt;code&gt;【9†source】&lt;/code&gt; 이런 참조 기호가 있습니다. 이건 Retrieval 도구에서 파일을 참조했다는 표시입니다. 파일의 어떤 내용을 참조했는지는 응답의 annotations에서 찾을 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;File Citation&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;응답에서 Annotations 부분에 어떤 내용이 있나 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread_messages.data[0].content[0].text.&lt;strong&gt;annotations&lt;/strong&gt;

## 결과

[&lt;strong&gt;TextAnnotationFileCitation&lt;/strong&gt;(end_index=130, file_citation=TextAnnotationFileCitationFileCitation(file_id=&apos;file-UdQTPO55auQ5CEEW562Ji9er&apos;, &lt;strong&gt;quote&lt;/strong&gt;=&apos;Four score and seven years ago, our fathers brought forth\r\nupon this continent a new nation:  conceived in liberty, and\r\ndedicated to the proposition that all men are created equal.\r\n\r\nNow we are engaged in a great civil war. . .testing whether\r\nthat nation, or any nation so conceived and so dedicated. . .\r\ncan long endure.  We are met on a great battlefield of that war.\r\n\r\nWe have come to dedicate a portion of that field as a final resting place\r\nfor those who here gave their lives that this nation might live.\r\nIt is altogether fitting and proper that we should do this.\r\n\r\nBut, in a larger sense, we cannot dedicate. . .we cannot consecrate. . .\r\nwe cannot hallow this ground.  The brave men, living and dead,\r\nwho struggled here have consecrated it, far above our poor power\r\nto add or detract.  The world will little note, nor long remember,\r\nwhat we say here, but it can never forget what they did here.\r\n\r\nIt is for us the living, rather, to be dedicated here to the unfinished\r\nwork which they who fought here have thus far so nobly advanced.\r\nIt is rather for us to be here dedicated to the great task remaining\r\nbefore us. . .that from these honored dead we take increased devotion\r\nto that cause for which they gave the last full measure of devotion. . .\r\nthat we here highly resolve that these dead shall not have died in vain. . .\r\nthat this nation, under God, shall have a new birth of freedom. . .\r\nand that government of the people. . .by the people. . .for the people. . .\r\nshall not perish from this earth&apos;), start_index=120, &lt;strong&gt;text&lt;/strong&gt;=&apos;【9†source】&apos;, type=&apos;file_citation&apos;)]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 내용을 보면 리스트 안에 TextAnnotationFileCitation 객체가 있고, text 항목에 인용 기호, quote에 인용한 내용이 있습니다. 인용 내용을 출력해봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;print(thread_messages.data[0].content[0].text.annotations[0].file_citation.quote)

## 결과

Four score and seven years ago, our fathers brought forth&amp;#13;
upon this continent a new nation:  conceived in liberty, and&amp;#13;
dedicated to the proposition that all men are created equal.&amp;#13;
&amp;#13;
Now we are engaged in a great civil war. . .testing whether&amp;#13;
that nation, or any nation so conceived and so dedicated. . .&amp;#13;
can long endure.  We are met on a great battlefield of that war.&amp;#13;
&amp;#13;
We have come to dedicate a portion of that field as a final resting place&amp;#13;
for those who here gave their lives that this nation might live.&amp;#13;
It is altogether fitting and proper that we should do this.&amp;#13;
&amp;#13;
But, in a larger sense, we cannot dedicate. . .we cannot consecrate. . .&amp;#13;
we cannot hallow this ground.  The brave men, living and dead,&amp;#13;
who struggled here have consecrated it, far above our poor power&amp;#13;
to add or detract.  The world will little note, nor long remember,&amp;#13;
what we say here, but it can never forget what they did here.&amp;#13;
&amp;#13;
It is for us the living, rather, to be dedicated here to the unfinished&amp;#13;
work which they who fought here have thus far so nobly advanced.&amp;#13;
It is rather for us to be here dedicated to the great task remaining&amp;#13;
before us. . .that from these honored dead we take increased devotion&amp;#13;
to that cause for which they gave the last full measure of devotion. . .&amp;#13;
that we here highly resolve that these dead shall not have died in vain. . .&amp;#13;
that this nation, under God, shall have a new birth of freedom. . .&amp;#13;
and that government of the people. . .by the people. . .for the people. . .&amp;#13;
shall not perish from this earth
&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;전체 문서 중에서 링컨 대통령의 연설 부분만 잘 추출해서 인용했습니다. 문서 생성시 LLM의 응답 메시지에서 위 text에 지정된 인용 기호 부분을 각주/미주 기호로 바꾸고 각주/미주 부분에 quote의 인용문을 넣으면 각주/미주를 만들 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;OpenAI RAG vs LangChain RAG&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain으로 RAG를 수행했을 때와 다른 부분을 생각해봅시다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;문서를 벡터 데이터베이스에 넣고 검색하는 부분이 없습니다. OpenAI에서 알아서 짧은 문서는 텍스트 검색을 이용해 인용해주고, 긴 문서는 임베딩 벡터를 만들어 벡터 데이터베이스에 넣었다가 벡터 검색을 이용해 찾아서 인용해줍니다. 프로그래밍이 편해진 대신 임베딩 방법, 벡터 데이터베이스 종류와 검색 방법은 선택할 수 없습니다.&lt;/li&gt;



&lt;li&gt;길이 제한에 맞춰 이전 대화와 인용문을 프롬프트에 넣는 부분이 사라졌습니다. OpenAI에서 알아서 프롬프트 길이 제한에 맞춰줍니다. 역시 프로그래밍이 편해진 대신 이전 대화 내용과 인용문을 어떻게, 얼마나 줄여서 프롬프트에 넣을 것인지는 선택할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI Assistants API로 대화 내용 저장하기</title><link>https://pkgpl.org/2023/11/08/openai-assistants-api%eb%a1%9c-%eb%8c%80%ed%99%94-%eb%82%b4%ec%9a%a9-%ec%a0%80%ec%9e%a5%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/08/openai-assistants-api%eb%a1%9c-%eb%8c%80%ed%99%94-%eb%82%b4%ec%9a%a9-%ec%a0%80%ec%9e%a5%ed%95%98%ea%b8%b0/</guid><pubDate>Wed, 08 Nov 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI에서 11월 6일 새로운 API들을 발표했는데, 그 중 Assistants API가 있었습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistants API의 Thread를 이용하면 &lt;a href=&quot;https://pkgpl.org/2023/09/22/langchain-memory/&quot;&gt;LangChain에서 Memory를 이용해 대화 내용을 저장&lt;/a&gt;했던 것처럼 대화를 저장할 수 있습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistants API의 Tools를 이용하면 &lt;a href=&quot;https://pkgpl.org/2023/10/26/langchain-tool들을-사용하는-agent/&quot;&gt;LangChain Agent처럼 도구를 사용&lt;/a&gt;할 수 있습니다. 이전에도 &lt;a href=&quot;https://pkgpl.org/2023/09/12/openai-api-function_call-사용하기/&quot;&gt;함수 호출 기능&lt;/a&gt;이 있었지만, 이번 업데이트를 통해 Code Interpreter와 Retrieval 도구도 사용할 수 있게 되었습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 글에서는 Threads를 이용한 대화 저장 방법을 살펴보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant, Thread, Message, and Run&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저 API에서 사용하는 기본 용어들을 정리하겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Assistant: 도구들을 사용할 수 있는 거대 언어 모델(GPT 모델들)입니다.&lt;/li&gt;



&lt;li&gt;Thread: Message들을 저장하는 대화입니다.&lt;/li&gt;



&lt;li&gt;Message: 대화에서 주고 받는 메시지들로, 텍스트 외에도 이미지나 파일을 포함할 수 있습니다.&lt;/li&gt;



&lt;li&gt;Run: Assistant가 Thread에 저장된 Message들을 읽고 LLM의 응답 Message를 추가하는 과정입니다.&lt;/li&gt;



&lt;li&gt;Run Step: Run을 실행할 때 단순히 LLM의 응답을 추가하는 경우도 있지만, 외부 도구들(Tools)을 사용한 후 결과를 이용해 응답하는 경우도 있습니다. 어떤 세부 단계를 거쳐 응답했는지 확인하고 싶을 때 Run Step을 이용합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run 상태&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM에 질문을 던지면 응답을 받는데 시간이 걸립니다. 그래서 Run을 실행한다고 바로 Thread에 응답이 추가되지 않습니다. Run을 실행하면 queued → in_progress → completed 과정을 거쳐 응답이 생성됩니다. 만약 사용자가 제공한 Tool을 사용할 경우에는 사용자가 실행 결과를 다시 LLM에 제공해야 합니다. 이 때 결과를 기다리는 동안 Run은 requires_action 상태가 됩니다. 정리해보면,&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;기본 응답: &lt;strong&gt;queued → in_progress → completed&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;Function calling 사용시: queued → in_progress → &lt;strong&gt;requires_action&lt;/strong&gt; → (함수 호출 결과 입력 후 다시 Run) → queued → in_progress → &lt;strong&gt;completed&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;응답 시간이 오래 걸리면: queued → in_progress → &lt;strong&gt;expired&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;응답 실패시: queued → in_progress → &lt;strong&gt;failed&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;사용자가 취소할 경우: queued → in_progress → (사용자가 취소) → cancelling → &lt;strong&gt;cancelled&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;따라서, Run 상태가 queued나 in_progress라면 응답을 얻기 위해 기다려야 합니다. 코드로 확인해보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant 만들기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI(api_key=&quot;sk-&quot;)

assistant = &lt;strong&gt;client.beta.assistants.create&lt;/strong&gt;(
  name=&quot;똑똑한 비서&quot;,
  description=&quot;당신은 똑똑한 비서입니다.&quot;,
  model=&quot;gpt-4-1106-preview&quot;
)
assistant

## 출력
Assistant(&lt;strong&gt;id&lt;/strong&gt;=&apos;asst_...&apos;, created_at=1699421567, description=&apos;당신은 똑똑한 비서입니다.&apos;, file_ids=[], instructions=None, metadata={}, model=&apos;gpt-4-1106-preview&apos;, name=&apos;똑똑한 비서&apos;, object=&apos;assistant&apos;, tools=[])&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;모델 이름이 “gpt-4-1106-preview”입니다. 아마 얼마 안 지나면 “gpt-4-turbo”로 바뀔 것입니다. API 호출 부분을 보면 beta가 들어가 있는데 이것도 얼마 안 있어 바뀌겠죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 생성한 assistant는 OpenAI의 서버에 저장되고, 고유한 id를 가지고 있습니다. 우리는 이 assistant를 id를 이용해 참조하게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Thread 만들기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread = &lt;strong&gt;client.beta.threads.create&lt;/strong&gt;(
  messages=[
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;링컨의 게티스버스 연설 내용을 한 문장으로 요약해주세요.&quot;
    }
  ]
)
thread

## 출력
Thread(&lt;strong&gt;id&lt;/strong&gt;=&apos;thread_...&apos;, created_at=1699421567, metadata={}, object=&apos;thread&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Thread를 만들면서 Message도 넣었는데, Message는 나중에 따로 추가할 수도 있습니다. Assistant와 Thread를 만들었으니 이제 Run을 실행할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run, 상태 확인&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run = &lt;strong&gt;client.beta.threads.runs.create&lt;/strong&gt;(
  thread_id=&lt;strong&gt;thread.id&lt;/strong&gt;,
  assistant_id=&lt;strong&gt;assistant.id&lt;/strong&gt;,
  #model=&quot;gpt-4-1106-preview&quot;,
  #instructions=&quot;additional instructions&quot;,
  #tools=[{&quot;type&quot;: &quot;code_interpreter&quot;}, {&quot;type&quot;: &quot;retrieval&quot;}]
)
run

## 출력
Run(&lt;strong&gt;id&lt;/strong&gt;=&apos;run_...&apos;, assistant_id=&apos;asst_...&apos;, cancelled_at=None, completed_at=None, created_at=1699421567, expires_at=1699422167, failed_at=None, file_ids=[], instructions=None, last_error=None, metadata={}, model=&apos;gpt-4-1106-preview&apos;, object=&apos;thread.run&apos;, required_action=None, started_at=None, &lt;strong&gt;status=&apos;queued&apos;&lt;/strong&gt;, thread_id=&apos;thread_...&apos;, tools=[])&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Run을 생성하면서 Thread의 id와 Assistant의 id를 입력합니다. 필요할 경우 Assistant의 model, instruction, tools를 덮어쓸 수도 있습니다. 이렇게 Run을 생성하고 바로 내용을 확인해보면 &lt;code&gt;status=&apos;queued&apos;&lt;/code&gt;라고 나오는 것을 볼 수 있습니다. 바로 Thread를 확인해보면 응답이 아직 추가되어 있지 않으므로 Run 상태가 바뀌는 것을 확인한 후에 Thread의 Message를 확인해야 합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import time

while True:
  run_check = &lt;strong&gt;client.beta.threads.runs.retrieve&lt;/strong&gt;(
    thread_id=&lt;strong&gt;thread.id&lt;/strong&gt;,
    run_id=&lt;strong&gt;run.id&lt;/strong&gt;
  )
  if run_check.status in [&apos;queued&apos;,&apos;in_progress&apos;]:
    time.sleep(2)
  else:
    break&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Run 상태가 바뀌면 위 루프가 끝납니다. 이후에 Thread의 Message를 확인합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Thread에 추가된 응답 Message 확인&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;thread_messages = &lt;strong&gt;client.beta.threads.messages.list&lt;/strong&gt;(thread.id)
for msg in thread_messages.data:
  print(f&quot;{msg.role}: {msg.content[0].text.value}&quot;)

## 출력
assistant: 링컨의 게티스버스 연설은 민주주의의 이상을 재확인하고, .....
user: 링컨의 게티스버스 연설 내용을 한 문장으로 요약해주세요.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 Assistant의 응답이 추가된 것을 확인할 수 있습니다. 이전의 대화 내용은 빼고 마지막 응답만 확인하고 싶다면 위 코드에서 list 함수 호출시 &lt;code&gt;limit=1&lt;/code&gt; 옵션을 주면 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;새로운 메시지 추가&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대화를 계속해 나가려면 Thread에 새로운 사용자 Message를 추가해주고 Run을 실행해서 Assistant Message를 확인하는 과정을 반복하면 됩니다. Thread에 새로운 Message를 추가하려면 Message를 생성하며 Thread id를 입력하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;new_message = &lt;strong&gt;client.beta.threads.messages.create&lt;/strong&gt;(
  thread_id = &lt;strong&gt;thread.id&lt;/strong&gt;,
  role=&quot;user&quot;,
  content=&quot;링컨은 어떤 사람이지?&quot;,
)
new_message

## 출력
ThreadMessage(&lt;strong&gt;id&lt;/strong&gt;=&apos;msg_...&apos;, assistant_id=None, content=[MessageContentText(text=Text(annotations=[], value=&apos;링컨은 어떤 사람이지?&apos;), type=&apos;text&apos;)], created_at=1699421965, file_ids=[], metadata={}, object=&apos;thread.message&apos;, role=&apos;user&apos;, run_id=None, thread_id=&apos;thread_...&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Run 반복&lt;/h3&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용자 Message를 추가했으니 다시 Run을 실행해서 Assistant의 응답을 Thread에 추가합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;run = client.beta.threads.runs.create(
  thread_id=thread.id,
  assistant_id=assistant.id
)
while True:
  run_check = client.beta.threads.runs.retrieve(
    thread_id=thread.id,
    run_id=run.id
  )
  run_check
  if run_check.status not in [&apos;queued&apos;,&apos;in_progress&apos;]:
    break
  else:
    time.sleep(2)

thread_messages = client.beta.threads.messages.list(thread.id)
for msg in thread_messages.data:
  print(f&quot;{msg.role}: {msg.content[0].text.value}&quot;)

## 출력
assistant: 에이브러햄 링컨(Abraham Lincoln, 1809-1865)은 ...
user: 링컨은 어떤 사람이지?
assistant: 링컨의 게티스버스 연설은 ...
user: 링컨의 게티스버스 연설 내용을 한 문장으로 요약해주세요.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, 이렇게 생성한 Assistant는 &lt;a href=&quot;https://platform.openai.com/assistants&quot;&gt;OpenAI Platform&lt;/a&gt;에서도 확인할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Assistant와 Thread 삭제&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Assistant와 Thread는 OpenAI 서버에 저장되어 있는데, 더이상 필요가 없으면 삭제해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# delete thread
response = &lt;strong&gt;client.beta.threads.delete&lt;/strong&gt;(thread.id)
print(response)

# delete assistant
response = &lt;strong&gt;client.beta.assistants.delete&lt;/strong&gt;(assistant.id)
print(response)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 외에도 다양한 함수들이 있는데 &lt;a href=&quot;https://platform.openai.com/docs/api-reference&quot;&gt;API Reference&lt;/a&gt;를 확인하면 되겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LangChain과 비교&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/22/langchain-memory/&quot;&gt;LangChain에서는 Memory를 이용해 대화 내용을 저장&lt;/a&gt;했는데, 토큰 제한을 고려하여 최근 대화 내용만 남기거나 이전 대화 내용을 요약하는 등의 방식으로 분량을 줄였습니다. OpenAI API에서는 Thread를 통해 OpenAI 서버에 대화 내용을 저장해주고 토큰 제한에 맞추는 과정도 알아서 진행해주기 때문에 대화 진행이 간편해졌습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대신 대화 내용 저장시 프로그래머가 컨트롤할 수 있는 부분은 별로 없습니다. 현재는 대화 내용을 최대한 보존하는 방식(토큰 소모가 많은 방식)인데, 앞으로 다른 방식을 사용할 수 있도록 옵션을 추가할 계획이라고 합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI 음성 합성 (Text to Speech) API 사용하기</title><link>https://pkgpl.org/2023/11/07/openai-%ec%9d%8c%ec%84%b1-%ed%95%a9%ec%84%b1-text-to-speech-api-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/07/openai-%ec%9d%8c%ec%84%b1-%ed%95%a9%ec%84%b1-text-to-speech-api-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</guid><pubDate>Tue, 07 Nov 2023 10:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI API에 음성 합성 (Text to Speech, TTS) 기능이 새로 추가되었습니다. 기존에는 음성과 관련하여 &lt;a href=&quot;https://pkgpl.org/2023/11/04/openai-whisper로-받아쓰기/&quot;&gt;음성 인식 (Speech to Text)&lt;/a&gt; 기능만 있었는데 API가 점점 다양해지고 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;TTS 모델&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용할 수 있는 모델은 다음과 같습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Model&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;td&gt;Pricing&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;tts-1&lt;/td&gt;&lt;td&gt;속도가 빠름 (실시간용)&lt;/td&gt;&lt;td&gt;$0.015 / 1K characters&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;tts-1-hd&lt;/td&gt;&lt;td&gt;고품질&lt;/td&gt;&lt;td&gt;$0.030 / 1K characters&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;&lt;a href=&quot;https://openai.com/pricing&quot;&gt;Audio models&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;TTS 목소리&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용할 수 있는 목소리는 6 종류 입니다. &lt;a href=&quot;https://platform.openai.com/docs/guides/text-to-speech&quot;&gt;OpenAI 사이트&lt;/a&gt;에 가보면 영어로 말하는 음성을 들어볼 수 있습니다. 한국말 하는 음성을 들어볼까요?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Alloy&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-a6177a972bda098d.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Echo&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-b3800746163e0378.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Fable&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-529b0f18d2ddcdca.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Onyx&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-f573ffcf8a16d3b6.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Nova&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-7ead81c2cff92071.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;Shimmer&lt;/strong&gt;&lt;/p&gt;



&lt;figure class=&quot;wp-block-audio&quot;&gt;&lt;audio controls=&quot;&quot; src=&quot;https://pkgpl.org/media/wp-9828aa7c7611e707.mp3&quot;&gt;&lt;/audio&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;약간 어색한 부분도 있긴 하지만, 무료 TTS에 비하면 확실히 좋네요.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;TTS API&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드를 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os
from openai import OpenAI

client = OpenAI(api_key=os.environ[&apos;OPENAI_API_KEY&apos;])

response = &lt;strong&gt;client.audio.speech.create&lt;/strong&gt;(
  model = &quot;tts-1&quot;,
  voice = &quot;alloy&quot;,
  input = text,
  speed = 1,
  response_format = &apos;mp3&apos;
)

response.stream_to_file(mp3_file_path)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;response_format&lt;/code&gt;은 mp3가 기본이고, opus, aac, flac 형식도 지원합니다. &lt;code&gt;speed&lt;/code&gt;는 1이 기본이고 0.25 ~ 4.0 범위의 값을 사용할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;혹시 실시간 음성 출력이 필요할 경우 &lt;a href=&quot;https://platform.openai.com/docs/guides/text-to-speech&quot;&gt;OpenAI 사이트의 도움말&lt;/a&gt;(streaming real time audio)을 참고하면 되겠습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI Whisper로 받아쓰기</title><link>https://pkgpl.org/2023/11/04/openai-whisper%eb%a1%9c-%eb%b0%9b%ec%95%84%ec%93%b0%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/11/04/openai-whisper%eb%a1%9c-%eb%b0%9b%ec%95%84%ec%93%b0%ea%b8%b0/</guid><pubDate>Sat, 04 Nov 2023 11:43:47 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;(아래 글은 이전 버전의 API와 Whisper를 이용해 작성한 글입니다. 새로운 OpenAI API와 Whisper v3를 이용한 글은 &lt;a href=&quot;https://pkgpl.org/2023/11/29/update된-openai-whisper로-받아쓰기/&quot;&gt;여기&lt;/a&gt;에 있습니다.)&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI에서 공개한 Whisper는 인공지능 음성 인식 프로그램입니다. Whisper 사용법을 알아봅시다. 실험을 위한 음성 파일이 필요하다면 유튜브 영상에서 음성을 mp3로 추출한 후 사용하면 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Youtube에서 mp3 추출하기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;!pip install pytube
from pytube import YouTube

video = YouTube(url)
stream = video.streams.filter(only_audio=True).first()
mp3_filename = stream.download(filename=&quot;test.mp3&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Whisper models&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Whisper는 OpenAI API를 통해 사용할 수도 있고, &lt;a href=&quot;https://github.com/openai/whisper&quot;&gt;open source&lt;/a&gt;로 공개된 프로그램을 받아서 사용할 수도 있습니다. 2023년 11월 현재 사용 가능한 모델들은 다음 표와 같습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Model&lt;/td&gt;&lt;td&gt;Parameters&lt;/td&gt;&lt;td&gt;Required VRAM&lt;/td&gt;&lt;td&gt;Relative speed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;tiny&lt;/td&gt;&lt;td&gt;39 M&lt;/td&gt;&lt;td&gt;~1 GB&lt;/td&gt;&lt;td&gt;~32x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;base&lt;/td&gt;&lt;td&gt;74 M&lt;/td&gt;&lt;td&gt;~1 GB&lt;/td&gt;&lt;td&gt;~16x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;small&lt;/td&gt;&lt;td&gt;244 M&lt;/td&gt;&lt;td&gt;~2 GB&lt;/td&gt;&lt;td&gt;~6x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;medium&lt;/td&gt;&lt;td&gt;769 M&lt;/td&gt;&lt;td&gt;~5 GB&lt;/td&gt;&lt;td&gt;~2x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;large&lt;/td&gt;&lt;td&gt;1550 M&lt;/td&gt;&lt;td&gt;~10 GB&lt;/td&gt;&lt;td&gt;1x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;Whisper models&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;VRAM은 open source 프로그램을 받아서 GPU로 실행할 때 필요한 비디오 메모리 용량을 의미합니다. 영어 전용 모델도 있는데, 여기서는 다국어 모델을 사용하겠습니다. 오류율(Word Error Rate)을 보면, 영어의 경우 4.2% 정도를 틀리게 받아쓰고, 한글의 경우 14.3% 정도를 틀린다고 하네요.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image.png&quot; href=&quot;https://pkgpl.org/media/wp-5e833b8840a0ac18.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;771&quot; src=&quot;https://pkgpl.org/media/wp-5e833b8840a0ac18.png&quot; alt=&quot;&quot; class=&quot;wp-image-2013&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;OpenAI API 이용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저 &lt;a href=&quot;https://platform.openai.com/docs/guides/speech-to-text/supported-languages&quot;&gt;API를 이용하는 방법&lt;/a&gt;을 보겠습니다. API에서는 large 모델을 제공합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;API를 이용하면 사용료가 드는 대신, GPU가 없어도 빠르게 결과를 얻을 수 있습니다. 사용료는 음성 파일 분당 $0.006입니다(2023년 11월). 100분 분량의 음성을 받아 적어도 1000원이 안 됩니다. 직접 받아 적는 노력을 생각하면 저렴하다고 할 수 있겠죠. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;입력할 수 있는 최대 파일 크기는 25 MB, 입력 파일의 형식은 mp3, mp4, mpeg, mpga, m4a, wav, webm 형식을 지원합니다. 파일 크기가 크다면 &lt;a href=&quot;https://github.com/jiaaro/pydub&quot;&gt;pydub&lt;/a&gt; 등을 이용해 잘라서 사용하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용법은 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import openai
openai.api_key = &apos;sk-&apos;

def stt(mp3_filename, response_format=&apos;text&apos;):
  audio_file = open(mp3_filename, &apos;rb&apos;)
  return openai.Audio.transcribe(&quot;whisper-1&quot;, audio_file, response_format=response_format)

text_en = stt(mp3_filename, &apos;text&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서 response_format은 text 외에도 json, verbose_json, srt, vtt 형식을 사용할 수 있습니다. Open source 버전은 사용법이 약간 다릅니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Whisper Open Source&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Open source 버전도 간단하게 설치해서 사용할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;! pip install git+https://github.com/openai/whisper.git -q
import whisper
model = whisper.load_model(&quot;medium&quot;)
result = model.transcribe(mp3_filename)

## results
{&apos;text&apos;: &quot;...&quot;,
&apos;segments&apos;: [
{&apos;id&apos;:0, &apos;start&apos;:0.0, &apos;end&apos;:3.0&apos;, &apos;text&apos;: &quot;..&quot;, ...},
{&apos;id&apos;:1, ...}, ...
],
&apos;language&apos;: &apos;..&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과는 딕셔너리 형식으로, API와 차이가 있습니다. 받아쓰기한 글은 딕셔너리의 &lt;code&gt;text&lt;/code&gt; 항목에서 찾을 수 있고, 자동으로 파악한 입력 언어는 &lt;code&gt;language&lt;/code&gt;에서 찾을 수 있습니다. &lt;code&gt;segments&lt;/code&gt; 리스트에는 시간대별로 나눠진 텍스트가 들어 있습니다. 각 segment의 id와 시작 시간, 마치는 시간 정보도 들어있으니 srt, vtt와 같은 자막 형식이 필요하다면 &lt;code&gt;segments&lt;/code&gt; 리스트의 항목들을 이용하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI의 공식 Whisper 외에도 CPU에서 빨리 돌아가도록 개선한 &lt;a href=&quot;https://github.com/ggerganov/whisper.cpp&quot;&gt;whisper.cpp,&lt;/a&gt; &lt;a href=&quot;https://github.com/guillaumekln/faster-whisper&quot;&gt;faster-whisper&lt;/a&gt;, 문장이 아닌, 단어 단위 시간을 반환하는 &lt;a href=&quot;https://github.com/m-bain/whisperX&quot;&gt;whisperX&lt;/a&gt;, &lt;a href=&quot;https://github.com/linto-ai/whisper-timestamped&quot;&gt;whisper-timestamped&lt;/a&gt; 같은 모델도 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Tool들을 사용하는 Agent</title><link>https://pkgpl.org/2023/10/26/langchain-tool%eb%93%a4%ec%9d%84-%ec%82%ac%ec%9a%a9%ed%95%98%eb%8a%94-agent/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/26/langchain-tool%eb%93%a4%ec%9d%84-%ec%82%ac%ec%9a%a9%ed%95%98%eb%8a%94-agent/</guid><pubDate>Thu, 26 Oct 2023 13:42:02 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;인공지능 Agent는 사용자의 요청을 받은 후 어떤 기능을 어떤 순서로 실행할지 결정하는 역할을 합니다. Agent의 주요 특징들은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;목표(정책) 기반 행동: 주어진 목표를 달성하기 위해 행동합니다.&lt;/li&gt;



&lt;li&gt;자율성: 목표가 주어지면 자동으로 작동합니다.&lt;/li&gt;



&lt;li&gt;감지: 주변 환경에서 정보를 수집합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Tools는 Agent가 할 수 있는 일에 해당합니다. 도구, 기술, 함수들이죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Agent의 작업 처리 순서도&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Agent의 처리 흐름은 다음과 같습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-image&quot;&gt;
&lt;figure class=&quot;aligncenter size-large is-resized&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-6.png&quot; href=&quot;https://pkgpl.org/media/wp-748a027e7ab021da.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;992&quot; src=&quot;https://pkgpl.org/media/wp-748a027e7ab021da.png&quot; alt=&quot;&quot; class=&quot;wp-image-1982&quot; style=&quot;width:308px;height:auto&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;


&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Input&lt;/strong&gt;: 사용자가 Agent에게 작업을 할당합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Thought&lt;/strong&gt;: Agent가 작업을 완수하기 위해 무엇을 할지 생각합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Action/Action Input&lt;/strong&gt;: 사용할 도구를 결정하고, 도구의 입력(함수의 입력값)을 결정합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Observation&lt;/strong&gt;: 도구의 출력 결과를 관찰합니다.&lt;/li&gt;



&lt;li&gt;관찰 결과 작업을 완료(&lt;strong&gt;Finish&lt;/strong&gt;)했다는 판단에 도달할 때까지 2~4번 과정을 반복합니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 과정이 Agent의 작업 수행 과정인데, LangChain에서는 이 과정을 처리하는 객체를 Agent Executor라고 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LangChain Agent의 종류&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에는 여러 종류의 Agent들이 있습니다. 몇 가지를 살펴보겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Zero-shot ReAct&lt;/strong&gt;: 작업과 도구 설명을 보고 사용할 도구를 결정합니다. ReAct는 Reasoning + Acting으로 &lt;a href=&quot;https://arxiv.org/abs/2210.03629&quot;&gt;Yao et al. (2022)의 논문&lt;/a&gt;에 소개된 개념입니다. Reasoning은 생각(Chain-of-Thought, COT), Acting은 외부 도구 실행을 의미합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Structured input ReAct&lt;/strong&gt;: input이 여러 개인 도구를 사용할 때 필요한 Agent입니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Conversational&lt;/strong&gt;: 대화 + ReAct로 대화 저장을 위한 &lt;a href=&quot;https://pkgpl.org/2023/09/22/langchain-memory/&quot;&gt;메모리&lt;/a&gt;가 필요합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Self-ask with search&lt;/strong&gt;: 인터넷 검색 후 답변하는 Agent로 검색 도구가 필요합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;ReAct document store&lt;/strong&gt;: 문서 저장소 + ReAct로 &lt;a href=&quot;https://pkgpl.org/2023/10/16/langchain-retrieval-augmented-generation-문서-기반-응답/&quot;&gt;문서 검색&lt;/a&gt; 도구가 필요합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;필요한 작업에 따라 정하면 되는데, Zero-shot ReAct가 가장 기본이 되는 Agent입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LangChain Tools&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain Tools는 Agent가 수행하는 특정 기능으로, 외부 환경에 영향을 끼쳐 Agent가 새로운 정보를 관찰할 수 있도록 합니다. 도구를 추가할 때마다 LLM에 새로운 능력을 부여하는 셈이죠. 영화 매트릭스에서 트리니티가 순식간에 헬리콥터 조종 기술을 다운받는 것처럼 LLM에게도 순식간에 새로운 능력을 가르칠 수 있습니다. LangChain에는 미리 준비된 다양한 도구들이 존재하고, 필요하면 직접 도구를 만들어 쓸 수도 있습니다. LangChain의 기본 도구들을 몇 가지 살펴보겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;일반적인 검색 도구: Google, Bing, DuckDuckGo&lt;/li&gt;



&lt;li&gt;특수 목적 검색 도구: Wolfram Alpha, Wikipedia, Youtube, Weather, News&lt;/li&gt;



&lt;li&gt;수학 계산: Math&lt;/li&gt;



&lt;li&gt;인터넷 &lt;a href=&quot;https://pkgpl.org/2023/09/05/restful-api/&quot;&gt;RestAPI&lt;/a&gt;: Requests&lt;/li&gt;



&lt;li&gt;컴퓨터: Shell, Python REPL&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 외에도 &lt;a href=&quot;https://python.langchain.com/docs/integrations/tools/&quot;&gt;여러 가지 도구들&lt;/a&gt;이 계속 추가되고 있습니다. 도구들 중에는 별도의 API 키가 필요한 도구도 있고, 무료로 사용할 수 있는 도구들도 있습니다. API 키가 필요한 도구들은 사용량에 따라 해당 서비스 제공자에게 사용료를 지불해야 할 수도 있습니다. 또한 도구들 중에는 실행을 위해 LLM이 필요한 도구도 있고 필요 없는 도구도 있습니다. LLM이 필요한 도구는 사용시 LLM을 지정해줘야 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제: Math, Wikipedia&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예제 코드를 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;!pip install langchain openai wikipedia

from langchain.chat_models import ChatOpenAI
from langchain.agents import load_tools, initialize_agent

llm = ChatOpenAI(temperature=0)
tools = load_tools([&quot;llm-math&quot;,&quot;wikipedia&quot;], llm=llm)
# llm-math 도구는 llm이 필요합니다.

agent= initialize_agent(
    tools,
    llm,
    agent=&apos;zero-shot-react-description&apos;,
    handle_parsing_errors=True,
    verbose = True)

# 수학 문제
agent(&quot;500의 20.5%는 몇인가요?&quot;)
# 결과: {&apos;input&apos;: &apos;500의 20.5%는 몇인가요?&apos;, &apos;output&apos;: &apos;102.5&apos;}

# wikipedia 검색 문제
question = &quot;광안대교 길이는 몇 km인가요?&quot;
result = agent(question)
# 결과: {&apos;input&apos;: &apos;광안대교 길이는 몇 km인가요?&apos;, &apos;output&apos;: &apos;The length of the Gwangan Bridge is 7,420 meters.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain 내부 프롬프트들이 영어로 되어 있어서 응답 결과는 기본적으로 영어로 나옵니다. Wikipedia 도구는 Wikipedia에서 검색한 페이지의 내용을 모두 가져오는게 아니라 요약 부분만 가져오기 때문에 요약 부분에 원하는 내용이 없으면 질문에 대한 답을 못 찾을 수도 있습니다. 그럴땐 Python wikipedia 라이브러리를 이용해 페이지 전체를 받아서 답을 찾는 사용자 정의 도구를 만들거나 다른 검색 도구를 사용할 수 있습니다. 다음 예제에서 DuckDuckGo 검색엔진을 사용해봅시다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제: DuckDuckGo Search&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;! pip install duckduckgo-search

tools = load_tools([&quot;ddg-search&quot;])
agent= initialize_agent(
    tools,
    llm,
    agent=&apos;zero-shot-react-description&apos;,
    handle_parsing_errors=True,
    verbose = True)

result = agent(question)
# 결과: {&apos;input&apos;: &apos;광안대교 길이는 몇 km인가요?&apos;, &apos;output&apos;: &apos;The length of the Gwangan Bridge is 7.4 kilometers.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Google이나 Bing은 API Key가 필요하지만, DuckDuckGo는 API Key 없이 사용할 수 있는 검색엔진입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제: Youtube&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번엔 인터넷 검색에 유튜브 검색까지 같이 해봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;! pip install youtube_search

from langchain.tools import YouTubeSearchTool
tools = load_tools([&quot;ddg-search&quot;]) + [YouTubeSearchTool()]

agent= initialize_agent(
    tools,
    llm,
    agent=&apos;zero-shot-react-description&apos;,
    handle_parsing_errors=True,
    verbose = True)

result = agent(&quot;이퀼리브리엄 영화에서 주인공이 저항군 아지트에서 들은 클래식 음악이 무엇인지 찾아서 유튜브 링크를 알려줘&quot;)

### &lt;strong&gt;길지만 이해를 위해 중간 과정을 살펴 봅시다.&lt;/strong&gt;
Entering new AgentExecutor chain...
- &lt;strong&gt;Thought&lt;/strong&gt;: I need to find the name of the classical music heard by the protagonist in the movie &quot;Equilibrium&quot; and provide a YouTube link.
- &lt;strong&gt;Action&lt;/strong&gt;: duckduckgo_search
- &lt;strong&gt;Action Input&lt;/strong&gt;: &quot;Equilibrium movie protagonist classical music&quot;
- &lt;strong&gt;Observation&lt;/strong&gt;: What classical music is played in the movie &apos;Equilibrium&apos;? The character of Preston listens to Ludwig van Beethoven &apos;s 9th Symphony, First Movement that he accidentally activates on the Victrola. If the audio is a recording of the actual song please check the replies to this comment to see if the bots u/RecognizeSong, u/songfinderbot and u/find-song identified it correctly :) (might take a few seconds to reply) . Please flair your post as Answered if the bots got it right, or comment to say if they listed the wrong song(s), so that people would know if help is still needed. What classical music is played in the movie &apos;Equilibrium&apos;? The character of Preston listens to Ludwig van Beethoven&apos;s 9th Symphony, First Movement that he accidentally activates on the Victrola. What classical music is played in the movie &apos;Equilibrium&apos;? The character of Preston listens to Ludwig van Beethoven&apos;s 9th Symphony, First Movement that he accidentally activates on the Victrola. Equilibrium hit theaters on Dec. 6, 2002, with a budget of $20 million. It only made $5 million back. That&apos;s despite a positive review from Roger Ebert, who praised the film&apos;s blend of ...
- &lt;strong&gt;Thought&lt;/strong&gt;:I have found the name of the classical music heard in the movie &quot;Equilibrium&quot; and it is Ludwig van Beethoven&apos;s 9th Symphony, First Movement.
- &lt;strong&gt;Action&lt;/strong&gt;: youtube_search
- &lt;strong&gt;Action Input&lt;/strong&gt;: &quot;Ludwig van Beethoven 9th Symphony First Movement,1&quot;
- &lt;strong&gt;Observation&lt;/strong&gt;: &apos;https://www.youtube.com/watch?v=VKxX2EJozxo&amp;amp;pp=ygUwTHVkd2lnIHZhbiBCZWV0aG92ZW4gOXRoIFN5bXBob255IEZpcnN0IE1vdmVtZW50&apos;
- &lt;strong&gt;Thought&lt;/strong&gt;:I now know the final answer.
- &lt;strong&gt;Final Answer&lt;/strong&gt;: The classical music heard by the protagonist in the movie &quot;Equilibrium&quot; is Ludwig van Beethoven&apos;s 9th Symphony, First Movement. You can listen to it on YouTube at this link: [https://www.youtube.com/watch?v=VKxX2EJozxo&amp;amp;pp=ygUwTHVkd2lnIHZhbiBCZWV0aG92ZW4gOXRoIFN5bXBob255IEZpcnN0IE1vdmVtZW50]
- &lt;strong&gt;Finished chain.&lt;/strong&gt;

# 최종 반환값입니다.
{&apos;input&apos;: &apos;이퀼리브리엄 영화에서 주인공이 저항군 아지트에서 들은 클래식 음악이 무엇인지 찾아서 유튜브 링크를 알려줘&apos;,
 &apos;output&apos;: &apos;The classical music heard by the protagonist in the movie &quot;Equilibrium&quot; is Ludwig van Beethoven\&apos;s 9th Symphony, First Movement. You can listen to it on YouTube at this link: [https://www.youtube.com/watch?v=VKxX2EJozxo&amp;amp;pp=ygUwTHVkd2lnIHZhbiBCZWV0aG92ZW4gOXRoIFN5bXBob255IEZpcnN0IE1vdmVtZW50]&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에 나온 순서도의 중간 과정을 두 번 반복했습니다. 먼저 DuckDuckGo 검색을 사용하고 그 결과를 이용해 두 번째에는 Youtube 검색으로 최종 결과를 얻었습니다. 만약 Youtube 링크가 주어졌을 때 영상을 틀어주는 도구를 추가한다면 바로 음악을 틀어달라고 요청할 수도 있겠죠? 이번엔 사용자 지정 도구를 만들어 봅시다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제: 사용자 도구 만들기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용자 도구는 LangChain의 &lt;code&gt;tool&lt;/code&gt; 데코레이터로 함수를 꾸며주면 됩니다. 함수 설명 문자열에 함수의 기능과 입력 인자 정보를 넣어야 Agent에서 해당 내용을 보고 어떤 도구인지, 어떻게 사용하는지 알 수 있습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/12/openai-api-function_call-사용하기/&quot;&gt;OpenAI API의 Function Call&lt;/a&gt;에서 함수와 인자의 description에 해당하는 부분이죠. LLM이 사용하는 도구이므로 함수의 입력과 출력은 모두 문자열로 해줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.agents import tool
from datetime import date

@tool
def date_today(text):
  &quot;&quot;&quot;오늘 날짜 반환, input은 &apos;&apos;&quot;&quot;&quot;
  return str(date.today())

agent= initialize_agent(
    [date_today],
    llm,
    agent=&apos;zero-shot-react-description&apos;,
    handle_parsing_errors=True,
    verbose = True)

agent(&quot;오늘 날짜는?&quot;)
{&apos;input&apos;: &apos;오늘 날짜는?&apos;, &apos;output&apos;: &apos;오늘 날짜는 2023-10-26입니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 OpenAI API의 함수 호출 기능에 비해 비교적 간단히 LLM에게 새로운 기능을 추가해줄 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Retrieval Augmented Generation 문서 기반 응답</title><link>https://pkgpl.org/2023/10/16/langchain-retrieval-augmented-generation-%eb%ac%b8%ec%84%9c-%ea%b8%b0%eb%b0%98-%ec%9d%91%eb%8b%b5/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/16/langchain-retrieval-augmented-generation-%eb%ac%b8%ec%84%9c-%ea%b8%b0%eb%b0%98-%ec%9d%91%eb%8b%b5/</guid><pubDate>Mon, 16 Oct 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/&quot;&gt;Retrieval Augmented Generation&lt;/a&gt; (RAG) 방법은 LLM에게 질문과 관련 정보를 함께 줘서 해당 정보를 바탕으로 응답하게 하는 방법입니다. LLM의 환각 현상을 줄일 수 있는 방법이자, 최신 정보나 특정 분야의 지식을 전달해줄 수 있는 방법입니다. LangChain에서 RAG를 구현하는 과정은 아래 그림과 같습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-image&quot;&gt;
&lt;figure class=&quot;aligncenter size-large is-resized&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-5.png&quot; href=&quot;https://pkgpl.org/media/wp-9037d6e5669d9069.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;569&quot; height=&quot;1024&quot; src=&quot;https://pkgpl.org/media/wp-9037d6e5669d9069.png&quot; alt=&quot;&quot; class=&quot;wp-image-1967&quot; style=&quot;width:346px;height:auto&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;


&lt;h2 class=&quot;wp-block-heading&quot;&gt;LangChain RAG 구현 과정&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;: 문서 파일을 준비합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Load&lt;/strong&gt;: &lt;a href=&quot;https://pkgpl.org/2023/10/06/langchain-document-loaders/&quot;&gt;document_loaders&lt;/a&gt; 모듈을 이용해 문서의 내용을 읽어들입니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Transform&lt;/strong&gt;: 문서가 길면 &lt;a href=&quot;https://pkgpl.org/2023/10/07/langchain-recursivecharactertextsplitter/&quot;&gt;text_splitter&lt;/a&gt; 모듈을 이용해 나눕니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Embed&lt;/strong&gt;: embeddings 모듈의 &lt;a href=&quot;https://pkgpl.org/2023/09/15/openai-임베딩과-벡터-거리/&quot;&gt;임베딩&lt;/a&gt; 모델을 이용해 텍스트를 벡터로 변환합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt;: vectorstores 모듈의 &lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;에 임베딩 벡터를 저장합니다. 벡터 데이터베이스에서는 &lt;a href=&quot;https://pkgpl.org/2023/09/15/openai-임베딩과-벡터-거리/&quot;&gt;유사도 기반 벡터 검색&lt;/a&gt; 기능도 제공합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Retrieve&lt;/strong&gt;: 질문과 가장 가까운 문서를 반환하는 인터페이스로, index나 vectorstore를 이용해 문서를 검색합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에서 index는 문서를 저장하고 검색하기 위한 데이터 구조로, 벡터 데이터베이스는 index의 일종이라고 할 수 있습니다. Index는 벡터 데이터베이스보다 더 큰 개념으로, 저장과 유사도 기반 검색 뿐 아니라 문서 관리(중복 제거, 업데이트, 삭제) 기능도 포함합니다. 위 과정을 코드로 살펴보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Retrieval Augmented Generation 예제&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 예제는 &lt;a href=&quot;https://learn.deeplearning.ai/&quot;&gt;DeepLearning.AI&lt;/a&gt;에서 가져온 예제입니다. 예제에서 사용하는 &lt;a href=&quot;https://raw.githubusercontent.com/Ryota-Kawamura/LangChain-for-LLM-Application-Development/main/OutdoorClothingCatalog_1000.csv&quot;&gt;CSV 파일&lt;/a&gt;은 1000 종류의 옷에 관한 정보를 포함한 파일입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Source, Load (Transform은 생략)&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.document_loaders import CSVLoader

loader = CSVLoader(file_path=&quot;09_OutdoorClothingCatalog_1000.csv&quot;)
docs = loader.load()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;docs&lt;/code&gt;는 1000개의 Document 객체를 포함한 리스트입니다. CSV 파일의 한 행이 하나의 문서가 되었습니다. Document 길이가 길지 않기 때문에 &lt;code&gt;text_splitter&lt;/code&gt;는 사용하지 않았습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Embed, Store&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;! pip install docarray
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import DocArrayInMemorySearch

embeddings = OpenAIEmbeddings()
db = &lt;strong&gt;DocArrayInMemorySearch&lt;/strong&gt;.from_documents(
    docs,
    embeddings
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다양한 &lt;code&gt;vectorstores&lt;/code&gt;들 중 &lt;code&gt;DocArrayInMemorySearch&lt;/code&gt;를 사용했습니다. 다른 벡터 데이터베이스를 사용하는 것도 가능합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Store (Vector Search)&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;query = &quot;한여름 산행에 좋은 여성 옷을 추천해줘. 추천 이유를 한국어로 간략하게 설명해줘.\nOutput format: &apos;name: reason&apos;&quot;

docs = db.similarity_search(query)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;docs&lt;/code&gt;는 네 개의 Document를 포함한 리스트입니다. 포함된 문서는 질문과 의미가 가장 가까운 문서들입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Retrieve&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(temperature = 0.0)
qdocs = &quot;&quot;.join([docs[i].page_content for i in range(len(docs))])
rag_prompt = f&quot;{qdocs} Question: {query}&quot;

response = llm.predict(rag_prompt)

## 출력
&quot;name: Women&apos;s Camo Mountain Fleece Vest\nreason: 한여름 산행에 좋은 여성 옷으로 추천합니다. 이 베스트는 두꺼운 300무게의 셔파 플리스로 제작되어 견고하고 따뜻한 착용감을 제공합니다. 여름에도 산행 시에는 밤에 추워질 수 있으므로 이 베스트는 완벽한 보온층이 될 것입니다. 또한, 팔 구멍과 밑단에 탄력 있는 실이 있어 편안하게 착용할 수 있으며 바람을 막아줍니다.&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 검색한 네 개의 Document 내용을 프롬프트에 넣어 LLM에 질문과 함께 전달했고, 옷을 하나 추천 받았습니다. 위의 Retrieve 과정은 &lt;strong&gt;RetrievalQA Chain&lt;/strong&gt;을 이용해 구현할 수도 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Retrieve: RetrievalQA Chain을 이용하는 방법&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chains import RetrievalQA

retriever = db.&lt;strong&gt;as_retriever&lt;/strong&gt;()

qa_stuff = &lt;strong&gt;RetrievalQA&lt;/strong&gt;.from_chain_type(
    llm=llm,
    chain_type=&quot;stuff&quot;,
    retriever=retriever,
    verbose=True
)
response = qa_stuff.run(query)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;문서 내용이 길지 않기 때문에 옵션에서 &lt;code&gt;chain_type&lt;/code&gt;을 &lt;a href=&quot;https://pkgpl.org/2023/10/10/langchain-긴-문서-다루기/&quot;&gt;stuff&lt;/a&gt;로 했습니다.네 개의 Document와 질문을 함께 전달하기 때문에 실행할 때마다 추천하는 옷이 달라질 수도 있습니다. 이러한 Retrieval Augmented Generation은 자주 사용하는 방법이기 때문에 index를 이용해 좀 더 간단하게 구현하는 방법도 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Vectorstore Index를 이용하는 방법&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;RAG 과정 중 Source와 Load (loader 선언까지) 과정은 앞과 동일합니다. 이후 Embed, Store, Retrieve는 다음과 같이 구현할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.indexes import VectorstoreIndexCreator

index = &lt;strong&gt;VectorstoreIndexCreator&lt;/strong&gt;(
    vectorstore_cls=DocArrayInMemorySearch,
    embedding=embeddings
).from_loaders([loader])

response = index.query(query)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞의 코드에 비해 많이 짧아졌죠? 중간 과정에서 별도의 처리가 필요하다면 앞의 코드를 사용해야겠지만, 그렇지 않다면 index를 사용하는 것이 편리하겠습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item><item><title>LangChain 긴 문서 다루기: Stuff, Refine, Map Reduce, Map Re-rank</title><link>https://pkgpl.org/2023/10/10/langchain-%ea%b8%b4-%eb%ac%b8%ec%84%9c-%eb%8b%a4%eb%a3%a8%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/10/langchain-%ea%b8%b4-%eb%ac%b8%ec%84%9c-%eb%8b%a4%eb%a3%a8%ea%b8%b0/</guid><pubDate>Tue, 10 Oct 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에서 &lt;a href=&quot;https://pkgpl.org/2023/10/06/langchain-document-loaders/&quot;&gt;document loader&lt;/a&gt;를 이용해 문서를 읽어들인 후 &lt;a href=&quot;https://pkgpl.org/2023/10/08/langchain-recursivecharactertextsplitter/&quot;&gt;text splitter&lt;/a&gt;를 이용해 긴 문서를 chunk들로 나누었습니다. 그 다음엔 분할한 문서들로 요약이나 질의응답(QA)과 같은 LLM 작업을 수행해야겠죠? 문서를 이용해 LLM 작업을 수행하는 방법들에 대해 알아보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Stuff&lt;/h2&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-1.png&quot; href=&quot;https://pkgpl.org/media/wp-afde74adf4eb07c4.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;128&quot; src=&quot;https://pkgpl.org/media/wp-afde74adf4eb07c4.png&quot; alt=&quot;&quot; class=&quot;wp-image-1933&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저 Stuff 방법입니다. 이 방법은 분할할 필요가 없는 짧은 문서 전체를 프롬프트에 넣어 LLM에 전달하는 방법입니다. 간단하고 API를 한 번만 호출하면 되지만, 문서 길이가 길어지면 사용할 수 없는 방법입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Refine&lt;/h2&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-2.png&quot; href=&quot;https://pkgpl.org/media/wp-cbd463885577049a.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;364&quot; src=&quot;https://pkgpl.org/media/wp-cbd463885577049a.png&quot; alt=&quot;&quot; class=&quot;wp-image-1936&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Refine 방법을 이용해 4개의 chunk로 나눠진 문서를 요약하는 과정을 생각해봅시다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;우선 1번 chunk를 요약합니다. &lt;/li&gt;



&lt;li&gt;1번 요약에 2번 chunk를 더한 내용을 요약합니다. &lt;/li&gt;



&lt;li&gt;1+2번 요약에 3번 chunk를 더한 내용을 요약합니다. &lt;/li&gt;



&lt;li&gt;1+2+3번 요약에 4번 chunk를 더한 내용을 요약합니다. 이 내용이 최종 결과가 됩니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 방법은 문서의 맥락을 유지하며 긴 문서를 요약할 수 있는 방법이지만, Stuff 방법에 비하면 API 호출 횟수가 많습니다. 또한 LLM을 순차적으로 호출해야 하므로 전체 작업 시간이 길어지게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Map Reduce&lt;/h2&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-3.png&quot; href=&quot;https://pkgpl.org/media/wp-8f461e217678854a.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;553&quot; src=&quot;https://pkgpl.org/media/wp-8f461e217678854a.png&quot; alt=&quot;&quot; class=&quot;wp-image-1938&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Map Reduce 방법을 이용해 4개의 chunk로 나눠진 문서를 요약하는 과정을 생각해봅시다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;1번부터 4번 chunk를 각각 요약합니다.&lt;/li&gt;



&lt;li&gt;4개의 요약 내용을 합해서 다시 요약합니다. 이 내용이 최종 결과가 됩니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 방법은 각 Chunk를 요약할 때 병렬로 요약할 수 있기 때문에 Refine 방법보다 빠르지만 Reduce 과정 포함하므로 API 호출 횟수가 더 많아집니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Map Re-rank&lt;/h2&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-4.png&quot; href=&quot;https://pkgpl.org/media/wp-67cb4e2b264673d3.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;526&quot; src=&quot;https://pkgpl.org/media/wp-67cb4e2b264673d3.png&quot; alt=&quot;&quot; class=&quot;wp-image-1939&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Map Re-rank 방법을 이용해 4개의 chunk로 나눈 문서에서 질문에 대한 답을 찾는 과정을 생각해봅시다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;1번부터 4번까지의 Chunk에서 각각 답을 찾습니다. 이 때 답에 대해 확신하는 정도를 점수로 나타냅니다.&lt;/li&gt;



&lt;li&gt;확신 점수가 가장 높은 답을 결과로 채택합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 방법은 Map Reduce 방법에 비하면 API 호출 횟수가 적지만, 몇 개의 Chunk에 걸쳐 답에 관한 정보가 나눠져 있을 경우 이 정보들을 조합해서 답을 찾을 수는 없습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Map Re-rank vs VectorDB&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;에서는 문서 Chunk들의 &lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;임베딩 벡터&lt;/a&gt;와 질문의 임베딩 벡터 사이의 &lt;a href=&quot;https://pkgpl.org/2023/09/15/openai-임베딩과-벡터-거리/&quot;&gt;코사인 거리&lt;/a&gt;를 이용해 질문과 의미가 가까운 내용을 찾았습니다. 이 방법도 일종의 점수를 매기는 방법이라고 할 수 있겠죠. 그럼 Map Re-rank와 벡터 임베딩을 이용하는 방법은 어떤 차이가 있을까요?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;벡터 임베딩을 이용하는 경우에는 벡터 거리를 이용하므로 글의 의미가 질문과 얼마나 가까운지만 고려합니다. 반면에, Map Re-rank 방법은 의미 뿐 아니라 글의 품질과 같은 요소도 고려할 수 있습니다. 따라서 벡터 임베딩과 함께 사용하면 벡터 임베딩 기법을 보완할 수 있는 방법이라고 할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: MarkdownHeaderTextSplitter로 마크다운 문서 나누기</title><link>https://pkgpl.org/2023/10/08/langchain-markdownheadertextsplitter/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/08/langchain-markdownheadertextsplitter/</guid><pubDate>Sun, 08 Oct 2023 11:59:12 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에서 &lt;a href=&quot;https://pkgpl.org/2023/10/06/langchain-document-loaders/&quot;&gt;Document loader&lt;/a&gt;로 읽어들인 문서의 텍스트를 적절한 길이의 chunk로 분할할 때Text splitter를 사용합니다. 지정한 문자들로 텍스트를 자르는 &lt;a href=&quot;https://pkgpl.org/2023/10/08/langchain-recursivecharactertextsplitter/&quot;&gt;RecursiveCharacterTextSplitter&lt;/a&gt;에 이어 MarkdownHeaderTextSplitter에 대해 살펴보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;MarkdownHeaderTextSplitter&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;MarkdownHeaderTextSplitter에서는 Markdown 파일에서 사용하는 #, ##, ### 등의 헤더를 기준으로 Markdown 텍스트를 분할합니다. 예제 코드를 보겠습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;간단한 마크다운 문자열이 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;md = &quot;&quot;&quot;
# Title

## Chapter 1

### Sub1
content 1-1

### Sub2
content 1-2

## Chapter 2
content 2-0

## Chapter 3

### Sub1
content 3-1

### Sub2
content 3-2
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;1단계 #, 2단계 ##, 3단계 ###까지 헤더를 사용한 문자열입니다. MarkdownHeaderTextSplitter로 분할해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.&lt;strong&gt;text_splitter&lt;/strong&gt; import &lt;strong&gt;MarkdownHeaderTextSplitter&lt;/strong&gt;

headers_to_split_on = [
    (&quot;#&quot;, &quot;Header 1&quot;),
    (&quot;##&quot;, &quot;Header 2&quot;),
    (&quot;###&quot;, &quot;Header 3&quot;)
]

markdown_splitter = &lt;strong&gt;MarkdownHeaderTextSplitter&lt;/strong&gt;(&lt;strong&gt;headers_to_split_on&lt;/strong&gt; = headers_to_split_on)
md_header_splits = markdown_splitter.&lt;strong&gt;split_text&lt;/strong&gt;(md)
md_header_splits

## 출력
[Document(page_content=&apos;content 1-1&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 1&apos;, &apos;Header 3&apos;: &apos;Sub1&apos;}),
 Document(page_content=&apos;content 1-2&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 1&apos;, &apos;Header 3&apos;: &apos;Sub2&apos;}),
 Document(page_content=&apos;content 2-0&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 2&apos;}),
 Document(page_content=&apos;content 3-1&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 3&apos;, &apos;Header 3&apos;: &apos;Sub1&apos;}),
 Document(page_content=&apos;content 3-2&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 3&apos;, &apos;Header 3&apos;: &apos;Sub2&apos;})]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 &lt;code&gt;headers_to_split_on&lt;/code&gt;을 이용해 어떤 헤더(#, ##, ###)를 기준으로 분할할지, 분할한 헤더의 이름(Header 1, Header 2, Header 3)을 무엇으로 할지 지정해줍니다. 분할한 헤더의 이름은 결과로 나온 Document 객체의 metadata에 들어갑니다. 출력 결과를 보면 지정해준 1, 2, 3단계 헤더들을 기준으로 문서를 분할한 것을 알 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번엔 2단계 헤더까지만 사용해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;headers_to_split_on = [
    (&quot;#&quot;, &quot;Header 1&quot;),
    (&quot;##&quot;, &quot;Header 2&quot;)
]

markdown_splitter = &lt;strong&gt;MarkdownHeaderTextSplitter&lt;/strong&gt;(&lt;strong&gt;headers_to_split_on&lt;/strong&gt; = headers_to_split_on)
md_header_splits = markdown_splitter.&lt;strong&gt;split_text&lt;/strong&gt;(md)
md_header_splits

## 출력
[Document(page_content=&apos;### Sub1\ncontent 1-1  \n### Sub2\ncontent 1-2&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 1&apos;}),
 Document(page_content=&apos;content 2-0&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 2&apos;}),
 Document(page_content=&apos;### Sub1\ncontent 3-1  \n### Sub2\ncontent 3-2&apos;, metadata={&apos;Header 1&apos;: &apos;Title&apos;, &apos;Header 2&apos;: &apos;Chapter 3&apos;})]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과를 보면 2단계 헤더까지만 이용해 텍스트가 나눠지고, 3단계 헤더는 page_content에 들어가 있는 것을 확인할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 봤던 &lt;a href=&quot;https://pkgpl.org/2023/10/08/langchain-recursivecharactertextsplitter/&quot;&gt;RecursiveCharacterTextSplitter&lt;/a&gt; 또는 다른 Text splitter와 달리, 길이를 기준으로 나누는 것이 아니라 헤더를 기준으로 나누기 때문에 길이가 매우 긴 Document가 나올 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;MarkdownHeaderTextSplitter와 유사한 Text splitter로 &lt;strong&gt;HTMLHeaderTextSplitter&lt;/strong&gt;가 있습니다. HTMLHeaderTextSplitter는 HTML 헤더를 이용해 HTML 파일을 분할합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: RecursiveCharacterTextSplitter로 긴 글 자르기</title><link>https://pkgpl.org/2023/10/07/langchain-recursivecharactertextsplitter/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/07/langchain-recursivecharactertextsplitter/</guid><pubDate>Sat, 07 Oct 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에서 &lt;a href=&quot;https://pkgpl.org/2023/10/06/langchain-document-loaders/&quot;&gt;Document loader&lt;/a&gt;를 이용해 문서를 읽어들인 후 문서가 길면 LLM에서 소화할 수 있도록 chunk로 분할해야 합니다. 이런 작업을 해주는 클래스들이 langchain.text_splitter 모듈에 들어 있습니다. 해당 모듈에는 다양한 클래스들이 있고, 계속 추가되고 있습니다. 몇 가지만 적어보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Text Splitter&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;CharacterTextSplitter: 특정 문자를 이용해 문자열을 나눕니다.&lt;/li&gt;



&lt;li&gt;RecursiveCharacterTextSplitter: 아래에서 자세히 살펴보겠습니다.&lt;/li&gt;



&lt;li&gt;MarkdownHeaderTextSplitter: 마크다운 파일의 헤더를 기준으로 나눕니다.&lt;/li&gt;



&lt;li&gt;HTMLHeaderTextSplitter: HTML 파일의 헤더를 기준으로 나눕니다.&lt;/li&gt;



&lt;li&gt;TokenTextSplitter: 토큰 수를 기준으로 나눕니다. OpenAI의 tiktoken을 이용합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;RecursiveCharacterTextSplitter&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;RecursiveCharacterTextSplitter&lt;/strong&gt;는 지정한 chunk_size 이하가 되도록 문자열을 자르는데, 기본적으로 &lt;code&gt;&lt;strong&gt;[&quot;\n\n&quot;, &quot;\n&quot;, &quot; &quot;, &quot;&quot;]&lt;/strong&gt;&lt;/code&gt;와 같은 문자를 이용해 자릅니다. 순서대로 가장 먼저 “\n\n”으로 자르고, 그래도 chunk_size 보다 긴 chunk는 “\n”으로 자르고, 그래도 길면 ” “로 자르는 방식으로 chunk를 만듭니다. 단순히 글자수로 자르는 것에 비해 문단, 문장, 단어 등으로 자르기 때문에 글의 의미를 보존하는데 좋은 방법이라 할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;구분 문자(separators)는 원하는 문자들의 리스트로 바꿀 수 있습니다. chunk_size를 계산하는 함수는 기본적으로 len인데, 토크나이저를 지정해서 토큰 수로 chunk_size를 계산할 수도 있습니다. 정규표현식을 이용해 나누는 것도 가능합니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예제를 살펴보겠습니다. 프로젝트 구텐베르그 사이트에서 명상록 텍스트 파일을 받아 파일로 저장했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import requests
url = &quot;https://www.gutenberg.org/cache/epub/2680/pg2680.txt&quot;
response = requests.get(url)

with open(&quot;Meditations_pg.txt&quot;,&apos;wb&apos;) as fh:
    fh.write(response.content)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음엔 &lt;a href=&quot;https://pkgpl.org/2023/10/06/langchain-document-loaders/&quot;&gt;Document loader&lt;/a&gt; 중 텍스트 파일을 읽는데 사용하는 TextLoader를 이용해 앞에서 쓴 텍스트 파일을 읽습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.&lt;strong&gt;document_loaders&lt;/strong&gt; import &lt;strong&gt;TextLoader&lt;/strong&gt;

loader = TextLoader(&quot;Meditations_pg.txt&quot;)
data = loader.load()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;data는 Document 자료형의 원소를 하나 가진 리스트입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;len(data[0].page_content) # 417445&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;길이가 길기 때문에 LLM에 그대로 입력으로 쓸 수는 없습니다. 분할해봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.&lt;strong&gt;text_splitter&lt;/strong&gt; import &lt;strong&gt;RecursiveCharacterTextSplitter&lt;/strong&gt;
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 1000,
    chunk_overlap  = 50,
    length_function = len,
    is_separator_regex = False,
)
texts = text_splitter.&lt;strong&gt;split_documents&lt;/strong&gt;(data)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;한 chunk의 길이가 1000자 이내가 되도록 나눴습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;len(texts) # 595
type(texts) # list

texts[0]
## 결과
Document(page_content=&apos;\ufeffThe Project Gutenberg eBook of Meditations\n    \nThis ebook is for the use of anyone anywhere in the United States and\nmost other parts of the world at no cost and with almost no restrictions\nwhatsoever. You may copy it, give it away or re-use it under the terms\nof the Project Gutenberg License included with this ebook or online\nat www.gutenberg.org. If you are not located in the United States,\nyou will have to check the laws of the country where you are located\nbefore using this eBook.\n\nTitle: Meditations\n\n\nAuthor: Emperor of Rome Marcus Aurelius\n\nRelease date: June 1, 2001 [eBook #2680]\n                Most recently updated: March 9, 2021\n\nLanguage: English\n\n\n\n*** START OF THE PROJECT GUTENBERG EBOOK MEDITATIONS ***\n\n\n\nMEDITATIONS\n\nBy Marcus Aurelius\n\n\n\n\nCONTENTS\n\n\n     NOTES\n\n     INTRODUCTION\n\n     FIRST BOOK\n\n     SECOND BOOK\n\n     THIRD BOOK\n\n     FOURTH BOOK\n\n     FIFTH BOOK\n\n     SIXTH BOOK\n\n     SEVENTH BOOK\n\n     EIGHTH BOOK\n\n     NINTH BOOK\n\n     TENTH BOOK&apos;, metadata={&apos;source&apos;: &apos;Meditations_pg.txt&apos;})&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 &lt;code&gt;split_documents&lt;/code&gt;를 이용하면 Document로 구성된 리스트를 분할할 수 있습니다. 문자열로 구성된 리스트를 분할하고 싶다면 &lt;code&gt;create_documents&lt;/code&gt;를, 그냥 문자열을 분할하고 싶다면 &lt;code&gt;split_text&lt;/code&gt; 메소드를 이용하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;with open(&quot;Meditations_pg.txt&quot;,&apos;r&apos;) as fh:
    txt = fh.read()
texts2 = text_splitter.&lt;strong&gt;create_documents&lt;/strong&gt;([txt])

len(texts2) # 595
type(texts2) # list

texts2[10]
## 출력
Document(page_content=&apos;from him, and he was assassinated. Marcus now went to the east, and\nwhile there the murderers brought the head of Cassius to him; but the\nemperor indignantly refused their gift, nor would he admit the men to\nhis presence.&apos;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;create_documents&lt;/code&gt;의 결과도 Document 자료형의 리스트로 나오는 것을 볼 수 있습니다. 반면에, &lt;code&gt;split_text&lt;/code&gt;를 이용해 문자열을 분할하면 그냥 문자열의 리스트가 나옵니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;texts3 = text_splitter.&lt;strong&gt;split_text&lt;/strong&gt;(txt)

len(texts3) # 595
type(texts3) # list

texts3[10]
## 출력
&apos;from him, and he was assassinated. Marcus now went to the east, and\nwhile there the murderers brought the head of Cassius to him; but the\nemperor indignantly refused their gift, nor would he admit the men to\nhis presence.&apos;&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Document Loaders로 문서 읽어들이기</title><link>https://pkgpl.org/2023/10/06/langchain-document-loaders/</link><guid isPermaLink="true">https://pkgpl.org/2023/10/06/langchain-document-loaders/</guid><pubDate>Fri, 06 Oct 2023 14:23:03 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;파일로 된 문서를 가지고 LLM으로 작업하기 위해서는 먼저 문서의 내용을 읽어들여야겠죠. 파이썬에서 직접 문서의 내용을 텍스트로 읽어서 LLM에 전달하는 것도 가능합니다. 하지만 LangChain에서 제공하는 Document loader를 이용하면 편리하게 다양한 문서를 통일된 방식으로 읽어들일 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에는 PDF, HTML, Text, Markdown, Json, CSV 파일 외에도 다양한 종류의 로컬 파일들과 클라우드 드라이브의 파일들을 읽을 수 있는 &lt;a href=&quot;https://python.langchain.com/docs/integrations/document_loaders/&quot;&gt;Document loader&lt;/a&gt;들이 있습니다. Document loader를 이용해 문서를 읽으면 Document 객체의 리스트를 반환합니다. 분할 여부에 따라 하나의 객체만 있는 리스트가 반환될 수도 있고, 페이지마다 하나씩 객체가 생성되어 여러 개의 원소를 가진 리스트가 반환될 수도 있습니다. 문서의 내용은 Document 객체의 &lt;code&gt;page_content&lt;/code&gt; 속성에 들어가고, 원본 파일, 문서 제목, 페이지 번호 등의 정보는 &lt;code&gt;metadata&lt;/code&gt; 속성에 저장됩니다. 예제를 살펴보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;HTML 문서 읽기&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import requests

url = &quot;https://www.gutenberg.org/cache/epub/2680/pg2680-images.html&quot;

response = requests.get(url)

with open(&quot;Meditations_pg.html&quot;,&apos;wb&apos;) as fh:
    fh.write(response.content)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;연습을 위해 &lt;a href=&quot;https://www.gutenberg.org&quot;&gt;프로젝트 구텐베르크 사이트&lt;/a&gt;에서 페이지를 하나 다운받아 &lt;code&gt;Meditations_pg.html&lt;/code&gt; 파일로 저장했습니다. 마르쿠스 아우렐리우스의 명상록입니다. 이 html 파일을 읽어보겠습니다. BSHTMLLoader를 이용할텐데, 이를 위해서는 BeautifulSoup4 패키지를 먼저 설치해야 합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# 설치: pip install beautifulsoup4

from langchain.&lt;strong&gt;document_loaders&lt;/strong&gt; import &lt;strong&gt;BSHTMLLoader&lt;/strong&gt;

loader = BSHTMLLoader(&quot;Meditations_pg.html&quot;)
data = loader.&lt;strong&gt;load&lt;/strong&gt;()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 data는 Document 객체가 하나 들어있는 리스트입니다. 메타데이터를 확인해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;data[0].&lt;strong&gt;metadata&lt;/strong&gt;
## 출력
{&apos;&lt;strong&gt;source&lt;/strong&gt;&apos;: &apos;Meditations_pg.html&apos;,
 &apos;&lt;strong&gt;title&lt;/strong&gt;&apos;: &apos;The Project Gutenberg eBook of Meditations, by Marcus Aurelius&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번엔 내용을 일부만 확인해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;data[0].&lt;strong&gt;page_content&lt;/strong&gt;[:1000]
## 출력
&apos;\n\nThe Project Gutenberg eBook of Meditations, by Marcus Aurelius\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nThe Project Gutenberg eBook of Meditations\nThis ebook is for the use of anyone anywhere in the United States and\nmost other parts of the world at no cost and with almost no restrictions\nwhatsoever. You may copy it, give it away or re-use it under the terms\nof the Project Gutenberg License included with this ebook or online\nat www.gutenberg.org. If you are not located in the United States,\nyou will have to check the laws of the country where you are located\nbefore using this eBook.\nTitle: Meditations\n\nAuthor: Emperor of Rome Marcus Aurelius\n\nRelease date: June 1, 2001 [eBook #2680]\n                Most recently updated: March 9, 2021\nLanguage: English\n\n*** START OF THE PROJECT GUTENBERG EBOOK MEDITATIONS ***\n\n\n      MEDITATIONS\n    \n\n      By Marcus Aurelius\n    \n\n      MARCUS AURELIUS ANTONINUS THE ROMAN EMPEROR\n    \n\n \n\n\n\n      BOOKS\n    \n\n INTRODUCTION \n\n\n\n\n\nHIS FIRST BOOK\n\n\nTHE SECOND BOOK\n\n\nTHE THI&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;전체 길이를 확인해보죠.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;len(data[0].page_content)
## 출력
487994&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;공백 포함 48만자가 넘네요. 이 내용을 LLM에 전달하면 token 제한에 걸리겠죠? LLM에 전달할 때는 내용을 chunk로 분할해서 전달하게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;PDF 문서 읽기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번에는 위 웹 페이지를 pdf로 출력한 파일을 읽어보겠습니다. 이를 위해서는 pypdf 패키지를 미리 설치해야 합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# 설치: pip install pypdf

from langchain.document_loaders import &lt;strong&gt;PyPDFLoader&lt;/strong&gt;

loader = PyPDFLoader(&quot;Meditations.pdf&quot;)
pages = loader.&lt;strong&gt;load_and_split&lt;/strong&gt;()
len(pages)
## 출력
151&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;load_and_split&lt;/code&gt; 명령으로 pdf 파일을 읽으면서 분할했습니다. 그랬더니 길이가 151인 리스트가 나왔습니다. 실제 pdf 파일의 페이지 수가 151입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pages[0].metadata  ## {&apos;&lt;strong&gt;source&lt;/strong&gt;&apos;: &apos;Meditations.pdf&apos;, &apos;&lt;strong&gt;page&lt;/strong&gt;&apos;: 0}
pages[150].metadata  ## {&apos;source&apos;: &apos;Meditations.pdf&apos;, &apos;page&apos;: 150}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Metadata에 들어있는 항목이 html 파일의 경우와 달라졌죠? 문서에 따라 &lt;code&gt;metadata&lt;/code&gt;의 내용이 달라진다는 것을 알 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pages[0]
## 출력
&lt;strong&gt;Document&lt;/strong&gt;(&lt;strong&gt;page_content&lt;/strong&gt;=&apos;10/6/23, 10:40 PM The Project Gutenberg eBook of Meditations, by Marcus Aurelius\nhttps://www.gutenberg.org/cache/epub/2680/pg2680-images.html 1/151The Project Gutenberg eBook of Meditations\nThis ebook is for the use of anyone anywhere in the United\nStates and most other parts of the world at no cost and with\nalmost no restrictions whatsoever . You may copy it, give it\naway or re-use it under the terms of the Project Gutenber g\nLicense included with this ebook or online at\nwww .gutenber g.org. If you are not located in the United\nStates, you will have to check the laws of the country where\nyou are located before using this eBook.\nTitle: Meditations\nAuthor : Emperor of Rome Marcus Aurelius\nRelease date : June 1, 2001 [eBook #2680]\nMost recently updated: March 9, 2021\nLanguage : English\n*** ST ART OF THE PROJECT  GUTENBERG EBOOK\nMEDIT ATIONS ***\nMEDIT A TIONS\nBy Mar cus Aurelius\nMARCUS AURELIUS ANTONINUS\nTHE ROMAN EMPEROR\nBOOKS\nINTRODUCTION\nHIS FIRST  BOOK\nTHE SECOND BOOK\nTHE THIRD BOOK\nTHE FOUR TH BOOK\nTHE FIFTH BOOK\nTHE SIXTH BOOK\nTHE SEVENTH BOOK\nTHE EIGHTH BOOK\nTHE NINTH BOOK&apos;, &lt;strong&gt;metadata&lt;/strong&gt;={&apos;source&apos;: &apos;Meditations.pdf&apos;, &apos;page&apos;: 0})&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;리스트의 첫 번째 원소를 확인해보니 Document 객체가 들어있고, 페이지 내용은 &lt;code&gt;page_content&lt;/code&gt; 속성에, 추가 정보는 &lt;code&gt;metadata&lt;/code&gt; 속성에 들어가 있는 것을 확인할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 LangChain의 Document loader를 이용하면 다양한 유형의 파일들을 편리하게 읽어들일 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item><item><title>LangChain: 조건문처럼 쓸 수 있는 RouterChain</title><link>https://pkgpl.org/2023/09/26/langchain-routerchain/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/26/langchain-routerchain/</guid><pubDate>Tue, 26 Sep 2023 14:08:58 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;라우터는 네트워크 중계장치로, 여러 통신망들 중 최적의 경로(route)를 지정해주는 장비입니다. &lt;strong&gt;RouterChain&lt;/strong&gt;은 라우터처럼 입력 query와 목적지 Chain들의 정보를 분석하여 최적의 Chain으로 연결해주는 Chain입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-16.png&quot; href=&quot;https://pkgpl.org/media/wp-7a3f731209871883.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;369&quot; src=&quot;https://pkgpl.org/media/wp-7a3f731209871883.png&quot; alt=&quot;&quot; class=&quot;wp-image-1833&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;몇 가지 개념들을 살펴봅시다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;destination_chains: RouterChain 다음 단계로 연결될 수 있는 목적지 Chain들로, 각각의 destination chain은 LLMChain이나 다른 복합적인 Chain으로 만듭니다.&lt;/li&gt;



&lt;li&gt;default_chain: 입력 query를 보낼만한 적합한 destination chain이 없을 때 연결하는 Chain입니다.&lt;/li&gt;



&lt;li&gt;RouterChain: destination_chains 정보와 입력 query를 비교하여 가장 적합한 Chain을 선택합니다. 적절한 Chain이 없으면 default chain을 선택합니다.&lt;/li&gt;



&lt;li&gt;RouterOutputParser: RouterChain의 출력 문자열을 다음 Chain에서 입력으로 사용할 수 있도록 딕셔너리로 바꿔줍니다. 딕셔너리는 목적지 Chain 정보와 목적지 Chain의 입력 프롬프트 정보를 포함합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Destination Chains&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드를 봅시다. 예제를 위해 철학, 물리학, 컴퓨터, 문학 네 분야의 전문가들을 모셨습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;philosophy_expert = &quot;&quot;&quot;
당신은 플라톤입니다. 철학 전문가입니다. 모르는 질문에는 모른다고 답합니다.
질문: {input}
&quot;&quot;&quot;
physics_expert = &quot;&quot;&quot;
당신은 아인슈타인입니다. 물리학 전문가입니다. 모르는 질문에는 모른다고 답합니다.
질문: {input}
&quot;&quot;&quot;
computer_expert = &quot;&quot;&quot;
당신은 폰 노이만입니다. 컴퓨터 전문가입니다. 모르는 질문에는 모른다고 답합니다.
질문: {input}
&quot;&quot;&quot;
literature_expert = &quot;&quot;&quot;
당신은 셰익스피어입니다. 문학 전문가입니다. 모르는 질문에는 모른다고 답합니다.
질문: {input}
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 문자열들은 목적지 Chain들의 프롬프트 템플릿으로 사용할겁니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;prompt_info = [
    {
        &quot;name&quot;:&quot;philosophy&quot;,
        &quot;description&quot;: &quot;철학 관련 질문에 대답&quot;,
        &quot;prompt_template&quot;: philosophy_expert
    },
    {
        &quot;name&quot;:&quot;physics&quot;,
        &quot;description&quot;: &quot;물리학 관련 질문에 대답&quot;,
        &quot;prompt_template&quot;: physics_expert
    },
    {
        &quot;name&quot;:&quot;computer&quot;,
        &quot;description&quot;: &quot;컴퓨터 관련 질문에 대답&quot;,
        &quot;prompt_template&quot;: computer_expert
    },
    {
        &quot;name&quot;:&quot;literature&quot;,
        &quot;description&quot;: &quot;문학 관련 질문에 대답&quot;,
        &quot;prompt_template&quot;: literature_expert
    }
]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 리스트에는 목적지 Chain들의 정보를 담았습니다. 각 Chain 정보는 딕셔너리로, name, description, prompt_template을 포함하고 있습니다. 목적지 Chain들에서 사용할 LLM을 정의하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

llm = ChatOpenAI(temperature=0)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 목적지 Chain들을 만들며 {“name”:Chain} 형태의 딕셔너리를 준비합니다. RouterChain에서 목적지 Chain의 이름을 지정해주면 해당 Chain으로 연결하기 위한 사전작업입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;destination_chains = {}
for p in prompt_info:
    name = p[&quot;name&quot;]
    prompt = ChatPromptTemplate.from_template(template=p[&quot;prompt_template&quot;])
    destination_chains[name] = LLMChain(llm=llm, prompt=prompt)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;RouterChain의 프롬프트에 넣을 목적지 Chain들의 정보를 준비합니다. 간단하게 “name”: “description” 형태의 문자열을 만들었습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;destinations = [f&quot;{p[&apos;name&apos;]}: {p[&apos;description&apos;]}&quot; for p in prompt_info]
destinations_str = &quot;\n&quot;.join(destinations)
print(destinations_str)

### 결과
philosophy: 철학 관련 질문에 대답
physics: 물리학 관련 질문에 대답
computer: 컴퓨터 관련 질문에 대답
literature: 문학 관련 질문에 대답&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Default Chain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;적절한 목적지 Chain이 없을 때 사용할 Default Chain도 준비합니다. 사용자 입력을 그대로 넘기도록 했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;default_prompt = ChatPromptTemplate.from_template(&quot;{input}&quot;)
default_chain = LLMChain(llm=llm, prompt=default_prompt)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;RouterChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;RouterChain을 만드는데 필요한 클래스들을 import 하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.prompts import PromptTemplate&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 RouterChain의 프롬프트를 준비합시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;MULTI_PROMPT_ROUTER_TEMPLATE = &quot;&quot;&quot;
입력받은 내용을 바탕으로 가장 적절한 모델 프롬프트를 선택하세요.
모델 프롬프트 정보는 다음과 같이 주어집니다.

&quot;프롬프트 이름&quot;: &quot;프롬프트 설명&quot;

&amp;lt;&amp;lt; FORMATTING &amp;gt;&amp;gt;
Return a markdown code snippet with a JSON object formatted to look like:
```json
{{{{
    &quot;destination&quot;: string \ name of the prompt to use or &quot;DEFAULT&quot;
    &quot;next_inputs&quot;: string \ a potentially modified version of the original input
}}}}
```

REMEMBER: &quot;destination&quot;은 아래 주어진 프롬프트 설명을 바탕으로 프롬프트 이름 중 하나를 선택하거나,
적절한 프롬프트가 없으면 &quot;DEFAULT&quot;를 선택할 수 있습니다.

REMEMBER: &quot;next_inputs&quot;은 원본 INPUT을 넣으세요.

&amp;lt;&amp;lt; CANDIDATE PROMPTS &amp;gt;&amp;gt;
{destinations}

&amp;lt;&amp;lt; INPUT &amp;gt;&amp;gt;
{{input}}

&amp;lt;&amp;lt; OUTPUT (remember to include the ```json)&amp;gt;&amp;gt;&quot;&quot;&quot;

router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(
    destinations=destinations_str
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 MULTI_PROMPT_ROUTER_TEMPLATE는 기본 문자열입니다. format을 거치며  &lt;code&gt;destination&lt;/code&gt;s만 치환하고 &lt;code&gt;input&lt;/code&gt;은 남기기 위해 &lt;code&gt;input&lt;/code&gt;에 중괄호를 두 개 사용했습니다. 하나만 쓰면 치환할 때 &lt;code&gt;input&lt;/code&gt; 정보도 넣으라고 에러가 납니다. &lt;code&gt;json&lt;/code&gt;은 치환하지 않을 것이기 때문에 중괄호를 중복해서 썼습니다. format을 거치면 &lt;code&gt;{{&lt;/code&gt;이 &lt;code&gt;{&lt;/code&gt;로 바뀌는데 여기서 한 번, 뒤에서 PromptTemplate에서 또 한 번 치환이 일어나므로 json의 중괄호를 끝까지 남겨두기 위해 중괄호를 네 개 썼습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 RouterChain의 PromptTemplate과 RouterChain을 만들 차례입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;router_prompt = PromptTemplate(
    template=router_template,
    input_variables=[&quot;input&quot;],
    output_parser=RouterOutputParser(),
)

router_chain = LLMRouterChain.from_llm(llm, router_prompt)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;MultiPromptChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음에는 RouterChain, 목적지 Chain, Default Chain을 모두 묶어서 MultiPromptChain을 만듭니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain = MultiPromptChain(router_chain=router_chain, 
                         destination_chains=destination_chains, 
                         default_chain=default_chain,
                         verbose=True
                        )&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;중간에 어떤 목적지 Chain을 선택했는지 확인하기 위해 &lt;code&gt;verbose=True&lt;/code&gt;로 입력했습니다. 이제 준비가 끝났습니다. 호출해볼까요?&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Run&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.run(&quot;상대성 이론이 뭐에요?&quot;)

### 결과
&amp;gt; Entering new MultiPromptChain chain...
&lt;strong&gt;physics&lt;/strong&gt;: {&apos;input&apos;: &apos;상대성 이론이 뭐에요?&apos;}
&amp;gt; Finished chain.
&apos;상대성 이론은 알버트 아인슈타인이 제시한 물리학 이론으로, 시간, 공간, 그리고 중력에 대한 새로운 이해를 제공합니다. 이론은 두 가지 주요한 부분으로 나뉩니다. 첫 번째는 특수 상대성 이론으로, 서로 다른 관측자들이 서로 다른 속도로 움직이더라도 물리적 법칙은 동일하게 적용된다는 것을 설명합니다. 두 번째는 일반 상대성 이론으로, 중력을 공간과 시간의 곡률로 설명하며, 질량이나 에너지가 공간과 시간을 구부리는 것을 설명합니다. 이론은 많은 실험적 검증을 거쳐 현대 물리학의 기초로 자리잡았습니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;목적지 Chain으로 물리학 Chain이 선택되며 아인슈타인에게 질문이 전달된 것을 볼 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.run(&quot;삶의 의미는?&quot;)

### 결과
&amp;gt; Entering new MultiPromptChain chain...
&lt;strong&gt;philosophy&lt;/strong&gt;: {&apos;input&apos;: &apos;삶의 의미는?&apos;}
&amp;gt; Finished chain.
&apos;플라톤: 삶의 의미는 인간의 존재와 관련된 복잡한 주제입니다. 제가 생각하기에 삶의 의미는 개인에 따라 다를 수 있으며, 각각의 사람들은 자신만의 의미를 발견하고 이해해야 합니다. 삶의 의미는 인간의 가치, 목적, 성장, 연결, 창조 등 다양한 측면을 포함할 수 있습니다. 그러나 이 질문에 대한 절대적인 답은 없으며, 이는 개인의 철학적, 종교적, 문화적 배경에 따라 다를 수 있습니다. 따라서, 삶의 의미에 대한 최종적인 답은 모른다고 말씀드릴 수밖에 없습니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;철학적인 질문은 철학 전문가 플라톤에게 전달되었네요.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.run(&quot;청년과 떠오르는 태양을 주제로 시를 써줘&quot;)

### 결과
&amp;gt; Entering new MultiPromptChain chain...
&lt;strong&gt;literature&lt;/strong&gt;: {&apos;input&apos;: &apos;청년과 떠오르는 태양을 주제로 시를 써줘&apos;}
&amp;gt; Finished chain.
&apos;나는 셰익스피어가 아니지만, 당신을 위해 청년과 떠오르는 태양을 주제로 한 시를 써보겠습니다.\n\n청년의 마음은 태양과 같아\n뜨겁고 밝게 빛나는 것 같아\n그의 꿈과 희망은 무궁무진하고\n떠오르는 태양처럼 높이 떠오르는 것 같아\n\n그의 눈은 태양과 같아\n찬란하고 아름다운 것 같아\n그의 시선은 멀리 향해\n떠오르는 태양처럼 빛을 비추는 것 같아\n\n청년의 에너지는 태양과 같아\n끊임없이 흘러나오는 것 같아\n그의 열정은 불타오르고\n떠오르는 태양처럼 모두를 따뜻하게 하는 것 같아\n\n청년과 떠오르는 태양은\n새로운 시작과 희망을 상징해\n그들은 우리에게 빛과 영감을 주며\n떠오르는 태양처럼 우리를 이끌어가는 것 같아\n\n이렇게 청년과 떠오르는 태양에 대한 시를 써봤습니다. 셰익스피어의 수준은 아니지만, 조금이나마 당신의 질문에 대한 답변이 되었기를 바랍니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;시를 써달라고 하니 문학 Chain으로 연결되긴 했는데, LLM에서 자신은 셰익스피어가 아니라고 부인합니다. 그냥 PromptTemplate 대신 ChatPromptTemplate을 써서 시스템 메시지로 당신은 셰익스피어라고 하면 인정할까요? 연습해보세요.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.run(&quot;비트와 바이트는 무슨 관계지?&quot;)

### 결과
&amp;gt; Entering new MultiPromptChain chain...
&lt;strong&gt;computer&lt;/strong&gt;: {&apos;input&apos;: &apos;비트와 바이트는 무슨 관계지?&apos;}
&amp;gt; Finished chain.
&apos;비트와 바이트는 컴퓨터에서 데이터를 표현하는 단위입니다. 비트는 0 또는 1의 값을 가지는 가장 작은 단위이고, 바이트는 8개의 비트로 이루어진 단위입니다. 즉, 바이트는 비트의 그룹이라고 볼 수 있습니다. 따라서, 1바이트는 8비트와 같고, 2바이트는 16비트와 같은 관계를 가지게 됩니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;비트와 바이트에 관한 질문은 컴퓨터 Chain에 전달되었습니다. 이렇게 RouterChain을 쓰면 자연어로 if문과 유사한 조건 분기 프로그램을 만들 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Chain들을 다양하게 연결하는 SequentialChain</title><link>https://pkgpl.org/2023/09/25/langchain-sequentialchain/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/25/langchain-sequentialchain/</guid><pubDate>Mon, 25 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/24/langchain-simplesequentialchain/&quot;&gt;앞서 살펴본 SimpleSequentialChain&lt;/a&gt;은 &lt;a href=&quot;https://pkgpl.org/2023/09/21/langchain-llmchain/&quot;&gt;작은 Chain들&lt;/a&gt;이 한 줄로 연결된 형태였습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image.png&quot; href=&quot;https://pkgpl.org/media/wp-61a8ce5e5e04b79d.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;132&quot; src=&quot;https://pkgpl.org/media/wp-61a8ce5e5e04b79d.png&quot; alt=&quot;&quot; class=&quot;wp-image-1883&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;SequentialChain&lt;/strong&gt;은 아래와 같이 작은 Chain들을 좀 더 복잡한 형태로 연결할 수 있는 Chain입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-14.png&quot; href=&quot;https://pkgpl.org/media/wp-0be115587f06bf0f.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;294&quot; src=&quot;https://pkgpl.org/media/wp-0be115587f06bf0f.png&quot; alt=&quot;&quot; class=&quot;wp-image-1819&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Example&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예제를 살펴보겠습니다. 간단하게 만들 수도 있지만 예시를 위해 조금 복잡하게 만들었습니다. 외국어로 된 사용자 리뷰를 받아서 한글로 번역하고, 번역한 내용을 한 문장으로 요약한 다음 요약을 보고 답변을 달려고 합니다. 답변 언어는 원래 리뷰의 언어로 하고, 추가로 감정 분석을 통해 긍정/부정 점수를 매기려고 합니다. 각각의 작업에 대한 Chain들을 다음과 같이 만들어 연결하겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Chain 1: 외국어 리뷰를 한글로 번역, input = review, output = translation&lt;/li&gt;



&lt;li&gt;Chain 2: 한글 리뷰를 한 문장으로 요약, input = translation, output = summary&lt;/li&gt;



&lt;li&gt;Chain 3: 리뷰를 읽고 감정 분석 점수 매기기, input = translation, output = sentiment_score&lt;/li&gt;



&lt;li&gt;Chain 4: 리뷰의 언어 알아내기, input = review, output = language&lt;/li&gt;



&lt;li&gt;Chain 5: 리뷰의 한글 요약에 대해 원래 언어로 답변 작성, input = language &amp;amp; summary, output = reply&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLM&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드를 봅시다. 먼저 필요한 모듈을 import하고, 공통으로 사용할 llm 변수를 생성했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

llm = ChatOpenAI(temperature=0.5)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;PromptTemplate, LLMChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음에는 위의 Chain 1~5에 해당하는 &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;PromptTemplate&lt;/a&gt;과 &lt;a href=&quot;https://pkgpl.org/2023/09/21/langchain-llmchain/&quot;&gt;LLMChain&lt;/a&gt;을 만들겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;prompt1 = PromptTemplate(
    input_variables=[&apos;review&apos;],
    template=&quot;다음 사용자 리뷰를 한글로 번역하세요.\n\n{review}&quot;
)
&lt;strong&gt;chain1&lt;/strong&gt; = LLMChain(llm=llm, prompt=prompt1, output_key=&quot;translation&quot;)

prompt2 = PromptTemplate.from_template(
    &quot;다음 리뷰를 한 문장으로 요약하세요.\n\n{translation}&quot;
)
&lt;strong&gt;chain2&lt;/strong&gt; = LLMChain(llm=llm, prompt=prompt2, output_key=&quot;summary&quot;)

prompt3 = PromptTemplate.from_template(
    &quot;다음 리뷰를 읽고 0점부터 10점 사이에서 부정/긍정 점수를 매기세요. 숫자만 대답하세요.\n\n{translation}&quot;
)
&lt;strong&gt;chain3&lt;/strong&gt; = LLMChain(llm=llm, prompt=prompt3, output_key=&quot;sentiment_score&quot;)

prompt4 = PromptTemplate.from_template(
    &quot;다음 리뷰에 사용된 언어가 무엇인가요? 언어 이름만 답하세요.\n\n{review}&quot;
)
&lt;strong&gt;chain4&lt;/strong&gt; = LLMChain(llm=llm, prompt=prompt4, output_key=&quot;language&quot;)

prompt5 = PromptTemplate.from_template(
    &quot;다음 리뷰 요약에 대해 공손한 답변을 작성하세요.\n답변 언어:{language}\n리뷰 요약:{summary}&quot;
)
&lt;strong&gt;chain5&lt;/strong&gt; = LLMChain(llm=llm, prompt=prompt5, output_key=&quot;reply&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;PromptTemplate을 만들 때 &lt;code&gt;from_template&lt;/code&gt;을 사용한 것도 있고 사용하지 않은 것도 있는데, 연습을 위해 섞어서 사용한 것입니다. 하나로 통일해도 괜찮습니다. LLMChain을 만들면서 &lt;code&gt;output_key&lt;/code&gt;를 사용했습니다. 이어지는 Chain들의 PromptTemplate에서는 &lt;code&gt;output_key&lt;/code&gt;에 지정한 변수들을 사용한 것을 볼 수 있습니다. 이렇게 앞 Chain의 출력을 다음 Chain의 입력으로 지정할 수 있습니다. 이제 이 Chain들을 연결하겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;SequentialChain&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chains import SequentialChain

all_chain = &lt;strong&gt;SequentialChain&lt;/strong&gt;(
    &lt;strong&gt;chains&lt;/strong&gt;=[chain1, chain2, chain3, chain4, chain5],
    &lt;strong&gt;input_variables&lt;/strong&gt;=[&apos;review&apos;],
    &lt;strong&gt;output_variables&lt;/strong&gt;=[&apos;translation&apos;,&apos;summary&apos;,&apos;sentiment_score&apos;,&apos;language&apos;,&apos;reply&apos;],
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;review를 입력하고 결과가 어떻게 나오는지 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;review=&quot;&quot;&quot;
I&apos;m somewhat satisfied with this product.
Considering its cost-effectiveness, it&apos;s not bad.
However, regardless of the product itself,
the shipping took too long, which was disappointing.
&quot;&quot;&quot;
all_chain(review)

### 결과
{&apos;review&apos;: &quot;\nI&apos;m somewhat satisfied with this product.\nConsidering its cost-effectiveness, it&apos;s not bad.\nHowever, regardless of the product itself,\nthe shipping took too long, which was disappointing.\n&quot;,
 &apos;translation&apos;: &apos;이 제품에 대해는 어느 정도 만족한 편입니다.\n비용 대비로 생각해보면 그렇게 나쁘지 않아요.\n하지만 제품 자체와는 상관없이,\n배송이 너무 오래 걸려서 실망스러웠습니다.&apos;,
 &apos;summary&apos;: &apos;제품은 만족스럽지만 배송이 너무 오래 걸려 실망스러웠습니다.&apos;,
 &apos;sentiment_score&apos;: &apos;7&apos;,
 &apos;language&apos;: &apos;영어&apos;,
 &apos;reply&apos;: &apos;Thank you for your feedback. We are glad to hear that you are satisfied with the product. We apologize for the disappointment caused by the delayed delivery. We will definitely take your feedback into consideration and work towards improving our shipping process. Thank you for bringing this to our attention.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;input_variables&lt;/code&gt;와 &lt;code&gt;output_variables&lt;/code&gt;에 지정한 key들이 포함된 딕셔너리가 반환되었습니다. 각각의 key에 해당하는 value들이 prompt에 따라 원하는 결과로 나온 것을 볼 수 있습니다. 이렇게 SequentialChain을 사용하면 여러 Chain들을 다양한 방식으로 연결해 사용할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Chain들을 차례로 연결하는 SimpleSequentialChain</title><link>https://pkgpl.org/2023/09/24/langchain-simplesequentialchain/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/24/langchain-simplesequentialchain/</guid><pubDate>Sun, 24 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain의 Chain에는 몇 가지 종류가 있습니다. 앞에서 &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;PromptTemplate&lt;/a&gt;, &lt;a href=&quot;https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/&quot;&gt;LLM&lt;/a&gt;, &lt;a href=&quot;https://pkgpl.org/2023/09/20/langchain-outputparser/&quot;&gt;OutputParser&lt;/a&gt;를 연결한 &lt;a href=&quot;https://pkgpl.org/2023/09/21/langchain-llmchain/&quot;&gt;LLMChain&lt;/a&gt;과 LLMChain에 &lt;a href=&quot;https://pkgpl.org/2023/09/22/langchain-memory/&quot;&gt;Memory&lt;/a&gt;를 추가해 대화가 가능한 &lt;a href=&quot;https://pkgpl.org/2023/09/23/langchain-conversationchain/&quot;&gt;ConversationChain&lt;/a&gt;을 살펴봤습니다. (사실 LLMChain에서 ChatModels를 사용하고 Memory를 할당하면 ConversationChain과 유사합니다.)&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번에는 LLMChain들을 간단하게 연결할 수 있는 &lt;strong&gt;SimpleSequentialChain&lt;/strong&gt;을 살펴보겠습니다. 아래 그림처럼 단순하게 이전 Chain의 출력을 다음 Chain의 입력으로 연결해주는 Chain입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-13.png&quot; href=&quot;https://pkgpl.org/media/wp-2ccb88048b4675e6.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;367&quot; src=&quot;https://pkgpl.org/media/wp-2ccb88048b4675e6.png&quot; alt=&quot;&quot; class=&quot;wp-image-1805&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드를 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
from langchain.chains import &lt;strong&gt;SimpleSequentialChain&lt;/strong&gt;

llm = ChatOpenAI(temperature=0.9)

prompt1 = ChatPromptTemplate.from_template(
    &quot;{area} 분야에서 역사적으로 가장 중요한 사람은?&quot;
)

prompt2 = ChatPromptTemplate.from_template(
    &quot;{name}: 이 사람이 속했던 기관은?&quot;
)

prompt3 = ChatPromptTemplate.from_template(
    &quot;{org}: 이 기관의 주요 업적은?&quot;
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;세 개의 Chain을 만들고 연결하기 위해 세 개의 PromptTemplate를 만들었습니다. 각각의 Chain은 위의 LLM과 PromptTemplate을 연결해 만들겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chains = []
for prompt in [prompt1, prompt2, prompt3]:
    chains.append(LLMChain(llm=llm, prompt=prompt))&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 Chain들의 리스트를 만들었습니다. SimpleSequentialChain은 이 리스트를 이용해 만듭니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;simple_chain = &lt;strong&gt;SimpleSequentialChain&lt;/strong&gt;(&lt;strong&gt;chains&lt;/strong&gt;=&lt;strong&gt;chains&lt;/strong&gt;, verbose=True)
simple_chain.run(&quot;중력 이론&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 &lt;code&gt;verbose&lt;/code&gt;는 중간 과정도 출력하기 위해 &lt;code&gt;True&lt;/code&gt;로 넣었습니다. &lt;code&gt;verbose=False&lt;/code&gt;로  놓으면(기본값) 최종 응답만 출력됩니다. 출력된 내용은 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;&amp;gt; Entering new SimpleSequentialChain chain...

### 첫 번째 Chain의 결과
중력 이론 분야에서 역사적으로 가장 중요한 사람은 아이작 뉴턴(Isaac Newton)입니다. 뉴턴은 17세기에 중력 이론을 개발하였으며, 그의 &quot;형성력학&quot;은 현대 물리학의 기초를 세우는 데 큰 영향을 주었습니다. 뉴턴의 중력 이론은 이후 약 200년 동안 가장 효과적이고 정확한 설명이었으며, 그의 업적은 고전 물리학의 기초와 현대 과학의 발전에 큰 영감을 주었습니다.

### 두 번째 Chain의 결과
아이작 뉴턴은 케임브리지 대학교에서 교수로 활동하였습니다.

### 세 번째 Chain의 결과
아이작 뉴턴은 케임브리지 대학교에서 교수로 활동하였으며, 그의 주요 업적은 다음과 같습니다:

1. 만유인력의 법칙과 중력: 뉴턴은 중력의 법칙을 제시하고 지구의 운동을 설명하는 뉴턴의 운동 법칙을 개발했습니다. 그는 또한 만유인력의 법칙을 제시하여 물체 간의 인력을 설명하였습니다.

2. 광학: 뉴턴은 광학 연구를 수행하여 &quot;광방사&quot;와 &quot;광굴절&quot;의 원리를 밝혀내었습니다. 그는 빛이 다양한 색상으로 구성되어 있다는 것을 발견하였고, 이는 후에 뉴턴의 색채 이론으로 알려지게 되었습니다.

3. 미적분학: 뉴턴은 미적분학의 기초를 개발하였습니다. 그의 연구는 운동, 탄성, 적분 등 다양한 수학적 문제들을 해결하는데 사용되었으며, 이는 현대 과학 및 공학의 핵심 개념 중 하나가 되었습니다.

4. 역학: 뉴턴의 연구는 역학의 발전에 큰 기여를 했습니다. 그는 뉴턴의 운동 법칙을 통해 물리학적 시스템의 움직임과 운동을 설명하였으며, 이를 통해 천문학, 공학, 물리학 등에서 다양한 응용분야에 사용되었습니다.

이러한 업적들은 뉴턴을 현대 과학의 선구자 중 한 명으로 여기게 되었으며, 그의 연구는 현대과학의 기반을 다지는 데 큰 역할을 한 것으로 평가되고 있습니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과를 보면 질문에 대한 답만 말한 것이 아니라 부연 설명이 들어가 있습니다. 최종 응답에서는 기관의 업적이 아니라 뉴턴의 업적이 결과로 나왔네요. OutputParser를 추가하면 첫 번째 응답은 “뉴턴”, 두 번째 응답은 “케임브리지 대학교”로 만들어 세 번째에 기관의 업적이 나오도록 만들 수 있을겁니다. 해봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser

schema = ResponseSchema(name=&apos;name&apos;, description=&quot;json object: key=name, value=person&apos;s name&quot;)
response_schemas = [schema]
output_parser1 = StructuredOutputParser.from_response_schemas(response_schemas)

schema = ResponseSchema(name=&apos;org&apos;, description=&quot;json object: key=org, value=organization&apos;s name&quot;)
response_schemas = [schema]
output_parser2 = StructuredOutputParser.from_response_schemas(response_schemas)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;첫 번째와 두 번째 LLM 출력을 위한 OutputParser들을 만들었습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;prompt1 = ChatPromptTemplate.from_template(
    &quot;{area} 분야에서 역사적으로 가장 중요한 사람은?\n{format_instructions}&quot;,
    partial_variables={&quot;format_instructions&quot;:output_parser1.get_format_instructions()}
)

prompt2 = ChatPromptTemplate.from_template(
    &quot;{name}: 이 사람이 속했던 기관은?\n{format_instructions}&quot;,
        partial_variables={&quot;format_instructions&quot;:output_parser2.get_format_instructions()}
)

prompt3 = ChatPromptTemplate.from_template(
    &quot;{org}: 이 기관의 주요 업적은?&quot;
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;첫 번째와 두 번째 프롬프트에 OutputParser의 format_instructions를 추가했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;new_chains=[]
new_chains.append(LLMChain(llm=llm, prompt=prompt1, output_parser=output_parser1))
new_chains.append(LLMChain(llm=llm, prompt=prompt2, output_parser=output_parser2))
new_chains.append(LLMChain(llm=llm, prompt=prompt3))

new_simple_chain = SimpleSequentialChain(chains=new_chains, verbose=True)

new_simple_chain.run(&quot;중력 이론&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OutputParser를 추가한 LLMChain들을 이용해 SimpleSequentialChain을 만들고 실행했습니다. 결과를 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;&amp;gt; Entering new SimpleSequentialChain chain...

### 첫 번째 Chain의 결과
{&apos;name&apos;: &apos;아이작 뉴턴&apos;}

### 두 번째 Chain의 결과
{&apos;org&apos;: &apos;옥스퍼드 대학교&apos;}

### 세 번째 Chain의 결과
옥스퍼드 대학교는 많은 주요 업적을 가지고 있습니다. 이 중 일부는 다음과 같습니다:

1. 학문적 우수성: 옥스퍼드 대학교는 국제적으로 인정받는 세계적인 연구 및 교육 기관으로, 학문적 우수성과 혁신적인 연구로 유명합니다. 이는 다양한 분야에서 많은 세계적인 수상을 받았음을 증명하고 있습니다.

2. 역사적인 유산: 옥스퍼드 대학교는 12세기에 설립되어 역사적인 유산을 가지고 있습니다. 옥스퍼드의 대학 조직 구조는 근대 대학의 모델로 사용되었으며, 다른 대학들에 큰 영향을 미쳤습니다.

3. 알럼니 네트워크: 옥스퍼드 대학교는 강력하고 영향력 있는 알럼니 네트워크를 가지고 있습니다. 많은 옥스퍼드 졸업생들이 세계적으로 성공한 사업가, 정치인, 문화인으로 알려져 있습니다.

4. 문화적 영향력: 옥스퍼드 대학교는 창의적이고 혁신적인 사고 방식을 장려하며, 학문의 자유를 존중합니다. 이러한 문화적인 영향력이 전 세계에서 영향을 미치고 있으며, 다양한 분야에서 지식과 이해를 증진시키는 역할을 합니다.

5. 국제 협력: 옥스퍼드 대학교는 다양한 국제 협력 프로그램을 통해 세계의 다른 연구기관과 협력하고 있습니다. 이를 통해 옥스퍼드는 국제적인 역량을 키우고, 글로벌 문제에 대한 해결책을 모색하는 데 기여하고 있습니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;첫 번째와 두 번째 Chain에서 원하는 출력 형식을 얻었으나, 두 번째 응답의 결과가 잘못 되었네요. 케임브리지 대학이 맞습니다. 이렇게 틀린 응답을 할 때가 종종 있으니 결과를 확인해볼 필요가 있습니다. 정확도가 중요할 때는 &lt;a href=&quot;https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/&quot;&gt;Retrieval Augmented Generation&lt;/a&gt;과 같은 방법을 쓰는게 좋겠죠.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: 대화를 위한 ConversationChain</title><link>https://pkgpl.org/2023/09/23/langchain-conversationchain/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/23/langchain-conversationchain/</guid><pubDate>Sat, 23 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLMChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 LangChain의 &lt;a href=&quot;https://pkgpl.org/2023/09/21/langchain-llmchain/&quot;&gt;LLMChain&lt;/a&gt;을 살펴봤습니다. PromptTemplate, LLM, OutputParser를 연결해서 편리하게 사용할 수 있는 기능이었죠. 그림으로 표현해봅시다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-11.png&quot; href=&quot;https://pkgpl.org/media/wp-a6d95b414182cc5c.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;794&quot; src=&quot;https://pkgpl.org/media/wp-a6d95b414182cc5c.png&quot; alt=&quot;&quot; class=&quot;wp-image-1795&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;사용자가 질문을 던집니다.&lt;/li&gt;



&lt;li&gt;질문은 PromptTemplate을 통과하며 최종 프롬프트가 됩니다.&lt;/li&gt;



&lt;li&gt;최종 프롬프트는 LLM(완성형 또는 대화형)에 전달되고, LLM에서 Output을 출력합니다.&lt;/li&gt;



&lt;li&gt;출력은 OutputParser를 거쳐 최종 응답이 되고, 사용자에게 전달됩니다&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 Chain은 한 번 입력을 받아서 한 번 출력하는 형태의 Chain입니다. LLMChain은 여러 개를 연결해서 더 복잡한 구조의 Chain을 만들 수 있지만, 기본적으로 대화용은 아닙니다. 챗봇과 같이 대화에 사용할 수 있는 Chain으로 ConversationChain이 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;ConversationChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ChatGPT와 달리 &lt;a href=&quot;https://pkgpl.org/2023/09/05/restful-api/&quot;&gt;REST API&lt;/a&gt;로 이용하는 LLM에는 대화를 기억하는 기능이 없습니다. 따라서 이전 대화 내용을 바탕으로 계속 대화를 이어가기 위해서는 대화하고 있는 내용을 저장해뒀다가 매번 프롬프트를 만들 때 추가해줘야 합니다. 그래야 LLM이 지금까지의 대화 내용을 기억하고 있는 것처럼 대답할 수 있죠. 이렇게 이전 대화를 기억하도록 하는 LangChain의 기능을 &lt;a href=&quot;https://pkgpl.org/2023/09/22/langchain-memory/&quot;&gt;Memory&lt;/a&gt;라고 했습니다. 대화를 위한 ConversationChain을 만들 때는 이 Memory가 필요합니다. 그림으로 보면 다음과 같습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-12.png&quot; href=&quot;https://pkgpl.org/media/wp-da374ef926b59421.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;506&quot; src=&quot;https://pkgpl.org/media/wp-da374ef926b59421.png&quot; alt=&quot;&quot; class=&quot;wp-image-1801&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;사용자가 질문을 던집니다.&lt;/li&gt;



&lt;li&gt;질문은 &lt;strong&gt;Memory에 저장된 이전 대화 내용과 함께&lt;/strong&gt; PromptTemplate에 전달되고, PromptTemplate를 거쳐 최종 프롬프트가 됩니다.&lt;/li&gt;



&lt;li&gt;최종 프롬프트는 대화형 LLM에 전달되고, 대화형 LLM에서 Output을 출력합니다.&lt;/li&gt;



&lt;li&gt;이 &lt;strong&gt;Output은 사용자의 Query와 함께 Memory에 저장&lt;/strong&gt;되고, OutputParser에도 전달됩니다.&lt;/li&gt;



&lt;li&gt;OutputParser를 거쳐 최종 응답이 사용자에게 전달됩니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드를 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.chains import &lt;strong&gt;ConversationChain&lt;/strong&gt;
from langchain.memory import &lt;strong&gt;ConversationBufferMemory&lt;/strong&gt;

llm = ChatOpenAI(temperature=0.0)

memory = &lt;strong&gt;ConversationBufferMemory&lt;/strong&gt;()

conversation = &lt;strong&gt;ConversationChain&lt;/strong&gt;(
    llm=llm, 
    &lt;strong&gt;memory&lt;/strong&gt; = memory
)
conversation.predict(input=&quot;안녕, 나는 토니 스타크라고 해.&quot;)

### 결과(응답)
&apos;안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서는 간단한 대화를 위해 PromptTemplate과 OutputParser를 생략했습니다. 이 경우 프롬프트에는 대화를 위한 기본 &lt;a href=&quot;https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/&quot;&gt;SystemMessage&lt;/a&gt;, 대화를 계속해 나가면서 누적된 대화 내용, 그리고 사용자의 새로운 질문이 들어가게 됩니다. OutputParser가 없으니 출력은 LLM의 대답이 그대로 문자열로 나옵니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Memory로 대화 내용 저장하기</title><link>https://pkgpl.org/2023/09/22/langchain-memory/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/22/langchain-memory/</guid><pubDate>Fri, 22 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain에는 LLM과 대화시 대화 내용을 저장하기 위한 &lt;strong&gt;Memory&lt;/strong&gt; 기능이 있습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;OpenAI API&lt;/a&gt;와 같은 &lt;a href=&quot;https://pkgpl.org/2023/09/05/restful-api/&quot;&gt;REST API&lt;/a&gt;는 상태를 저장하지 않습니다(stateless). 따라서 API 실행시 이전 대화 내용을 전달하지 않고 새로운 메시지만 던지면 처음 받는 질문으로 판단하고 대답하게 됩니다. 대화를 이어가기 위해서는 지난 대화 내용을 프롬프트에 포함해 전달하면서 새로운 메시지를 추가해야 합니다. 지난 대화 내용을 저장할 때 사용하는 것이 바로 Memory입니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그런데, 대화가 길어지면 문제가 생깁니다. API를 통해 한 번에 입출력할 수 있는 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;토큰 수가 정해져 있죠&lt;/a&gt;. 지난 대화가 길면 토큰 수를 넘어가서 답변을 듣지 못하게 됩니다. 물론 API 사용료도 더 많이 나가죠. 그래서 LangChain의 Memory 중에는 지난 대화 내용을 줄이는 Memory도 있습니다. 기본적인 메모리들을  몇 가지 살펴보겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;ConversationBufferMemory&lt;/li&gt;



&lt;li&gt;ConversationBufferWindowMemory&lt;/li&gt;



&lt;li&gt;ConversationTokenBufferMemory&lt;/li&gt;



&lt;li&gt;ConversationSummaryBufferMemory&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;ConversationBufferMemory&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;ConversationBufferMemory&lt;/strong&gt;는 지난 대화 내용을 그대로 저장하는 메모리입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.chains import &lt;strong&gt;ConversationChain&lt;/strong&gt;
from langchain.memory import &lt;strong&gt;ConversationBufferMemory&lt;/strong&gt;

llm = ChatOpenAI(temperature=0.0)

memory = &lt;strong&gt;ConversationBufferMemory&lt;/strong&gt;()

conversation = &lt;strong&gt;ConversationChain&lt;/strong&gt;(
    llm=llm, 
    &lt;strong&gt;memory&lt;/strong&gt; = memory
)
conversation.predict(input=&quot;안녕, 나는 토니 스타크라고 해.&quot;)

### 결과(응답)
&apos;안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코드에서 사용한 ConversationChain은 한 번 응답을 받는 &lt;a href=&quot;https://pkgpl.org/2023/09/21/langchain-llmchain/&quot;&gt;LLMChain&lt;/a&gt;과 달리 여러 번 대화를 주고 받을 때 사용하는 Chain입니다. Chain을 생성할 때 memory 인자에 LangChain의 Memory 객체를 입력하는 방식으로 Memory를 사용합니다. Chain 내부에서는 사용자가 input 메시지를 입력하면 메모리에 메시지를 추가한 후 LLM에 전달하고, LLM이 응답하면 메모리에 응답을 추가한 후 사용자에게 응답을 반환합니다. 대화를 이어나가겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;conversation.predict(input=&quot;내 인공지능 비서 이름이 뭐지?&quot;)
# 응답: &apos;당신의 인공지능 비서의 이름은 &quot;지니&quot;입니다. 어떤 일을 도와드릴까요?&apos;
conversation.predict(input=&quot;내 이름이 뭐였지?&quot;)
# 응답: &apos;당신의 이름은 &quot;토니 스타크&quot;입니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 이전 대화 내용을 기억하며 대화를 이어나갈 수 있습니다. 메모리에 저장된 내용은 다음과 같이 확인할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;print(&lt;strong&gt;memory.buffer&lt;/strong&gt;)

### 결과
Human: 안녕, 나는 토니 스타크라고 해.
AI: 안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?
Human: 내 인공지능 비서 이름이 뭐지?
AI: 당신의 인공지능 비서의 이름은 &quot;지니&quot;입니다. 어떤 일을 도와드릴까요?
Human: 내 이름이 뭐였지?
AI: 당신의 이름은 &quot;토니 스타크&quot;입니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;load_memory_variables&lt;/code&gt;를 이용할 수도 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;memory.&lt;strong&gt;load_memory_variables({})&lt;/strong&gt;

### 결과
{&apos;history&apos;: &apos;Human: 안녕, 나는 토니 스타크라고 해.\nAI: 안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?\nHuman: 내 인공지능 비서 이름이 뭐지?\nAI: 당신의 인공지능 비서의 이름은 &quot;지니&quot;입니다. 어떤 일을 도와드릴까요?\nHuman: 내 이름이 뭐였지?\nAI: 당신의 이름은 &quot;토니 스타크&quot;입니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;save_context&lt;/code&gt;를 이용해 메모리에 직접 내용을 추가할 수도 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;memory = ConversationBufferMemory()
memory.save_context({&quot;input&quot;: &quot;안녕, 나는 토니 스타크라고 해.&quot;}, 
                    {&quot;output&quot;: &quot;안녕하세요, 토니 스타크님! 반갑습니다.&quot;})
print(memory.buffer)

### 결과
Human: 안녕, 나는 토니 스타크라고 해.
AI: 안녕하세요, 토니 스타크님! 반갑습니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;더 추가해볼까요?&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;memory.save_context({&quot;input&quot;: &quot;내 비서 이름이 뭐지?&quot;}, 
                    {&quot;output&quot;: &quot;JARVIS입니다.&quot;})
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;Human: 안녕, 나는 토니 스타크라고 해.\nAI: 안녕하세요, 토니 스타크님! 반갑습니다.\nHuman: 내 비서 이름이 뭐지?\nAI: JARVIS입니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;ConversationBufferWindowMemory&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;ConversationBufferWindowMemory&lt;/strong&gt;는 윈도우 크기 k를 지정하면 최근 k개의 대화만 기억하고 이전 대화는 삭제합니다. 여기서 1개의 대화는 한 번 주고 받는 대화를 말합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.memory import &lt;strong&gt;ConversationBufferWindowMemory&lt;/strong&gt;
memory = &lt;strong&gt;ConversationBufferWindowMemory&lt;/strong&gt;(&lt;strong&gt;k&lt;/strong&gt;=1) 
memory.save_context({&quot;input&quot;: &quot;안녕, 나는 토니 스타크라고 해.&quot;},
                    {&quot;output&quot;: &quot;안녕하세요, 토니 스타크님! 반갑습니다.&quot;})
memory.save_context({&quot;input&quot;: &quot;내 비서 이름이 뭐지?&quot;},
                    {&quot;output&quot;: &quot;JARVIS입니다.&quot;})
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;Human: 내 비서 이름이 뭐지?\nAI: JARVIS입니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;k=1로 했더니 마지막 대화만 기억하고 그 앞의 대화는 잊어버렸습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;memory = &lt;strong&gt;ConversationBufferWindowMemory(k=1)&lt;/strong&gt;
conversation = ConversationChain(
    llm=llm, 
    memory = memory
)
conversation.predict(input=&lt;strong&gt;&quot;안녕, 나는 토니 스타크라고 해.&quot;&lt;/strong&gt;)
# 응답: &apos;안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?&apos;
conversation.predict(input=&quot;내 인공지능 비서 이름은 뭐지?&quot;)
# 응답: &apos;당신의 인공지능 비서의 이름은 &quot;제이비&quot;입니다.&apos;
conversation.predict(input=&quot;내 이름이 뭐라고?&quot;)
# 응답: &lt;strong&gt;&apos;죄송합니다, 저는 당신의 이름을 알 수 없습니다.&apos;&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이전 대화를 잊어버렸으니 이전 대화에 있던 정보를 물으면 답할 수가 없습니다. 보통 대화에서는 k=1보다 큰 값을 사용합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;ConversationTokenBufferMemory&quot;&gt;ConversationTokenBufferMemory&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;ConversationTokenBufferMemory&lt;/strong&gt;는 기억되는 토큰 수를 제한합니다. 최대 토큰 수를 넘지 않는 범위에서 최근 대화들을 기억합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.memory import ConversationTokenBufferMemory
memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=50)
memory.save_context({&quot;input&quot;: &quot;안녕, 나는 토니 스타크라고 해.&quot;},
                    {&quot;output&quot;: &quot;안녕, 토니 스타크! 반가워요. 저는 OpenAI의 인공지능입니다. 무엇을 도와드릴까요?&quot;})
memory.save_context({&quot;input&quot;: &quot;내 인공지능 비서 이름은 뭐지?&quot;},
                    {&quot;output&quot;: &quot;당신의 인공지능 비서의 이름은 JARVIS입니다.&quot;})
memory.save_context({&quot;input&quot;: &quot;내 이름이 뭐라고?&quot;}, 
                    {&quot;output&quot;: &quot;당신의 이름은 &apos;토니 스타크&apos;입니다.&quot;})
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &quot;Human: 내 이름이 뭐라고?\nAI: 당신의 이름은 &apos;토니 스타크&apos;입니다.&quot;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;최대 토큰 수를 50으로 작게 잡았기 때문에 마지막 대화밖에 안 남았습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;ConversationSummaryMemory&quot;&gt;ConversationSummaryBufferMemory&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;ConversationSummaryMemory&lt;/strong&gt;는 이전 대화 내용 그대로 기억하지 않고 요약해서 기억합니다. 요약은 LLM이 하기 때문에 Memory 생성시 LLM을 지정해줍니다. &lt;strong&gt;ConversationSummaryBufferMemory&lt;/strong&gt;는 ConversationSummaryMemory의 확장판이라고 볼 수 있습니다. 이전 대화를 요약해 기억하면서 최근 대화는 최대 토큰 범위 내에서 유지합니다. 이를 위해 최대 토큰 길이도 지정해줍니다. 코드에서는 ConversationSummaryBufferMemory를 사용하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.memory import &lt;strong&gt;ConversationSummaryBufferMemory&lt;/strong&gt;

schedule = &quot;내일 아침 8시에는 퓨리랑 미팅이 있습니다. \
어벤져스와 가디언즈 오브 갤럭시 팀의 관계에 대해 상의할 예정입니다. \
12시에는 페퍼와 점심식사가 있습니다. 치즈버거를 먹기로 했습니다. \
3시에는 해피와 스파이더맨 교육 계획 회의가 있습니다 \
5시에는 아크 원자로 개선 버전 공개 행사가 있습니다. \
간단한 소개 자료를 준비해 놓았습니다.&quot;

memory = &lt;strong&gt;ConversationSummaryBufferMemory&lt;/strong&gt;(&lt;strong&gt;llm&lt;/strong&gt;=llm, &lt;strong&gt;max_token_limit&lt;/strong&gt;=100)
memory.save_context({&quot;input&quot;: &quot;자비스&quot;}, {&quot;output&quot;: &quot;네, 말씀하세요.&quot;})
memory.save_context({&quot;input&quot;: &quot;자기 전에 확인할게 있어.&quot;},
                    {&quot;output&quot;: &quot;무엇을 확인해드릴까요?&quot;})
memory.save_context({&quot;input&quot;: &quot;내일 일정에 대해 알려줘.&quot;}, 
                    {&quot;output&quot;: f&quot;{schedule}&quot;})
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;System: The human asks the AI to check something before they go to bed. The AI asks what they would like to check. The human asks the AI to inform them about their schedule for tomorrow. The AI informs the human that they have a meeting with Fury at 8 am to discuss the relationship between the Avengers and the Guardians of the Galaxy teams. At 12 pm, they have a lunch with Pepper, where they will be having a cheeseburger. At 3 pm, they have a meeting with Happy and Spiderman to discuss educational plans. At 5 pm, there is a public event for the unveiling of an improved version of the Arc Reactor, and the AI has prepared a brief introduction material.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대화 내용을 요약해서 기억하는 것을 볼 수 있습니다. 대화를 이어가면 메모리 내용이 어떻게 달라지는가 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=True
)
conversation.predict(input=&quot;행사 전 4시에 닥터 스트레인지와 약속을 추가해줘.&quot;)
# 응답: &apos;행사 전 4시에 닥터 스트레인지와 약속을 추가했습니다.&apos;
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;System: The human asks the AI to check something before they go to bed. The AI asks what they would like to check. The human asks the AI to inform them about their schedule for tomorrow. The AI informs the human that they have a meeting with Fury at 8 am to discuss the relationship between the Avengers and the Guardians of the Galaxy teams. At 12 pm, they have a lunch with Pepper, where they will be having a cheeseburger. At 3 pm, they have a meeting with Happy and Spiderman to discuss educational plans. At 5 pm, there is a public event for the unveiling of an improved version of the Arc Reactor, and the AI has prepared a brief introduction material.\nHuman: 행사 전 4시에 닥터 스트레인지와 약속을 추가해줘.\nAI: 행사 전 4시에 닥터 스트레인지와 약속을 추가했습니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞의 내용은 요약되어 있지만 최근 대화는 그대로 들어가 있습니다. 대화를 더 이어가봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;conversation.predict(input=&quot;내일 행사 참석 인원은 100명 정도야.&quot;)
# 응답: &apos;내일 행사에는 약 100명 정도의 참석자가 있을 것으로 예상됩니다.&apos;
memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;System: The human asks the AI to check something before they go to bed. The AI asks what they would like to check. The human asks the AI to inform them about their schedule for tomorrow. The AI informs the human that they have a meeting with Fury at 8 am to discuss the relationship between the Avengers and the Guardians of the Galaxy teams. At 12 pm, they have a lunch with Pepper, where they will be having a cheeseburger. At 3 pm, they have a meeting with Happy and Spiderman to discuss educational plans. At 5 pm, there is a public event for the unveiling of an improved version of the Arc Reactor, and the AI has prepared a brief introduction material. The human requests to add a meeting with Doctor Strange at 4 pm before the event.\nAI: 행사 전 4시에 닥터 스트레인지와 약속을 추가했습니다.\nHuman: 내일 행사 참석 인원은 100명 정도야.\nAI: 내일 행사에는 약 100명 정도의 참석자가 있을 것으로 예상됩니다.&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 그대로 들어가 있던 대화의 일부가 요약에 포함된 것을 볼 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;conversation.predict(input=&quot;내일 원자로 소개할 때 뭐라고 시작할까?&quot;)
# 응답
&apos;내일 원자로 소개할 때, &quot;안녕하세요 여러분, 오늘 저희는 개선된 아크 리액터의 공개 행사에 참석하게 되어 매우 기쁩니다. 이번 개발은 이전 버전에 비해 더욱 효율적이고 안전한 에너지 공급을 제공합니다. 이 아크 리액터는 우리의 노력과 협력으로 만들어진 결과물이며, 앞으로의 미래에 대한 희망과 발전을 상징합니다. 이제부터 자세한 소개를 시작하도록 하겠습니다.&quot;라고 시작하시면 좋을 것 같습니다.&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;마지막 대화가 길었습니다.  토큰 수 제한이 있기 때문에 마지막에 주고 받은 대화가 길어지면 다음과 같이 마지막 대화까지 요약에 포함될 수도 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;memory.load_memory_variables({})

### 결과
{&apos;history&apos;: &apos;System: The human asks the AI to check their schedule for tomorrow. The AI informs the human that they have a meeting with Fury at 8 am, a lunch with Pepper at 12 pm, a meeting with Happy and Spiderman at 3 pm, and a public event for the unveiling of an improved version of the Arc Reactor at 5 pm. The human requests to add a meeting with Doctor Strange at 4 pm before the event. The AI adds the meeting to the schedule. The human mentions that there will be around 100 attendees at the event. The AI estimates that there will be about 100 attendees. The human asks for suggestions on how to start the introduction for the Arc Reactor unveiling. The AI suggests starting with &quot;Hello everyone, we are delighted to have you all here today for the unveiling of the improved Arc Reactor. This development provides more efficient and safe energy supply compared to the previous version. It is a result of our efforts and collaboration, symbolizing hope and progress for the future. Now, let\&apos;s begin with a detailed introduction.&quot;&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이전 대화 내용을 요약하는 메모리의 경우 요약을 위해 내부적으로 LLM 호출이 추가된다는 점을 기억합시다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;(추가) OpenAI Thread&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;2023년 11월 6일 OpenAI에서 새로운 API들을 발표했습니다. 그중 Assistants API의 Thread가 있는데, Thread에 Message를 추가하면 OpenAI 서버에 대화 내용을 저장해주고, 프롬프트에 이전 대화 내용을 넣는 과정도 알아서 진행해줍니다. 참고: &lt;a href=&quot;https://pkgpl.org/2023/11/08/openai-assistants-api로-대화-내용-저장하기/&quot;&gt;OpenAI Assistants API로 대화 내용 저장하기&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: LLMChain으로 PromptTemplate, LLM, OutputParser 연결하기</title><link>https://pkgpl.org/2023/09/21/langchain-llmchain/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/21/langchain-llmchain/</guid><pubDate>Thu, 21 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 LangChain의 거대 언어 모델 유형으로 &lt;a href=&quot;https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/&quot;&gt;문장 완성을 위한 LLMs와 대화를 위한 ChatModels&lt;/a&gt;가 있다는 것을 확인했습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;프롬프트 작성을 위한 PromptTemplate&lt;/a&gt;들도 봤고, &lt;a href=&quot;https://pkgpl.org/2023/09/20/langchain-outputparser/&quot;&gt;출력 형식 지정을 위한 OutputParser&lt;/a&gt;도 봤습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain의 Chain 기능은 여러 기능들을 연결해서(chain) 편리하게 이용할 수 있는 기능입니다. 이 기능을 이용하면 사용자의 입력을 받아 PromptTemplate을 이용해 프롬프트를 만들고 LLM에 전달한 후 OutputParser를 이용해 결과를 반환하는 하나의 Chain을 만들 수 있습니다. 필요하면 Chain들끼리 연결하는 것도 가능합니다. 여러 Chain들 중 가장 기본이 되는 Chain은 &lt;strong&gt;LLMChain&lt;/strong&gt;입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLMChain: PromptTemplate + LLM&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예제를 위해 먼저 LLM과 프롬프트 템플릿을 만들었습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate

llm = ChatOpenAI(temperature=0.9)

prompt = PromptTemplate(
    input_variables=[&quot;what&quot;],
    template=&quot;{what} 이름 세 개를 추천해줘.&quot;,
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 ChatOpenAI (gpt-3.5-turbo)를 사용했는데, 문장 완성 모델인 OpenAI (text-davinci-003)를 사용해도 됩니다. 여기서는 성능이 더 좋아서 ChatOpenAI를 선택했습니다. 이제 둘을 LLMChain으로 연결합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.&lt;strong&gt;chains&lt;/strong&gt; import &lt;strong&gt;LLMChain&lt;/strong&gt;
chain = &lt;strong&gt;LLMChain&lt;/strong&gt;(llm=llm, prompt=prompt)

print(chain.run(&quot;새로 만든 거대 언어 모델&quot;))

### 결과
1. GigaMinds
2. MegaLinguo
3. SuperVerse&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLMChain 실행 방법&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 LLMChain으로 &lt;code&gt;llm&lt;/code&gt;과 &lt;code&gt;prompt&lt;/code&gt;를 연결한 후 &lt;code&gt;chain.run&lt;/code&gt;으로 한 번에 실행할 수 있습니다. 참고로, chain을 실행하는 방법에는 여러 가지가 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.&lt;strong&gt;run&lt;/strong&gt;(&quot;새로 만든 거대 언어 모델&quot;)
chain.&lt;strong&gt;run&lt;/strong&gt;({&quot;what&quot;:&quot;새로 만든 거대 언어 모델&quot;})
chain.&lt;strong&gt;predict&lt;/strong&gt;(what=&quot;새로 만든 거대 언어 모델&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 세 가지 방법은 앞의 결과처럼 문자열을 반환합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;&lt;strong&gt;chain&lt;/strong&gt;(&quot;새로 만든 거대 언어 모델&quot;)

### 결과
{&apos;&lt;strong&gt;what&lt;/strong&gt;&apos;: &apos;새로 만든 거대 언어 모델&apos;,
 &apos;&lt;strong&gt;text&lt;/strong&gt;&apos;: &apos;1. 인지어 (CogniLang)\n2. 심대어 (MenteLingua)\n3. 우주어 (CosmoLexis)&apos;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 경우에는 딕셔너리를 반환했고, 결과는 ‘text’에 들어 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;input_list = [
    {&quot;what&quot;:&quot;새로 만든 거대 언어 모델&quot;},
    {&quot;what&quot;:&quot;새로 만든 그림 생성 AI&quot;}
]
chain.&lt;strong&gt;apply&lt;/strong&gt;(input_list)

### 결과
[{&apos;&lt;strong&gt;text&lt;/strong&gt;&apos;: &apos;1. &quot;Aether&quot;\n2. &quot;Luminex&quot;\n3. &quot;Omnilingua&quot;&apos;},
 {&apos;&lt;strong&gt;text&lt;/strong&gt;&apos;: &apos;1. PaintPal\n2. CreativeCanvas\n3. ArtGenius&apos;}]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;리스트를 만들어 입력했고, 결과를 담은 딕셔너리들의 리스트를 받았습니다. LLM으로 ChatOpenAI를 사용했지만, 기본적으로 LLMChain은 대화를 이어가는 기능이 아닙니다. 위에서 응답 결과는 input_list 내에 있는 각각의 질문에 대한 대답입니다. 대화를 위해서는 ConversationChain이 별도로 존재합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain.&lt;strong&gt;generate&lt;/strong&gt;(input_list)

### 결과
&lt;strong&gt;LLMResult&lt;/strong&gt;(
generations=[
[ChatGeneration(text=&apos;1. 바나나AI\n2. 루나\n3. 메가클라우드&apos;, generation_info={&apos;finish_reason&apos;: &apos;stop&apos;}, message=AIMessage(content=&apos;1. 바나나AI\n2. 루나\n3. 메가클라우드&apos;, additional_kwargs={}, example=False))], 
[ChatGeneration(text=&apos;1. CreARTist\n2. AImagination\n3. ArtiVision&apos;, generation_info={&apos;finish_reason&apos;: &apos;stop&apos;}, message=AIMessage(content=&apos;1. CreARTist\n2. AImagination\n3. ArtiVision&apos;, additional_kwargs={}, example=False))]
],
llm_output={&apos;token_usage&apos;: {&apos;prompt_tokens&apos;: 62, &apos;completion_tokens&apos;: 40, &apos;total_tokens&apos;: 102}, &apos;model_name&apos;: &apos;gpt-3.5-turbo&apos;}, 
run=[RunInfo(run_id=UUID(&apos;144c8d77-c1a6-48d3-a65a-983db734b6e9&apos;)), RunInfo(run_id=UUID(&apos;939a315a-b71c-48f1-9814-0abf6bfca23a&apos;))]
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;generate&lt;/code&gt;를 사용하면 LLMResult 객체를 반환하는데, 여기에는 토큰수와 같은 추가 정보가 들어가 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;PromptTemplate에 변수를 여러 개 넣는 것도 가능하죠.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;prompt = PromptTemplate(
    input_variables=[&quot;desc&quot;, &quot;what&quot;],
    template=&quot;{desc} {what} 이름 세 개를 추천해줘.&quot;,
)
chain2 = LLMChain(llm=llm, prompt=prompt)
print(chain2.run({
    &apos;desc&apos;: &quot;한국적인&quot;,
    &apos;what&apos;: &quot;거대 언어 모델&quot;
    }))&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;PromptTemplate 대신 ChatPromptTemplate을 사용하는 것도 가능합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
)
human_message_prompt = &lt;strong&gt;HumanMessagePromptTemplate&lt;/strong&gt;(
        prompt=PromptTemplate(
            template=&quot;{what} 이름 세 개를 추천해줘.&quot;,
            input_variables=[&quot;what&quot;],
        )
    )
chat_prompt_template = &lt;strong&gt;ChatPromptTemplate&lt;/strong&gt;.from_messages([human_message_prompt])
chat = ChatOpenAI(temperature=0.9)

chain = LLMChain(llm=chat, prompt=chat_prompt_template)
print(chain.run(&quot;새로 만든 거대 언어 모델&quot;))&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLMChain: PromptTemplate + LLM + OutputParser&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OutputParser도 chain으로 연결할 수 있습니다. 여기서는 CommaSeparatedListOutputParser를 사용하겠습니다. 문자열을 쉼표로 분리하여 리스트로 만들어주는 파서입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.&lt;strong&gt;output_parsers&lt;/strong&gt; import CommaSeparatedListOutputParser

output_parser=&lt;strong&gt;CommaSeparatedListOutputParser&lt;/strong&gt;()
prompt = PromptTemplate(
    input_variables=[&quot;what&quot;],
    template=&quot;{what} 이름 세 개를 추천해줘. \n{format_instructions}&quot;,
    &lt;strong&gt;partial_variables&lt;/strong&gt;={&quot;format_instructions&quot;: output_parser.get_format_instructions()}
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서 &lt;code&gt;partial_variables&lt;/code&gt;를 사용했는데, 이는 템플릿 안의 변수들 중 일부만 미리 치환할 수 있는 기능입니다. PromptTemplate에 &lt;code&gt;output_parser&lt;/code&gt;의 포맷 명령을 넣었는데, chain에 &lt;code&gt;output_parser&lt;/code&gt;를 안 넣고 실행해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain = LLMChain(llm=chat, prompt=prompt)
chain.predict(what=&quot;새로 만든 거대 언어 모델&quot;)

### 결과
&apos;GigaNLP, MegaLang, SuperGPT&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;프롬프트에 출력 포맷을 지정했기 때문에 결과가 쉼표로 구분되 나오기는 했는데, 문자열이 반환되어 나왔습니다. 이번에는 chain에 &lt;code&gt;output_parser&lt;/code&gt;를 추가해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;chain = LLMChain(llm=chat, prompt=prompt, &lt;strong&gt;output_parser&lt;/strong&gt;=output_parser)
chain.predict(what=&quot;새로 만든 거대 언어 모델&quot;)

### 결과
[&apos;GLOMO&apos;, &apos;MEGALINGUA&apos;, &apos;LEXICON3000&apos;]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과가 리스트로 나왔습니다! 이렇게 Chain을 이용하면 PromptTemplate과 LLM, OutputParser를 연결해 사용할 수 있습니다. Chain은 LangChain 이름에서 알 수 있는 것처럼 LangChain의 핵심 기능입니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: OutputParser로 LLM 출력 다루기</title><link>https://pkgpl.org/2023/09/20/langchain-outputparser/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/20/langchain-outputparser/</guid><pubDate>Wed, 20 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/19/chatgpt에서-json-출력하기/&quot;&gt;앞에서&lt;/a&gt; ChatGPT와 OpenAI API를 이용해 json 형식의 문자열을 출력하는 예제를 살펴봤습니다. LangChain에는 이렇게 원하는 형식의 출력을 얻을 수 있도록 OutputParser 기능을 제공합니다. 앞에서 봤던 예제를 OutputParser를 이용해 구현해보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;OutputParser&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain의 OutputParser에는 미리 만들어져있는 parser들도 있지만 여기서는 직접 만들어보겠습니다. 아래 예제에서 ResponseSchema는 특정 항목이 어떤 형식으로 출력되어야 하는지 지정하는데 사용하고, StructuredOutputParser는 전체 schema들을 모아 parser를 생성하는데 사용합니다. 여기서는 하나의 항목만 ‘output’이라는 이름으로 추출하려고 합니다. 이 항목의 내용은 &lt;code&gt;{&quot;사람 이름&quot;: &quot;영어 색깔 이름&quot;}&lt;/code&gt;의 json 형식(파이썬 딕셔너리)으로 만들고 싶습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.output_parsers import &lt;strong&gt;ResponseSchema&lt;/strong&gt;
from langchain.output_parsers import &lt;strong&gt;StructuredOutputParser&lt;/strong&gt;

schema = &lt;strong&gt;ResponseSchema&lt;/strong&gt;(name=&apos;&lt;strong&gt;output&lt;/strong&gt;&apos;, description=&quot;json object, key=name, value=color in English&quot;)

response_schemas = [schema]

output_parser = &lt;strong&gt;StructuredOutputParser&lt;/strong&gt;.&lt;strong&gt;from_response_schemas&lt;/strong&gt;(response_schemas)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 만든 &lt;code&gt;output_parser&lt;/code&gt;에서는 &lt;code&gt;&lt;strong&gt;get_format_instructions&lt;/strong&gt;&lt;/code&gt;라는 메소드와 &lt;code&gt;&lt;strong&gt;parse&lt;/strong&gt;&lt;/code&gt; 메소드를 지원합니다. &lt;code&gt;get_format_instructions&lt;/code&gt;는 출력 형식 지정 프롬프트를 만들어주는 메소드입니다. 형식 지정 프롬프트는 LLM에 보낼 전체 프롬프트에 포함시킵니다. &lt;code&gt;parse&lt;/code&gt; 메소드는 LLM의 출력이 문자열로 나오니 최종적으로 원하는 형식으로 바꿔주는 메소드입니다. &lt;code&gt;format_instructions&lt;/code&gt;를 확인해보죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;format_instructions: 출력 형식 지정 프롬프트&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;format_instructions = output_parser.get_format_instructions()
print(format_instructions)

### 출력
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing &quot;```json&quot; and &quot;```&quot;:

```json
{
	&quot;&amp;lt;strong&amp;gt;output&amp;lt;/strong&amp;gt;&quot;: string  // json object, key=name, value=color in English
}
```&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위와 같이 json 형식의 문자열을 포함한 마크다운 코드를 출력하라는 내용은 StructuredOutputParser에 미리 입력되어 있고, ResponseSchema에 적은 내용이 json 항목 설명으로 들어가게 됩니다. 그럼 전체 프롬프트를 만들어보죠.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts import ChatPromptTemplate

template=&quot;&quot;&quot;
주어진 text로부터 다음 정보를 추출하세요.

&quot;사람 이름&quot;: &quot;color in English&quot;

text: ```{text}```

{format_instructions}
&quot;&quot;&quot;

prompt = ChatPromptTemplate.from_template(template)

messages = prompt.format_messages(text=&quot;영희는 파란색을 좋아하고 영수는 분홍색을 좋아한다.&quot;,
format_instructions=format_instructions)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;최종 프롬프트 &lt;code&gt;messages&lt;/code&gt;의 내용은 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;[HumanMessage(content=&apos;\n주어진 text로부터 다음 정보를 추출하세요.\n\n&quot;사람 이름&quot;: &quot;color in English&quot;\n\ntext: ```영희는 파란색을 좋아하고 영수는 분홍색을 좋아한다.```\n\nThe output should be a markdown code snippet formatted in the following schema, including the leading and trailing &quot;```json&quot; and &quot;```&quot;:\n\n```json\n{\n\t&quot;output&quot;: string  // json object, key=name, value=color in English\n}\n```\n&apos;, additional_kwargs={}, example=False)]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 메시지를 LLM에 보내 응답을 받습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI(temperature=0.0, model=&apos;gpt-3.5-turbo&apos;)
response = chat(messages)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;response&lt;/code&gt;는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;AIMessage(content=&apos;```json\n{\n\t&quot;output&quot;: {\n\t\t&quot;영희&quot;: &quot;blue&quot;,\n\t\t&quot;영수&quot;: &quot;pink&quot;\n\t}\n}\n```&apos;, additional_kwargs={}, example=False)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;response.content&lt;/code&gt;는 문자열입니다. 최종적으로 원하는 결과를 얻기 위해 이 내용을 &lt;code&gt;output_parser&lt;/code&gt;에 전달합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;parser: 최종 결과 출력&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;output = output_parser.parse(response.content)

### 결과
{&apos;output&apos;: {&apos;영희&apos;: &apos;blue&apos;, &apos;영수&apos;: &apos;pink&apos;}}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그 결과로 딕셔너리를 얻었고, &lt;code&gt;output[&apos;output&apos;]&lt;/code&gt;에 원하는 결과를 얻었습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>ChatGPT에서 JSON 출력하기</title><link>https://pkgpl.org/2023/09/19/chatgpt%ec%97%90%ec%84%9c-json-%ec%b6%9c%eb%a0%a5%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/19/chatgpt%ec%97%90%ec%84%9c-json-%ec%b6%9c%eb%a0%a5%ed%95%98%ea%b8%b0/</guid><pubDate>Tue, 19 Sep 2023 14:43:01 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;ChatGPT에서의 프롬프트 엔지니어링&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ChatGPT에서 원하는 출력을 얻기 위해서는 &lt;a href=&quot;https://pkgpl.org/2023/08/22/시행착오를-통한-학습과-과학적-방법론/&quot;&gt;시행착오&lt;/a&gt;가 필요합니다. 원하는 출력을 얻는 프롬프트를 찾아내는 과정을 &lt;a href=&quot;https://pkgpl.org/2023/09/09/프롬프트-엔지니어링-좋은-프롬프트-작성하기/&quot;&gt;프롬프트 엔지니어링&lt;/a&gt;이라고 하죠. 문자열을 해석해서 컴퓨터에서 작업하기 좋도록 &lt;a href=&quot;https://pkgpl.org/2023/09/11/파이썬에서-json-파일-다루기/&quot;&gt;json 형식&lt;/a&gt;으로 만들고 싶습니다. 그래서 ChatGPT에게 다음과 같이 요청했습니다. &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;One-shot learning&lt;/a&gt;을 위한 예시도 넣었죠.&lt;/p&gt;



&lt;blockquote class=&quot;wp-block-quote is-layout-flow wp-block-quote-is-layout-flow&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;문자열에서 정보를 추출해서 json으로 바꿔줘. &lt;/strong&gt;&lt;br&gt;&lt;br&gt;## 예시 &lt;br&gt;“수연이는 파란색을 좋아하고, 철호는 빨간색을 좋아한다” =&amp;gt; {“수연”: “blue”,”철호”: “red”} &lt;br&gt;&lt;br&gt;## 입력 &lt;br&gt;“영희는 노란색을 좋아하고, 민수는 초록색을 좋아한다” =&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그랬더니 직접 json을 만들어주는 대신 json으로 변환하는 코드를 만들어 줬습니다.(결과는 물어볼 때마다 달라질 수 있습니다.)&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;입력된 문자열에서 정보를 추출하고 JSON 형식으로 바꾸려면 Python 프로그래밍 언어를 사용하여 다음과 같이 할 수 있습니다.

import re
import json

# 입력 문자열
input_string = &quot;영희는 노란색을 좋아하고, 민수는 초록색을 좋아한다&quot;

# 이름과 색상 정보 추출
name_color_pattern = r&apos;(\w+)는\s(\w+)색을\s좋아한다&apos;
matches = re.findall(name_color_pattern, input_string)

# 결과를 JSON 형식으로 변환
result = {name: color for name, color in matches}

# JSON 문자열로 변환
json_result = json.dumps(result, ensure_ascii=False)

print(json_result)


위 코드는 입력된 문자열에서 이름과 색상 정보를 추출하고 이를 JSON 형식으로 변환합니다. 코드를 실행하면 원하는 결과가 출력됩니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그러나 이 코드는 예시에서 보여준 것처럼 색깔을 영어로 만들지 못하죠. 그래서 “키는 이름, 값은 색깔을 영어로” 만들어 달라고 프롬프트에 추가했는데 앞에서와 비슷한 대답을 했습니다. 이번엔 코드를 작성하지 말고 직접 바꿔달라고 했습니다.&lt;/p&gt;



&lt;blockquote class=&quot;wp-block-quote is-layout-flow wp-block-quote-is-layout-flow&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;입력 문자열에서 정보를 추출해서 아래와 같이 json으로 바꿔줘. &lt;strong&gt;키는 이름, 값은 색깔을 영어로.&lt;/strong&gt; &lt;strong&gt;코드를 작성하지 말고 직접 바꿔서 결과를 보여줘.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;## 예시&lt;br&gt;“수연이는 파란색을 좋아하고, 철호는 빨간색을 좋아한다” =&amp;gt; {“수연”: “blue”,”철호”: “red”}&lt;br&gt;&lt;br&gt;## 입력&lt;br&gt;“영희는 노란색을 좋아하고, 민수는 초록색을 좋아한다” =&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그랬더니 아래와 같이 대답했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;입력 문자열을 파싱하여 아래와 같이 JSON 형식으로 변환합니다.

입력 문자열:
&quot;영희는 노란색을 좋아하고, 민수는 초록색을 좋아한다&quot;

JSON 결과:
{
&quot;영희&quot;: &quot;yellow&quot;,
&quot;민수&quot;: &quot;green&quot;
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;원하는 결과가 마지막에 나오긴 했지만 앞에 불필요한 설명이 들어가 있습니다. 그래서 다시 프롬프트를 수정했습니다.&lt;/p&gt;



&lt;blockquote class=&quot;wp-block-quote is-layout-flow wp-block-quote-is-layout-flow&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;당신은 json 변환기입니다. 보기처럼 문장을 입력 받으면 json 형식으로 출력하세요. 설명 없이 json만 출력하세요.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;## 보기&lt;br&gt;“수연이는 파란색을 좋아하고, 철호는 빨간색을 좋아한다” =&amp;gt; {“수연”: “blue”, “철호”: “red”}&lt;br&gt;&lt;br&gt;## 문장&lt;br&gt;“민수는 노란색을 좋아하고, 은정이는 분홍색을 좋아한다”&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 원하는 답이 나옵니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;{&quot;민수&quot;: &quot;yellow&quot;, &quot;은정이&quot;: &quot;pink&quot;}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;입력 문장을 바꿔가며 실행해봐도 결과가 잘 나옵니다. 몇 번 실행해봤을 때 결과가 잘 나왔으나 항상 잘 나온다는 보장은 없습니다. 응답이 확률적으로 나오므로 언제 부연 설명이 들어가게 될지 알 수 없죠. 앞에 설명이 들어가면 &lt;code&gt;{}&lt;/code&gt; 기호를 이용해 json 부분만 추출할 수도 있으나 결과가 항상 json 형식으로 나온다면 더 좋겠죠?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사실 json 출력은 ChatGPT에서 대화할 때 보다는 &lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;API&lt;/a&gt;를 사용할 때 더 유용합니다. LLM의 응답을 바로 파이썬에서 딕셔너리로 바꿔서 사용할 수 있기 때문이죠. 위의 프롬프트를 가지고 API를 사용할 수도 있지만, &lt;a href=&quot;https://pkgpl.org/2023/09/12/openai-api-function_call-사용하기/&quot;&gt;함수 호출 기능&lt;/a&gt;을 이용하면 더 확실하게 부연 설명 없는 json 결과물을 얻을 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;API에서 function_call을 이용해 json 출력하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI API 호출시 &lt;a href=&quot;https://pkgpl.org/?page_id=1725&quot;&gt;functions 인자&lt;/a&gt;를 이용해 함수 사용법을 알려줄 수 있습니다. LLM은 필요하다고 판단될 경우 응답의 function_call을 통해 호출할 함수 이름과 호출할 때 사용할 인자(arguments)를 알려줍니다. 이 때 인자를 json object 형식(파이썬 딕셔너리에 해당)으로 받아서 출력하면 됩니다. 이를 위해 사용할 functions 인자는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;functions = [
    {
        &quot;name&quot;: &quot;name_and_color&quot;,
        &quot;&lt;strong&gt;description&lt;/strong&gt;&quot;: &quot;&lt;strong&gt;사람 이름과 좋아하는 색깔의 영어 이름을 매칭시킴&lt;/strong&gt;&quot;,
        &quot;parameters&quot;: {
            &quot;type&quot;:&quot;object&quot;,
            &quot;properties&quot;: {
                &quot;match&quot;: {
                    &quot;&lt;strong&gt;type&lt;/strong&gt;&quot;: &quot;&lt;strong&gt;object&lt;/strong&gt;&quot;,
                    &quot;&lt;strong&gt;description&lt;/strong&gt;&quot;: &quot;&lt;strong&gt;key=name, value=color&lt;/strong&gt;&quot;
                }
            },
            &quot;required&quot;: [&quot;match&quot;]
        }
    }
]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 함수 이름은 중요하지 않습니다. 실제로는 존재하지 않는 함수입니다. 중요한 것은 함수 설명과 함수 인자 설명입니다. 함수 설명에는 우리의 목적에 대한 설명을 넣어서 LLM에서 호출해야 하는 함수로 판단할 수 있도록 합니다. 인자는 object 형식으로 만들고 인자 설명에 key는 사람 이름, value는 색깔을 넣도록 했습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;messages = [{&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
           {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;수연이는 파란색을 좋아하고 철호는 빨간색을 좋아한다.&quot;}]
response = openai.ChatCompletion.create(
    model=&quot;gpt-3.5-turbo&quot;,
    messages=messages,
    functions=functions
)
print(response[&quot;choices&quot;][0][&apos;message&apos;][&quot;function_call&quot;][&quot;arguments&quot;])

### 결과
{
  &quot;수연&quot;: &quot;blue&quot;,
  &quot;철호&quot;: &quot;red&quot;
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;원하는대로 json 문자열이 결과로 나왔습니다. 문장을 바꿔도 잘 나옵니다. 이제 부연 설명이 나올지 안 나올지 걱정할 필요가 없죠. &lt;a href=&quot;https://pkgpl.org/2023/09/11/파이썬에서-json-파일-다루기/&quot;&gt;json.loads&lt;/a&gt; 함수를 이용해 파이썬 딕셔너리로 바꿔서 사용하면 이후 과정을 편리하게 진행할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: FewShotPromptTemplate + ExampleSelector</title><link>https://pkgpl.org/2023/09/18/langchain-fewshotprompttemplate-exampleselector/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/18/langchain-fewshotprompttemplate-exampleselector/</guid><pubDate>Mon, 18 Sep 2023 12:29:39 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 &lt;a href=&quot;https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/&quot;&gt;LangChain&lt;/a&gt;의 &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;PromptTemplate과 ChatPromptTemplate&lt;/a&gt;에 대해 살펴봤습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/09/프롬프트-엔지니어링-좋은-프롬프트-작성하기/&quot;&gt;좋은 프롬프트를 만드는 방법&lt;/a&gt; 중 하나가 예시(one-shot, few-shot)를 주는 것이었죠? 이번에는 예시를 포함한 프롬프트를 만들기 위한 &lt;strong&gt;FewShotPromptTemplate&lt;/strong&gt;에 대해 살펴보겠습니다. 먼저 사용할 예시들을 보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Few-shot 예시 리스트&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;examples = [
    {
        &quot;question&quot;:&quot;선희는 빨강색을 좋아하고 영호는 노란색을 좋아한다.&quot;,
        &quot;answer&quot;:&apos;&quot;선희&quot;:&quot;빨강색&quot;, &quot;영호&quot;:&quot;노란색&quot;&apos;
    },
    {
        &quot;question&quot;:&quot;영철이는 탕수육을 좋아하고, 숙희는 깐풍기를 좋아한다.&quot;,
        &quot;answer&quot;:&apos;&quot;영철&quot;:&quot;탕수육&quot;,&quot;숙희&quot;:&quot;깐풍기&quot;&apos;
    },
    {
        &quot;question&quot;:&quot;한주는 국어를 좋아하고 영수는 수학을 좋아한다.&quot;,
        &quot;answer&quot;:&apos;&quot;한주&quot;:&quot;국어&quot;, &quot;영수&quot;:&quot;수학&quot;&apos;
    },
    {
        &quot;question&quot;:&quot;민지는 에너지자원공학과이고 민석이는 국어국문학과이다.&quot;,
        &quot;answer&quot;:&apos;&quot;민지&quot;:&quot;에너지자원공학과&quot;,&quot;민석&quot;:&quot;국어국문학과&quot;&apos;
    },
    {
        &quot;question&quot;:&quot;남주는 부산에 살고, 남식이는 서울에 산다.&quot;,
        &quot;answer&quot;:&apos;&quot;남주&quot;:&quot;부산&quot;, &quot;남식&quot;:&quot;서울&quot;&apos;
    }
]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 예시는 문장을 입력받아 사람:색깔, 사람:음식, 사람:과목, 사람:학과, 사람:도시 – 이런 형태로 바꿔주는 예시들입니다. 딕셔너리들의 리스트로 주어져있고, 프롬프트에 넣기 위해서는 문자열로 바꿔야겠죠? 문자열로 바꾸기 위해 &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;PromptTemplate&lt;/a&gt;를 이용하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts.prompt import PromptTemplate
example_prompt = &lt;strong&gt;PromptTemplate&lt;/strong&gt;(
    &lt;strong&gt;input_variables&lt;/strong&gt;=[&quot;question&quot;,&quot;answer&quot;],
    &lt;strong&gt;template&lt;/strong&gt;=&quot;Text: {question}\nParsed: {answer}&quot;
)
print(example_prompt.format(**examples[0]))

### 출력
Text: 선희는 빨강색을 좋아하고 영호는 노란색을 좋아한다.
Parsed: &quot;선희&quot;:&quot;빨강색&quot;, &quot;영호&quot;:&quot;노란색&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;확인을 위해 첫 번째 예시만 추출해서 Text와 Parsed를 앞에 붙이도록 포맷했습니다. 이제 예시를 포함한 실제 프롬프트를 만들어보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;FewShotPromptTemplate&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts.few_shot import FewShotPromptTemplate

prompt = &lt;strong&gt;FewShotPromptTemplate&lt;/strong&gt;(
    &lt;strong&gt;examples&lt;/strong&gt; = examples,
    &lt;strong&gt;example_prompt&lt;/strong&gt; = example_prompt,
    &lt;strong&gt;suffix&lt;/strong&gt; = &quot;Text: {input}\nParsed: &quot;,
    &lt;strong&gt;input_variables&lt;/strong&gt; = [&quot;input&quot;]
)

input_prompt = prompt.format(input=&quot;성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.&quot;)
print(input_prompt)

### 출력
Text: 선희는 빨강색을 좋아하고 영호는 노란색을 좋아한다.
Parsed: &quot;선희&quot;:&quot;빨강색&quot;, &quot;영호&quot;:&quot;노란색&quot;

Text: 영철이는 탕수육을 좋아하고, 숙희는 깐풍기를 좋아한다.
Parsed: &quot;영철&quot;:&quot;탕수육&quot;,&quot;숙희&quot;:&quot;깐풍기&quot;

Text: 한주는 국어를 좋아하고 영수는 수학을 좋아한다.
Parsed: &quot;한주&quot;:&quot;국어&quot;, &quot;영수&quot;:&quot;수학&quot;

Text: 민지는 에너지자원공학과이고 민석이는 국어국문학과이다.
Parsed: &quot;민지&quot;:&quot;에너지자원공학과&quot;,&quot;민석&quot;:&quot;국어국문학과&quot;

Text: 남주는 부산에 살고, 남식이는 서울에 산다.
Parsed: &quot;남주&quot;:&quot;부산&quot;, &quot;남식&quot;:&quot;서울&quot;

Text: 성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.
Parsed: &lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여기에 나온 프롬프트가 LLM에 전달할 메시지입니다. 전달해서 응답을 얻어봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.llms import OpenAI

llm = OpenAI(temperature=0.9)

response = llm.predict(input_prompt)
print(response)

### 결과
&lt;strong&gt;&quot;성훈&quot;:&quot;김치찌개&quot;, &quot;소영&quot;:&quot;파스타&quot;&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;원하는 결과가 잘 나왔습니다. 그런데, 예시가 많다보니 토큰 사용량이 많아지고 따라서 API 사용료가 많이 나오겠네요. 최종 질문과 유사한 예시 한 두 개만 남겨도 같은 결과를 얻을 수 있지 않을까요? 이 때 쓰는게 &lt;strong&gt;ExampleSelector&lt;/strong&gt;입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;ExampleSelector&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여러 개의 예시들중 질문과 비슷한 것만 실제 프롬프트에 넣으면 토큰 소모량을 줄일 수 있습니다. API 사용료도 줄일 수 있지만, &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;토큰 제한&lt;/a&gt;도 있으니 토큰 소모량을 줄일 수 있다면 줄이는게 좋습니다. ExampleSelector에도 여러 종류가 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;BaseExampleSelector: 상속 받아 사용자 정의 ExampleSelector를 만들 수 있습니다.&lt;/li&gt;



&lt;li&gt;LengthBasedExampleSelector: 지정 길이가 넘어가지 않도록 예시 개수를 조절합니다.&lt;/li&gt;



&lt;li&gt;MaxMarginalRelevanceExampleSelector: Maximal Marginal Relevance (MMR)을 이용해 질문과 가까우면서도 다양한 예시를 선택합니다.&lt;/li&gt;



&lt;li&gt;SemanticSimilarityExampleSelector: 벡터 임베딩의 &lt;a href=&quot;https://pkgpl.org/2023/09/15/openai-임베딩과-벡터-거리/&quot;&gt;코사인 유사도&lt;/a&gt;를 이용해 질문과 의미가 가까운 예시를 추출합니다.&lt;/li&gt;



&lt;li&gt;NGramOverlapExampleSelector: n-gram overlap score를 이용해 질문과 가까운 예시를 추출합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;SemanticSimilarityExampleSelector&lt;/strong&gt;를 사용해보겠습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/15/openai-임베딩과-벡터-거리/&quot;&gt;벡터 임베딩&lt;/a&gt;을 이용하기 때문에 임베딩 모델도 필요하고 임베딩 벡터를 저장하기 위한 &lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;도 필요합니다. 임베딩은 OpenAIEmbedding, 벡터 데이터베이스는 ChromaDB를 사용하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts.example_selector import &lt;strong&gt;SemanticSimilarityExampleSelector&lt;/strong&gt;
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

example_selector = &lt;strong&gt;SemanticSimilarityExampleSelector&lt;/strong&gt;.&lt;strong&gt;from_examples&lt;/strong&gt;(
    &lt;strong&gt;examples&lt;/strong&gt;,
    OpenAIEmbeddings(), # embedding
    Chroma, # VectorDB
    k=1, # number of examples
)

selected_examples = example_selector.&lt;strong&gt;select_examples&lt;/strong&gt;(
    {&quot;question&quot;: &quot;성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.&quot;}
)

### 결과 selected_examples
[{&apos;answer&apos;: &apos;&quot;영철&quot;:&quot;탕수육&quot;,&quot;숙희&quot;:&quot;깐풍기&quot;&apos;,
  &apos;question&apos;: &apos;영철이는 탕수육을 좋아하고, 숙희는 깐풍기를 좋아한다.&apos;}]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;SemanticSimilarityExampleSelector에서 선택할 예시 개수를 한 개로 지정했습니다(k=1). 질문으로 &lt;code&gt;&quot;성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.&quot;&lt;/code&gt;를 넣었더니 음식이 들어간 예시를 선택했습니다!&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;FewShotPromptTemplate + ExampleSelector&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 FewShotPromptTemplate과 ExampleSelector를 함께 사용해봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;prompt = FewShotPromptTemplate(
    &lt;strong&gt;example_selector&lt;/strong&gt; = example_selector,
    example_prompt = example_prompt,
    suffix = &quot;Text: {input}\nParsed: &quot;,
    input_variables = [&quot;input&quot;]
)

input_prompt = prompt.format(input=&quot;성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.&quot;)
print(input_prompt)

### 결과
Text: 영철이는 탕수육을 좋아하고, 숙희는 깐풍기를 좋아한다.
Parsed: &quot;영철&quot;:&quot;탕수육&quot;,&quot;숙희&quot;:&quot;깐풍기&quot;

Text: 성훈이는 김치찌개를 좋아하고 소영이는 파스타를 좋아한다.
Parsed: &lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;FewShotPromptTemplate의 인자에 examples 대신 example_selector를 사용했고, 질문과 유사한 예시를 포함한 프롬프트를 얻었습니다. 이번에는 다른 질문을 넣어볼까요?&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;input_prompt2 = prompt.format(input=&quot;영훈이는 영어를 좋아하고 수영이는 체육을 좋아한다.&quot;)
print(input_prompt2)

### 결과
Text: 한주는 국어를 좋아하고 영수는 수학을 좋아한다.
Parsed: &quot;한주&quot;:&quot;국어&quot;, &quot;영수&quot;:&quot;수학&quot;

Text: 영훈이는 영어를 좋아하고 수영이는 체육을 좋아한다.
Parsed: &lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;질문과 가장 가까운 예시가 잘 선택된 것을 볼 수 있습니다. LLM에 위의 프롬프트를 전달해서 원하는 결과가 나오는지 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = llm.predict(input_prompt)
print(response) # 결과 - &quot;성훈&quot;:&quot;김치찌개&quot;,&quot;소영&quot;:&quot;파스타&quot;

response = llm.predict(input_prompt2)
print(response) # 결과 - &quot;영훈&quot;:&quot;영어&quot;, &quot;수영&quot;:&quot;체육&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;각각 예시를 하나만 추출해서 One-shot learning을 수행했고, 원하는 결과가 잘 나왔습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: Prompt Template으로 프롬프트 다루기</title><link>https://pkgpl.org/2023/09/17/langchain-prompt-template/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/17/langchain-prompt-template/</guid><pubDate>Sun, 17 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;PromptTemplate&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain의 프롬프트 템플릿은 &lt;a href=&quot;https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/&quot;&gt;LLMs&lt;/a&gt;에 메시지를 전달하기 전에 문장 구성을 편리하게 만들어주는 기능입니다. 코드를 보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from &lt;strong&gt;langchain.prompts&lt;/strong&gt; import &lt;strong&gt;PromptTemplate&lt;/strong&gt;

prompt = PromptTemplate.&lt;strong&gt;from_template&lt;/strong&gt;(&quot;부산에 대해 알려줘.&quot;)
prompt.&lt;strong&gt;format&lt;/strong&gt;() # 결과: &quot;부산에 대해 알려줘.&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이게 다라면 그냥 문자열을 쓰는게 더 간편하겠죠? 포맷 기능을 봅시다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts import PromptTemplate

prompt = PromptTemplate.from_template(&quot;{&lt;strong&gt;city&lt;/strong&gt;}에 대해 알려줘.&quot;)
prompt.format(&lt;strong&gt;city&lt;/strong&gt;=&quot;부산&quot;) # 결과: &quot;부산에 대해 알려줘.&quot;

# 다른 방법
prompt = &lt;strong&gt;PromptTemplate&lt;/strong&gt;(&lt;strong&gt;input_variables&lt;/strong&gt;=[&quot;city&quot;],
                        &lt;strong&gt;template&lt;/strong&gt;=&quot;{city}에 대해 알려줘.&quot;)
prompt.format(&lt;strong&gt;city&lt;/strong&gt;=&quot;부산&quot;) # 결과: &quot;부산에 대해 알려줘.&quot;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사실 위의 포맷 기능도 파이썬 기본 문자열에서 지원하는 기능입니다. 그럼에도 불구하고 프롬프트 템플릿을 사용하면 코드 가독성, 일관성과 재사용성이 좋아지고, 에러를 방지할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;ChatPromptTemplate&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 본 PromptTemplate은 기본적으로 문장 완성 모델(Completion model: llms)을 위한 템플릿입니다. 챗모델(Chat completion model: chat_models)을 위한 템플릿은 ChatPromptTemplate입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts import (
    &lt;strong&gt;ChatPromptTemplate&lt;/strong&gt;,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

system_message_prompt = &lt;strong&gt;SystemMessagePromptTemplate&lt;/strong&gt;.from_template(
    &quot;당신은 {input_language}를 {output_language}로 번역하는 전문 번역가입니다.&quot;
)

human_message_prompt = &lt;strong&gt;HumanMessagePromptTemplate&lt;/strong&gt;.from_template(&quot;{text}&quot;)

chat_prompt = &lt;strong&gt;ChatPromptTemplate.from_messages&lt;/strong&gt;(
    &lt;strong&gt;[system_message_prompt, human_message_prompt]&lt;/strong&gt;
)

chat_prompt.&lt;strong&gt;format_messages&lt;/strong&gt;(&lt;strong&gt;input_language&lt;/strong&gt;=&quot;영어&quot;, &lt;strong&gt;output_language&lt;/strong&gt;=&quot;한국어&quot;, &lt;strong&gt;text&lt;/strong&gt;=&quot;I love programming.&quot;)

### 결과
[SystemMessage(content=&apos;당신은 영어를 한국어로 번역하는 전문 번역가입니다.&apos;, additional_kwargs={}),
 HumanMessage(content=&apos;I love programming.&apos;, additional_kwargs={}, example=False)]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;SystemMessagePromptTemplate과 HumanMessagePromptTemplate은 각각 시스템 메시지와 사용자 메시지를 만드는 템플릿입니다. ChatPromptTemplate은 위 코드에서와 같이 메시지들의 리스트를 입력으로 받습니다. 포맷할 때도 &lt;code&gt;format_messages&lt;/code&gt;를 사용하는데, 시스템 메시지의 변수인 &lt;code&gt;input_language&lt;/code&gt;와 &lt;code&gt;output_language&lt;/code&gt;, 사용자 메시지의 변수인 &lt;code&gt;text&lt;/code&gt;를 모두 치환할 수 있습니다. 위 코드는 아래와 같이 쓸 수도 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts import ChatPromptTemplate

chat_prompt = ChatPromptTemplate.from_messages(
    [(&quot;&lt;strong&gt;system&lt;/strong&gt;&quot;,&quot;당신은 {input_language}를 {output_language}로 번역하는 전문 번역가입니다.&quot;),
     (&quot;&lt;strong&gt;human&lt;/strong&gt;&quot;,&quot;{text}&quot;)]
)

chat_prompt.format_messages(input_language=&quot;영어&quot;, output_language=&quot;한국어&quot;, text=&quot;I love programming.&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;시스템 메시지와 사용자 메시지를 &lt;strong&gt;&lt;code&gt;(type, content)&lt;/code&gt; 튜플&lt;/strong&gt;로 만들어서 입력했습니다. 앞에서는 &lt;strong&gt;MessagePromptTemplate&lt;/strong&gt;를 사용했었죠. 그래도 결과는 동일합니다. 치환이 필요 없는 경우 &lt;strong&gt;BaseMessage&lt;/strong&gt; 객체(아래에서 SystemMessage)를 사용하는 것도 가능합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.prompts import ChatPromptTemplate
from langchain.prompts.chat import SystemMessage, HumanMessagePromptTemplate

template = ChatPromptTemplate.from_messages(
    [
        &lt;strong&gt;SystemMessage&lt;/strong&gt;(content=&quot;당신은 영어를 한국어로 번역하는 전문 번역가입니다.&quot;),
        HumanMessagePromptTemplate.from_template(&quot;{text}&quot;)
    ]
)

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI()
llm(template.format_messages(text=&apos;I love programming.&apos;))

### 결과
AIMessage(content=&apos;나는 프로그래밍을 사랑합니다.&apos;, additional_kwargs={}, example=False)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, 위 코드들에서 ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate은 langchain.prompts 또는 langchain.prompts.chat 모듈에서 import 가능합니다. 반면에 SystemMessage는 langchain.prompts.chat 모듈에서 import 해야 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;기타 프롬프트 템플릿, 메시지 프롬프트 템플릿과 메시지 클래스&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 다룬 프롬프트 템플릿 외에도 예제를 제시하기 위한 FewShotPromptTemplate, FewShotChatMessagePromptTemplate이 있고, 여러 개의 예제들 중 몇 개를 추출해서 넣을 수 있는 ExampleSelector들도 있습니다. StringPromptTemplate을 이용해 사용자 정의 프롬프트 템플릿을 만들 수도 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;MessagePromptTemplate에는 HumanMessagePromptTemplate 외에도 SystemMessagePromptTemplate과 AIMessagePromptTemplate이 있습니다. 다른 role을 지정하고 싶으면 ChatMessagePromptTemplate를 사용하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;BaseMessage에는 SystemMessage 외에도 HumanMessage, AIMessage, FunctionMessage도 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>LangChain: llms vs. chat_models</title><link>https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/16/langchain-llms-vs-chat_models/</guid><pubDate>Sat, 16 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;랭체인 LangChain&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LangChain은 다양한 LLM들을 공통된 인터페이스로 사용할 수 있도록 만든 파이썬/자바스크립트 패키지입니다. LLM 뿐 아니라 프롬프트 템플릿, 출력 파서, 외부 API 호출 기능도 지원하고, 각각의 기능들을 연결(chain)하는 기능도 제공합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;각 기능들의 이름은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;LLM&lt;/strong&gt; (Wrappers): 다양한 LLM의 표준 인터페이스를 제공합니다.&lt;/li&gt;



&lt;li&gt;Prompt Templates: LLM에게 전달할 메시지를 구성하기 쉽게 만들어줍니다.&lt;/li&gt;



&lt;li&gt;Output Parsers: LLM의 응답을 사용하기 쉽게 변환해줍니다.&lt;/li&gt;



&lt;li&gt;Indexes: LLM 응답 품질 향상을 위해 외부 정보를 가지고 올 때 사용합니다.&lt;/li&gt;



&lt;li&gt;LLMChain: 위의 구성 요소들을 연결합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;설치는 다음과 같이 합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pip install langchain&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;간단한 코드를 봅시다. OPENAI_API_KEY라는 &lt;a href=&quot;https://pkgpl.org/2023/09/13/환경-변수와-파이썬-dotenv/&quot;&gt;환경변수&lt;/a&gt;가 지정된 상태입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from &lt;strong&gt;langchain.llms&lt;/strong&gt; import OpenAI

llm = OpenAI(temperature=0.9)
response = &lt;strong&gt;llm.predict&lt;/strong&gt;(&quot;이순신은 누구지?&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLMs, ChatModels&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM에는 두 가지 유형이 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;LLMs: 문자열(하나의 메시지)을 입력받아 문자열을 반환하는 LLM&lt;/li&gt;



&lt;li&gt;ChatModels: 메시지 리스트를 입력받아 문자열을 반환하는 LLM&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 봤던 코드에서는 llms를 이용했죠? chat_models도 사용할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from &lt;strong&gt;langchain.chat_models&lt;/strong&gt; import ChatOpenAI

chat_model = ChatOpenAI()
response = chat_model.predict(&quot;이순신은 누구지?&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞의 코드랑 다를게 없네요. 같다면 llms와 chat_models를 따로 만들 이유가 없겠죠? 앞에서 LLM을 호출하기 위해 predict를 사용했는데, LLMs와 ChatModels 모두 두 가지 메서드가 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;predict: 문자열을 입력받아 문자열을 반환합니다.&lt;/li&gt;



&lt;li&gt;predict_messages: 메시지 리스트를 입력받아 하나의 메시지를 반환합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;predict_messages를 사용한 코드입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;from langchain.schema import HumanMessage

messages = [HumanMessage(content=&quot;이순신은 누구지?&quot;)]

llm.predict_messages(messages)
&lt;strong&gt;chat_model.predict_messages&lt;/strong&gt;(messages)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ChatModels의 입력인 ChatMessages에는 두 가지 필수 구성 요소가 있는데, OpenAI API에서 봤던 role과 content입니다. &lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;OpenAI API&lt;/a&gt;에서 role에는 “user”, “assistant”, “system”, “&lt;a href=&quot;https://pkgpl.org/2023/09/12/openai-api-function_call-사용하기/&quot;&gt;function&lt;/a&gt;“이 올 수 있었는데, LangChain에는 이에 해당하는 객체들이 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;HumanMessage: 사용자가 입력한 ChatMessage&lt;/li&gt;



&lt;li&gt;AIMessage: LLM 응답&lt;/li&gt;



&lt;li&gt;SystemMessage: 시스템 메시지&lt;/li&gt;



&lt;li&gt;FunctionMessage: 함수 호출 결과 메시지&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 외에 사용자가 역할을 별도로 지정할 수 있는 ChatMessage 클래스도 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;predict vs. predict_messages&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;잠깐, 앞에서 LLMs는 문자열을 입력받아 문자열을 반환한다고 했는데, predict_messages 메소드를 가지고 있고 이 메소드는 메시지 리스트를 입력받는다고요? ChatModels는 메시지 리스트를 입력받는다고 했는데, 문자열을 입력받는 predict 메소드가 있다고요? 네 그렇습니다. 작동은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;llm.predict&lt;/strong&gt;, chat_model.predict: 문자열을 입력받아 문자열 반환. chat_model의 경우 문자열을 입력받으면 하나의 메시지만 있는 리스트를 입력받은 것과 유사합니다.&lt;/li&gt;



&lt;li&gt;llm.predict_messages: 메시지의 리스트를 입력받는데, 리스트의 각 원소별로 LLM의 응답을 구합니다. 리스트의 메시지들은 &lt;strong&gt;서로 관련 없는 별개의 메시지&lt;/strong&gt;가 됩니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;chat_model.predict_messages&lt;/strong&gt;: 메시지의 리스트를 입력받는데, 리스트의 원소들은 &lt;strong&gt;연속된 대화&lt;/strong&gt;로 인식됩니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;따라서 일반적으로 &lt;strong&gt;llm.predict&lt;/strong&gt; 또는 &lt;strong&gt;chat_model.predict_messages&lt;/strong&gt;를 사용하는 것이 좋습니다. 이 때 predict는 문자열을 반환하지만 predict_messages는 AIMessage 객체를 반환합니다. 응답은 객체의 content 속성에 저장됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음 글에서는 &lt;a href=&quot;https://pkgpl.org/2023/09/17/langchain-prompt-template/&quot;&gt;프롬프트 템플릿&lt;/a&gt;에 대해 알아보겠습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI 임베딩과 벡터 거리</title><link>https://pkgpl.org/2023/09/15/openai-%ec%9e%84%eb%b2%a0%eb%94%a9%ea%b3%bc-%eb%b2%a1%ed%84%b0-%ea%b1%b0%eb%a6%ac/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/15/openai-%ec%9e%84%eb%b2%a0%eb%94%a9%ea%b3%bc-%eb%b2%a1%ed%84%b0-%ea%b1%b0%eb%a6%ac/</guid><pubDate>Fri, 15 Sep 2023 12:40:50 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;OpenAI 임베딩 모델&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;OpenAI API&lt;/a&gt;를 이용해 문자열을 &lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;임베딩 벡터&lt;/a&gt;로 변환해보겠습니다. 임베딩 모델에 몇 가지가 있지만 그 중 OpenAI에서 권장하는 &lt;strong&gt;text-embedding-ada-002 모델&lt;/strong&gt;을 사용하면 됩니다. &lt;a href=&quot;https://platform.openai.com/docs/guides/embeddings/what-are-embeddings&quot;&gt;모델 정보&lt;/a&gt;는 아래 표에 정리했습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;토크나이저&lt;/td&gt;&lt;td&gt;cl100k_base&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;최대 입력 토큰수&lt;/td&gt;&lt;td&gt;8192&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;출력 벡터 차원&lt;/td&gt;&lt;td&gt;1536&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;API 사용료&lt;/td&gt;&lt;td&gt;$0.0001/1K tokens&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;text-embedding-ada-002 모델&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파이썬 API&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;임베딩 계산을 위한 파이썬 코드는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os
import openai
openai.api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)

text = &quot;I love Python!&quot;

response = &lt;strong&gt;openai.Embedding.create&lt;/strong&gt;(
    input = text,
    model = &quot;text-embedding-ada-002&quot;
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과로 나오는 &lt;code&gt;response&lt;/code&gt;는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;{
  &quot;object&quot;: &quot;list&quot;,
  &quot;data&quot;: [
    {
      &quot;object&quot;: &quot;embedding&quot;,
      &quot;index&quot;: 0,
      &quot;embedding&quot;: [
        -0.0078111737966537476,
        -0.01599879004061222,
        -0.0008188456413336098,
        -0.03275046497583389,
        -0.01546101551502943,
        ...
        0.027292054146528244,
        -0.0034115067683160305,
        -0.005542438011616468,
        -0.006056685000658035,
        -0.03979530930519104
      ]
    }
  ],
  &quot;model&quot;: &quot;text-embedding-ada-002-v2&quot;,
  &quot;usage&quot;: {
    &quot;prompt_tokens&quot;: 4,
    &quot;total_tokens&quot;: 4
  }
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과 임베딩 벡터는 1536차원이기 때문에 중간은 생략했습니다. &lt;code&gt;response&lt;/code&gt;에서 임베딩 벡터만 추출하려면 다음과 같이 합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;embeddings = response[&apos;data&apos;][0][&apos;embedding&apos;]&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;벡터 거리와 의미 검색&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;텍스트를 임베딩 벡터로 변환하면 &lt;strong&gt;벡터들 사이의 거리&lt;/strong&gt;를 계산할 수 있게 됩니다. 두 임베딩 벡터의 거리가 가까우면 의미가 유사한 텍스트, 벡터의 거리가 멀먼 관련 없는 텍스트라고 할 수 있습니다. 따라서 텍스트 사이에 일치하는 단어가 없더라도 벡터 거리를 이용해 관련된 텍스트를 찾아낼 수 있죠. &lt;strong&gt;의미 검색&lt;/strong&gt;(Semantic Search)에서 사용하는 방법입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;코사인 유사도와 코사인 거리&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;벡터 사이의 거리를 계산하는 방법에는 여러 가지가 있는데, &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;LLM&lt;/a&gt;에서 많이 사용하는 방법은 &lt;strong&gt;코사인 유사도&lt;/strong&gt;(Cosine Similarity)를 이용하는 방법입니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;A&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;B&lt;/mi&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;A&lt;/mi&gt;&lt;mo&gt;⋅&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;∥&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;A&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;∥&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;∥&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;B&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;∥&lt;/mo&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S_C \left(\mathbf{A}, \mathbf{B} \right) = \frac{\mathbf{A} \cdot \mathbf{B}}{\lVert\mathbf{A}\rVert \lVert \mathbf{B} \rVert}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코사인 유사도는 두 벡터가 가까우면 1, 멀면 0이 됩니다. 거리를 재려면 가까운게 0, 먼게 1이 되도록 하는게 좋겠죠? &lt;strong&gt;코사인 거리&lt;/strong&gt;(Cosine Distance)는 다음과 같이 계산합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;D&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;A&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;B&lt;/mi&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/msub&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;A&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;bold&quot;&gt;B&lt;/mi&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;D_C \left( \mathbf{A},\mathbf{B}  \right) = 1- S_C \left( \mathbf{A},\mathbf{B}  \right)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;“&lt;strong&gt;I love Python!&lt;/strong&gt;“에서 한 단어씩만 바꾼 문장을 몇 개 만들어서 임베딩 벡터를 만들고, 원래 문장의 임베딩 벡터와 코사인 거리를 계산해보겠습니다. 사용할 문장들입니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;I love Python (느낌표 삭제)&lt;/li&gt;



&lt;li&gt;I like Python!&lt;/li&gt;



&lt;li&gt;I hate Python!&lt;/li&gt;



&lt;li&gt;I love JavaScript!&lt;/li&gt;



&lt;li&gt;I love you!&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음은 테스트에 사용한 함수들입니다. 먼저 임베딩 벡터를 한 번에 얻는 get_embedding 함수를 만들고 코사인 유사도와 코사인 거리를 계산하는 함수를 만들었습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import numpy as np
from numpy.linalg import norm

def get_embedding(text):
    response = openai.Embedding.create(
        input=text,
        model=&quot;text-embedding-ada-002&quot;
    )
    return np.array(response[&apos;data&apos;][0][&apos;embedding&apos;])

def cosine_similarity(a,b):
    return np.dot(a,b) / (norm(a)*norm(b))

def cosine_dist(a,b):
    return 1-cosine_similarity(a,b)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;테스트 코드입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;text_org = &quot;I love Python!&quot;
texts = [&quot;I love Python&quot;,
        &quot;I like Python!&quot;,
        &quot;I hate Python!&quot;,
        &quot;I love JavaScript!&quot;,
        &quot;I love you!&quot;]

# 임베딩 벡터 구하기
emb_org = get_embedding(text_org)
emb_comp = [get_embedding(t) for t in texts]

# 코사인 거리 계산
dist = [cosine_dist(emb_org, emb) for emb in emb_comp]

# 결과 출력
for t,d in zip(texts,dist):
    print(f&quot;{d:.4f}: {t}&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음은 출력된 결과입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;0.0235: I love Python
0.0164: I like Python!
0.0790: I hate Python!
0.0888: I love JavaScript!
0.1631: I love you!&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과를 관찰해 봅시다. 숫자는 옆에 있는 문장이 기준 문장 “&lt;strong&gt;I love Python!&lt;/strong&gt;“과 얼마나 가까운 문장인지 나타냅니다. 값이 작을수록 의미가 더 가깝죠.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;“I like Python!”이 “I love Python”보다 더 가깝습니다. love/like 차이보다 느낌표 유무의 차이가 더 크네요!&lt;/li&gt;



&lt;li&gt;hate는 당연히 like에 비해 love로부터의 거리가 멀죠. &lt;/li&gt;



&lt;li&gt;하지만 “I hate Python!”은 “I love JavaScript!” 보다는 가깝습니다. 좋던 싫던(정반대의 의미지만) 파이썬 선호도를 나타낸 문장들끼리는 JavaScript 선호도를 나타낸 문장보다 의미가 가깝네요.&lt;/li&gt;



&lt;li&gt;JavaScript가 Python은 아니지만 둘 다 프로그래밍 언어이기 때문에 “I love JavaScript!”는 “I love you!” 보다 의미가 훨씬 가깝습니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 텍스트를 임베딩 벡터로 만들면 벡터 사이의 거리를 이용해 의미가 가까운 정도를 정량적으로 계산할 수 있습니다. &lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;&lt;/strong&gt;를 이용하면 데이터베이스에 저장해놓은 수많은 임베딩 벡터들 중 기준이 되는 문장(query)과 거리가 가까운 벡터들을 빠르게 추출할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>OpenAI tiktoken을 이용한 토큰 수 계산하기</title><link>https://pkgpl.org/2023/09/14/openai-tiktoken%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%86%a0%ed%81%b0-%ec%88%98-%ea%b3%84%ec%82%b0%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/14/openai-tiktoken%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%86%a0%ed%81%b0-%ec%88%98-%ea%b3%84%ec%82%b0%ed%95%98%ea%b8%b0/</guid><pubDate>Thu, 14 Sep 2023 13:31:57 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;OpenAI API&lt;/a&gt;를 이용할 때 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;모델별로 최대 토큰 수&lt;/a&gt;가 정해져 있습니다. API를 호출하기 전에 토큰 수를 미리 알 수 있으면 좋겠죠? 파이썬에서 텍스트를 토큰으로 변환해주는 tiktoken 패키지를 이용하면 토큰 수를 알 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;tiktoken-설치&quot;&gt;tiktoken 설치&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;tiktoken은 pip를 이용해 설치할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pip install tiktoken&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;인코딩-방법-토크나이저-결정&quot;&gt;인코딩 방법(토크나이저) 결정&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI에 여러 종류의 &lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;토크나이저&lt;/a&gt;들이 있기 때문에 토큰화하기 전에 먼저 토크나이저를 지정해줍니다. 지정 방법에는 두 가지가 있는데, 토크나이저 이름을 이용하는 방법과 &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;LLM&lt;/a&gt; 이름을 이용하는 방법 중 하나를 선택해 사용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import &lt;strong&gt;tiktoken&lt;/strong&gt;

# 토크나이저 이름을 이용하는 방법
encoder = tiktoken.&lt;strong&gt;get_encoding&lt;/strong&gt;(&quot;cl100k_base&quot;)

# LLM 이름을 이용하는 방법
encoder = tiktoken.&lt;strong&gt;encoding_for_model&lt;/strong&gt;(&quot;gpt-3.5-turbo&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;인코딩&quot;&gt;인코딩&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;토크나이저를 정한 후에는 다음과 같이 텍스트를 인코딩(토큰화)할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;text = &quot;I love Python!&quot;

result = encoder.&lt;strong&gt;encode&lt;/strong&gt;(text)
print(result) # 결과: [40, 3021, 13325, 0]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;토큰 번호로 결과가 출력되네요. 토큰의 길이를 알고 싶다면 토큰 리스트의 길이를 이용하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;len(result) # 결과: 4&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;디코딩&quot;&gt;디코딩&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다시 텍스트로 변환하려면 &lt;code&gt;decode&lt;/code&gt;를 사용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;encoder.&lt;strong&gt;decode&lt;/strong&gt;(result) # 결과: &apos;I love Python!&apos;&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;처음 입력했던 텍스트가 반환되는 것을 볼 수 있습니다. 토큰별로 확인하고 싶다면 &lt;code&gt;decode_single_token_bytes&lt;/code&gt;를 사용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;[encoder.&lt;strong&gt;decode_single_token_bytes&lt;/strong&gt;(token) for token in result]
# 결과: [b&apos;I&apos;, b&apos; love&apos;, b&apos; Python&apos;, b&apos;!&apos;]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 결과에서 작은 따옴표 앞에 붙은 &lt;code&gt;b&lt;/code&gt;는 &lt;code&gt;bytes&lt;/code&gt; 자료형을 의미합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;한글-인코딩-디코딩&quot;&gt;한글 인코딩/디코딩&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번에는 한글을 토큰화해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;text2 = &quot;나는 파이썬이 좋아요!&quot;

result2 = encoder.encode(text2)
print(result2) 
# 결과: [61415, 16969, 56069, 13094, 168, 235, 105, 13094, 66799, 233, 54059, 36811, 0]

print(len(result2)) # 결과: 13&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;한글 문장과 영어 문장의 단어수는 같은데 한글의 토큰 수가 훨씬 많은 것을 볼 수 있습니다. 토큰 수가 많아지면 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;OpenAI API 사용료&lt;/a&gt;도 증가하게 됩니다. 디코딩 결과는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;encoder.decode(result2) # &apos;나는 파이썬이 좋아요!&apos;

[encoding.decode_single_token_bytes(token) for token in result2]
# 결과: [b&apos;\xeb\x82\x98&apos;, b&apos;\xeb\x8a\x94&apos;, b&apos; \xed\x8c\x8c&apos;, b&apos;\xec\x9d\xb4&apos;, b&apos;\xec&apos;, b&apos;\x8d&apos;, b&apos;\xac&apos;, b&apos;\xec\x9d\xb4&apos;, b&apos; \xec\xa2&apos;, b&apos;\x8b&apos;, b&apos;\xec\x95\x84&apos;, b&apos;\xec\x9a\x94&apos;, b&apos;!&apos;]&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>환경 변수와 파이썬 dotenv</title><link>https://pkgpl.org/2023/09/13/%ed%99%98%ea%b2%bd-%eb%b3%80%ec%88%98%ec%99%80-%ed%8c%8c%ec%9d%b4%ec%8d%ac-dotenv/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/13/%ed%99%98%ea%b2%bd-%eb%b3%80%ec%88%98%ec%99%80-%ed%8c%8c%ec%9d%b4%ec%8d%ac-dotenv/</guid><pubDate>Wed, 13 Sep 2023 13:44:45 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;환경 변수 Environment Variables&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;환경 변수는 컴퓨터 운영체제 또는 쉘 차원에서 관리하는 변수로, 환경 변수를 이용하면 서로 다른 프로세스 간에 변수를 공유할 수 있습니다. 환경 변수는 언어, 시간대 같은 시스템 설정, 프로그램의 동작을 변경하는 설정, API 키, 프로그램 경로 등 다양한 목적으로 사용할 수 있습니다. 윈도우즈 운영체제에서는 환경 변수 설정 메뉴를 이용해, 리눅스나 맥OS에서는 쉘에서 export 명령을 이용해 설정할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파이썬에서 환경 변수 다루기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;파이썬에서는 &lt;strong&gt;&lt;code&gt;os&lt;/code&gt; 모듈&lt;/strong&gt;의 &lt;code&gt;environ&lt;/code&gt; 또는 &lt;code&gt;getenv&lt;/code&gt;를 사용해 환경 변수에 접근할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os

# 읽기
val = os.environ[&quot;MY_VARIABLE&quot;]
val = os.environ.get(&quot;MY_VARIABLE&quot;)
val = os.getenv(&quot;MY_VARIABLE&quot;)

# 쓰기
os.environ[&quot;MY_VARIABLE&quot;] = val&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;&lt;strong&gt;os.environ&lt;/strong&gt;&lt;/code&gt;을 이용하면 환경 변수를 딕셔너리처럼 다룰 수 있습니다. 존재하지 않는 환경 변수에 접근하려고 하면 에러가 발생합니다. 이 때 &lt;code&gt;get&lt;/code&gt; 메소드를 이용하면 변수가 존재하지 않을 때 사용할 default 값을 지정해줄 수 있습니다. 별도로 default 값을 지정하지 않으면 환경 변수가 존재하지 않을 때 &lt;code&gt;None&lt;/code&gt;을 반환합니다. &lt;code&gt;&lt;strong&gt;os.getenv&lt;/strong&gt;&lt;/code&gt;는 &lt;code&gt;os.environ.get&lt;/code&gt;과 동일하게 동작합니다. 보통 좀 더 간결한 &lt;code&gt;os.getenv&lt;/code&gt;를 사용합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;os.environ&lt;/code&gt;을 이용해 설정한 환경 변수는 현재 실행 중인 프로세스에만 영향을 미치고, 시스템 전체 환경 변수를 변경하지는 않습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Colab에서 환경 변수&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;API 키&lt;/strong&gt;와 같은 비밀번호의 경우 코드 내에 저장하는 것은 보안 문제로 인해 보통 추천하지 않습니다. API 키는 환경 변수에 저장하고 사용하는 것이 좋습니다. 하지만, Colab과 같이 직접 환경 변수를 지정하기 어려운 상황도 있습니다. 이런 경우에는 환경 변수에 저장하는 대신 설정 파일에 API 키를 저장해놓고 코드에서 읽어서 쓸 수 있습니다. 파이썬에는 ini, cfg와 같은 &lt;strong&gt;설정 파일&lt;/strong&gt;을 다루는 configparser 모듈이 있습니다. YAML, TOML이나 &lt;a href=&quot;https://pkgpl.org/2023/09/11/파이썬에서-json-파일-다루기/&quot;&gt;JSON&lt;/a&gt; 파일을 설정 파일로 쓰는 경우도 있습니다. 아래 살펴볼 &lt;code&gt;dotenv&lt;/code&gt; 패키지는 설정 파일에서 읽어들인 값을 환경 변수처럼 이용할 수 있도록 만드는 패키지입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;dotenv 패키지&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://github.com/theskumar/python-dotenv&quot;&gt;dotenv&lt;/a&gt; 패키지는 다음과 같이 설치할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pip install python-dotenv&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Colab 노트북에서 설치하려면 위의 명령 앞에 느낌표(&lt;code&gt;!&lt;/code&gt;)를 붙이면 됩니다. 기본 설정 파일은 &lt;code&gt;&lt;strong&gt;.env&lt;/strong&gt;&lt;/code&gt; 파일입니다. 파일 내용은 다음과 같이 적습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;TEMPERATURE=0.8
OPENAI_API_KEY=sk-my-key&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 변수들은 같은 디렉토리에서 다음의 코드로 읽어들일 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os
&lt;strong&gt;from dotenv import load_dotenv
load_dotenv()&lt;/strong&gt;

temperature = float(os.getenv(&quot;TEMPERATURE&quot;))
openai_api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;만약 &lt;code&gt;.env&lt;/code&gt; 파일이 다른 경로에 있다면 &lt;code&gt;load_dotenv(dotenv_path=&quot;/path/to/dotenv&quot;)&lt;/code&gt;와 같이 절대 또는 상대 경로를 넣어주면 됩니다. 이미 동일한 이름의 시스템 환경 변수가 존재하는 경우 .env 파일에 적은 환경 변수는 무시되는데, 시스템 환경 변수를 덮어쓰고 싶으면 &lt;code&gt;override=True&lt;/code&gt; 옵션을 주면 됩니다. 단순히 API 키나 변수를 읽어들이는 경우 위의 코드로 충분합니다. 다른 기능이 필요할 경우 &lt;a href=&quot;https://saurabh-kumar.com/python-dotenv/reference/&quot;&gt;여기&lt;/a&gt;에서 &lt;code&gt;load_dotenv&lt;/code&gt; 함수의 다른 인자와 패키지 내의 다른 함수 설명을 찾을 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, &lt;code&gt;dotenv&lt;/code&gt;로 읽어들인 환경 변수는 모두 문자열(&lt;code&gt;str&lt;/code&gt;) 자료형이 됩니다. 따라서 필요할 경우 적절히 형변환을 해서 사용해야 합니다. 불리언 값의 경우 &lt;code&gt;.env&lt;/code&gt; 파일에 적은 TRUE, FALSE 값은 파이썬 문자열로 변환된 후 &lt;code&gt;bool(&quot;FALSE&quot;)&lt;/code&gt;와 같이 쓰면 모두 &lt;code&gt;True&lt;/code&gt; 값이 되니 주의해야 합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>OpenAI API function_call 사용하기</title><link>https://pkgpl.org/2023/09/12/openai-api-function_call-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/12/openai-api-function_call-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</guid><pubDate>Tue, 12 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;OpenAI API&lt;/a&gt;를 이용할 때 &lt;code&gt;ChatCompletion.create&lt;/code&gt; 함수에 &lt;code&gt;&lt;strong&gt;functions&lt;/strong&gt;&lt;/code&gt;라는 인자(argument)가 있습니다. LLM에게 사용할 수 있는 함수 정보를 알려줄 때 사용합니다. 이를 이용하면 LLM이 질문에 응답하기 위해 함수 호출이 필요할 경우 함수를 호출해달라는 출력(&lt;strong&gt;function_call&lt;/strong&gt;)을 내놓습니다. 실제 호출은 파이썬 프로그램에서 하고 LLM은 어떤 함수를 어떤 인자들을 사용해 호출해야 하는지 알려주는 것이죠. 사용자는 함수 호출 결과를 기존 질문과 함께 다시 LLM에 전달하고 LLM은 결과를 바탕으로 질문에 응답합니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-10.png&quot; href=&quot;https://pkgpl.org/media/wp-757c659ac95bcafb.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;512&quot; src=&quot;https://pkgpl.org/media/wp-757c659ac95bcafb.png&quot; alt=&quot;&quot; class=&quot;wp-image-1746&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예제: Wikipedia 함수&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저, LLM이 호출할 수 있는 함수를 하나 만들어보겠습니다. 검색 문자열을 받아 Wikipedia를 검색하고 첫 번째로 검색된 페이지의 내용을 반환하는 함수입니다. 페이지 내용은 다시 LLM에 보내 LLM이 답변하는데 참고할 수 있도록 합니다. 이를 위해 파이썬 &lt;a href=&quot;https://github.com/goldsmith/Wikipedia&quot;&gt;wikipedia 패키지&lt;/a&gt;를 설치하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pip install wikipedia&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt; 패키지를 설치했으면 파이썬에서 다음과 같이 사용할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import wikipedia
wikipedia.set_lang(&quot;en&quot;)
r = wikipedia.search(&quot;Large language model&quot;)
print(r)

## 출력 결과
[&apos;Large language model&apos;,
 &apos;Language model&apos;,
 &apos;BERT (language model)&apos;,
 &apos;BLOOM (language model)&apos;,
 &apos;LLaMA&apos;,
 &apos;Prompt engineering&apos;,
 &apos;Modeling language&apos;,
 &apos;Generative pre-trained transformer&apos;,
 &apos;Transformer (machine learning model)&apos;,
 &apos;GPT-3&apos;]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;한글 검색을 위해서는 언어를 한글로 바꾼 후 검색하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;wikipedia.set_lang(&quot;ko&quot;)
r = wikipedia.search(&quot;광안대교 정식 개통일&quot;)
print(r)

## 출력 결과
[&apos;광안대교&apos;,
 &apos;수영강변대로&apos;,
 &apos;남항대교&apos;,
 &apos;인천대교&apos;,
 &apos;해운대&apos;,
 &apos;세토 대교&apos;,
 &apos;만덕대로&apos;,
 &apos;교량&apos;,
 &apos;부산광역시&apos;,
 &apos;남구 (부산광역시)&apos;]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 결과들을 보면, 검색 결과는 검색 관련 내용이 있는 Wikipedia 페이지 제목 10개입니다. 페이지의 내용은 다음과 같이 받아올 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;p = wikipedia.page(r[0])
print(p.content)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 내용을 종합해서 다음과 같은 함수를 만들었습니다. 검색 내용과 언어를 입력받으면 Wikipedia를 검색해서 가장 먼저 나오는 페이지의 내용을 반환하는 함수입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;def search_wikipedia(query, lang):
    wikipedia.set_lang(lang)
    r = wikipedia.search(query, results=1)
    p = wikipedia.page(r[0])
    return p.content&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 함수가 LLM에서 사용할 함수입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;입력: functions&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;함수 사용법을 LLM에게 알려줄 때는 아래와 같은 형식으로 알려줍니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;functions = [
    {
        &quot;name&quot;: &quot;&lt;strong&gt;search_wikipedia&lt;/strong&gt;&quot;,
        &quot;description&quot;: &quot;wikipedia 검색&quot;,
        &quot;parameters&quot;: {
            &quot;type&quot;:&quot;object&quot;,
            &quot;properties&quot;: {
                &quot;&lt;strong&gt;query&lt;/strong&gt;&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;description&quot;: &quot;검색할 내용&quot;
                },
                &quot;&lt;strong&gt;lang&lt;/strong&gt;&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;enum&quot;: [&quot;en&quot;,&quot;ko&quot;],
                    &quot;description&quot;: &quot;wikipedia 언어&quot;
                }
            },
            &quot;required&quot;: [&quot;query&quot;,&quot;lang&quot;]
        }
    }
]&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여기서는 하나의 함수, 두 개의 인자를 사용했는데, 함수가 여러 개 있으면 &lt;code&gt;functions&lt;/code&gt; 리스트에 같은형식으로 추가하면 됩니다. 함수 정의 부분을 살펴보면, name에 함수 이름이 들어가고, description 부분에 함수 설명이 들어갑니다. parameters – properties에 인자 설명이 들어가는데, 입력 자료형은 type으로 지정해주고, 설명은 description에 들어가게 됩니다. 선택 가능한 경우가 정해져 있으면 enum으로 지정해주면 됩니다. 필수 인자는 required로 지정해줍니다. 위 내용을 추가해서 OpenAI API를 호출해보겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os
import openai
openai.api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)

messages = [{&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
           {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;&lt;strong&gt;광안대교 정식 개통일이 언제야?&lt;/strong&gt;&quot;}]

response = openai.ChatCompletion.create(
    model=&quot;gpt-3.5-turbo&quot;,
    messages=messages,
    functions=functions
)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;출력: function_call&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;광안대교 정식 개통일이 언제인지 질문했죠. 참고로, 제가 ChatGPT에게 같은 질문을 했을 때는 틀린 답을 내놓았습니다. LLM은 질문을 바탕으로 주어진 함수 호출이 필요한지 아닌지 판단합니다. 함수 호출이 필요하다면 &lt;code&gt;response[&apos;choices&apos;][0][&apos;message&apos;]&lt;/code&gt; 내에 &lt;code&gt;function_call&lt;/code&gt; 항목이 생기고, 필요 없다면 이 항목이 생기지 않습니다. 따라서 함수를 실제로 호출할 것인지는 &lt;code&gt;function_call&lt;/code&gt;이 존재하는지 여부로 판단할 수 있습니다. 위 코드의 실행 결과로 얻은 &lt;code&gt;response&lt;/code&gt;는 다음과 같습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# 생략
  &quot;model&quot;: &quot;gpt-3.5-turbo-0613&quot;,
  &quot;choices&quot;: [
    {
      &quot;index&quot;: 0,
      &quot;message&quot;: {
        &quot;role&quot;: &quot;assistant&quot;,
        &quot;content&quot;: null,
        &quot;&lt;strong&gt;function_call&lt;/strong&gt;&quot;: {
          &quot;&lt;strong&gt;name&lt;/strong&gt;&quot;: &quot;&lt;strong&gt;search_wikipedia&lt;/strong&gt;&quot;,
          &quot;&lt;strong&gt;arguments&lt;/strong&gt;&quot;: &quot;{\n\&quot;&lt;strong&gt;query&lt;/strong&gt;\&quot;: \&quot;\uad11\uc548\ub300\uad50 \uac1c\ud1b5\uc77c\&quot;,\n\&quot;&lt;strong&gt;lang&lt;/strong&gt;\&quot;: \&quot;ko\&quot;\n}&quot;
        }
      },
      &quot;finish_reason&quot;: &quot;function_call&quot;
    }
  ],
# 생략&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;function_call&lt;/code&gt;이 존재하고, 호출할 함수의 이름과 인자 정보가 있는 것을 알 수 있습니다. 참고로, &lt;code&gt;query&lt;/code&gt; 부분이 알아보기 어렵게 나오는데, json 인코딩 때문에 그렇습니다. &lt;code&gt;\n&lt;/code&gt;은 개행, &lt;code&gt;\&quot;&lt;/code&gt;는 큰 따옴표로 감싼 문자열 안에 큰 따옴표 문자를 넣기 위한 표시죠. &lt;code&gt;print&lt;/code&gt; 해보면 한글이 제대로 나옵니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;print(response[&quot;choices&quot;][0][&apos;message&apos;][&quot;function_call&quot;][&quot;arguments&quot;])

## 아래는 출력 결과
{
    &quot;query&quot;: &quot;광안대교 개통일&quot;,
    &quot;lang&quot;: &quot;ko&quot;
}&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;실제 함수 호출&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 정보를 이용해 함수를 호출하고 그 결과를 다시 LLM에게 전달해주면 됩니다. 함수 호출을 위해서는 아래 함수를 이용하겠습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import json

def execute_function_call(msg):
    function_name = msg[&quot;function_call&quot;][&quot;name&quot;]
    args = json.loads(msg[&apos;function_call&apos;][&quot;arguments&quot;])
    if function_name == &quot;search_wikipedia&quot;:
        results = search_wikipedia(**args)
        return results&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;response[&quot;choices&quot;][0][&apos;message&apos;][&quot;function_call&quot;][&quot;arguments&quot;]&lt;/code&gt;에 있는 인자는 문자열로 되어 있으므로 dictionary로 바꾸기 위해 &lt;code&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/11/파이썬에서-json-파일-다루기/&quot;&gt;json.loads&lt;/a&gt;&lt;/code&gt;를 이용했고, 읽어들인 &lt;code&gt;args&lt;/code&gt;를 &lt;code&gt;search_wikipedia&lt;/code&gt;함수의 keyword arguments로 넘겼습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;함수 호출 결과를 LLM에 전달하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 함수를 실행해 얻은 결과는 LLM에 보내는 &lt;code&gt;messages&lt;/code&gt;에 추가한 후 OpenAI API를 다시 호출합니다. 이 때 &lt;code&gt;role&lt;/code&gt;에는 &lt;code&gt;function&lt;/code&gt;이 들어가고, 기존에 없던 &lt;code&gt;name&lt;/code&gt;에 호출한 함수 이름, &lt;code&gt;content&lt;/code&gt;에 함수의 결과가 들어갑니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;msg = response[&quot;choices&quot;][0][&quot;message&quot;]
content = execute_function_call(msg)
messages.append(
    {
        &quot;&lt;strong&gt;role&lt;/strong&gt;&quot;:&quot;&lt;strong&gt;function&lt;/strong&gt;&quot;,
        &quot;&lt;strong&gt;name&lt;/strong&gt;&quot;:&quot;search_wikipedia&quot;,
        &quot;&lt;strong&gt;content&lt;/strong&gt;&quot;:content
    }
)

response = openai.ChatCompletion.create(
    model=&quot;gpt-3.5-turbo&quot;,
    messages=messages,
    functions=functions
)
print(response[&quot;choices&quot;][0][&quot;message&quot;][&quot;content&quot;])

## 출력 결과
광안대교의 정식 개통일은 2003년 1월 6일입니다.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 맞는 답을 얻었습니다. 참고로, wikipedia 페이지 중에는 길이가 긴 것들도 있으므로 페이지 내용을 전달할 때 &lt;code&gt;content&lt;/code&gt;를 모두 전달하면 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;token 수 제한&lt;/a&gt;에 걸릴 수 있습니다. &lt;code&gt;functions&lt;/code&gt;에 들어가는 함수 설명은 system 메시지에 들어가 token 수를 차지하므로 너무 많은 함수를 넣으면 역시 token 수 제한에 걸릴 수 있습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/&quot;&gt;Retrieval Augmented Generation&lt;/a&gt;에서처럼 페이지 내용을 &lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;임베딩 벡터&lt;/a&gt;로 만들고 &lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 검색&lt;/a&gt;을 이용해 질문과 관련된 내용만 추출하면 token 수를 줄일 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>파이썬에서 json 파일 다루기</title><link>https://pkgpl.org/2023/09/11/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%97%90%ec%84%9c-json-%ed%8c%8c%ec%9d%bc-%eb%8b%a4%eb%a3%a8%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/11/%ed%8c%8c%ec%9d%b4%ec%8d%ac%ec%97%90%ec%84%9c-json-%ed%8c%8c%ec%9d%bc-%eb%8b%a4%eb%a3%a8%ea%b8%b0/</guid><pubDate>Mon, 11 Sep 2023 12:52:31 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;JSON 형식&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;JSON (JavaScript Object Notation) 파일은 인터넷에서 서버와 클라이언트 사이 통신에 많이 사용하는 텍스트 표기 형식입니다. &lt;a href=&quot;https://pkgpl.org/2023/09/05/restful-api/&quot;&gt;REST API&lt;/a&gt;에서도 많이 사용하고, 설정 파일로 사용하기도 하죠. 다음과 같이 사람과 컴퓨터가 읽을 수 있는 텍스트 형식입니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;{
    &quot;key&quot;: &quot;value&quot;,
    &quot;list&quot;: [
        {&quot;str&quot;: &quot;text string&quot;},
        {
            &quot;number&quot;: {&quot;int&quot;: 1234, &quot;float&quot;: 12.34}
        },
        {&quot;True&quot;: true},
        {&quot;False&quot;: false},
        {&quot;None&quot;: null}
    ]
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;JSON에는 &lt;code&gt;{ }&lt;/code&gt;로 표기하는 &lt;strong&gt;객체&lt;/strong&gt;(object), &lt;code&gt;[ ]&lt;/code&gt;로 표기하는 &lt;strong&gt;배열&lt;/strong&gt;(array), 큰 따옴표로 감싸는 &lt;strong&gt;문자열&lt;/strong&gt;(string), &lt;strong&gt;숫자&lt;/strong&gt;(number), &lt;strong&gt;불리언&lt;/strong&gt;(boolean), &lt;strong&gt;null&lt;/strong&gt; 자료형이 있습니다. 객체는 키와 값으로 이루어지는데, 키는 문자열이고, 값은 위의 6가지 자료형 중 하나가 될 수 있습니다. 객체 안에 객체를 넣는 것도 가능합니다. 배열에도 여러 자료형들이 함께 들어갈 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파이썬에서 JSON 읽기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;파이썬에서 JSON 파일을 읽으려면 다음과 같이 &lt;a href=&quot;https://docs.python.org/ko/3/library/json.html&quot;&gt;json 모듈&lt;/a&gt;의 &lt;code&gt;&lt;strong&gt;load&lt;/strong&gt;&lt;/code&gt; 함수를 사용하면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import json
with open(&apos;data.json&apos;) as fj:
    data = &lt;strong&gt;json.load&lt;/strong&gt;(fj)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;문자열(str 또는 bytes, bytearray)에 json 내용이 들어있을 경우 &lt;code&gt;&lt;strong&gt;loads&lt;/strong&gt;&lt;/code&gt;를 이용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import json
js = &apos;{&quot;key&quot;: &quot;value&quot;}&apos;
data = &lt;strong&gt;json.loads&lt;/strong&gt;(js)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 읽어들인 &lt;code&gt;data&lt;/code&gt;는 파이썬에서 dict 자료형이 됩니다. JSON 자료형은 읽었을 때 아래와 같이 파이썬 자료형으로 변환됩니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;JSON&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;object&lt;/td&gt;&lt;td&gt;dict&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;array&lt;/td&gt;&lt;td&gt;list&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;str&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;number (integer)&lt;/td&gt;&lt;td&gt;int&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;number (real)&lt;/td&gt;&lt;td&gt;float&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;false&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;null&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;JSON to Python&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파이썬에서 JSON 쓰기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;파이썬에서 JSON 파일을 쓰려면 &lt;code&gt;&lt;strong&gt;dump&lt;/strong&gt;&lt;/code&gt;, 문자열에 쓰려면 &lt;code&gt;&lt;strong&gt;dumps&lt;/strong&gt;&lt;/code&gt; 함수를 이용합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import json
data = [&quot;list&quot;, {&apos;key&apos;: &apos;value&apos;}]

with open(&apos;data.json&apos;, &apos;w&apos;) as fj:
    &lt;strong&gt;json.dump&lt;/strong&gt;(data, fj)

js = &lt;strong&gt;json.dumps&lt;/strong&gt;(data, indent=4)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;dumps&lt;/code&gt;에서 &lt;code&gt;indent&lt;/code&gt; 옵션을 넣으면 출력시 보기 좋게 만들어줍니다. 파이썬 자료형은 아래와 같이 JSON 자료형으로 변환됩니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Python&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;JSON&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;dict&lt;/td&gt;&lt;td&gt;object&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;list, tuple&lt;/td&gt;&lt;td&gt;array&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;str&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;int, float, (int, float 열거형)&lt;/td&gt;&lt;td&gt;number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;True&lt;/td&gt;&lt;td&gt;true&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;False&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;None&lt;/td&gt;&lt;td&gt;null&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;Python to JSON&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;JSON 파일에 한글 쓰기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;파이썬 문자열에 한글이 포함되어 있을 경우 위의 &lt;code&gt;dump&lt;/code&gt;, &lt;code&gt;dumps&lt;/code&gt;를 이용해 JSON 파일이나 문자열을 쓰면 한글이 바로 표시되지 않습니다. 그래도 &lt;code&gt;load&lt;/code&gt;, &lt;code&gt;loads&lt;/code&gt;로 읽으면 제대로 읽어지기는 합니다. 파일이나 문자열로 썼을 때 한글이 바로 표시되게 만들고 싶으면 &lt;code&gt;dump&lt;/code&gt;, &lt;code&gt;dumps&lt;/code&gt;에 &lt;code&gt;&lt;strong&gt;ensure_ascii=False&lt;/strong&gt;&lt;/code&gt; 옵션을 주면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import json
data = [&quot;list&quot;, {&apos;key&apos;: &apos;한글&apos;}]

with open(&apos;data.json&apos;, &apos;w&apos;) as fj:
    json.dump(data, fj, &lt;strong&gt;ensure_ascii=False&lt;/strong&gt;)

js = json.dumps(data, indent=4, &lt;strong&gt;ensure_ascii=False&lt;/strong&gt;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;제어 문자가 들어간 문자열&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;\n&lt;/code&gt;, &lt;code&gt;\t&lt;/code&gt;, &lt;code&gt;\r&lt;/code&gt;, &lt;code&gt;\0&lt;/code&gt;과 같은 제어 문자가 들어간 문자열을 &lt;code&gt;json.loads&lt;/code&gt;로 읽어들이려고 하면 &lt;code&gt;JSONDecodeError&lt;/code&gt;가 발생합니다. 제어 문자를 포함하고 싶으면 &lt;code&gt;strict=False&lt;/code&gt; 옵션을 주면 됩니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;js = &quot;&quot;&quot;
[&quot;list&quot;,
{&quot;key&quot;: &quot;        
한글        
&quot;}]
&quot;&quot;&quot;

data = json.loads(js, strict=False)&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>ChatGPT 하이퍼파라미터</title><link>https://pkgpl.org/2023/09/10/chatgpt-%ed%95%98%ec%9d%b4%ed%8d%bc%ed%8c%8c%eb%9d%bc%eb%af%b8%ed%84%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/10/chatgpt-%ed%95%98%ec%9d%b4%ed%8d%bc%ed%8c%8c%eb%9d%bc%eb%af%b8%ed%84%b0/</guid><pubDate>Sun, 10 Sep 2023 14:59:33 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI의 &lt;a href=&quot;https://pkgpl.org/2023/09/08/chatgpt-api-사용하기/&quot;&gt;GPT 모델들의 API&lt;/a&gt; 호출시 사용 가능한 하이퍼파라미터들이 있습니다. 하이퍼파라미터는 훈련되는 신경망 가중치가 아니라 사용자가 직접 입력하는 매개변수로, 모델의 응답에 영향을 미치게 됩니다. &lt;a href=&quot;https://platform.openai.com/docs/api-reference/chat/create&quot;&gt;주요 하이퍼파라미터들&lt;/a&gt;은 다음과 같습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;하이퍼파라미터&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;기본값&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;범위&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;temperature&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0.0~2.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;top-p&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0.0~1.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;max_tokens&lt;/td&gt;&lt;td&gt;inf&lt;/td&gt;&lt;td&gt;정수&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;frequency_penalty&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;-2.0~2.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;presence_penalty&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;-2.0~2.0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;Hyperparameters&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;각 하이퍼파라미터를 통해 얻을 수 있는 결과를 살펴봅시다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;temperature&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과의 다양성과 예측 가능성을 조절합니다. 값이 클수록 더 무작위적인 응답(더 창의적인 응답)을 얻을 수 있습니다. 예측 가능하고 일관된 응답을 얻어야 할 경우에는 0에 가까운 값을 사용합니다. 보통 아래 나오는 top_p나 temperature 중 하나를 조정합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;top_p&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;단어 샘플링시 사용하는 확률 분포의 상위 부분을 의미합니다. 예를 들어, top_p=0.9라면 확률 분포 상위 90% 내에서만 단어를 샘플링합니다. 이렇게 되면 이상치를 제거하는 효과를 얻을 수 있겠죠. top_p=0.1이라면 상위 10% 내의 확률 분포 내에서만 단어를 샘플링하므로 좀 더 예측 가능한 결과를 얻을 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;max_tokens&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;답변의 최대 &lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;토큰 수&lt;/a&gt;를 제한할 때 사용합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;presence_penalty&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;0보다 큰 값을 사용할 경우 앞에서 나왔던 단어(토큰)가 또 나오는 것을 억제합니다. 즉, 새로운 내용을 이야기할 가능성이 높아집니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;frequency_penalty&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;0보다 큰 값을 사용할 경우 특정 단어(토큰)의 출현 빈도가 높아지는 것을 억제합니다. 즉, 같은 말을 문자 그대로 반복하는 것을 막습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예시&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://platform.openai.com/playground&quot;&gt;OpenAI Playground&lt;/a&gt;에서는 직접 API를 호출하지 않고도 위의 하이퍼파라미터들을 바꿔가며 테스트해볼 수 있습니다. ChatGPT에서도 메시지 입력시 아래와 같이 하이퍼파라미터를 입력하여 응답 결과를 조정할 수  있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-small-font-size&quot;&gt;예시: temperature=0.1&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;나는 대학생이야. 다음 괄호에 들어갈만한 장소를 10군데 적어줘. &lt;strong&gt;temperature=0.1&lt;/strong&gt;

나는 내일 ( )에 갈 것이다. 
=====
주어진 문장에서 괄호에 들어갈 수 있는 장소를 10군데 제안해 드립니다:

나는 내일 (도서관)에 갈 것이다.
나는 내일 (학교)에 갈 것이다.
나는 내일 (카페)에 갈 것이다.
나는 내일 (식당)에 갈 것이다.
나는 내일 (공원)에 갈 것이다.
나는 내일 (영화관)에 갈 것이다.
나는 내일 (체육관)에 갈 것이다.
나는 내일 (박물관)에 갈 것이다.
나는 내일 (친구 집)에 갈 것이다.
나는 내일 (도시 쇼핑몰)에 갈 것이다.&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading has-small-font-size&quot;&gt;예시: temperature=1.0&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;나는 대학생이야. 다음 괄호에 들어갈만한 장소를 10군데 적어줘. &lt;strong&gt;temperature=1.0&lt;/strong&gt;

나는 내일 ( )에 갈 것이다. 
=====
온도 (temperature)가 높은 경우, 모델은 더 다양한 창조적인 답변을 생성할 수 있습니다. 다음은 온도가 높을 때 가능한 10개의 장소 예시입니다:

나는 내일 (자연휴양림)에 갈 것이다.
나는 내일 (물놀이공원)에 갈 것이다.
나는 내일 (미술갤러리)에 갈 것이다.
나는 내일 (음악 페스티벌)에 갈 것이다.
나는 내일 (카페트매장)에 갈 것이다.
나는 내일 (과학 박물관)에 갈 것이다.
나는 내일 (헬스 클럽)에 갈 것이다.
나는 내일 (해변)에 갈 것이다.
나는 내일 (캠핑장)에 갈 것이다.
나는 내일 (동물원)에 갈 것이다.
이것들은 더 다양한 장소를 나타내는 창조적인 예시입니다.&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading has-small-font-size&quot;&gt;예시: top_p=0.1&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;나는 대학생이야. 다음 괄호에 들어갈만한 행동을 10가지 적어줘. &lt;strong&gt;top_p=0.1&lt;/strong&gt;

나는 1시간 후 ( )을/를 할 것이다. 
=====
top_p (penalty) 값이 낮은 경우, 모델은 더 확실한 예상 답변에 가까운 답변을 생성합니다. 따라서 가능한 10가지 행동 예시는 다음과 같습니다:

나는 1시간 후 (공부)를 할 것이다.
나는 1시간 후 (운동)을 할 것이다.
나는 1시간 후 (음악 듣기)를 할 것이다.
나는 1시간 후 (친구와 만남)을 할 것이다.
나는 1시간 후 (요리)를 할 것이다.
나는 1시간 후 (영화 보기)를 할 것이다.
나는 1시간 후 (독서)를 할 것이다.
나는 1시간 후 (산책)을 할 것이다.
나는 1시간 후 (미술 활동)을 할 것이다.
나는 1시간 후 (봉사 활동)을 할 것이다.
이러한 답변은 top_p 값이 낮아 더 일반적이고 확실한 행동을 나타냅니다.&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading has-small-font-size&quot;&gt;예시: top_p=1.0&lt;/h2&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;나는 대학생이야. 다음 괄호에 들어갈만한 행동을 10가지 적어줘. &lt;strong&gt;top_p=1.0&lt;/strong&gt;

나는 1시간 후 ( )을/를 할 것이다. 
=====
top_p (penalty) 값이 높은 경우, 모델은 더 다양하고 창조적인 답변을 생성할 수 있습니다. 따라서 가능한 10가지 행동 예시는 다음과 같습니다:

나는 1시간 후 (하늘을 바라볼 것이다).
나는 1시간 후 (별을 관찰할 것이다).
나는 1시간 후 (음악을 연주할 것이다).
나는 1시간 후 (그림을 그릴 것이다).
나는 1시간 후 (배낭을 싸고 여행을 떠날 것이다).
나는 1시간 후 (심리적인 독서를 할 것이다).
나는 1시간 후 (새로운 요리를 시도할 것이다).
나는 1시간 후 (사진을 찍으러 나갈 것이다).
나는 1시간 후 (봉사 활동을 할 것이다).
나는 1시간 후 (친구와 대화를 나눌 것이다).
이러한 답변은 top_p 값이 높아 더 창조적이고 다양한 행동을 나타냅니다.&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>프롬프트 엔지니어링: 좋은 프롬프트 작성하기</title><link>https://pkgpl.org/2023/09/09/%ed%94%84%eb%a1%ac%ed%94%84%ed%8a%b8-%ec%97%94%ec%a7%80%eb%8b%88%ec%96%b4%eb%a7%81-%ec%a2%8b%ec%9d%80-%ed%94%84%eb%a1%ac%ed%94%84%ed%8a%b8-%ec%9e%91%ec%84%b1%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/09/%ed%94%84%eb%a1%ac%ed%94%84%ed%8a%b8-%ec%97%94%ec%a7%80%eb%8b%88%ec%96%b4%eb%a7%81-%ec%a2%8b%ec%9d%80-%ed%94%84%eb%a1%ac%ed%94%84%ed%8a%b8-%ec%9e%91%ec%84%b1%ed%95%98%ea%b8%b0/</guid><pubDate>Sat, 09 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api&quot;&gt;OpenAI 사이트&lt;/a&gt;에 소개된 챗GPT 프롬프트 엔지니어링 Best practices를 소개해드립니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;1. 최신 모델 사용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;현재 챗GPT 최신 모델은 gpt-3.5-turbo와 gpt-4입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;2. 앞부분에 Instruction 쓰고 ###, “”” 같은 기호를 이용해 Context와 분리하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Summarize the text below as a bullet point list of the most important points.

{text input here}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Summarize the text below as a bullet point list of the most important points.

&lt;strong&gt;Text: &quot;&quot;&quot;&lt;/strong&gt;
{text input here}
&lt;strong&gt;&quot;&quot;&quot;&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;3. 구체적으로 쓰기, 자세히 설명하기(상황, 원하는 결과, 출력 형식, 길이, 스타일 등)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Write a poem about OpenAI.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Write a short inspiring poem about OpenAI, focusing on the recent DALL-E product launch (DALL-E is a text to image ML model) in the style of a {famous poet}&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;4. 출력 형식 자세히 알려주기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Extract the entities mentioned in the text below. Extract the following 4 entity types: company names, people names, specific topics and themes.

Text: {text}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Extract the important entities mentioned in the text below. First extract all company names, then extract all people names, then extract specific topics which fit the content and finally extract general overarching themes

&lt;strong&gt;Desired format:
Company names: &amp;lt;comma_separated_list_of_company_names&amp;gt;
People names: -||-
Specific topics: -||-
General themes: -||-&lt;/strong&gt;

Text: {text}&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;5. Zero-shot으로 안 되면 few-shot, few-shot으로 안 되면 fine-tune&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Zero-shot&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Extract keywords from the below text.

Text: {text}

Keywords:&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Few-shot&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Extract keywords from the corresponding texts below.

Text 1: Stripe provides APIs that web developers can use to integrate payment processing into their websites and mobile applications.
Keywords 1: Stripe, payment processing, APIs, web developers, websites, mobile applications
##
Text 2: OpenAI has trained cutting-edge language models that are very good at understanding and generating text. Our API provides access to these models and can be used to solve virtually any task that involves processing language.
Keywords 2: OpenAI, language models, text processing, API.
##
Text 3: {text}
Keywords 3:&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;6. 애매모호한 설명 쓰지 않기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;The description for this product should be fairly short, a few sentences only, and not too much more.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;Use a 3 to 5 sentence paragraph to describe this product.&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;7. 하지 말라는 명령 대신 하라는 명령 사용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;The following is a conversation between an Agent and a Customer. DO NOT ASK USERNAME OR PASSWORD. DO NOT REPEAT.

Customer: I can’t log in to my account.
Agent:&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;The following is a conversation between an Agent and a Customer. The agent will attempt to diagnose the problem and suggest a solution, whilst refraining from asking any questions related to PII. Instead of asking for PII, such as username or password, refer the user to the help article www.samplewebsite.com/help/faq

Customer: I can’t log in to my account.
Agent:&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;8. 코드 생성시 코드 시작 구문을 보여줘서 LLM이 해당 구문으로 시작하는 패턴을 따르도록 하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;안 좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# Write a simple python function that
# 1. Ask me for a number in mile
# 2. It converts miles to kilometers&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좋은 예&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# Write a simple python function that
# 1. Ask me for a number in mile
# 2. It converts miles to kilometers
 
&lt;strong&gt;import&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;기타&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 내용들 외에도 영어로 명령하기(보통 영어로 명령했을 때 더 좋은 결과가 나옵니다), 역할 부여하기, 자기 목적에 맞는 프롬프트를 여러 가지 실험해보기, 다른 사람의 좋은 프롬프트 보고 배우기 등의 방법이 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;좀 더 복잡한 문제 해결을 위한 &lt;a href=&quot;https://arxiv.org/abs/2201.11903&quot;&gt;Chain-of-Thought&lt;/a&gt;, &lt;a href=&quot;https://arxiv.org/abs/2305.10601&quot;&gt;Tree-of-Thought&lt;/a&gt;, &lt;a href=&quot;https://arxiv.org/abs/2203.11171&quot;&gt;Self-Consistency&lt;/a&gt;, &lt;a href=&quot;https://arxiv.org/abs/2210.03629&quot;&gt;ReAct&lt;/a&gt; 등의 프롬프팅 프레임워크도 계속 발표되고 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>ChatGPT API 사용하기</title><link>https://pkgpl.org/2023/09/08/chatgpt-api-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/08/chatgpt-api-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/</guid><pubDate>Fri, 08 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;ChatGPT vs GPT&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이해를 돕기 위해 제목에 ChatGPT라고 썼지만, 엄밀히 말하면 대화형 ChatGPT와 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;OpenAI API&lt;/a&gt;를 통해 사용하는 GPT 모델은 다른 모델입니다. 대화형 ChatGPT는 자연스러운 대화를 위해 GPT 모델을 별도로 훈련시킨 모델입니다. 특히, 이전 대화 내용을 기억하는 기능이 추가되어 있죠. API를 통해 이용하는 GPT 모델들은 대화의 맥락을 기억하는 기능이 없기 때문에 API를 이용해 대화를 이어가기 위해서는 사용자가 이전 대화의 내용을 입력으로 전달해야 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;파이썬으로 API 사용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;파이썬에서는 openai 패키지를 설치하면 OpenAI API를 쉽게 사용할 수 있습니다. 명령줄에서 다음을 실행합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;pip install openai&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;설치 후에는 &lt;code&gt;openai&lt;/code&gt; 패키지를 import하고 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;API Key&lt;/a&gt;를 지정해줍니다. 아래 예제에서는 환경변수로 지정해놓은 API Key를 가지고 왔습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;import os
import openai
openai.api_key = os.getenv(&quot;OPENAI_API_KEY&quot;)&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;ChatCompletion&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://platform.openai.com/docs/guides/gpt/chat-completions-api&quot;&gt;OpenAI 문서&lt;/a&gt;에 있는 예제를 보겠습니다. &lt;code&gt;ChatCompletion.create&lt;/code&gt;를 이용해 LLM 모델을 사용할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;response = openai.ChatCompletion.create(
    &lt;strong&gt;model&lt;/strong&gt;=&quot;gpt-3.5-turbo&quot;,
    &lt;strong&gt;messages&lt;/strong&gt;=[
        {&quot;role&quot;: &quot;&lt;strong&gt;system&lt;/strong&gt;&quot;, &quot;content&quot;: &quot;You are a helpful assistant.&quot;},
        {&quot;role&quot;: &quot;&lt;strong&gt;user&lt;/strong&gt;&quot;, &quot;content&quot;: &quot;Who won the world series in 2020?&quot;},
        {&quot;role&quot;: &quot;&lt;strong&gt;assistant&lt;/strong&gt;&quot;, &quot;content&quot;: &quot;The Los Angeles Dodgers won the World Series in 2020.&quot;},
        {&quot;role&quot;: &quot;&lt;strong&gt;user&lt;/strong&gt;&quot;, &quot;content&quot;: &quot;Where was it played?&quot;}
    ]
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서 &lt;code&gt;model&lt;/code&gt;에는 OpenAI에서 제공하는 &lt;a href=&quot;https://pkgpl.org/2023/09/07/openai-api-gpt-사용-준비/&quot;&gt;LLM 모델들&lt;/a&gt; 중 원하는 것을 적습니다. &lt;code&gt;messages&lt;/code&gt;는 LLM에 전달할 입력입니다. 입력값을 보면 &lt;code&gt;role&lt;/code&gt;과 &lt;code&gt;content&lt;/code&gt;로 이루어진 딕셔너리들의 배열임을 알 수 있습니다. &lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;Role&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;&lt;strong&gt;role&lt;/strong&gt;&lt;/code&gt;에는 “system”, “user”, “assistant” 중 하나가 오는데, “system”과 “user”는 사용자가 LLM에 요청하는 내용이고, “assistant”는 LLM의 응답입니다. 앞에서 API를 통해 사용하는 LLM은 이전 대화 내용을 기억하지 못한다고 했죠? 위 코드는 이전 대화를 기억할 수 있도록 전달하는 코드임을 알 수 있습니다. “&lt;strong&gt;system&lt;/strong&gt;” 메시지는 LLM에게 대화 전체에 적용될 역할 등을 지정해주는 메시지로, 보통 대화 처음에 한 번 나오는데, 꼭 필요한 것은 아닙니다. 생략하면 “You are a helpful assistant.”라고 주는 것과 유사합니다. 이후에는 보통 “user”와 “assistant”가 번갈아 나옵니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 예제에서는 &lt;code&gt;model&lt;/code&gt;과 &lt;code&gt;messages&lt;/code&gt;를 입력했는데, 이 두 항목은 필수로 입력해야 하고, 그 외에도 &lt;a href=&quot;https://pkgpl.org/2023/09/10/chatgpt-하이퍼파라미터/&quot;&gt;하이퍼파라미터들&lt;/a&gt;과 기타 &lt;a href=&quot;https://platform.openai.com/docs/api-reference/chat/create&quot;&gt;여러 가지 항목들&lt;/a&gt;이 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;Response&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과는 다음과 같이 확인합니다. 여러분이 실행하면 결과가 약간씩 다르게 나올 수 있습니다. 아래 있는 제 실행 결과도 OpenAI 문서에 나온 결과와 단어 순서에 약간 차이가 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;print(response[&apos;choices&apos;][0][&apos;message&apos;][&apos;content&apos;])
# 실행 결과
# The World Series in 2020 was played at Globe Life Field in Arlington, Texas.&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과 확인하기가 좀 복잡하죠? &lt;code&gt;response&lt;/code&gt; 전체를 출력해보면 다음과 같이 다른 정보들을 포함하고 있는 것을 알 수 있습니다. 사실 &lt;code&gt;response&lt;/code&gt;는 chat completion 객체로, 세부 항목 설명은 &lt;a href=&quot;https://platform.openai.com/docs/api-reference/chat/object&quot;&gt;여기&lt;/a&gt;에 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;{
  &quot;id&quot;: &quot;chatcmpl-7wi85qbDjFeDclPTjepMccfCbiWHa&quot;,
  &quot;object&quot;: &quot;chat.completion&quot;,
  &quot;created&quot;: 1694227013,
  &quot;model&quot;: &quot;gpt-3.5-turbo-0613&quot;,
  &quot;&lt;strong&gt;choices&lt;/strong&gt;&quot;: [
    {
      &quot;index&quot;: 0,
      &quot;&lt;strong&gt;message&lt;/strong&gt;&quot;: {
        &quot;role&quot;: &quot;assistant&quot;,
        &quot;&lt;strong&gt;content&lt;/strong&gt;&quot;: &quot;The World Series in 2020 was played at Globe Life Field in Arlington, Texas.&quot;
      },
      &quot;finish_reason&quot;: &quot;stop&quot;
    }
  ],
  &quot;usage&quot;: {
    &quot;prompt_tokens&quot;: 53,
    &quot;completion_tokens&quot;: 18,
    &quot;total_tokens&quot;: 71
  }
}&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;API를 이용한 대화&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM을 한 번만 호출한다면 위와 같이 실행하면 되고, LLM과 대화를 이어가고 싶다면 반복문 내에서 이전 대화 내용을 누적해서 다음 입력으로 전달해주면 됩니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-8.png&quot; href=&quot;https://pkgpl.org/media/wp-2ae5fd52399e0ffc.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;798&quot; src=&quot;https://pkgpl.org/media/wp-2ae5fd52399e0ffc.png&quot; alt=&quot;&quot; class=&quot;wp-image-1530&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대화가 길어지면 입력 토큰 수가 크게 증가하겠죠? 비용도 문제지만, 토큰 수 제한에 걸릴 수도 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그럴 경우 이전 대화 내용을 요약해서 전달하면 됩니다. 요약하는 것 역시 LLM을 이용하죠. 현재 대화와는 별도로 API를 호출하면서 이전 대화 내용을 전달하고 요약해달라고 하면 됩니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-9.png&quot; href=&quot;https://pkgpl.org/media/wp-3afc96ad7acf5952.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;965&quot; height=&quot;1023&quot; src=&quot;https://pkgpl.org/media/wp-3afc96ad7acf5952.png&quot; alt=&quot;&quot; class=&quot;wp-image-1531&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 때 이전 대화 전체를 전달하며 요약할 수도 있고, 기존 요약된 내용에 새로운 대화를 추가해서 전달하며 요약할 수도 있습니다. 이전 대화 전체를 전달하면 과거 내용을 유지할 수 있지만 토큰이 많이 필요하고, 요약된 내용에 새로운 대화를 추가해서 요약하면 토큰 수를 줄일 수 있지만, 과거 대화 내용이 여러 번 요약되며 사라질 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>OpenAI API (GPT) 사용 준비</title><link>https://pkgpl.org/2023/09/07/openai-api-gpt-%ec%82%ac%ec%9a%a9-%ec%a4%80%eb%b9%84/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/07/openai-api-gpt-%ec%82%ac%ec%9a%a9-%ec%a4%80%eb%b9%84/</guid><pubDate>Thu, 07 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;OpenAI에서는 다양한 서비스들을 API를 이용해 사용할 수 있도록 &lt;a href=&quot;https://pkgpl.org/2023/09/05/restful-api/&quot;&gt;REST API&lt;/a&gt;를 제공하고 있습니다. &lt;a href=&quot;https://platform.openai.com/docs/models/overview&quot;&gt;사용할 수 있는 모델&lt;/a&gt;들에는 GPT-3.5, GPT-4 외에도 DALL-E (그림 그리기), Whisper (음성 인식), Embeddings (&lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;텍스트 임베딩&lt;/a&gt;) 등이 있습니다. API를 사용하기 위해서는 &lt;a href=&quot;https://openai.com/blog/openai-api&quot;&gt;OpenAI API 사이트&lt;/a&gt;에 &lt;strong&gt;회원 가입&lt;/strong&gt; 후 &lt;code&gt;sk-&lt;/code&gt;로 시작하는 &lt;strong&gt;API Key&lt;/strong&gt;를 받아야 합니다. API는 사용료가 있는데, 처음 가입하면 3개월간 쓸 수 있는 $5를 제공하므로, 여러 가지 테스트를 해볼 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LLM 모델 – 성능, 가격, 토큰 수&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;LLM&lt;/a&gt; 모델은 &lt;strong&gt;gpt-3.5-turbo&lt;/strong&gt;나 &lt;strong&gt;gpt-4&lt;/strong&gt;를 사용하면 됩니다. 물론 gpt-4의 성능이 더 좋지만 비용이 더 비싸므로 gpt-3.5-turbo의 성능으로 충분한 경우에는 해당 모델을 사용하면 됩니다. 아래 표에 이 글을 작성하는 시점의 가격을 적었지만 앞으로 바뀔 수 있으므로 최신 &lt;strong&gt;가격&lt;/strong&gt;은 &lt;a href=&quot;https://openai.com/pricing&quot;&gt;OpenAI 사이트&lt;/a&gt;에서 확인하시기 바랍니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM 모델에는 입출력 &lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;토큰&lt;/a&gt; 수 제한&lt;/strong&gt;이 있습니다. &lt;a href=&quot;https://pkgpl.org/2023/09/14/openai-tiktoken을-이용한-토큰-수-계산하기/&quot;&gt;토큰 수&lt;/a&gt;는 단어 수보다 많죠. 입력과 출력 토큰의 합계로 제한하는데, gpt-3.5-turbo 모델의 경우 4K, gpt-4의 경우 8K 토큰을 지원합니다. 더 많은 토큰이 필요한 경우에 사용할 수 있는 &lt;strong&gt;gpt-3.5-turbo-16k&lt;/strong&gt;, &lt;strong&gt;gpt-4-32k&lt;/strong&gt; 모델도 있습니다. &lt;strong&gt;LLM 모델 정보&lt;/strong&gt;는 &lt;a href=&quot;https://platform.openai.com/docs/models/overview&quot;&gt;여기&lt;/a&gt;에서 확인할 수 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Model&lt;/td&gt;&lt;td&gt;Max Tokens&lt;/td&gt;&lt;td&gt;Input Price&lt;br&gt;(per 1K tokens)&lt;/td&gt;&lt;td&gt;Output Price&lt;br&gt;(per 1K tokens)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gpt-3.5-turbo&lt;/td&gt;&lt;td&gt;4,097&lt;/td&gt;&lt;td&gt;$0.0015&lt;/td&gt;&lt;td&gt;$0.002&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gpt-3.5-turbo-16k&lt;/td&gt;&lt;td&gt;16,385&lt;/td&gt;&lt;td&gt;$0.003&lt;/td&gt;&lt;td&gt;$0.004&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gpt-4&lt;/td&gt;&lt;td&gt;8,192&lt;/td&gt;&lt;td&gt;$0.03&lt;/td&gt;&lt;td&gt;$0.06&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gpt-4-32k&lt;/td&gt;&lt;td&gt;32,768&lt;/td&gt;&lt;td&gt;$0.06&lt;/td&gt;&lt;td&gt;$0.12&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;OpenAI LLM Models&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, gpt-3.5-turbo 모델의 경우 자신의 데이터를 이용해 &lt;a href=&quot;https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/&quot;&gt;&lt;strong&gt;Fine Tuning&lt;/strong&gt;&lt;/a&gt;할 수 있습니다. 훈련 가격은 $0.008/1K, 입력 가격은 $0.012/1K, 출력 가격은 $0.016/1K로, 기본 gpt-3.5-turbo 모델보다 8배 비싸네요.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;임베딩 모델&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;텍스트 임베딩&lt;/a&gt;이 필요할 경우 &lt;strong&gt;text-embedding-ada-002&lt;/strong&gt; 모델을 사용하면 됩니다. 이 때 임베딩 모델에서 사용하는 토크나이저는 cl100k_base, 최대 입력 토큰수는 8192, 출력 벡터는 1536 차원입니다. 임베딩 모델 정보는 &lt;a href=&quot;https://platform.openai.com/docs/guides/embeddings/what-are-embeddings&quot;&gt;여기&lt;/a&gt;에서 확인할 수 있습니다. API 사용 가격은 $0.0001/1K로, 1달러를 쓰기 위해서는 10,000K 토큰이 필요하네요. LLM에 비해 임베딩 가격은 무시할만하다고 할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>마인드맵 Mindmap</title><link>https://pkgpl.org/2023/09/06/%eb%a7%88%ec%9d%b8%eb%93%9c%eb%a7%b5-mindmap/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/06/%eb%a7%88%ec%9d%b8%eb%93%9c%eb%a7%b5-mindmap/</guid><pubDate>Wed, 06 Sep 2023 14:53:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Mind_map&quot;&gt;마인드맵&lt;/a&gt;은 토니 부잔이 개발한 노트법입니다. 제가 학생 때 시험 공부하며 마인드맵의 도움을 많이 받았습니다. 물리탐사 수업을 들은 학생들은 몇 번 그려봤죠? 컴퓨터 마인드맵 프로그램도 있지만 마인드맵을 처음 접한다면 먼저 손으로 그려보는 것을 추천합니다. 마인드맵 작성 방법은 위 그림에 나와 있습니다. 책에 나온 작성 규칙을 옮기면 아래와 같습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;강조 기법&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;항상 중심 이미지 사용, 중심 이미지에 3가지 이상의 색상 사용&lt;/li&gt;



&lt;li&gt;마인드맵 전체에 걸쳐 이미지 사용&lt;/li&gt;



&lt;li&gt;이미지와 단어를 입체화&lt;/li&gt;



&lt;li&gt;공감각 사용&lt;/li&gt;



&lt;li&gt;글자, 가지, 이미지를 다양한 크기로 사용&lt;/li&gt;



&lt;li&gt;적절한 공간 배분&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;연상 결합&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;가지끼리 연결할 때 화살표 사용&lt;/li&gt;



&lt;li&gt;색상, 부호 사용&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;명료화 기법&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;하나의 가지 위에 하나의 &lt;strong&gt;키워드&lt;/strong&gt;만 사용&lt;/li&gt;



&lt;li&gt;모든 단어는 알아보기 좋게 쓰기&lt;/li&gt;



&lt;li&gt;가지의 길이는 단어 길이와 비슷하게&lt;/li&gt;



&lt;li&gt;주가지는 중심 이미지에 연결, 두껍게 그리기&lt;/li&gt;



&lt;li&gt;가지와 가지는 연결해서 그리기&lt;/li&gt;



&lt;li&gt;필요시 가지 외곽을 둘러싸는 경계선 그리기&lt;/li&gt;



&lt;li&gt;용지는 가로로&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;레이아웃&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;위계적 조직화&lt;/li&gt;



&lt;li&gt;번호 사용&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;규칙이 많은데 외울 필요는 없고, 몇 번 연습해보면서 익히면 됩니다. 제 경우 암기할 것이 많은 과목에 특히 유용했습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 내용중 키워드가 중요합니다. 공부하는 내용 중 핵심 키워드들을 뽑아서 마인드맵에 적습니다. 핵심 키워드를 뽑기 위해서는 공부하는 내용을 잘 알아야겠죠? 그래서 마인드맵을 만들면 마인드맵을 보며 빠르게 복습하기에도 좋지만, 마인드맵을 만드는 과정에서 공부하는 내용을 더 잘 이해할 수 있습니다. 중심으로부터 위계적으로 연결되어 있으니 큰 그림을 보며 세부 지식의 연관성을 파악하기도 좋습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;아래는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Mind_map&quot;&gt;위키피디아&lt;/a&gt;에서 손으로 그린 그림만 가져 왔습니다. 그림을 잘 못 그린다고 부담을 가질 필요는 없습니다. 그림을 못 그려도, 안 그려도 충분히 유용합니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-embed is-type-rich&quot;&gt;&lt;div class=&quot;wp-block-embed__wrapper&quot;&gt;
&lt;a href=&quot;https://pkgpl.org/media/wp-f7c5b16cf4d562ba.png&quot;&gt;&lt;img src=&quot;https://pkgpl.org/media/wp-f7c5b16cf4d562ba.png&quot; style=&quot;max-width:100%;&quot; alt=&quot;테니스의 원칙, 기술, 대회, 코트 종류와 점수 체계를 가지로 연결한 마인드맵&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;/figure&gt;



&lt;figure class=&quot;wp-block-embed is-type-rich&quot;&gt;&lt;div class=&quot;wp-block-embed__wrapper&quot;&gt;
&lt;a href=&quot;https://pkgpl.org/media/wp-a82c3b7e2687ba5d.png&quot;&gt;&lt;img src=&quot;https://pkgpl.org/media/wp-a82c3b7e2687ba5d.png&quot; style=&quot;max-width:100%;&quot; alt=&quot;질문, 가치, 감정, 탐색과 아이디어를 그림과 가지로 연결한 창의성 마인드맵&quot;&gt;&lt;/a&gt;
&lt;/div&gt;&lt;/figure&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>RESTful API 설명</title><link>https://pkgpl.org/2023/09/05/restful-api/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/05/restful-api/</guid><pubDate>Tue, 05 Sep 2023 14:38:44 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;API (Application Programming Interface)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;API는 어떤 프로그램의 함수를 호출하고 결과를 받는 대화 형식을 정해놓은 것입니다. API에는 SOAP API, GraphQL API, gRPC API 등 여러 종류들이 있는데 인터넷에서 가장 많이 사용하고 있는 API 중 하나가 &lt;strong&gt;REST API &lt;/strong&gt;입니다. REST API 규약을 잘 따르면 RESTful 하다고 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Representation State Transfer (REST) API&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;REST API는 웹 상의 자원(Resource)을 고유한 URL을 통해 나타내고, HTTP 메소드를 사용하여 해당 자원과 관련된 작업을 수행하는 API입니다. 사용할 수 있는 &lt;strong&gt;메소드&lt;/strong&gt;(행위)는 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;GET: 데이터를 조회하거나 검색 (Read)&lt;/li&gt;



&lt;li&gt;POST: 새로운 데이터를 생성 (Create)&lt;/li&gt;



&lt;li&gt;PUT: 기존 데이터를 업데이트하거나 대체 (Update)&lt;/li&gt;



&lt;li&gt;PATCH: 기존 데이터의 일부를 업데이트 (Update)
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;DELETE: 데이터를 삭제 (Delete)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이러한 Create-Read-Update-Delete 작업을 &lt;strong&gt;CRUD&lt;/strong&gt; 작업이라고도 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;REST API는 &lt;strong&gt;자원 식별자, 메소드, 내용&lt;/strong&gt;(입력값, Pay Load)으로 이루어집니다. 메소드는 위에 주어져 있고, 내용은 데이터에 관한 정보가 되겠습니다. 입출력 내용에 고정된 형식이 있는 것은 아니지만 JSON (JavaScript Object Nation)과 XML (eXtensible Markup Language) 형식을 많이 사용합니다. 자원 식별자는 뭘까요?&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;자원 식별자&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;고유한 URL을 이용해 웹 상에서 내가 원하는 자원에 접근할 수 있는데, 자원 식별을 위해 사용하는 고유한 식별자를 자원 식별자 &lt;strong&gt;URI (Uniform Resource Identifier)&lt;/strong&gt;라고 합니다. URL과 URN은 모두 URI의 일종입니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;URL (Uniform Resource Locator)&lt;/strong&gt;: 인터넷 상에서 자원의 위치를 나타내는 주소&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;URN (Uniform Resource Name)&lt;/strong&gt;: 자원에 대한 유일한 이름으로, 위치와 상관없이 식별 가능&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;상태 코드&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;자원 식별자, 메소드, 내용이 있으면 REST API를 호출해서 결과를 받아볼 수 있습니다. 구체적인 호출 방법은 사용하는 언어나 프로그램에 따라 달라집니다. GET 메소드의 경우 요청한 정보를 결과물로 받게 되지만, 다른 메소드(생성, 업데이트, 삭제)의 경우 서버 내에서 처리하면 되기 때문에 반환하는 데이터가 없을 수 있습니다. 그럼 요청이 정상적으로 처리되었는지 알 수가 없겠죠? 그래서 REST API에서는 항상 숫자로 된 상태 코드를 반환합니다. 숫자 범위에 따른 상태 코드입니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;2xx: 성공적인 응답 – 200은 성공적인 응답, 201은 자원이 성공적으로 생성되었음&lt;/li&gt;



&lt;li&gt;3xx: 리다이렉션 – 301은 자원 위치가 영구적으로 변경되었음, 302는 자원 위치 임시 변경&lt;/li&gt;



&lt;li&gt;4xx: 클라이언트 오류 – 400은 잘못된 요청, 404는 찾을 수 없는 자원&lt;/li&gt;



&lt;li&gt;5xx: 서버 오류 – 500은 서버 내부 오류(서버에서 요청을 처리할 수 없는 상태)&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;URL 주소로 웹 페이지를 열면 GET 메서드를 호출하는 셈입니다. 찾는 페이지가 없을 때 404 Error – Page not found 오류를 보신 적이 있을겁니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;인공지능 비서와 외부 API&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;인공지능 비서&lt;/a&gt;를 만들 때 LLM은 두뇌라 할 수 있습니다. 두뇌만 있는 것보다는 손발이 있어야 더 많은 일들을 할 수 있겠죠? LLM에게 각종 함수나 API들을 손발로 쓸 수 있도록 만들어줄 수 있습니다. 파이썬에서 LLM의 API를 이용해 인공지능 비서를 만든다고 해봅시다. 다음은 LLM에게 API 사용 기술을 전수하는 과정입니다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;LLM에게 명령과 함께 REST API와 같은 외부 API 사용법을 알려주고 명령 수행을 위해 필요하면 API 호출을 요청하라고 알려줍니다.&lt;/li&gt;



&lt;li&gt;LLM이 필요할 경우 REST API를 특정 메소드와 내용으로 호출하라고 프로그램에 요청합니다.&lt;/li&gt;



&lt;li&gt;파이썬에서는 LLM의 요청대로 REST API를 호출한 후 얻은 결과를 LLM에 알려줍니다.&lt;/li&gt;



&lt;li&gt;LLM은 API 호출 결과를 가지고 계속해서 명령을 수행합니다. 필요하면 여러 개의 API를 호출할 수도 있습니다.&lt;/li&gt;



&lt;li&gt;이 과정을 주어진 명령을 완수할 때까지 반복합니다.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>부동 소수와 딥러닝에서의 양자화</title><link>https://pkgpl.org/2023/09/04/%eb%b6%80%eb%8f%99-%ec%86%8c%ec%88%98%ec%99%80-%eb%94%a5%eb%9f%ac%eb%8b%9d%ec%97%90%ec%84%9c%ec%9d%98-%ec%96%91%ec%9e%90%ed%99%94/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/04/%eb%b6%80%eb%8f%99-%ec%86%8c%ec%88%98%ec%99%80-%eb%94%a5%eb%9f%ac%eb%8b%9d%ec%97%90%ec%84%9c%ec%9d%98-%ec%96%91%ec%9e%90%ed%99%94/</guid><pubDate>Mon, 04 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;부동 소수 Floating point numbers&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;부동 소수는 실수를 표현하는 방법 중 하나입니다. 고정 소수와 달리 소숫점 자리가 움직인다고 부동 소수라고 부릅니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;고정 소수: 123.45&lt;/li&gt;



&lt;li&gt;부동 소수: &lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0.12345&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0.12345\times10^3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;, &lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1.2345&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1.2345\times 10^2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;, 등&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;부동 소수는 &lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;±&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pm m\times n^e&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt; 라고 쓸 수 있는데 각 부분의 명칭은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;±&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pm&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;: 부호 sign&lt;/li&gt;



&lt;li&gt;m: 가수 significand&lt;/li&gt;



&lt;li&gt;n: 기수 base=2 (항상 2)&lt;/li&gt;



&lt;li&gt;e: 지수 exponent&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;정밀도 Precision&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;부동 소수는 숫자를 표현(저장)하기 위해 사용하는 비트 수에 따라 반정도, 단정도, 배정도 자료형 등으로 나눌 수 있습니다(&lt;a href=&quot;https://en.wikipedia.org/wiki/IEEE_754&quot;&gt;IEEE754 표준&lt;/a&gt;). 비트 수를 많이 사용할수록 정밀도가 높죠.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;반정도&lt;/strong&gt; FP16, half-precision: 16 비트 = 2 바이트&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;단정도&lt;/strong&gt; FP32, single-precision: 32 비트 = 4 바이트&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;배정도&lt;/strong&gt; FP64, double-precision: 64 비트 = 8 바이트&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;표준에는 더 많은 비트를 사용한 부동 소수도 있는데 보통 위의 세 가지 자료형을 많이 사용합니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-table&quot;&gt;&lt;table tabindex=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;정밀도&lt;/td&gt;&lt;td&gt;부호 비트&lt;/td&gt;&lt;td&gt;지수 비트&lt;/td&gt;&lt;td&gt;가수 비트&lt;/td&gt;&lt;td&gt;최소 양수 (근사치)&lt;/td&gt;&lt;td&gt;최대 양수 (근사치)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;반정도&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;5.96&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;8&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;5.96\times10^{-8}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;6.55&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;4&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;6.55\times10^4&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;단정도&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;23&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1.40&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;45&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1.40\times10^{-45}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3.40&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;38&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3.40\times 10^{38}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;배정도&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;52&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;4.941&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;324&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;4.941\times10^{-324}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;td&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1.798&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;308&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1.798\times10^{308}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class=&quot;wp-element-caption&quot;&gt;부동 소수 비트&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 표를 보면 기수(base) 저장에는 비트를 사용하지 않는 것을 알 수 있습니다. 항상 2이기 때문에 저장할 필요가 없죠. 지수 비트를 더 많이 사용할수록 더 넓은 범위를 표현할 수 있고, 가수 비트를 더 많이 사용할수록 소숫점 아래 더 많은 자리까지 정밀한 값을 표현할 수 있습니다. &lt;strong&gt;많은 비트를 사용할수록 더 정확하지만 메모리를 많이 차지하고 계산 속도가 느려지게 됩니다.&lt;/strong&gt;&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;자료형 변환&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;자료형 사이에는 변환이 가능합니다.&lt;/strong&gt; 낮은 비트의 자료형에서 높은 비트의 자료형으로 변환할 때는 저장된 숫자의 정밀도에 변함이 없지만, 높은 비트의 자료형에서 낮은 비트의 자료형으로 변환하면 저장된 숫자의 정밀도를 일부 희생하게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;양자화 Quantization&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;딥러닝에서는 신경망 매개변수(가중치) 저장에 기본적으로 단정도 부동 소수를 사용합니다. 거대 언어 모델과 같이 큰 모델의 경우 수많은 매개변수(보통 수십억 개가 넘어갑니다)가 존재하기 때문에 메모리와 계산량 부담을 줄이기 위해 반정도나 더 낮은 정밀도(8비트 정수)의 자료형으로 변환을 하는 경우가 많습니다. 이를 &lt;strong&gt;양자화(Quantization)&lt;/strong&gt;라고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;양자화에는 신경망 훈련 중 양자화, 훈련을 마친 후 양자화, 동적 양자화, 정적 양자화 등 다양한 기법이 존재합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category><category>Computer</category></item><item><title>Retrieval Augmented Generation &amp; Fine Tuning</title><link>https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/03/retrieval-augmented-generation-fine-tuning/</guid><pubDate>Sun, 03 Sep 2023 12:54:12 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;기초 모델(Foundation Model)의 한계&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ChatGPT나 Bard와 같은 거대 언어 모델(LLM)을 다양한 분야의 일반적인 지식에 대해 훈련된 &lt;strong&gt;기초 모델(Foundation Model)&lt;/strong&gt;이라고 합니다. 기초 모델은 일반적인 작업을 대체로 잘 수행합니다. LLM은 질문에 따라 응답이 달라지기 때문에 응답의 질을 향상시키기 위해 어떻게 메시지를 보내야 하는지 연구하는 것을 &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;프롬프트 엔지니어링&lt;/a&gt;이라고 합니다. 프롬프트 엔지니어링을 통해 훌륭한 프롬프트를 찾아냈다고 하더라도 &lt;strong&gt;LLM에는 한계&lt;/strong&gt;가 존재합니다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;특정 시기까지의 데이터만 가지고 훈련되었기 때문에 최신 정보를 반영하지 못합니다. 최신 정보를 물어보면 엉터리 대답(hallucination)을 하기도 하죠.&lt;/li&gt;



&lt;li&gt;다양한 분야의 일반적인 자료를 이용해 훈련시켰기 때문에 특정 세부 분야의 지식이 부족합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이러한 한계를 극복하기 위해 &lt;strong&gt;Retrieval Augmented Generation&lt;/strong&gt;과 &lt;strong&gt;Fine Tuning&lt;/strong&gt;을 많이 사용합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Retrieval Augmented Generation (RAG)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;를 이용하면 문서에서 질문과 관련된 부분을 추출하여 &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;LLM 프롬프트&lt;/a&gt;에 Context로 전달할 수 있습니다. LLM은 Context의 내용을 바탕으로 질문에 맞는 답을 내놓을 수 있죠. 특정 분야의 최신 정보를 반영한 문서를 사용하면 위에서 말한 LLM의 한계를 극복할 수 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-5.png&quot; href=&quot;https://pkgpl.org/media/wp-3a2a1d2c89116518.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;294&quot; src=&quot;https://pkgpl.org/media/wp-3a2a1d2c89116518.png&quot; alt=&quot;&quot; class=&quot;wp-image-1445&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Fine Tuning&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Fine Tuning은 이미 훈련되어 있는 기초 모델에 목적에 맞는 자료를 이용해 추가 훈련을 시키는 전이학습 과정입니다. 이를 통해 LLM이 특정 분야의 최신 정보를 반영하도록 만들 수 있죠. 이렇게 훈련된 LLM에 질문을 던지면 추가 훈련 정보를 반영한 응답을 얻을 수 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-6.png&quot; href=&quot;https://pkgpl.org/media/wp-82ac6a20123deba4.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;288&quot; src=&quot;https://pkgpl.org/media/wp-82ac6a20123deba4.png&quot; alt=&quot;&quot; class=&quot;wp-image-1447&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;RAG or Fine Tuning?&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;두 가지 기법은 모두 LLM의 한계를 극복하여 성능을 향상시키기 위한 기법입니다. 하지만 서로 다른 기법으로, 장단점 차이가 있기 때문에 목적에 맞는 기법을 이용하는게 좋습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;RAG 장점, Fine Tuning 단점&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;새로운 정보 업데이트&lt;/strong&gt;: RAG에서 최신 정보나 새로운 분야의 정보를 반영하려면 새 문서를 이용해 벡터 데이터베이스를 업데이트하면 됩니다. LLM은 건드릴 필요가 없습니다. 하지만 Fine Tuning에서는 새로운 정보를 추가할 때마다 전이학습이 필요하고, 거대한 LLM일수록 추가 학습 비용이 높아집니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;추가 정보 준비&lt;/strong&gt;: RAG에서는 추가 정보를 입력하는데 특별한 형식이 필요하지 않습니다. 주어진 문서를 일정 길이로 나누어 임베딩 모델을 통해 벡터로 만들고 벡터 데이터베이스에 입력하면 됩니다. 하지만 Fine Tuning을 위해서는 바람직한 질문-응답(Label) 쌍을 충분히 준비해야 합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;해석 가능성&lt;/strong&gt;: RAG에서는 LLM이 벡터 검색 결과를 바탕으로 응답하기 때문에 벡터 검색 결과를 확인하면 LLM이 왜 그렇게 대답했는지 알 수 있습니다. Fine Tuning의 경우 기초 모델과 같이 왜 그런 대답을 했는지 명확히 알기 어렵습니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Fine Tuning 장점, RAG 단점&lt;/h2&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;응답 속도&lt;/strong&gt;: Fine Tuning은 훈련을 통해 가중치가 업데이트된 LLM을 이용하기 때문에 실제 사용시 기초 모델과 응답 속도 차이가 거의 없습니다. 하지만 RAG는 기초 모델에 벡터 검색 과정이 추가되므로 응답 속도가 느려지게 됩니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;실제 사용시 계산 비용&lt;/strong&gt;: Fine Tuning은 추가 훈련 비용이 들지만 훈련 후 실제 사용시 계산 비용은 기초 모델과 동일합니다. RAG는 추가 훈련 비용은 안 들지만 벡터 검색 비용이 추가됩니다. 단, 전체 계산 비용은 추가 훈련을 얼마나 많이 하느냐에 따라 달라질 수 있습니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;특정 스타일 반영&lt;/strong&gt;: Fine Tuning은 훈련 자료를 이용해 LLM이 특정 스타일(문어체, 구어체 등)로 응답하도록 훈련시킬 수 있습니다. RAG에서도 &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;Few-shot learning&lt;/a&gt;을 이용해 스타일을 학습시킬 수 있지만, 그렇게 되면 토큰 수가 증가하고, 이는 비용 증가로 이어집니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;물론, Fine Tuning한 모델에 RAG를 추가하는 것도 가능합니다. 대신 비용이 더 증가하죠.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>벡터 데이터베이스</title><link>https://pkgpl.org/2023/09/02/%eb%b2%a1%ed%84%b0-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%b2%a0%ec%9d%b4%ec%8a%a4/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/02/%eb%b2%a1%ed%84%b0-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%b2%a0%ec%9d%b4%ec%8a%a4/</guid><pubDate>Sat, 02 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;벡터 임베딩과 벡터 검색&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;텍스트는 토크나이저와 임베딩을 거쳐 벡터가 됩니다&lt;/a&gt;. 토큰화와 임베딩을 합해서 그냥 임베딩이라고 이야기하기도 합니다. 벡터를 이용한 검색 과정에 대해 생각해봅시다. 문서를 문단, 문장 등 작은 단위(chunk)로 분리하고 각각을 벡터로 만들어 저장해 놓습니다. 질문이 들어왔을 때 질문도 임베딩 벡터로 만들면 저장된 벡터와 질문의 임베딩 벡터 사이의 거리를 계산할 수 있습니다. 거리가 가까운 벡터는 질문과 관련된 내용을 포함할 가능성이 높습니다. 이렇게 질문과 관련된 벡터를 찾는 과정이 &lt;strong&gt;벡터 검색&lt;/strong&gt;입니다. &lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-4.png&quot; href=&quot;https://pkgpl.org/media/wp-d39f5e8ed4f59068.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;157&quot; src=&quot;https://pkgpl.org/media/wp-d39f5e8ed4f59068.png&quot; alt=&quot;&quot; class=&quot;wp-image-1431&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;검색 후에는 거리가 가장 가까운 벡터 K개를 추출하여 &lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;거대 언어 모델의 프롬프트&lt;/a&gt;에 포함시킵니다. 이 방법을 &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;라고 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;벡터 거리 측정&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;검색을 위해 벡터 사이의 거리를 측정하는 방법에는 여러 가지가 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;코사인 유사도&lt;/li&gt;



&lt;li&gt;해밍&lt;/li&gt;



&lt;li&gt;유클리드 거리 (L2)&lt;/li&gt;



&lt;li&gt;맨하탄 거리 (L1)&lt;/li&gt;



&lt;li&gt;내적&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 외에도 여러 가지가 있는데, LLM과 관련해서 코사인 유사도를 많이 사용합니다. 보통 질문의 임베딩 벡터와 가장 가까운 벡터를 하나만 찾는게 아니라 K개를 찾습니다. K-Nearest Neighbor (KNN)라고 하죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 때 문서가 짧으면 벡터도 많지 않고 거리를 구하는 계산이 금방 끝나지만 문서가 길어지게 되면 벡터 검색 시간이 크게 증가하게 됩니다. 그래서 보통 &lt;strong&gt;Approximate Nearest Neighbor (ANN)&lt;/strong&gt; 기법을 사용해 근사적으로 가장 가까운 벡터들을 찾습니다. 정확도를 약간 희생하고 검색 속도를 높이는 방법입니다. ANN 관련 기술도 여러 가지가 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Locality Sensitive Hashing (LSH)&lt;/li&gt;



&lt;li&gt;Random Projection&lt;/li&gt;



&lt;li&gt;Hierarchical Navigable Small World (HNSW) Graphs&lt;/li&gt;



&lt;li&gt;Product Quantization&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;벡터 라이브러리&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ANN 기법은 검색 범위를 좁히거나 벡터의 길이를 짧게 만들어 벡터 검색 계산량을 줄이는데, 그렇게 하기 위해서는 미리 벡터를 인덱싱하는 과정이 필요합니다. 이렇게 인덱스를 만들고 벡터간의 거리를 계산해서 검색하는 프로그램을 &lt;strong&gt;벡터 라이브러리&lt;/strong&gt;라고 합니다. 다음은 많이 사용하는 벡터 라이브러리들입니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;메타에서 개발한 FAISS (Facebook AI Similarity Search)&lt;/li&gt;



&lt;li&gt;스포티파이에서 개발한 Annoy (Approximate Nearest Neighbors Oh Yeah)&lt;/li&gt;



&lt;li&gt;구글에서 개발한 ScaNN (Scalable Nearest Neighbors)&lt;/li&gt;



&lt;li&gt;NMSLIB&lt;/li&gt;



&lt;li&gt;HNSWLIB&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;벡터 데이터베이스&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;실제 LLM에서 벡터 임베딩을 이용한 검색을 위해서는 벡터 라이브러리의 기능 외에도 추가 기능들이 필요합니다. 벡터 외에 벡터의 원본 텍스트와 같은 메타 정보를 포함하는 기능, 메타 정보를 이용한 필터링, 벡터의 손쉬운 추가/제거/업데이트, 병렬 연산 지원, 백업이나 보안 지원 등과 같은 기능을 추가한 벡터 라이브러리가 &lt;strong&gt;벡터 데이터베이스&lt;/strong&gt;입니다. 최근에는 기존 데이터베이스에서 벡터 검색을 지원하기도 하는데, 많이 사용하는 벡터 전용 데이터베이스는 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Pinecone&lt;/li&gt;



&lt;li&gt;Milvus&lt;/li&gt;



&lt;li&gt;Chroma&lt;/li&gt;



&lt;li&gt;Weaviate&lt;/li&gt;



&lt;li&gt;Deep Lake&lt;/li&gt;



&lt;li&gt;Qdrant&lt;/li&gt;



&lt;li&gt;Vespa&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM을 이용해 RAG를 구현할 때 위 내용들을 몰라도, 벡터 데이터베이스 사용법만 알면 구현이 가능합니다^^ 하지만, 어느 정도의 배경 지식은 알고 만들면 더 좋겠죠?&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>토큰과 임베딩 벡터</title><link>https://pkgpl.org/2023/09/01/%ed%86%a0%ed%81%b0%ea%b3%bc-%ec%9e%84%eb%b2%a0%eb%94%a9-%eb%b2%a1%ed%84%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/09/01/%ed%86%a0%ed%81%b0%ea%b3%bc-%ec%9e%84%eb%b2%a0%eb%94%a9-%eb%b2%a1%ed%84%b0/</guid><pubDate>Fri, 01 Sep 2023 14:55:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/31/거대-언어-모델-large-language-model-llm/&quot;&gt;거대 언어 모델(LLM)&lt;/a&gt;에 우리는 텍스트 문자열을 입력해 답을 얻습니다. 그러나 컴퓨터에서 실제 계산은 숫자로 이뤄지죠. 우리가 입력한 글자들은 토크나이저(Tokenizer)를 거쳐 토큰으로 분리되고, 각각의 토큰은 임베딩(Embedding) 모델을 거쳐 숫자들로 이루어진 벡터가 됩니다. 거대 언어 모델에는 이 벡터들이 순차적으로 전달되고, 연산을 통해 응답이 나오게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;토크나이저와 토큰&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;토크나이저는 텍스트를 단어나 더 작은 단위(subwords)로 나누는 프로그램입니다. 나눠진 결과를 토큰이라고 하고, 이 과정을 토큰화(tokenize)라고 합니다. 토큰은 아직 문자죠. 토크나이저에는 단어 기반, 서브워드 기반, 문자 기반 토크나이저가 있는데, 거대 언어 모델들은 주로 서브워드 기반 토크나이저를 사용합니다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;단어 기반: [인공지능을]&lt;/li&gt;



&lt;li&gt;서브워드 기반: [인공, ##지능, ##을]&lt;/li&gt;



&lt;li&gt;문자 기반: [인, 공, 지, 능, 을]&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;임베딩&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;토큰이 임베딩 층을 거치면 벡터가 되고, 이 벡터를 임베딩 벡터라 합니다. 거대 언어 모델에서 임베딩 벡터는 보통 수백~수천 차원의 밀집 벡터(0이 별로 없는)를 이용합니다. 이렇게 토큰별로 만들어진 벡터들은 차례대로 거대 언어 모델에 입력으로 전달됩니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-2.png&quot; href=&quot;https://pkgpl.org/media/wp-b80a59922a14f59a.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;232&quot; src=&quot;https://pkgpl.org/media/wp-b80a59922a14f59a.png&quot; alt=&quot;&quot; class=&quot;wp-image-1427&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;예시&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이해를 돕기 위해 간략한 예시를 봅시다(실제 결과와는 차이가 있습니다). “인공지능을 활용합시다”라는 텍스트를 입력으로 사용했다고 해봅시다. 그럼 텍스트는 토크나이저를 거쳐 토큰으로 분리가 됩니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;입력: 인공지능을 활용합시다&lt;/li&gt;



&lt;li&gt;토큰화: [인공, ##지능, ##을, 활용, ##합, ##시다]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결과 토큰은 사용하는 토크나이저에 따라 달라지게 됩니다. 각 토큰은 임베딩을 거쳐 벡터가 됩니다. 실제는 고차원 벡터이지만 아래에는 간략하게 3차원으로 표시했습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;인공: [0.32, -0.21, 0.59]&lt;/li&gt;



&lt;li&gt;##지능: [0.12, 0.45, -0.22]&lt;/li&gt;



&lt;li&gt;…&lt;/li&gt;



&lt;li&gt;##시다: [0.15, -0.33, 0.72]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;거대 언어 모델은 실제로 이런 숫자를 받아들여 자연어 처리 작업을 수행합니다. 요즘 많이 사용하는 트랜스포머 신경망에서 각각의 벡터는 순차적으로 입력으로 사용되는데, 이 벡터들에 위치 정보가 추가되고 신경망의 여러 층을 거치면서 토큰들 사이의 관계와 문맥이 반영된 출력이 계산됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;문장, 문서 수준의 임베딩&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞에서 다룬 임베딩은 거대 언어 모델의 입력으로 사용하기 위한 임베딩이고, 주어진 텍스트의 전체적인 의미와 문맥을 벡터로 표현하기 위한 임베딩 모델들도 있습니다. 벡터 데이터베이스 검색에 사용하는 임베딩이죠. 이러한 모델을 사용하면 임베딩 벡터를 이용해 문장의 유사도를 계산하거나 정보 검색, 클러스터링, 분류 등을 수행할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이러한 모델에서는 주어진 입력을 먼저 토크나이저를 이용해 토큰으로 분리하고, 각 토큰들의 벡터 임베딩을 생성한 후, 이 벡터들을 조합하여 전체 문서를 대표하는 하나의 벡터를 만드는 과정을 거칩니다. 대표 벡터를 만드는 방법에는 벡터의 평균을 이용하는 평균 임베딩 방법, 단어의 등장 빈도를 이용하는 TF-IDF 가중치 방법, 딥 러닝 모델을 사용하는 방법 등이 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-3.png&quot; href=&quot;https://pkgpl.org/media/wp-f1df23474a1336cf.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;198&quot; src=&quot;https://pkgpl.org/media/wp-f1df23474a1336cf.png&quot; alt=&quot;&quot; class=&quot;wp-image-1428&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>거대 언어 모델(Large Language Model, LLM)과 프롬프트 엔지니어링</title><link>https://pkgpl.org/2023/08/31/%ea%b1%b0%eb%8c%80-%ec%96%b8%ec%96%b4-%eb%aa%a8%eb%8d%b8-large-language-model-llm/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/31/%ea%b1%b0%eb%8c%80-%ec%96%b8%ec%96%b4-%eb%aa%a8%eb%8d%b8-large-language-model-llm/</guid><pubDate>Thu, 31 Aug 2023 14:45:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;프롬프트와 프롬프트 엔지니어링&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;ChatGPT와 같은 거대 언어 모델(Large Language Model, LLM)을 사용할 때 모델에 전달하는 메시지를 &lt;strong&gt;프롬프트&lt;/strong&gt;(Prompt)라고 하죠. 프롬프트를 잘 만들어서 원하는 결과물을 얻기 위해 연구하는 것을 &lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/09/프롬프트-엔지니어링-좋은-프롬프트-작성하기/&quot;&gt;프롬프트 엔지니어링&lt;/a&gt;&lt;/strong&gt;이라고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;프롬프트는 한 문장이 될 수도 있고 여러 문단이 될 수도 있죠. 프롬프트를 몇 가지 &lt;strong&gt;주요 구성 요소들&lt;/strong&gt;로 나눠보면 아래와 같이 정리할 수 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Goal: 달성해야 하는 목표&lt;/li&gt;



&lt;li&gt;Instruction: 구체적인 지시, 요구 사항 또는 질문&lt;/li&gt;



&lt;li&gt;Role: 모델에게 조언자나 편집자, 작가 등의 역할을 지정해주는 부분&lt;/li&gt;



&lt;li&gt;Context: 작업의 배경 지식이나 상황 제공&lt;/li&gt;



&lt;li&gt;Output Format: 원하는 응답 형식을 지정해주는 부분&lt;/li&gt;



&lt;li&gt;Systematic Approach: 특정 시스템이나 알고리즘을 따르도록 지시&lt;/li&gt;



&lt;li&gt;Step-by-step: 복잡한 작업을 단계별로 처리하라고 지시&lt;/li&gt;



&lt;li&gt;Clarifying Questions: 불확실한 부분은 모델이 사용자에게 질문하도록 권장&lt;/li&gt;



&lt;li&gt;Examples: 질문과 응답 예제&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이러한 분류는 정해져 있는 것은 아니고, 사람에 따라 다르게 분류할 수 있습니다. 또 매번 위의 모든 요소가 다 들어갈 필요도 없죠. 사용 목적에 따라 들어가는 요소들이 달라지게 됩니다. LLM은 예제로부터 학습할 수 있는데, 예제가 없으면 Zero-shot, 하나 있으면 One-shot, 두 개 이상 있으면 Few-shot learning이라고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;아래 나오는 내용은 주로 대화형 환경 보다는 LLM의 API (Application Programming Interface)를 이용해 사용자에게 드러나지 않게 구현하게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;환각 현상의 완화&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;거대 언어 모델에서 나타나는 &lt;strong&gt;환각&lt;/strong&gt;(hallucination, 거짓 응답) 현상을 줄이는 방법 중 하나가 &lt;strong&gt;Context&lt;/strong&gt;를 제공하고 주어진 정보를 이용해 답하라고 지시하는 방법입니다. 물론 Context에는 사실을 담아야겠죠. 그러려면 Context 정보를 어디선가 가지고 와야 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;Bing Chat, Bard&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;질문을 가지고 인터넷을 검색해서 Context에 들어갈 내용을 가져오면 Microsoft의 Bing Chat이나 Google의 Bard와 같이 최신 정보를 반영한 모델이 됩니다. 검색한 웹문서를 직접 열어서 필요한 부분을 찾을 필요 없이 질문에 대한 답을 알아서 정리해주죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;문서에 대한 질의 응답: ChatPDF&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Context를 PDF 파일과 같은 문서에서 가져오면 문서의 내용에 대해 질문할 수 있는 챗봇, ChatPDF가 됩니다. 인터넷 검색의 경우 이미 있는 Google이나 Bing과 같은 검색 엔진의 검색 결과에서 가장 먼저 나오는 몇 개의 인터넷 문서에서 정보를 가져오면 됩니다. PDF 파일은 어떻게 할까요?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;PDF나 워드 문서의 경우 문서에서 텍스트 정보를 추출하여 텍스트를 컴퓨터에서 처리할 수 있는 숫자들의 벡터로 변환합니다. 이 과정을 &lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/01/토큰과-임베딩-벡터/&quot;&gt;벡터 임베딩&lt;/a&gt;&lt;/strong&gt;(Vector Embedding)이라고 하죠. 문서 전체의 텍스트를 일정 길이(Chunk)로 나눠서 벡터로 변환한 후 벡터들을 &lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/09/02/벡터-데이터베이스/&quot;&gt;벡터 데이터베이스&lt;/a&gt;&lt;/strong&gt;(VectorDB)에 저장해 놓습니다. 질문이 들어오면 질문도 벡터로 변환합니다. 벡터들끼리는 &lt;strong&gt;거리&lt;/strong&gt;를 측정할 수 있죠? 질문 벡터와 문서의 벡터들 사이의 거리를 측정하여 거리가 가까운 벡터들을 몇 개 추출하면 그 벡터에 해당하는 원본 텍스트가 Context에 들어가게 됩니다. 그럼 LLM은 질문에 대한 답을 포함할 가능성이 높은 Context의 정보를 이용해서 대답을 해주죠. 정리해보면, 다음과 같습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;답을 찾고자 하는 문서(문서들)에서 텍스트 추출&lt;/li&gt;



&lt;li&gt;텍스트를 일정 길이로 나누기&lt;/li&gt;



&lt;li&gt;나눈 내용을 벡터 임베딩을 이용해 벡터로 변환&lt;/li&gt;



&lt;li&gt;변환한 벡터들을 벡터 데이터베이스에 저장&lt;/li&gt;



&lt;li&gt;사용자 질문 (사용자 질문이 제일 처음에 문서와 함께 주어질 수도 있습니다)&lt;/li&gt;



&lt;li&gt;사용자 질문을 벡터 임베딩을 이용해 벡터로 변환&lt;/li&gt;



&lt;li&gt;질문 벡터와 벡터 데이터베이스에 저장된 벡터들 사이의 거리 계산&lt;/li&gt;



&lt;li&gt;거리가 가장 가까운 벡터들 추출&lt;/li&gt;



&lt;li&gt;추출한 벡터들의 원본 텍스트를 LLM에 질문에 대한 Context로 제공&lt;/li&gt;



&lt;li&gt;LLM은 질문에 대한 답을 Context에서 찾아서 사용자에게 응답&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;일반 검색에서는 검색하는 단어나 문장과 글자가 일치하는 것을 찾지만 벡터 검색은 의미가 유사한 내용을 찾는 &lt;strong&gt;의미 검색&lt;/strong&gt;(semantic search)입니다. 벡터 데이터베이스에 회사의 제품에 관한 여러 가지 문서들을 넣으면 회사의 &lt;strong&gt;제품 상담 챗봇&lt;/strong&gt;이 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;문서에는 PDF 뿐 아니라 Word, Excel, Power Point, Gmail, Notion 등 다양한 문서들이 있습니다. 이러한 문서들에서 텍스트를 편리하게 추출해주는 라이브러리로 &lt;a href=&quot;https://github.com/jerryjliu/llama_index&quot;&gt;Llama-Index&lt;/a&gt;가 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;인공지능 비서: AutoGPT, BabyAGI&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM의 API를 호출하는 프로그램에서 &lt;strong&gt;Instruction&lt;/strong&gt;에 특정 함수의 사용법을 알려줄 수 있습니다. 예를 들면 위키피디아 검색을 하고 싶으면 &lt;code&gt;wikipedia(query)&lt;/code&gt;라고 출력하라고 알려줄 수 있습니다. 수학 계산을 하고 싶으면 &lt;code&gt;calculate(equation)&lt;/code&gt;이라고 출력하라고 알려줄 수도 있죠. 질문과 함께 함수 사용법을 알려주고 함수를 사용할 수 있다고 LLM에 알려주면 LLM은 최종 대답을 하기 전에 필요한 정보를 얻기 위해 함수를 사용하게 됩니다. 직접 함수를 호출하는 것은 아니고 함수 호출에 필요한 명령을 출력하게 되는거죠. 그럼 프로그램에서 해당 함수를 호출하여 결과를 LLM에 전달해줍니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;질문과 함께 사용할 수 있는 함수들을 LLM에 제시&lt;/li&gt;



&lt;li&gt;LLM에서 필요한 함수를 호출하는 명령 출력&lt;/li&gt;



&lt;li&gt;LLM을 호출하는 프로그램에서 함수 실행&lt;/li&gt;



&lt;li&gt;함수 실행 결과를 LLM에 알려주기&lt;/li&gt;



&lt;li&gt;LLM에서 최종 응답&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예를 들어, 광안대교를 언제 개통했는지 질문하고 위의 함수를 사용할 수 있다고 알려주면, &lt;code&gt;wikipedia(광안대교 개통일)&lt;/code&gt;과 같은 출력을 내놓게 됩니다. 그럼 이 함수 호출 내용을 프로그램에서 분석해서 위키피디아 검색을 수행하고 결과 페이지(위키피디아 광안대교 페이지)의 내용을 LLM에 질문과 함께 Context로 전달하게 됩니다. 그럼 LLM은 Context에서 답을 찾아 대답하게 되죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LLM에서 Python 코드를 출력하면 코드를 실행해서 결과를 알려주겠다고 지시할 수도 있습니다. LLM에 지시를 내리면 LLM에서 지시를 수행하기 위한 코드를 작성해서 출력하고, 프로그램에서 코드를 실행한 후 실행 결과를 다시 LLM에 전달합니다. 그럼 LLM은 결과를 이용해 이후의 응답을 생성할 수 있죠. ChatGPT Plus의 &lt;strong&gt;Advanced Data Analysis&lt;/strong&gt; (&lt;strong&gt;Code Interpreter&lt;/strong&gt;의 새 이름)의 기본 원리입니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 LLM에 알려주는 함수는 LLM의 &lt;strong&gt;Tool&lt;/strong&gt; 또는 &lt;strong&gt;Skill&lt;/strong&gt;이라고 부릅니다. 많은 함수를 알려줄수록 LLM이 할 수 있는 일도 많아지죠. 복잡한 문제의 경우 문제 풀이 단계를 논리적으로 분석해서 제시하고 하나씩 차례대로 수행하라고 지시할 수도 있습니다. 각 단계를 수행할 때 사용할 수 있는 함수들도 같이 알려주죠. &lt;strong&gt;&lt;a href=&quot;https://github.com/Significant-Gravitas/Auto-GPT&quot;&gt;AutoGPT&lt;/a&gt;&lt;/strong&gt;와 &lt;strong&gt;&lt;a href=&quot;https://github.com/yoheinakajima/babyagi&quot;&gt;BabyAGI&lt;/a&gt;&lt;/strong&gt;의 기본 원리입니다. 이런 LLM 프로그래밍을 편리하게 만들어주는 라이브러리로 &lt;a href=&quot;https://github.com/langchain-ai/langchain&quot;&gt;&lt;strong&gt;LangChain&lt;/strong&gt;&lt;/a&gt;이 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;J.A.R.V.I.S.&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;말로 지시를 내리고 소리로 응답을 듣고 싶다면? &lt;strong&gt;음성 인식&lt;/strong&gt;(Speech Recognition) 기술을 이용해 말을 글로 바꿔서 지시를 내릴 수 있습니다. LLM의 출력은 글을 읽어주는 &lt;strong&gt;음성 합성&lt;/strong&gt;(Text-to-Speech) 기술을 이용하면 됩니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;사용자가 음성으로 명령&lt;/li&gt;



&lt;li&gt;음성 인식: 음성을 글자로 변환&lt;/li&gt;



&lt;li&gt;글자를 LLM (AutoGPT)에 전달&lt;/li&gt;



&lt;li&gt;LLM (AutoGPT)에서 응답&lt;/li&gt;



&lt;li&gt;음성 합성: 응답 결과를 읽어주기&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;간단한 &lt;strong&gt;자비스&lt;/strong&gt;(JARVIS)가 됩니다. 토니 스타크의 자비스에 비하면 아직 한참 멀었지만, 점점 향상되고 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>AI</category></item><item><title>페이퍼 학습법</title><link>https://pkgpl.org/2023/08/30/%ed%8e%98%ec%9d%b4%ed%8d%bc-%ed%95%99%ec%8a%b5%eb%b2%95/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/30/%ed%8e%98%ec%9d%b4%ed%8d%bc-%ed%95%99%ec%8a%b5%eb%b2%95/</guid><pubDate>Wed, 30 Aug 2023 14:29:57 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/166654&quot;&gt;페이퍼 학습법&lt;/a&gt;은 B4 용지에 공부할 내용을 정리한 후 여러 번 복습하는 공부 방법입니다. 제가 학부생 때 암기할 것이 많은 과목을 공부하며 요긴하게 사용했던 학습법입니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;먼저 B4 용지를 준비합니다. B4 용지는 A4 용지보다 큽니다. B4 용지를 세로로 둔 상태에서 가로 세로 반씩 접었다가 폅니다. 가장 윗부분에는 제목 적을 부분을 약간 접었다가 폅니다. 그럼 아래와 같은 종이를 얻을 수 있습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-image&quot;&gt;
&lt;figure class=&quot;aligncenter size-large is-resized&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-6.png&quot; href=&quot;https://pkgpl.org/media/wp-bb3ab366cc816231.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;936&quot; src=&quot;https://pkgpl.org/media/wp-bb3ab366cc816231.png&quot; alt=&quot;&quot; class=&quot;wp-image-1387&quot; style=&quot;width:196px;height:auto&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;


&lt;p class=&quot;wp-block-paragraph&quot;&gt;1행에 공부하는 주제를 적고 1열부터 아래로 차례대로 공부하며 채워갑니다. 공부한 내용을 정리해서 한 장을 앞뒤로 채우는 데 보통 몇 시간이 걸립니다. 공부하는 과목의 분량이 많으면 B4 용지가 여러 장 필요하겠죠. 이렇게 공부하는 과목을 다 정리했다면 이제 페이퍼를 이용해 빠르게 복습할 수 있습니다. 작게 접어서 볼 수 있기 때문에 등하교길 기차, 버스 안에서 또는 잠깐 잠깐 시간 날때 쉽게 복습할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;단순한 방법이지만, 공부해야 할 내용 전체를 직접 손으로 써가며 정리할 수 있고, 빠르게 여러 번 복습할 수 있기 때문에 암기할 것이 많은 과목의 시험 준비에 좋습니다. 물론 제게 좋았다고 여러분에게도 좋다는 법은 없으니 한 번 시험해보고 자신에게 맞을 때 쓰면 되겠습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>숫자-압운 기억법</title><link>https://pkgpl.org/2023/08/29/%ec%88%ab%ec%9e%90-%ec%95%95%ec%9a%b4-%ea%b8%b0%ec%96%b5%eb%b2%95/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/29/%ec%88%ab%ec%9e%90-%ec%95%95%ec%9a%b4-%ea%b8%b0%ec%96%b5%eb%b2%95/</guid><pubDate>Tue, 29 Aug 2023 14:27:03 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/28/어떻게-공부할-것인가/&quot;&gt;어떻게 공부할 것인가&lt;/a&gt;에서 새로 배운 것을 이전에 알고 있던 것과 연결하면 더 잘 기억할 수 있다고 했습니다. 숫자-압운 기억법은 숫자의 이름을 이용해 숫자를 이미지와 연결해 놓습니다. 외워야 할 목록이 있을 때 목록의 내용을 미리 만들어놓은 이미지와 연결시켜 외우면 쉽게 오래 외울 수 있습니다. 저는 암기해야 할 목록이 있을 경우 숫자-압운 기억법을 이용해 도움을 많이 받았습니다. 여러분도 이 기법을 미리 연습해 놓으면 시험 공부할 때나 외울 것이 있을 때 큰 도움이 될겁니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;기본 이미지&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;숫자를 이미지와 연결하는 방법에는 여러 가지가 있는데, 제가 책에서 보고 사용한 방법을 소개해드리겠습니다. 숫자의 영어 이름과 발음이 유사한 단어의 이미지를 사용하는 방법입니다. 이미지를 사용하는 이유는 사람이 숫자나 글자보다는 이미지를 잘 기억하기 때문입니다. 아래 단어들을 보고 숫자 발음과 연결된 이미지를 상상해보세요. 새로운 목록을 외울 때마다 기준이 되는 이미지들입니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;One: Bun 번 빵&lt;/li&gt;



&lt;li&gt;Two: Shoe 신발&lt;/li&gt;



&lt;li&gt;Three: Tree 나무&lt;/li&gt;



&lt;li&gt;Four: Door 문&lt;/li&gt;



&lt;li&gt;Five: Hive 벌집&lt;/li&gt;



&lt;li&gt;Six: Sticks 막대기&lt;/li&gt;



&lt;li&gt;Seven: Heaven 천국&lt;/li&gt;



&lt;li&gt;Eight: Skate 스케이트&lt;/li&gt;



&lt;li&gt;Nine: Vine 포도나무&lt;/li&gt;



&lt;li&gt;Ten: Hen 암탉&lt;/li&gt;
&lt;/ol&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;암기할 목록&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 다음의 목록을 외워야 한다고 해봅시다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;달팽이&lt;/li&gt;



&lt;li&gt;병아리&lt;/li&gt;



&lt;li&gt;고슴도치&lt;/li&gt;



&lt;li&gt;수탉&lt;/li&gt;



&lt;li&gt;깃털&lt;/li&gt;



&lt;li&gt;깨진 달걀&lt;/li&gt;



&lt;li&gt;둥지에 있는 세 개의 달걀&lt;/li&gt;



&lt;li&gt;지렁이&lt;/li&gt;



&lt;li&gt;토끼&lt;/li&gt;



&lt;li&gt;애벌레&lt;/li&gt;



&lt;li&gt;계란 프라이&lt;/li&gt;



&lt;li&gt;꽃&lt;/li&gt;
&lt;/ol&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;입력하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;숫자-압운 기억법을 이용해 외워봅시다. 앞에서 만들어 놓은 이미지와 목록의 이미지를 결합해서 상상하면 됩니다. 이 때 구체적이고 특이한(비정상적인) 이미지가 기억하기 좋습니다. 그런데 목록에 12개의 항목이 있어 기본 이미지가 부족합니다. 이 때는 11번에서 20번까지는 얼음 속에서, 21번부터 30번까지는 불 속에서 있는 이미지와 같이 추가 환경을 상상하면 됩니다. 다음은 예시 이미지입니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;빵과 달팽이가 함께 있는 이미지를 상상합니다 – 달팽이가 롤빵을 등껍질로 지니고 기어가는 이미지&lt;/li&gt;



&lt;li&gt;신발에 들어간 병아리&lt;/li&gt;



&lt;li&gt;고슴도치의 가시가 나무에 박힌 이미지&lt;/li&gt;



&lt;li&gt;문을 뚫고 나오는, 큰 볏을 가진 수탉&lt;/li&gt;



&lt;li&gt;깃털에서 꿀이 뚝뚝 떨어지는 이미지&lt;/li&gt;



&lt;li&gt;깨진 달걀을 막대기로 더 깨는 이미지&lt;/li&gt;



&lt;li&gt;둥지에 담긴 달걀이 천국으로 날아 올라가는 이미지&lt;/li&gt;



&lt;li&gt;스케이트 날이 지렁이처럼 생겼네요&lt;/li&gt;



&lt;li&gt;포도나무에 토끼가 열렸네요&lt;/li&gt;



&lt;li&gt;암닭이 애벌레를 목도리로 사용합니다&lt;/li&gt;



&lt;li&gt;계란 프라이를 싼 얼어붙은 햄버거 빵&lt;/li&gt;



&lt;li&gt;얼음 신발에서 피어 나온 꽃&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;미리 연습을 해두면 새로운 목록이 주어졌을 때 기본 이미지와 결합해서 상상하고 외우는데 하나에 몇 초밖에 안 걸립니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;출력하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이미지를 상상해서 외웠으면 이제 임의의 순서대로 숫자 – 기본이미지 – 결합이미지 순서로 연상하며 출력할 수 있습니다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;5번? 벌집: 꿀 – 깃털에서 꿀이 떨어지는 이미지 – 답: 깃털&lt;/li&gt;



&lt;li&gt;8번? 스케이트: 지렁이 스케이트 날 – 답: 지렁이&lt;/li&gt;



&lt;li&gt;2번? 신발: 병아리가 신발에 들어갔죠 – 답: 병아리&lt;/li&gt;



&lt;li&gt;12번? 얼음 + 신발: 얼음 신발에서 꽃이 피었습니다 – 답: 꽃&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이런 식으로 임의의 순서로, 1번부터 12번까지 또는 역순으로도 외울 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;응용하기&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사실 위의 목록은 ‘치킨 차차’ 보드게임에서 가지고 왔습니다. 자신의 말 앞에 있는 이미지를 뒤집힌 카드들 중에 찾아서 전진하는 게임인데, 상대방의 말을 잡으면 이기게 됩니다. 대학생 때 여자친구와 보드게임방에 가서 치킨 차차 게임을 한 적이 있습니다. 서로 이겼다가 졌다가 하면서 게임을 하다가 숫자-압운 기억법을 쓸 수 있겠다는 생각이 들었습니다. 그래서 다음번 게임할 때 12개의 뒤집힌 카드들에 속으로 번호를 매기고 하나씩 뒤집어보며 외웠습니다. 극적인 효과를 위해 일부러 하나도 안 맞추다가 한번에 모든 카드를 다 맞춰서 역전했습니다. 결과는? 완승. 여자친구 표정은? 당연히 안 좋았죠. 그 이후로 여러 사람들과 치킨 차차 게임을 해봤는데 한 번도 진 적이 없습니다. 단, 부작용도 있습니다. 사람들이 한 두 번 진 후에는 더이상 게임을 안 하려고 하죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;숫자-압운 기억법을 적용하기 어려운 목록도 있습니다. 이미지가 유사한 목록(예 – 고등어, 삼치, 명태, 민어, 광어)은 헷갈릴 수 있습니다. 이미지로 만들기 어려운 목록은 다른 암기 방법을 찾아보세요(예 – 캄오실데석페트쥐백34).&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;시험 볼 때도 여러 번 사용했습니다. 여러분도 시험 때 외워야 할 목록이 있으면 숫자-압운 기억법을 적용해보세요.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>어떻게 공부할 것인가?</title><link>https://pkgpl.org/2023/08/28/%ec%96%b4%eb%96%bb%ea%b2%8c-%ea%b3%b5%eb%b6%80%ed%95%a0-%ea%b2%83%ec%9d%b8%ea%b0%80/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/28/%ec%96%b4%eb%96%bb%ea%b2%8c-%ea%b3%b5%eb%b6%80%ed%95%a0-%ea%b2%83%ec%9d%b8%ea%b0%80/</guid><pubDate>Mon, 28 Aug 2023 13:00:13 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;평생 공부&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞으로 사람들은 평생 여러 개의 직업/직장을 가지게 될 것이고 그에 따라 평생 공부해야 할 것이라는 전망들이 많습니다. 대학생 때 배운 전공 지식만 가지고 평생 살아가기는 힘들다는 말입니다. 대학 전공은 첫 번째 직업/직장을 결정하는 역할로 축소될 수도 있습니다. 전공 지식 자체도 물론 중요하지만, 전공 공부를 하며 &lt;a href=&quot;https://pkgpl.org/2023/08/21/혁신-수업의-숨겨진-메시지/&quot;&gt;소프트스킬&lt;/a&gt;과 효율적으로 공부하는 방법(학습법)을 익혀두면 평생 도움이 될 것입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;효율적인 공부법&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000625448&quot;&gt;어떻게 공부할 것인가&lt;/a&gt;라는 책에 인지과학 분야에서 밝혀낸 효율적인 공부법(잘 기억할 수 있는 공부법)들이 안내되어 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;노력: 쉽게 배운 지식보다 노력을 많이 들여 배운 지식이 더 깊고 오래 간다고 합니다.&lt;/li&gt;



&lt;li&gt;인출 연습: 단순히 읽기만 하는 것보다 배운 것을 떠올리는 연습을 하는 것이 더 효율적입니다. 시험 보는 것이 공부에 도움이 된다는 말입니다.&lt;/li&gt;



&lt;li&gt;생성 효과: 지식의 빈 부분을 채우기 위한 노력이 기억력을 강화합니다.&lt;/li&gt;



&lt;li&gt;반추: 새로 배운 것을 이전에 알고 있던 것과 연결하면 더 잘 기억할 수 있습니다.&lt;/li&gt;



&lt;li&gt;정교화: 생소한 내용을 자신의 언어로 표현하여 기존 지식과 연결하기&lt;/li&gt;



&lt;li&gt;시간 간격을 두고 복습하기, 교차연습: 망각이 일어날 만한 시간 간격을 두거나 두 가지 이상의 주제 번갈아 배우기&lt;/li&gt;



&lt;li&gt;심성 모형: 새로운 자료의 핵심 내용을 뽑아 심성 모형으로 만들고 사전 지식과 연결하기&lt;/li&gt;



&lt;li&gt;상위인지 (메타 인지): 무엇을 알고 무엇을 모르는지 자신의 생각을 지켜보기&lt;/li&gt;



&lt;li&gt;해법을 배우기 전 문제를 풀기 위해 애쓰기&lt;/li&gt;



&lt;li&gt;다양한 문제 유형에서 근본 원칙이나 규칙을 이끌어내기&lt;/li&gt;



&lt;li&gt;새로운 지식을 더 넓은 맥락에서 살펴보기&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;실천&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;알기만 해서는 별로 도움이 안 되고 &lt;a href=&quot;https://pkgpl.org/2021/09/02/의식적인-연습-deliberate-practice/&quot;&gt;의도적으로 연습&lt;/a&gt;해야 합니다. 앞으로 공부할 때 새로 배우는 내용을 자신의 말로 정리하고 이전에 알던 것과 관련지어 봅시다. 마인드맵을 이용하여 지식의 지도를 만들어 봅시다. 배운 후 자신이 아는 내용과 잘 모르겠는 내용을 생각해보고 부족한 부분을 채우기 위해 노력합시다. 공부할 때 한 과목을 다 본 후 다음 과목으로 넘어가는 것이 아니라 여러 과목을 번갈아가며 공부해 보세요.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;평생 공부의 시대에 효율적인 공부법을 통해 시간을 절약하고 절약한 시간에 &lt;a href=&quot;https://pkgpl.org/2023/08/20/대학생의-옵션-구매/&quot;&gt;자신만의 옵션&lt;/a&gt;을 준비해보세요.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>대학생의 자유로부터의 도피</title><link>https://pkgpl.org/2023/08/27/%eb%8c%80%ed%95%99%ec%83%9d%ec%9d%98-%ec%9e%90%ec%9c%a0%eb%a1%9c%eb%b6%80%ed%84%b0%ec%9d%98-%eb%8f%84%ed%94%bc/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/27/%eb%8c%80%ed%95%99%ec%83%9d%ec%9d%98-%ec%9e%90%ec%9c%a0%eb%a1%9c%eb%b6%80%ed%84%b0%ec%9d%98-%eb%8f%84%ed%94%bc/</guid><pubDate>Sun, 27 Aug 2023 13:34:35 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;책 – 자유로부터의 도피&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;에리히 프롬은 ‘자유로부터의 도피’에서 중세에서 근대로 오면서 사람들이 자유를 얻었을 때 어떻게 반응해왔는지 알려줍니다. 중세 사회는 사람들이 사회 체제 안에서 자신의 역할에 묶여 있는 사회였습니다. 자유가 없는 대신 소속감, 안전, 속박이 있는 사회였죠. 근대 자본주의 사회에서 사람들은 속박에서 해방되어 자유를 얻게 되었지만, 대신 소속감을 잃고 고립되어 불안해하는 경우가 많았습니다. 이러한 불안감으로부터 도피하기 위해 사람들은 크게 세 가지 방법을 선택했습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;권위주의: 자기 이외의 어떤 사람이나 사물에 의지하는 방법입니다.&lt;/li&gt;



&lt;li&gt;파괴성: 어떤 대상을 파괴하는 행동입니다.&lt;/li&gt;



&lt;li&gt;자동 인형적 순응: 자아를 상실하고 타인의 기대에 따라 살아가는 방법입니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;세 가지 방법 모두 바람직한 방법은 아닙니다. 에리히 프롬이 제안한 대안은 소극적 자유로부터 &lt;strong&gt;적극적 자유&lt;/strong&gt;로 나아가는 것입니다. 소극적 자유가 속박으로부터의 자유라면, 적극적 자유는 사랑과 일 속에서 자신의 능력을 발휘하며 바깥 세계와 자연스럽게 관계를 맺는 자유입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;대학생의 자유로부터의 도피&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;고등학생 때까지 별다른 자유 없이 공부만 하다가 대학에 들어온 학생들은 갑자기 대인관계, 수강신청, 동아리 등 다양한 선택의 자유를 얻게 됩니다. 하지만 자유에 따르는 책임, 취업, 진로, 인간관계의 어려움 등으로 인해 불안감이 생기죠. 에리히 프롬의 분류에 따른 대학생의 도피 방식은 다음과 같이 생각해볼 수 있습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;권위주의: 학교의 규칙, 교수나 멘토의 기대에 맞는 틀 안에서만 움직이는 방법입니다.&lt;/li&gt;



&lt;li&gt;파괴성: 갈등이나 대인관계의 문제 등을 파괴적인 행동으로 해결하려고 시도합니다.&lt;/li&gt;



&lt;li&gt;자동 인형적 순응: 사회의 기대에 맞추어 행동하고 자신의 개성 없이 트렌드나 패션을 맹목적으로 따릅니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;바람직한 반응은 적극적 자유로 나아가는 것이죠. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;다른 사람의 기대에 따라 사는 것이 아니라 &lt;a href=&quot;https://pkgpl.org/2021/09/03/자율성-숙련-목적/&quot;&gt;자신의 삶을 주도&lt;/a&gt;하겠다고 결심합시다.&lt;/li&gt;



&lt;li&gt;자신만의 고유한 가치를 긍정적으로 받아들여 자신만의 정체성을 찾아가시기 바랍니다.&lt;/li&gt;



&lt;li&gt;다양한 책을 읽으며 스스로 생각하는 힘을 키웁시다.&lt;/li&gt;



&lt;li&gt;&lt;a href=&quot;https://pkgpl.org/2021/09/04/삶의-의미/&quot;&gt;삶의 의미&lt;/a&gt;를 찾아가며 &lt;a href=&quot;https://pkgpl.org/2018/12/31/책-소유냐-존재냐-에리히-프롬/&quot;&gt;존재하는 삶&lt;/a&gt;을 살아가시길 바랍니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이러한 과정에서 여러 어려움과 실패가 있겠지만 &lt;a href=&quot;https://pkgpl.org/2023/08/22/시행착오를-통한-학습과-과학적-방법론/&quot;&gt;우리는 실패를 통해 배우고 성장할 수 있습니다&lt;/a&gt;.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item><item><title>시행착오를 통한 학습, 팅커링, 그리고 경사하강법</title><link>https://pkgpl.org/2023/08/25/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5-%ed%8c%85%ec%bb%a4%eb%a7%81-%ea%b7%b8%eb%a6%ac%ea%b3%a0-%ea%b2%bd%ec%82%ac%ed%95%98%ea%b0%95%eb%b2%95/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/25/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5-%ed%8c%85%ec%bb%a4%eb%a7%81-%ea%b7%b8%eb%a6%ac%ea%b3%a0-%ea%b2%bd%ec%82%ac%ed%95%98%ea%b0%95%eb%b2%95/</guid><pubDate>Fri, 25 Aug 2023 13:44:52 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/22/시행착오를-통한-학습과-과학적-방법론/&quot;&gt;우리는 시행착오(Trial &amp;amp; Error)를 통해 배웁니다.&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;팅커링(Tinkering)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;팅커링은 &lt;a href=&quot;https://pkgpl.org/2023/08/21/혁신-수업의-숨겨진-메시지/&quot;&gt;혁신 수업&lt;/a&gt; 중 하나인 메이커 교육에서 많이 사용하는 단어입니다. 자유롭게 주어진 재료를 가지고 무엇인가를 만들거나 개선하며 창의적인 실험과 조작을 하는 과정입니다. 이것 저것 시도해보며 배우는 시행착오 과정이죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;나심 탈레브도 &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000625400&quot;&gt;안티프래질&lt;/a&gt;에서 팅커링에 대해 이야기했습니다. 책에서는 복잡한 시스템이나 현상을 이해하거나 개선하기 위한 작은 실험을 의미했죠. 팅커링은 손실은 작지만 커다란 이익을 얻을 수 있는 시행착오로, &lt;a href=&quot;https://pkgpl.org/2023/08/20/대학생의-옵션-구매/&quot;&gt;옵션&lt;/a&gt;의 특성을 가지고 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;경사하강법&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;복잡한 시스템의 거동을 잘 모를 때 작은 실험을 통해 결과를 개선해가는 과정. 수치해석이나 머신러닝의 최적화 분야에서도 같은 방법을 사용합니다. 복잡한 시스템은 목적함수 또는 손실함수라 부릅니다. 우리가 바꿀 수 있는 것은 매개변수이고, 작은 실험은 현재 매개변수를 이용해 목적함수의 값과 기울기를 계산하는 과정이 됩니다. 계산한 값을 이용해 매개변수를 어떻게 개선해야 하는지에 대한 피드백을 얻고 매개변수를 개선하는 과정을 반복해가며 점점 향상된 결과를 얻게 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 시행착오를 통해 결과를 개선해가는 과정에는 작은 실패와 성공들, 피드백들이 포함됩니다. 실패는 학습 과정의 일부분입니다. 실패에 낙심하지 말고 다시 시도합시다. &lt;a href=&quot;https://www.stdio.co.kr/index_famous.htm?s_no=770&quot;&gt;실패는 다시 하라는 뜻입니다.&lt;/a&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>시행착오를 통한 학습과 린 스타트업 방법론</title><link>https://pkgpl.org/2023/08/24/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%eb%a6%b0-%ec%8a%a4%ed%83%80%ed%8a%b8%ec%97%85-%eb%b0%a9%eb%b2%95%eb%a1%a0/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/24/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%eb%a6%b0-%ec%8a%a4%ed%83%80%ed%8a%b8%ec%97%85-%eb%b0%a9%eb%b2%95%eb%a1%a0/</guid><pubDate>Thu, 24 Aug 2023 14:50:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/22/시행착오를-통한-학습과-과학적-방법론/&quot;&gt;우리는 시행착오(Trial &amp;amp; Error)를 통해 배웁니다.&lt;/a&gt;&lt;/strong&gt; 린 스타트업 방법론은 시행착오를 통한 학습을 스타트업에 적용한 기법입니다. &lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;린 스타트업 방법론&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;창업가들은 소비자를 만족시키는 또는 소비자들의 문제를 해결해주는 상품이나 서비스를 통해 돈을 버는 사람들입니다. 이러한 상품이나 서비스를 개발할 때 린 제조 기법과 애자일 방법론에서 아이디어를 얻어 &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000001032948&quot;&gt;린 스타트업&lt;/a&gt; 방법론이 나왔습니다. 창업가들은 소비자들을 만족시키기 위해 다양한 가설을 세우고 시도합니다. 스타트업은 보통 회사 자금이 많지 않기 때문에 비용이 많이 드는 시도를 했다가 실패하면 망하기 쉽습니다. 그래서 최종 목표는 높게 잡더라도 각각의 시도는 작게 만들 필요가 있죠. 작은 시도를 여러 번 할 수 있도록 우선 최소 기능 제품(Minimum Viable Product)부터 내놓습니다. 이후 제품을 가지고 소비자로부터 피드백을 받아 빨리 배우며(유효한 학습) 제품을 개선하는 과정을 계속 반복합니다. &lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;문제: 소비자 만족&lt;/li&gt;



&lt;li&gt;여러 가지 가설 시도: 최소 기능 제품부터 시작해 조금씩 개선된 상품/서비스 자주 출시&lt;/li&gt;



&lt;li&gt;실패한 해결책 제거: 피드백을 통해 학습하며 소비자 불만 제거 (2, 3 단계 반복)&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;시행착오를 통한 학습과 같은 과정을 거치죠. &lt;strong&gt;창업가들도 시행착오를 통해 배웁니다.&lt;/strong&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>시행착오를 통한 학습과 애자일 방법론</title><link>https://pkgpl.org/2023/08/23/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%ec%95%a0%ec%9e%90%ec%9d%bc-%eb%b0%a9%eb%b2%95%eb%a1%a0/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/23/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%ec%95%a0%ec%9e%90%ec%9d%bc-%eb%b0%a9%eb%b2%95%eb%a1%a0/</guid><pubDate>Wed, 23 Aug 2023 14:43:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/22/시행착오를-통한-학습과-과학적-방법론/&quot;&gt;우리는 시행착오(Trial &amp;amp; Error)를 통해 배웁니다.&lt;/a&gt;&lt;/strong&gt; 애자일 방법론은 시행착오를 통한 학습을 프로그램 개발에 적용한 기법입니다. &lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;폭포수 방법론&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;프로그래밍 분야에서 예전부터 사용하던 폭포수 방법론에서는 프로그램 설계 – 구현 – 배포 (단순화했습니다) 단계가 순차적으로 진행됩니다. 설계가 끝나면 구현을 시작하고, 구현이 끝나면 배포하는 방식이지요. 구현이 끝나야 최종 결과물이 나오기 때문에 결과물을 얻는데 소요되는 기간이 길어지게 됩니다. 그래서 예전에는 소프트웨어가 1년에 한 번 정도씩 업데이트되어 나왔죠. 최종 결과물이 소비자 마음에 안 든다면? 피드백을 받아 개선해서 새 제품을 내놓는데 또 오랜 시간이 걸립니다. 소비자들의 요구 사항이 빠르게 변하는 세상, 불확실성이 큰 세상에서는 적절치 못한 방법이죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;애자일 방법론&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그래서 &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000001033102&quot;&gt;애자일 방법론&lt;/a&gt;이 나왔습니다. 애자일 방법론에서는 설계 – 구현 – 배포로 이어지는 개발 주기(피드백 고리)를 몇 주 정도로 짧게 잡습니다. 전체 기능을 작은 부분들로 나눠서 중요한 것부터 구현해갑니다. 핵심 기능부터 시작해서 점점 개선해가는데, 완제품이 나오기 전부터 소비자들에게 배포해서 빠르게 피드백을 수집하고 반영합니다. 그래서 요즘 프로그램들 중에는 몇 주 또는 몇 달 간격으로 새로운 버전이 나오는 경우가 많죠. &lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;문제: 소비자 만족&lt;/li&gt;



&lt;li&gt;여러 가지 가설 시도: 조금씩 개선된 버전 자주 출시&lt;/li&gt;



&lt;li&gt;실패한 해결책 제거: 피드백을 통해 소비자 불만 제거 (2, 3 단계 반복)&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;각각의 버전들(작은 시도들)이 소비자 만족이라는 문제를 해결하기 위한 가설이 됩니다. 여러 시도들로부터 빠르게 피드백을 받아 프로그램을 개선해갑니다. 소비자를 만족시킬 완벽한 해결책은 존재하지 않을지 모르지만, 이러한 과정을 통해 쓸만한 해결책에 점점 가까워집니다. &lt;strong&gt;개발자들도 시행착오를 통해 배웁니다.&lt;/strong&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>시행착오를 통한 학습과 과학적 방법론</title><link>https://pkgpl.org/2023/08/22/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%ea%b3%bc%ed%95%99%ec%a0%81-%eb%b0%a9%eb%b2%95%eb%a1%a0/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/22/%ec%8b%9c%ed%96%89%ec%b0%a9%ec%98%a4%eb%a5%bc-%ed%86%b5%ed%95%9c-%ed%95%99%ec%8a%b5%ea%b3%bc-%ea%b3%bc%ed%95%99%ec%a0%81-%eb%b0%a9%eb%b2%95%eb%a1%a0/</guid><pubDate>Tue, 22 Aug 2023 14:50:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;우리는 시행착오(Trial &amp;amp; Error)를 통해 배웁니다.&lt;/strong&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000201054001&quot;&gt;칼 포퍼&lt;/a&gt;는 시행착오를 통한 학습의 3단계 모델과 과학적 방법론 4단계 모델에 대해 설명했습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;시행착오를 통한 학습의 3단계 모델&lt;/h2&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;(답이 알려지지 않은) 문제&lt;/li&gt;



&lt;li&gt;여러 가지 해결책들(가설) 시도&lt;/li&gt;



&lt;li&gt;실패한 해결책 제거(2, 3단계 반복)&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;여러 가지 가설들 중 하나가 문제 해결에 성공하면 이를 통해 성공적인 해결책을 배우게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;과학적 방법론 4단계 모델&lt;/h2&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;기존 문제&lt;/li&gt;



&lt;li&gt;잠정적 이론들(가설) 세우기&lt;/li&gt;



&lt;li&gt;실험적 검증을 포함하여 비판적 논의를 통한 제거 시도들(실패한 해결책 제거)&lt;/li&gt;



&lt;li&gt;이론들의 비판적 논의에서 도출되는 새로운 문제들&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;과학적 방법론도 기본 틀은 시행착오를 통한 학습과 같습니다. 문제가 있을 때 여러 가지 가설들을 세우고 하나씩 시도해봅니다. 시도하면서 피드백도 얻습니다. 문제가 해결되지 않으면 다음 가설로 넘어가는 과정을 반복하다가 성공적인 가설을 찾으면 문제 해결책을 배우게 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;간단한 방법이지만 과학 분야 뿐 아니라 불확실성이 큰 다양한 분야에서 시행착오를 통해 배우며 전진해 나갑니다. 이 때 주의해야 할 점은 가설이 실패하더라도 피드백을 통해 배워야 한다는 점, 실패했을 때 입는 피해가 크지 않도록 해야 한다는 것입니다. 빠른 피드백은 &lt;a href=&quot;https://pkgpl.org/2021/09/02/의식적인-연습-deliberate-practice/&quot;&gt;의식적인 연습&lt;/a&gt;에서도 중요한 요소입니다. 실패했을 때의 리스크가 크지 않고 성공했을 때의 보상이 크다면 &lt;a href=&quot;https://pkgpl.org/2023/08/20/대학생의-옵션-구매/&quot;&gt;좋은 옵션&lt;/a&gt;이 될 수도 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>혁신 수업의 숨겨진 메시지</title><link>https://pkgpl.org/2023/08/21/%ed%98%81%ec%8b%a0-%ec%88%98%ec%97%85%ec%9d%98-%ec%88%a8%ea%b2%a8%ec%a7%84-%eb%a9%94%ec%8b%9c%ec%a7%80/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/21/%ed%98%81%ec%8b%a0-%ec%88%98%ec%97%85%ec%9d%98-%ec%88%a8%ea%b2%a8%ec%a7%84-%eb%a9%94%ec%8b%9c%ec%a7%80/</guid><pubDate>Mon, 21 Aug 2023 14:35:00 GMT</pubDate><content:encoded>
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;미디어 = 학교 수업&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;메시지 = 전공 지식&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;미디어는 메시지를 전달하는 도구입니다. 학교 수업이 미디어라면 전공 지식은 메시지에 해당합니다. &lt;a href=&quot;https://pkgpl.org/2021/09/06/미디어의-이해-인간의-확장/&quot;&gt;미디어의 이해&lt;/a&gt;에서 말하는 것처럼, 미디어는 공개적으로 메시지를 전달하지만, 비공개적으로 미디어 자체의 메시지도 전달합니다. 수업에는 어떤  메시지가 숨어 있을까요? 숨겨진 메시지는 수업 방식에 따라 달라지게 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;가장 일반적인 수업 방식은 강의식 수업입니다. 최근에는 플립러닝, 프로젝트 기반 학습, 문제 기반 학습, 액션 러닝, 메이커 교육, 팀 티칭… 등등 다양한 혁신 수업들이 늘어나고 있죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;강의식 수업은 ‘무대 위의 현자’ 모델을 따릅니다. 학생은 모르는 내용을 전문가인 선생님에게 배웁니다. 여기에는 전문가의 전공 지식이 중요하다는 메시지가 숨어있는 셈이죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;혁신 수업들은 강의식 수업도 포함하지만 학생들의 적극적 활동에 좀 더 중점을 두고 있습니다. 능동적으로 배울 때 더 잘 배울 수 있다는 연구 결과도 반영되어 있겠죠. 학생들이 주인공으로 활동하는 동안 선생님은 옆에서 돕는 사람이 됩니다. 조별 활동, 토론, 실습 등의 활동을 통해 전공 지식도 전달하지만, 여기에는 학생들의 의사소통 능력, 협동, 창의력, 비판적 사고 능력 등을 향상시키고자 하는 숨은(?) 의도가 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;하드스킬 = 전공 지식&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;소프트스킬 = 의사소통, 협동, 창의력, 비판적 사고력 등&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;전공 지식은 하드스킬과 관련이 있습니다. 하드스킬과 대비되는 소프트스킬에는 앞에서 이야기한 의사소통 능력, 협동 능력, 창의력, 비판적 사고 등이 있습니다. 교육 전문가 Fullan은 소프트스킬로 6C를 이야기했습니다(Character, Citizenship, Collaboration, Communication, Creativity, Critical thinking).&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;강의식 수업 = 하드스킬 강조&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;혁신 수업 = 소프트스킬도 강조&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;어떤 방식이 맞고 어떤 방식이 틀렸다고 할 수는 없습니다. 혁신 수업이 늘고 있다는 것은 사회에서 이러한 소프트스킬의 중요성이 점점 커지고 있다, 또는 교육계에서 소프트스킬의 중요성을 깨닫게 되었다는 것을 의미한다고 볼 수 있겠죠. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;소프트스킬 향상을 위해서는 학생들의 능동적인 참여가 중요합니다. 가만히 앉아서 듣는 것보다는 노력이 더 필요합니다. 대신 졸음은 덜 올겁니다^^ 코로나 이후 &lt;a href=&quot;https://pkgpl.org/2016/10/16/거꾸로-수업-4학기/&quot;&gt;플립러닝&lt;/a&gt; 수업에서 학생들의 참여도가 떨어져 지난 학기 수업에서 강의의 비중을 늘렸었는데, 앞으로 점차 나아질 것이라 기대합니다!&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>대학생의 옵션 구매</title><link>https://pkgpl.org/2023/08/20/%eb%8c%80%ed%95%99%ec%83%9d%ec%9d%98-%ec%98%b5%ec%85%98-%ea%b5%ac%eb%a7%a4/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/20/%eb%8c%80%ed%95%99%ec%83%9d%ec%9d%98-%ec%98%b5%ec%85%98-%ea%b5%ac%eb%a7%a4/</guid><pubDate>Sun, 20 Aug 2023 14:51:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;옵션이란?&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;경제에서 &lt;strong&gt;옵션은 선택할 수 있는 권리를 말합니다.&lt;/strong&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;예를 들어, 현재 브렌트유 가격이 리터당 1700원이라고 해봅시다. 한 달 후에 1리터를 1750원에 살 수 있는 권리를 50원에 팔고 있다고 해봅시다. 사겠습니까? &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;한 달 후 유가가 리터당 1800원이 넘어갈 것이라 예상한다면 이 권리를 사는 것이 좋습니다. 만약 2000원이 된다면 1750원을 내고 2000원짜리 브렌트유 1리터를 살 수 있으므로 250원 이득이네요. 옵션 구매에 50원을 투자했으니 총 이득은 250원에서 50원을 뺀 200원이 됩니다. 50원 투자해서 한 달만에 200원 순이익을 남겼다면 대단히 성공적인 투자죠?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;반대로 유가가 1400원으로 떨어졌다고 해봅시다. 얼마나 손해를 볼까요? 옵션은 권리라고 했습니다. 손해볼 것 같으면 안 사면 됩니다. 따라서 유가가 아무리 떨어져도 최대 손실은 옵션 구매에 쓴 50원으로 제한됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;이렇게 이득은 커질 수 있고, 손실은 제한되는 비대칭적 선택권이 바로 옵션입니다.&lt;/strong&gt; 미래에 변동이 없다면 옵션은 필요 없습니다. 유가가 한 달 후에도 1700원이라면 옵션을 구매할 이유가 없죠.&lt;strong&gt; 변동성이 크고 불확실할수록 옵션은 빛을 발합니다.&lt;/strong&gt;&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;대학생의 옵션&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;옵션을 대학 생활에 적용해봅시다. 4년 동안 열심히 공부해서 우수한 성적으로 졸업하고 원하는 기업에 취직할 것이 확실하다면 옵션이 필요 없습니다. 부모님께 물려받을 재산이 많다면 역시 옵션이 필요 없습니다. 졸업 후가 불확실하다면 나만의 옵션을 준비하는 것이 어떻까요?&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학생은 돈이 별로 없으니 옵션은 시간과 노력으로 구매해야 합니다. 예를 들면 인스타그램 보는 시간을 줄이고, A0 받을 만큼 공부하는 대신 B+ 받을 만큼만 공부해서 남는 시간과 노력으로 미래에 도움이 될 수도 있을만한 다른 것을 공부하거나 만드는 것입니다. 이 때 많이들 하는 스펙 쌓기가 아니라 남들과 차별화할 수 있는 일을 해야 좋은 옵션이 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;어학 연수? 단순히 어학 연수 다녀왔다는 것은 좋은 옵션이 아닙니다. 원어민처럼 말하고 듣는다면 물론 좋은 옵션이 될 수 있지만 시간, 노력 뿐 아니라 돈도 많이 들 수 있습니다. 생성AI 공부? 빠르게 실력을 쌓는다면 향후 몇 년간 좋은 옵션이 될 수 있을 것으로 보입니다. 컨텐츠 크리에이터? 2년 이상 한 가지 분야에서 전문성을 쌓아가는 과정을 보여준다면 훌륭한 옵션이 될 수 있습니다. 창업? 대학생 때 창업을 한다면 우선 위험 부담 없는 창업으로 경험을 쌓기를 권장합니다. 역시 좋은 옵션이 될 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;옵션은 권리라고 했습니다. &lt;strong&gt;자신이 준비한 옵션이 졸업 후 취업이나 창업에 도움이 된다면 사용하면 되고, 도움이 되지 않는다면 안 쓰면 됩니다.&lt;/strong&gt; 손해보는 것은 물론 옵션을 준비하는데 들어간 시간과 노력(나중에 보면 손해가 아닐 수도 있습니다)이지만 잘 될 경우 옵션으로 인해 여러분의 진로와 인생이 달라질 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item><item><title>📦 연구도 상자 안에서</title><link>https://pkgpl.org/2023/08/19/%f0%9f%93%a6-%ec%97%b0%ea%b5%ac%eb%8f%84-%ec%83%81%ec%9e%90-%ec%95%88%ec%97%90%ec%84%9c/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/19/%f0%9f%93%a6-%ec%97%b0%ea%b5%ac%eb%8f%84-%ec%83%81%ec%9e%90-%ec%95%88%ec%97%90%ec%84%9c/</guid><pubDate>Sat, 19 Aug 2023 14:35:17 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;컨테이너를 이용하면 컴퓨터를 이용한 과학 기술 연구 효율성을 높일 수 있습니다.&lt;/strong&gt;&lt;/p&gt;



&lt;div class=&quot;wp-block-group&quot;&gt;&lt;div class=&quot;wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained&quot;&gt;
&lt;div class=&quot;wp-block-group&quot;&gt;&lt;div class=&quot;wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;컨테이너가 왜 중요할까요?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;연구 프로젝트들의 작업 공간을 분리하여 관리하기 쉬워집니다.&lt;/li&gt;



&lt;li&gt;프로그램 설치 및 환경 설정이 간단해집니다.&lt;/li&gt;



&lt;li&gt;연구 재현성(reproducibility)을 높일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;div class=&quot;wp-block-group&quot;&gt;&lt;div class=&quot;wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;자세한 내용&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/18/컨테이너를-이용한-프로젝트-작업-공간-분리/&quot;&gt;컨테이너를 이용한 프로젝트 작업 공간 분리&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/16/소프트웨어를-이용한-연구에서-발생하는-몇-가지-문/&quot;&gt;소프트웨어를 이용한 연구에서 발생하는 몇 가지 문제들 예방하기&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href=&quot;https://pkgpl.org/2021/06/23/docker와-github를-이용한-소프트웨어-연구-환경-구축/&quot;&gt;Docker와 GitHub를 이용한 소프트웨어 연구 환경 구축&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>컨테이너를 이용한 프로젝트 작업 공간 분리</title><link>https://pkgpl.org/2023/08/18/%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%94%84%eb%a1%9c%ec%a0%9d%ed%8a%b8-%ec%9e%91%ec%97%85-%ea%b3%b5%ea%b0%84-%eb%b6%84%eb%a6%ac/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/18/%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%94%84%eb%a1%9c%ec%a0%9d%ed%8a%b8-%ec%9e%91%ec%97%85-%ea%b3%b5%ea%b0%84-%eb%b6%84%eb%a6%ac/</guid><pubDate>Fri, 18 Aug 2023 13:04:12 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000625549&quot;&gt;정리하는 뇌&lt;/a&gt;라는 책에 보면 여러 개의 프로젝트를 진행하고 있을 경우 프로젝트별로 작업 공간을 분리하는 것이 두뇌 활동에 도움이 된다는 이야기가 나옵니다. 2018년 이 책을 읽고 학교 연구실에서 수업 준비 및 행정 업무용 책상과 연구용 책상(그리고 컴퓨터)을 분리했던 적이 있습니다. 수업 준비를 하다가 연구를 하려면 자리를 옮겨야 했고, 이를 통해 두뇌에 작업이 달라졌다는 것을 확실히 알려주기 위해서였죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;연구용 책상을 따로 분리할 수는 있었지만 공간 제약으로 인해 여러 연구 프로젝트들끼리의 물리적 공간 분리는 할 수 없었습니다. 대신 &lt;a href=&quot;https://github.com/tmux/tmux/wiki&quot;&gt;Tmux&lt;/a&gt;를 이용해 클러스터 서버에서 터미널을 분리해서 작업할 수 있었고, 실제로 이 프로젝트 작업하다가 저 프로젝트 작업하면서 뒤죽박죽되는 상황이 많이 줄었습니다. Tmux에서 프로젝트별로 터미널 세션을 만들어 작업했했는데, 세션 전환을 통해 이제 다른 프로젝트 작업을 시작한다는 것을 두뇌에 알려준 셈이죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이후 &lt;a href=&quot;https://www.docker.com/&quot;&gt;도커&lt;/a&gt; 사용법을 배워 &lt;a href=&quot;https://pkgpl.org/2023/08/17/컨테이너와-표준화/&quot;&gt;컨테이너 가상화&lt;/a&gt;도 프로젝트 작업 공간 분리에 함께 사용하기 시작했습니다. 이전에는 같은 호스트 운영체제에서 터미널만 분리해 작업했던 반면, 컨테이너를 사용하면 프로젝트별로 서로 다른 운영체제를 사용하는 셈이기에 작업 공간 분리에 더 좋습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000201140661&quot;&gt;세컨드 브레인&lt;/a&gt; 책에도 프로젝트별 파일 정리에 대한 언급이 나옵니다. 트와일라 타프라는 창의적인 안무가도 새로운 작품을 시작하면 새로운 상자를 준비해 작품과 관련된 모든 자료를 상자에 보관했다고 합니다. 프로젝트를 잠시 보류했다가도 나중에 다시 상자를 쉽게 찾아 진행할 수 있었고, 내용물을 공유하기도 좋았다고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;연구 프로젝트들도 컨테이너 상자를 이용해 정리합시다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>컨테이너와 표준화</title><link>https://pkgpl.org/2023/08/17/%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%ec%99%80-%ed%91%9c%ec%a4%80%ed%99%94/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/17/%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%ec%99%80-%ed%91%9c%ec%a4%80%ed%99%94/</guid><pubDate>Thu, 17 Aug 2023 14:53:43 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;부산에서 부두 근처를 지나다 보면 부두에 쌓인 컨테이너들과 컨테이너선, 컨테이너를 싣고 다니는 트럭들을 볼 수 있습니다. 최초의 컨테이너선은 1956년 운항을 시작한 말콤 맥린이라는 사람의 배였다고 합니다. 당시 컨테이너들은 규격이 일정하지 않았지만 이후 컨테이너의 표준화와 항구 대형 크레인 설치를 통해 화물 운송 효율이 증가하고 선박 운송 비용이 감소하여 국제 무역이 크게 증가했다고 합니다. 컨테이너는 단순한 박스이지만 세계 경제를 바꾼 혁신이었죠(&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000000600476&quot;&gt;마크 레빈슨, 더 박스&lt;/a&gt;).&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-1.png&quot; href=&quot;https://pkgpl.org/media/wp-1fd5339e8a238dc5.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;679&quot; src=&quot;https://pkgpl.org/media/wp-1fd5339e8a238dc5.png&quot; alt=&quot;&quot; class=&quot;wp-image-1243&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-2.png&quot; href=&quot;https://pkgpl.org/media/wp-69725610ec276266.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;394&quot; src=&quot;https://pkgpl.org/media/wp-69725610ec276266.png&quot; alt=&quot;&quot; class=&quot;wp-image-1244&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: image-3.png&quot; href=&quot;https://pkgpl.org/media/wp-0f18c75702bae873.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;263&quot; src=&quot;https://pkgpl.org/media/wp-0f18c75702bae873.png&quot; alt=&quot;&quot; class=&quot;wp-image-1248&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;도커에서 말하는 컨테이너가 바로 이 컨테이너입니다. 그래서 도커의 로고도 컨테이너선을 따라 만들었죠. 컴퓨터에서 컨테이너는 가상화 기술의 일종입니다. 실제로는 격리된 프로세스들의 집합이지만, 호스트 운영체제와 구분된 별도의 운영체제인 것처럼 생각할 수 있습니다. 컨테이너 기술은 도커 전에도 존재했지만 2013년 공개된 도커에서 컨테이너 기술을 쉽게 쓸 수 있도록 만든 후 컨테이너 기술이 널리 쓰이게 되었습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;종류별로 컨테이너들을 쌓아놓고 작업에 따라 필요한 컨테이너를 꺼내서 그 안에서 작업하고, 다 쓴 후에는 다시 넣어놓는 방식으로 일하는 경우를 생각해봅시다. 도커에서 쌓아놓은 컨테이너에 해당하는게 이미지입니다. 도커에는 필요한 프로그램들을 미리 설치해놓은 이미지들이 있습니다. 필요할 때 원하는 이미지를 실행해서 메모리에 올리면 그게 도커 컨테이너입니다. 메모리에 올린 후에는 컨테이너 안의 프로그램들을 이용해 작업을 할 수 있죠. 작업이 끝나면 컨테이너를 정지시키는데, 이미지는 그대로 남아 있어서 나중에 필요할 때 다시 쓸 수 있습니다. 이미지가 필요 없다면 지울 수도 있고, 직접 원하는 프로그램을 설치해서 나만의 이미지를 만들 수도 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;컨테이너는 해상 운송 뿐 아니라 컴퓨터 가상화 방식도 바꿨습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>소프트웨어를 이용한 연구에서 발생하는 몇 가지 문제들 예방하기</title><link>https://pkgpl.org/2023/08/16/%ec%86%8c%ed%94%84%ed%8a%b8%ec%9b%a8%ec%96%b4%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%97%b0%ea%b5%ac%ec%97%90%ec%84%9c-%eb%b0%9c%ec%83%9d%ed%95%98%eb%8a%94-%eb%aa%87-%ea%b0%80%ec%a7%80-%eb%ac%b8/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/16/%ec%86%8c%ed%94%84%ed%8a%b8%ec%9b%a8%ec%96%b4%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%97%b0%ea%b5%ac%ec%97%90%ec%84%9c-%eb%b0%9c%ec%83%9d%ed%95%98%eb%8a%94-%eb%aa%87-%ea%b0%80%ec%a7%80-%eb%ac%b8/</guid><pubDate>Wed, 16 Aug 2023 12:06:49 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;저는 대학원생 때부터 수학적/공학적 알고리즘을 개발하고 프로그래밍을 통해 구현해서 검증하는 방식의 연구를 많이 해왔습니다. &lt;a href=&quot;https://pkgpl.org/2023/08/14/ai가-연구도-집어-삼키고-있습니다/&quot;&gt;컴퓨터를 이용해 연구&lt;/a&gt;를 수행하다 보니 다양한 소프트웨어 관련 문제들을 겪어 왔습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;정전으로 클러스터 서버 전원이 꺼지면서 하드디스크가 고장나 소스 코드 파일이 손상되는 문제&lt;/li&gt;



&lt;li&gt;실수 소스 코드를 지워버리는 문제 (리눅스 커맨드라인에서 파일을 지우면 복구하기가 매우 어렵습니다)&lt;/li&gt;



&lt;li&gt;코드 수정 후 결과가 달라졌는데 한꺼번에 너무 많은 부분을 수정해서 어디를 어떻게 수정했는지 찾기 어려워지는 문제&lt;/li&gt;



&lt;li&gt;동일한 코드인데 다른 서버에서 컴파일이 안 되는 문제&lt;/li&gt;



&lt;li&gt;동일한 코드인데 다른 서버에서 실행 결과가 달라지는 문제&lt;/li&gt;



&lt;li&gt;새 서버가 들어올 때마다 연구에 필요한 프로그램들을 설치하기 전까지 사용하지 못하는 문제&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학원생 때는 이러한 문제들로 인해 시간을 많이 빼앗겼는데, 새로운 기술들로 인해 이제는 위의 상황들이 발생하지 않거나 발생해도 심각한 문제가 되지 않습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;1-3번 문제는 &lt;a href=&quot;https://pkgpl.org/2021/06/20/git과-github를-이용한-소스-코드-버전-관리/&quot;&gt;소스 코드 버전 관리 시스템&lt;/a&gt;을 이용해, 4-6번 문제는 &lt;a href=&quot;https://pkgpl.org/2021/06/23/docker와-github를-이용한-소프트웨어-연구-환경-구축/&quot;&gt;Docker 컨테이너&lt;/a&gt;를 이용해 예방/해결할 수 있습니다. 1, 2번은 Git 로컬 저장소와 GitHub 원격 저장소에 2중으로 코드를 백업하기 때문에 소스 코드가 지워져도 금방 복구가 가능합니다. 3번의 경우 git diff 명령으로 수정 부분을 쉽게 확인할 수 있습니다. 한꺼번에 많은 부분을 수정하기보다는 &lt;a href=&quot;https://pkgpl.org/2023/08/13/이슈-관리-프로그램을-이용한-작업-방법/&quot;&gt;작게 나눠서 수정하고 자주 commit하는게 좋습니다&lt;/a&gt;. 4, 5번은 서버의 라이브러리나 컴파일러 등이 달라서 생기는 문제인데, Docker 컨테이너 가상환경을이용해 서버의 환경을 동일하게 만들어 주면 연구 결과 재현성(reproducibility)을 높일 수 있습니다. 6번 또한 시스템에 Docker만 설치해 놓으면 금방 Docker 이미지를 받아 컨테이너를 실행하여 다른 서버와 동일한 연구 환경을 준비할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Git과 GitHub는 제가 대학원에 있을 때 공개 되었습니다. 버전 관리 소프트웨어는 그 전부터 존재했죠. 박사과정 때는 Mercurial이라는 소프트웨어를 잠깐 이용했었는데, 이후 Git과 GitHub가 버전 관리 업계를 거의 평정(?)했죠. Docker는 제가 박사과정을 마친 후에 나왔습니다. 컨테이너 기술은 그 이전에도 있었지만 Docker가 컨테이너 기술을 대중화했죠. 연구에서 프로그래밍을 진지하게 다룬다면 Git은 거의 필수입니다. Docker는 서버 컴퓨터를 많이 다루는 연구실에서 유용하게 쓸 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>생성AI 학부 수업</title><link>https://pkgpl.org/2023/08/15/%ec%83%9d%ec%84%b1ai-%ed%95%99%eb%b6%80-%ec%88%98%ec%97%85/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/15/%ec%83%9d%ec%84%b1ai-%ed%95%99%eb%b6%80-%ec%88%98%ec%97%85/</guid><pubDate>Tue, 15 Aug 2023 12:34:30 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/14/ai가-연구도-집어-삼키고-있습니다/&quot;&gt;머신러닝이 점점 널리 쓰이고 있습니다.&lt;/a&gt; 2019년 대학원에, 2020년 학부에 처음 머신러닝(기계학습) 수업을 개설했습니다. 수업에서 2021년까지는 지도학습과 비지도 학습, 모델 훈련, 심층신경망, 합성곱신경망, 순환신경망, 오토인코더, GAN과 같은 내용을 다뤘습니다. 2022년에는 연구년이라 제 수업이 없었고요. 2023년 2학기부터 학부 수업은 머신러닝 모델을 직접 만들고 훈련시키는 내용이 아니라 이미 만들어진 각종 AI 모델들, 특히 생성AI를 활용하는데 중점을 두고 진행하려고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;데이터 분석 도구들 중 널리 사용하는 엑셀에 대해 생각해봅시다. 데이터를 분석하는데 엑셀에서 지원하지 않는 기능이 필요하다면 해당 기능을 지원하는 다른 도구를 찾아 쓰던가 직접 도구를 만들어 사용해야 합니다. 하지만 엑셀에 해당 기능이 있다면 엑셀 사용법을 배워서 쓰는게 더 효율적이죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;머신러닝의 경우도 필요한 모델을 직접 만들어 쓸 수도 있지만, 많은 경우 원하는 기능을 제공하는 모델의 사용법을 익혀서 쓰는게 효율적입니다. 대학원에서는 연구를 위해 직접 모델을 개발하는 경우가 많기 때문에 기존의 내용을 유지하겠지만, 학부 수업에서는 활용법을 다루는 것도 학생들에게 도움이 되리라 생각합니다. 학과에 다른 교수님의 머신러닝 수업이 있기에 파이썬 프로그래밍, 머신러닝 기본 개념과 같은 내용들은 알고 있다고 생각하고 바로 활용으로 넘어가려고 합니다. 3학년 “지구물리기계학습 및 실습” 수업을 들을 학생들은 먼저 2학년 “에너지자원 머신러닝 및 실습” 수업을 듣고 오시길 바랍니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Study</category></item><item><title>AI가 연구도 집어 삼키고 있습니다</title><link>https://pkgpl.org/2023/08/14/ai%ea%b0%80-%ec%97%b0%ea%b5%ac%eb%8f%84-%ec%a7%91%ec%96%b4-%ec%82%bc%ed%82%a4%ea%b3%a0-%ec%9e%88%ec%8a%b5%eb%8b%88%eb%8b%a4/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/14/ai%ea%b0%80-%ec%97%b0%ea%b5%ac%eb%8f%84-%ec%a7%91%ec%96%b4-%ec%82%bc%ed%82%a4%ea%b3%a0-%ec%9e%88%ec%8a%b5%eb%8b%88%eb%8b%a4/</guid><pubDate>Mon, 14 Aug 2023 12:55:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;소프트웨어가 세상을 집어 삼키고 있습니다&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;소프트웨어가 세상을 집어 삼키고 있습니다(&lt;a href=&quot;http://scieng.net/sisatoron/59516&quot;&gt;Andreessen&lt;/a&gt;). 각종 아날로그 매체에 담겨있던 정보들은 디지털 비트로 증발하고 있죠(&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000001391824&quot;&gt;Negroponte&lt;/a&gt;; &lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000001674987&quot;&gt;Tercek&lt;/a&gt;). 레코드판, 카세트테이프, 비디오테이프가 증발하였고, 신문과 책도 증발하고 있습니다. 증발된 정보는 클라우드에(cloud) 존재하며, 사용자가 원할 때(on-demand) 아날로그 매체 없이 비트만 받아 텔레비전, 컴퓨터, 스마트폰으로 보고 들을 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;하드웨어 장치들도 증발하고 있습니다. 비디오플레이어, CD 플레이어, MP3 플레이어, 카메라, 계산기 등은 이제 컴퓨터 소프트웨어나 손바닥 안의 앱으로 존재합니다. 각 기관들에서 운영하던 서버 컴퓨터들도 클라우드로 옮겨가고 있습니다. 소프트웨어 개발자들은 이제 인프라도 코드로 관리합니다(&lt;a href=&quot;https://product.kyobobook.co.kr/detail/S000061695654&quot;&gt;Morris&lt;/a&gt;).&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;코로나19는 회사 사무실들을 증발시켰고, 학교와 학원 교실에서 진행되던 수업들을 증발시켰습니다. 재택 근무와 온라인 강의는 코로나19 이후에도 일정 부분 남아 있겠죠. 앞으로 많은 사회적 경제적 활동들이 가상의 소프트웨어 세상인 메타버스에서 일어날 것입니다(&lt;a href=&quot;https://dl.acm.org/doi/10.1145/2480741.2480751&quot;&gt;Dionisio et al.&lt;/a&gt;).&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;소프트웨어가 연구도 집어 삼키고 있습니다&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다양한 과학 기술 분야의 연구도 컴퓨터 소프트웨어로 진행되고 있습니다(&lt;a href=&quot;https://ieeexplore.ieee.org/document/5069155&quot;&gt;Hannay et al.&lt;/a&gt;; &lt;a href=&quot;https://dl.acm.org/doi/10.1145/2063348.2063374&quot;&gt;Prabhu et al.&lt;/a&gt;). 수치해석을 이용한 컴퓨터 시뮬레이션은 많은 물리 모형 실험을 대체했습니다. 디지털 트윈은 현실 상황을 컴퓨터로 재현합니다(&lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S2351978917304067&quot;&gt;Negri et al.&lt;/a&gt;). 물론, 실제 계산은 CPU, GPU와 같은 하드웨어에서 수행하지만 사용자는 소프트웨어를 이용해 하드웨어를 제어하죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;AI가 소프트웨어를 집어 삼키고 있습니다&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그런데 세상을 집어 삼키고 있는 소프트웨어를 AI가 집어 삼키고 있습니다(&lt;a href=&quot;https://www.technologyreview.com/2017/05/12/151722/nvidia-ceo-software-is-eating-the-world-but-ai-is-going-to-eat-software/&quot;&gt;Huang&lt;/a&gt;). 머신러닝/딥러닝을 통해 기존의 소프트웨어들로는 하지 못했던 일들도 가능해지고 있습니다. 생성AI는 코드를 작성해주기도 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;연구에 있어서도, 제 전공 분야에서 체감상 최근 발표되는 연구의 반 이상은 머신러닝을 이용한 연구인듯 합니다. 물리탐사 자료처리 분야가 예전부터 컴퓨터를 많이 사용하던 분야라 머신러닝 도입이 빠르기는 합니다. 탄성파 탐사 연구실에서도 최근에는 딥러닝을 이용한 연구들을 주로 진행하고 있습니다. 이제는 머신러닝이 수치해석과 같은 필수 도구가 되었습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>이슈 관리 프로그램을 이용한 작업 방법</title><link>https://pkgpl.org/2023/08/13/%ec%9d%b4%ec%8a%88-%ea%b4%80%eb%a6%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%9e%91%ec%97%85-%eb%b0%a9%eb%b2%95/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/13/%ec%9d%b4%ec%8a%88-%ea%b4%80%eb%a6%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%9e%91%ec%97%85-%eb%b0%a9%eb%b2%95/</guid><pubDate>Sun, 13 Aug 2023 12:30:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;이슈 관리 프로그램&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이슈(Issue)는 소프트웨어 개발에서 기능 추가, 버그 수정 등의 작업을 의미합니다. 이슈 관리 프로그램들로는 JIRA, YouTrack, Redmine, GitHub Issues 등 다양한 소프트웨어들이 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;제가 이슈 관리 프로그램을 본격적으로 사용하기 시작한 것은 2020년입니다. 그 전에도 연구용 소프트웨어 개발을 위해 Trello 보드를 이용해 간단하게 이슈를 관리했습니다. 하지만 &lt;a href=&quot;https://pkgpl.org/2020/11/18/gpu를-이용한-병렬-처리-전산-유체-역학-시뮬레이션-성능/&quot;&gt;GPU 병렬 연산 최적화 프로젝트&lt;/a&gt;를 위해 본격적인 이슈 관리 프로그램의 필요성을 느껴 BitBucket 저장소에 JIRA를 연결해 사용했습니다. Git으로 소스코드를 관리하며 커밋 메시지를 통해 이슈를 자동으로 관리하는 기능도 유용하지만 제게는 필요한 기능들을 적어놓고 하나씩 구현하는 작업 방식 자체가 개발 속도 향상에 큰 도움이 되었습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;작업 절차: 시행 착오(작은 성공, 빠른 실패, 빠른 피드백)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;요구사항에 따른 초기 설계 후에 제가 이슈 관리 프로그램을 이용해 소프트웨어를 개발하는 절차는 다음과 같습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;필요한 작업을 30분~1시간 작업 분량 정도의 작은 단위로 나눠 이슈 관리 프로그램에 등록합니다. 짧은 시간 작업해서 빠르게 피드백을 얻을 수 있도록 작업을 잘게 나눕니다. 이슈는 생각 날 때마다 수시로 등록합니다.&lt;/li&gt;



&lt;li&gt;작업할 이슈를 하나 정해서 해당 개발 작업을 수행합니다. 한 번에 하나의 이슈에만 집중해서 개발을 진행합니다.&lt;/li&gt;



&lt;li&gt;작업 결과를 점검합니다. 원하는 결과가 나오면 작은 성공을 얻은 것이죠. 원하는 결과가 안 나왔다면 피드백을 통해 프로그램이나 이슈를 수정합니다.&lt;/li&gt;



&lt;li&gt;잠깐 쉬었다가 2번 과정으로 (반복)&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 때 빠르게 피드백을 얻을 수 있도록 하나 하나의 실험(이슈)을 작게 설계합니다. 큰 기능도 작게 나눠서 구현하며 중간중간 확인하면 실패의 리스크를 줄일 수 있습니다. 실험별 성공/실패를 판단하기 위해서는 원하는 결과가 명확해야겠죠. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2020/11/18/gpu를-이용한-병렬-처리-전산-유체-역학-시뮬레이션-성능/&quot;&gt;GPU 최적화&lt;/a&gt; 때 성공적인 결과는 수치해석 결과가 달라지지 않으면서 계산 속도가 향상되는 것이었습니다. 속도가 향상될 수 있을 만한(일부는 불확실한) 내용들을 이슈 관리 프로그램에 등록해 놓고 하나씩 구현한 후 GPU 프로파일러로 실행하며 속도와 결과를 비교했습니다. 동일한 결과에 계산 속도가 빨라지면 다음 이슈로 넘어갑니다. 속도가 빨라지지 않거나 결과가 달라지면 수정 이전의 코드로 돌아가고 해당 이슈는 취소하는 방식으로 작업했습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2023/08/12/슈퍼컴퓨터-작업-관리-프로그램-제작-시작/&quot;&gt;HPC 작업 관리 프로그램&lt;/a&gt;에서는 추가하는 기능에 따라 원하는 결과가 다릅니다. 입력이 잘 되는지, 배치 파일이 잘 만들어지는지, 작업 제출이나 취소가 잘 되는지, 모니터링이 잘 되는지 등을 확인하며 피드백을 받습니다. 잘 안 되면 버그를 찾아 고치거나 다른 구현 방식을 시도합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;보통 연구를 진행할 때는 어떤 결과가 나올지 잘 모르는 경우가 많기 때문에 연구용 수치해석 소프트웨어 개발 과정과는 약간 차이가 있네요.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이렇게 다양한 시행 착오를 통해 배우며 경험을 쌓아가고 있습니다. 특별한 것은 없지만 나름대로 과학적 방법론, 애자일 개발, 린 스타트업, 리스크 관리, 뽀모도로 기법, 인지심리학 등을 통합 적용한 &lt;a href=&quot;https://pkgpl.org/2021/09/02/의식적인-연습-deliberate-practice/&quot;&gt;의식적인 개발 방법&lt;/a&gt;이고, 이 작업 방법도 세부적으로 시행 착오를 거치며 조금씩 바꿔가는 중입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;JIRA에서 Linear로&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://www.atlassian.com/software/jira&quot;&gt;JIRA&lt;/a&gt;가 좋기는 하지만 이름이 별로 마음에 안 들고^^; 프로그램 인터페이스가 약간 불편하고, 결정적으로 최근에 JIRA 개발사에서 MacOS용 프로그램 개발을 중단해서 다른 이슈 관리 프로그램들을 찾아봤습니다. &lt;a href=&quot;https://linear.app&quot;&gt;Linear&lt;/a&gt;라는 소프트웨어를 알게 되었는데, 수학적인 이름이 마음에 들고^^ 프로그램 인터페이스가 멋지고, MacOS에서 키보드를 이용해 대부분의 작업을 수행할 수 있어서 Linear로 옮겼습니다. 현재는 Linear와 GitHub를 사용하고 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: screenshot-2023-08-12-at-9.28.35-pm.png&quot; href=&quot;https://pkgpl.org/media/wp-6986a2af7445d210.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;688&quot; src=&quot;https://pkgpl.org/media/wp-6986a2af7445d210.png&quot; alt=&quot;&quot; class=&quot;wp-image-1196&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;바흐와 함께&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;평소 소프트웨어를 개발할 때 바흐의 “평균율 클라비어곡집”이나 “골드베르크 변주곡”을 배경 음악으로 틀어놓고 작업하는 경우가 많습니다. 이번 여름엔 방열기 공사로 연구실 벽에 구멍이 뚫려 있어서 조용히 작업하고 있네요. 글을 쓰다 보니 “바흐: 천상의 음악”이라는 책을 반 정도 읽다가 만 것이 생각나 책을 꺼냈습니다. 이제 책을 읽어야겠습니다^^&lt;/p&gt;


&lt;div class=&quot;wp-block-image&quot;&gt;
&lt;figure class=&quot;aligncenter size-large is-resized&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: screenshot-2023-08-12-at-6.10.38-pm.png&quot; href=&quot;https://pkgpl.org/media/wp-28a2a9648968c35d.png&quot;&gt;&lt;img loading=&quot;lazy&quot; src=&quot;https://pkgpl.org/media/wp-28a2a9648968c35d.png&quot; alt=&quot;&quot; class=&quot;wp-image-1193&quot; style=&quot;width:460px;height:421px&quot; width=&quot;460&quot; height=&quot;421&quot;&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>슈퍼컴퓨터 작업 관리 프로그램 제작 시작</title><link>https://pkgpl.org/2023/08/12/%ec%8a%88%ed%8d%bc%ec%bb%b4%ed%93%a8%ed%84%b0-%ec%9e%91%ec%97%85-%ea%b4%80%eb%a6%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8-%ec%a0%9c%ec%9e%91-%ec%8b%9c%ec%9e%91/</link><guid isPermaLink="true">https://pkgpl.org/2023/08/12/%ec%8a%88%ed%8d%bc%ec%bb%b4%ed%93%a8%ed%84%b0-%ec%9e%91%ec%97%85-%ea%b4%80%eb%a6%ac-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%a8-%ec%a0%9c%ec%9e%91-%ec%8b%9c%ec%9e%91/</guid><pubDate>Sat, 12 Aug 2023 03:50:37 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;한 컴퓨터 회사의 의뢰로 7월 말부터 슈퍼컴퓨터(High Performance Computer)의 작업 관리 프로그램을 만들기 시작했습니다. 이 프로그램의 목적은 클러스터 서버 사용자들이 작업 스케줄러 프로그램 사용법을 몰라도 쉽게 서버에 작업(Job)을 제출하고 모니터링할 수 있도록 만들어주는 것입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;작업 스케줄러(Job Scheduler)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;클러스터 컴퓨터는 보통 여러 사용자들이 사용합니다. 여러 사용자가 동시에 자신의 작업을 실행하면 멀티태스킹으로 인해 전체적인 계산 효율이 떨어지게 됩니다. 서버 자원(CPU, GPU 등)을 효율적으로 사용하기 위해 작업들에 계산 자원을 효율적으로 할당하는 역할을 하는 것이 작업 스케줄러입니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;작업 스케줄러에는 Slurm, PBS, TORQUE, Oracle Grid Engine 등 여러 가지들이 있는데 일단 만들고 있는 것은 Slurm의 명령어를 이용하는 GUI (Graphical User Interface)입니다. 이런 GUI 프로그램들은 대부분 상용이고 공개 프로그램도 소수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;최소 기능 제품 (MVP, Minimum Viable Product)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;회사의 피드백을 받아가면서 빠르게 작업할 수 있도록 최소한의 기능을 담은 제품을 만들었습니다. 현재 일반적인 MPI 작업을 제출하고 모니터링하고 취소할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음은 현재 진행중인 작업을 확인/취소할 수 있는 페이지입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: jobs-1.png&quot; href=&quot;https://pkgpl.org/media/wp-9e4fd55f9c2c3fd0.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;456&quot; src=&quot;https://pkgpl.org/media/wp-9e4fd55f9c2c3fd0.png&quot; alt=&quot;&quot; class=&quot;wp-image-1159&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음은 현재 클러스터 컴퓨터의 전체/파티션(노드 그룹)별/노드별 CPU/Memory 사용량을 모니터링할 수 있는 페이지입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: cluster-1.png&quot; href=&quot;https://pkgpl.org/media/wp-0e9e64e698e2bc31.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;935&quot; src=&quot;https://pkgpl.org/media/wp-0e9e64e698e2bc31.png&quot; alt=&quot;&quot; class=&quot;wp-image-1160&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;아래는 작업에 필요한 파일들을 서버에 업로드하고 관리하는 페이지입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: filemanager-1.png&quot; href=&quot;https://pkgpl.org/media/wp-247002e1243d9b99.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;485&quot; src=&quot;https://pkgpl.org/media/wp-247002e1243d9b99.png&quot; alt=&quot;&quot; class=&quot;wp-image-1161&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;다음은 작업 제출에 필요한 정보를 입력하고 제출할 수 있는 페이지입니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: submit1-1.png&quot; href=&quot;https://pkgpl.org/media/wp-5e80fffcddac75b6.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;843&quot; src=&quot;https://pkgpl.org/media/wp-5e80fffcddac75b6.png&quot; alt=&quot;&quot; class=&quot;wp-image-1162&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;고급 사용자의 경우 앞에서 입력한 정보를 바탕으로 생성된 작업 제출 스크립트를 확인/수정하고 제출할 수도 있습니다.&lt;/p&gt;



&lt;figure class=&quot;wp-block-image size-large&quot;&gt;&lt;a aria-label=&quot;이미지 원본 열기: submit2.png&quot; href=&quot;https://pkgpl.org/media/wp-6a2a2c41fd9f63ce.png&quot;&gt;&lt;img loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;908&quot; src=&quot;https://pkgpl.org/media/wp-6a2a2c41fd9f63ce.png&quot; alt=&quot;&quot; class=&quot;wp-image-1163&quot;&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞으로 상용 해석 프로그램(Abaqus, Ansys, StarCCM+ 등) 작업 제출 기능과 사용자 관리 기능 등을 추가할 계획입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading has-medium-font-size&quot;&gt;외부 기관을 위한 소프트웨어 제작&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;외부 기관을 위한 소프트웨어 제작은 이번이 세 번째입니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;첫 번째는 2019년 국방과학연구소의 GPU를 이용한 수중채널모델링 프로그램이었습니다. 파동 전파를 이용하는 프로그램이었기 때문에, 제 연구 분야와도 관련이 있었죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;두 번째는 2020년 부산대/대우조선해양의 &lt;a href=&quot;https://pkgpl.org/2020/11/18/gpu를-이용한-병렬-처리-전산-유체-역학-시뮬레이션-성능/&quot;&gt;쇄빙선 모델링 프로그램의 GPU 병렬화 프로젝트&lt;/a&gt;였습니다. 제 전공 분야가 아니었기에 2019년 처음 의뢰가 들어왔을 때는 거절했었죠. 부산대에서 자체적으로 1년간 진행했으나 원하는 성능이 나오지 않는다고 2020년 여름에 다시 의뢰가 들어왔습니다. 그래서 8월 한 달간 프로그램 개발을 진행했고 만족할만한 성능을 얻었습니다. 해당 경험을 통해 보유 기술을 전공 분야에만 한정하는 것보다 기술을 필요로 하는 다른 분야에 적용하는 것이 사회적으로 더 큰 가치가 있을 수 있다는 것을 깨달았습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앞의 두 번은 모두 수치해석 프로그램이었지만 이번 프로그램은 직접적인 수치해석 프로그램은 아닙니다. GUI 프로그램이나 웹 개발도 평소 연구와 거리가 멀기에 몇 달 전 의뢰가 들어왔을 때 처음에는 거절했었죠. 회사에서는 다른 곳에 의뢰해서 개발을 진행했으나 결과가 마음에 들지 않아서 제게 다시 의뢰가 들어왔고, 이번에도 한여름에 개발을 진행하고 있습니다. 앞의 프로젝트와 패턴이 유사하네요. 이번 2학기 지구물리 기계학습 수업과 내년 1학기 지구물리 클러스터 컴퓨팅 수업에서 웹 개발을 일부 다룰 계획인데, 이번 개발이 좋은 경험이 될 듯 합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Docker 이미지 저장 경로 바꾸기</title><link>https://pkgpl.org/2023/06/28/docker-%ec%9d%b4%eb%af%b8%ec%a7%80-%ec%a0%80%ec%9e%a5-%ea%b2%bd%eb%a1%9c-%eb%b0%94%ea%be%b8%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2023/06/28/docker-%ec%9d%b4%eb%af%b8%ec%a7%80-%ec%a0%80%ec%9e%a5-%ea%b2%bd%eb%a1%9c-%eb%b0%94%ea%be%b8%ea%b8%b0/</guid><pubDate>Wed, 28 Jun 2023 04:41:26 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;Docker pull을 사용하다가 리눅스 서버의 root에 마운트된 디스크가 꽉 차서 Docker Root 경로를 바꾸는 방법을 찾아봤습니다(참고: &lt;a href=&quot;https://tienbm90.medium.com/how-to-change-docker-root-data-directory-89a39be1a70b&quot;&gt;link&lt;/a&gt;). &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;현재 Docker Root Dir이 &lt;code&gt;/var/lib/docker&lt;/code&gt;, 변경할 이미지 저장 경로는 /data/docker/root라고 하겠습니다. 이미지 저장 경로는 미리 만들어 둡니다. 참고로, 현재 Docker Root Dir은 다음 명령으로 확인할 수 있습니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ docker info |grep Root&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;아래 작업들은 root 계정으로 진행합니다. 먼저 docker daemon을 정지합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# service docker stop&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; 파일에 다음 내용을 추가합니다(Docker v17.05.0 이상).&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;{ 
   &quot;data-root&quot;: &quot;/data/docker/root&quot;
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;기존의 Docker 데이터를 새로운 경로로 복사합니다. 기존 데이터를 지우기 전에 Docker가 잘 작동하는 것을 확인하려고 합니다. 이를 위해 기존 경로의 이름을 바꾸고 Docker를 재시작합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# cp -rp /var/lib/docker/* /data/docker/root/
# mv /var/lib/docker /var/lib/docker.old
# service docker start&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Docker가 잘 작동하는지 확인한 후 기존 경로를 삭제합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# docker info |grep Root
# docker images
# rm -rf /var/lib/docker.old&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Windows Subsystem Linux 2 (WSL2) Setting</title><link>https://pkgpl.org/2022/03/16/windows-subsystem-linux-2-wsl2-setting/</link><guid isPermaLink="true">https://pkgpl.org/2022/03/16/windows-subsystem-linux-2-wsl2-setting/</guid><pubDate>Wed, 16 Mar 2022 09:01:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;Windows에서 Linux를 사용하기 위해 설치하는 방법입니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Ubuntu 설치&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고: &lt;a href=&quot;https://docs.microsoft.com/ko-kr/windows/wsl/install&quot;&gt;https://docs.microsoft.com/ko-kr/windows/wsl/install&lt;/a&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Windows 10 Build 19041 이상 또는 Windows 11 이상에서 Windows PowerShell을 관리자 권한으로 실행한 후 다음 명령을 실행합니다.&lt;/p&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ wsl --install&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;설치하면서 사용자 아이디와 비밀번호를 지정해주면 Ubuntu Linux를 사용할 수 있습니다. 그러나 X-window 프로그램을 사용하기 위해서는 아래 추가 설정이 필요합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;X windows 설정 (WSL2)&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고: &lt;a href=&quot;https://evandde.github.io/wsl2-x/&quot;&gt;https://evandde.github.io/wsl2-x/&lt;/a&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;WSL2에서는 X-window 설정 방법이 달라졌습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;먼저 Linux X-window 화면을 Windows 상에 띄워주는 &lt;a href=&quot;https://sourceforge.net/projects/xming/&quot;&gt;Xming&lt;/a&gt; 설치 프로그램을 다운로드하고 실행합니다. &lt;/li&gt;



&lt;li&gt;설치된 Xming 프로그램을 한 번 실행했다가 종료합니다.&lt;/li&gt;



&lt;li&gt;Xming 단축아이콘을 만들고 우클릭-속성-대상에서 명령어 끝에 &lt;code&gt; -ac&lt;/code&gt;를 추가해줍니다.&lt;/li&gt;



&lt;li&gt;Windows PowerShell을 관리자 권한으로 실행한 후 다음 명령어를 입력합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ Set-NetFirewallRule -DisplayName &quot;Xming X Server&quot; -Enabled True -Profile Any&lt;/code&gt;&lt;/pre&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Ubuntu Linux 창에서는 다음 명령어를 입력해줍니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ echo &apos;export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk &apos;&quot;&apos;&quot;&apos;{print $2}&apos;&quot;&apos;&quot;&apos;):0&apos; &amp;gt;&amp;gt; ~/.bashrc&lt;/code&gt;&lt;/pre&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;방화벽 허용: 제어판-업데이트 및 보안-Windows 보안-Windows 보안 열기-방화벽 및 네트워크 보호-방화벽에서 앱 허용-Xming을 허용해줍니다.&lt;/li&gt;



&lt;li&gt;앞에서 만든 단축아이콘을 이용해 Xming을 다시 실행하면 Linux에서 X-window 프로그램들을 Windows 화면에 띄울 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Seismic Unix 설치&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;탄성파 자료 처리를 위해 Seismic Unix를 &lt;code&gt;$HOME/SU&lt;/code&gt;에 설치하는 방법입니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Ubuntu에서 &lt;code&gt;~/.bashrc&lt;/code&gt; 파일에 다음 줄들을 추가합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;export CWPROOT=$HOME/SU
export PATH=$PATH:$CWPROOT/bin&lt;/code&gt;&lt;/pre&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Ubuntu Linux 창에서 다음 명령어들을 실행합니다. XDR 형식이 아닌, native binary 형식을 사용하도록 만들었는데, XDR 형식을 사용할 경우 제일 아래 두 줄에서 &lt;code&gt;XDRFLAG=&lt;/code&gt; 부분을 지워주면 됩니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ source ~/.bashrc
$ apt install -y build-essential libx11-dev libxt-dev freeglut3 freeglut3-dev libxmu-dev libxi-dev gfortran
$ cd $CWPROOT 
$ wget &apos;https://nextcloud.seismic-unix.org/s/LZpzc8jMzbWG9BZ/download?path=%2F&amp;amp;files=cwp_su_all_44R19.tgz&apos; -O cwp_su_all_44R19.tgz
$ tar -zxvf cwp_su_all_44R19.tgz 
$ cd src 
$ make XDRFLAG= install
$ make XDRFLAG= xtinstall&lt;/code&gt;&lt;/pre&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;GNU plot 설치&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;과학 기술 그래프를 그리는데 사용하는 &lt;a href=&quot;http://www.gnuplot.info&quot;&gt;gnuplot&lt;/a&gt;을 설치하는 방법입니다(참고로 Windows용 gnuplot도 있습니다). &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Ubuntu Linux에서 다음 명령을 실행합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;$ sudo apt install gnuplot gnuplot-x11&lt;/code&gt;&lt;/pre&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Ubuntu에서 &lt;code&gt;~/.bashrc&lt;/code&gt; 파일에 다음 줄을 추가합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;pre tabindex=&quot;0&quot; class=&quot;wp-block-code&quot;&gt;&lt;code&gt;export GNUTERM=x11&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 Linux 창을 새로 시작하면 gnuplot을 사용할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;LaTeX 설치&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;LaTeX는 Linux에 설치할 수도 있으나 Windows용도 있으므로 Windows에서 사용한다면 &lt;a href=&quot;https://miktex.org/download&quot;&gt;MikTex&lt;/a&gt; 설치 프로그램을 받아서 실행하면 됩니다. 설치하면 PowerShell 또는 Windows 명령 프롬프트에서 &lt;code&gt;latex&lt;/code&gt;, &lt;code&gt;pdflatex&lt;/code&gt; 등의 명령을 사용할 수 있습니다. &lt;a href=&quot;https://www.xm1math.net/texmaker/download.html&quot;&gt;TexMaker&lt;/a&gt;와 같은 전용 에디터를 사용하면 더 쉽게 LaTeX 문서를 만들 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>서버의 Docker 컨테이너에서 실행한 jupyter, tensorboard에 접속하기</title><link>https://pkgpl.org/2021/11/22/ssh-tunneling%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%b4-%ec%84%9c%eb%b2%84%ec%9d%98-docker-%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%ec%97%90-%ec%a0%91%ec%86%8d%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2021/11/22/ssh-tunneling%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%b4-%ec%84%9c%eb%b2%84%ec%9d%98-docker-%ec%bb%a8%ed%85%8c%ec%9d%b4%eb%84%88%ec%97%90-%ec%a0%91%ec%86%8d%ed%95%98%ea%b8%b0/</guid><pubDate>Mon, 22 Nov 2021 07:40:33 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2021/06/23/docker와-github를-이용한-소프트웨어-연구-환경-구축/&quot;&gt;Docker와 GitHub를 이용한 소프트웨어 연구 환경 구축&lt;/a&gt;에서 Docker &lt;a href=&quot;https://github.com/pkgpl/project_template&quot;&gt;프로젝트 템플릿&lt;/a&gt;에 대해 소개해드렸습니다. 리눅스 서버에서 프로젝트 템플릿을 이용해 만든 Docker 컨테이너를 실행하고, 컨테이너 내에서 Jupyter lab/notebook 또는 tensorboard를 실행한 후 데스크탑 PC의 웹브라우저를 이용해 접속하는 방법을 살펴보겠습니다. 아래 명령들을 실행하기 전에 먼저 컨테이너를 만들고(&lt;code&gt;build.sh&lt;/code&gt;) 실행해주세요(&lt;code&gt;run.sh&lt;/code&gt;).&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;jupyter-lab-notebook&quot;&gt;Jupyter lab/notebook&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;서버의 프로젝트 내 docker 디렉토리에서 다음 명령을 실행합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;$ ./exec.sh lab &lt;/code&gt;(또는 &lt;code&gt;./exec.sh notebook&lt;/code&gt;)&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 명령을 실행하면 jupyter lab/notebook이 background로 실행됩니다. 실제로는 다음 명령이 실행됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;$ jupyter lab[notebook] --no-browser --ip=0.0.0.0 --NotebookApp.token=****&lt;/code&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위에서 ****는 접속 비밀번호로, Env.sh 파일에서 지정해줍니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;컨테이너의 jupyter port, tensorboard port와 서버의 해당 port는 컨테이너 실행시 연결된 상태이므로 이제 데스크탑 PC의 port를 서버의 해당 port로 연결하면 됩니다. 참고로, Port 번호는 &lt;code&gt;Env.sh&lt;/code&gt; 파일에서 바꿀 수 있습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;데스크탑 PC에서 서버로 연결하기 위해 웹브라우저에서 server_ip:8888 주소로 접속하면 됩니다. 만약, localhost 주소로 사용하고 싶다면 다음 ssh tunneling 명령을 실행합니다. 리눅스나 MacOS의 경우 터미널에서, 윈도우즈의 경우 PowerShell에서 실행하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;$ ssh -N -L 8888:localhost:8888 your_id@server_ip&lt;/code&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 명령을 통해 서버와 데스크탑 PC의 port를 연결했다면 데스크탑 웹브라우저에서 &lt;code&gt;localhost:8888&lt;/code&gt; 주소로 서버 컨테이너의 jupyter lab/notebook에 접속하여 사용할 수 있습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot; id=&quot;tensorboard&quot;&gt;TensorBoard&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;텐서보드도 사용할 수 있습니다. 텐서보드 파일이 &lt;code&gt;src/logs&lt;/code&gt; 디렉토리에 있을 경우 docker 컨테이너 내에서 src 디렉토리로 이동한 후 tensorboard를 실행합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;$ ./exec.sh # 컨테이너 내 터미널 접속&lt;br&gt;&lt;code&gt;$ cd src&lt;br&gt;$ tensorboard --bind_all --logdir=logs&lt;/code&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 명령을 실행한 후에는 tensorboard port를 이용하여 앞에서와 같이 웹브라우저에서 server_ip:6006으로 접속하던가 ssh tunneling 명령을 실행합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;$ ssh -N -L 6006:localhost:6006 your_id@server_ip&lt;/code&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이제 데스크탑 웹브라우저에서 &lt;code&gt;localhost:6006&lt;/code&gt; 주소로 서버 컨테이너에서 실행한 tensborboard에 접속할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;참고로, Jupyter lab/notebook과 TensorBoard를 동시에 사용한다면 다음과 같이 한 번에 연결할 수도 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;code&gt;$ ssh -N &lt;/code&gt;&lt;code&gt;-L 8888:localhost:8888&lt;/code&gt; &lt;code&gt;-L 6006:localhost:6006 your_id@server_ip&lt;/code&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>열정과 의지력</title><link>https://pkgpl.org/2021/11/02/%ec%97%b4%ec%a0%95%ea%b3%bc-%ec%9d%98%ec%a7%80%eb%a0%a5/</link><guid isPermaLink="true">https://pkgpl.org/2021/11/02/%ec%97%b4%ec%a0%95%ea%b3%bc-%ec%9d%98%ec%a7%80%eb%a0%a5/</guid><pubDate>Mon, 01 Nov 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;그릿&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;앤절라 더크워스는 “그릿”이라는 책에서 성공하는 사람들의 열정과 끈기에 대해 이야기합니다. 그릿에서 말하는 열정과 끈기는 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;열정&lt;/strong&gt;: 멀리 목표를 두고 일함, 단순한 변덕으로 과제를 포기하지 않음&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;끈기&lt;/strong&gt;: 의지력, 인내심, 결단력, 장애물 앞에서 과업을 포기하지 않는 성향, 집요함, 완강함&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;성숙한 그릿의 사람들은 다음과 같은 특징이 있다고 합니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;관심&lt;/strong&gt;: 자신이 하는 일 진정으로 즐김&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;연습&lt;/strong&gt;: &lt;a href=&quot;https://pkgpl.org/2021/09/02/의식적인-연습-deliberate-practice/&quot;&gt;의식적인 연습&lt;/a&gt; 활용&lt;/li&gt;



&lt;li&gt;&lt;a href=&quot;https://pkgpl.org/2021/09/03/자율성-숙련-목적/&quot;&gt;&lt;strong&gt;목적&lt;/strong&gt;&lt;/a&gt;: 자신의 일이 중요하다는 확신이 있음, 개인적으로 흥미로운 동시에 타인의 안녕과 밀접한 관련이 있는 일을 함&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;희망&lt;/strong&gt;: 위기에 대처하게 해주는 끈기가 있음&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;그릿이 높은 사람일수록 건강한 정서적 삶을 즐길 가능성이 높다고 합니다. 여러분은 그릿이 높은, 열정과 끈기가 있는 사람인가요? 그렇다면, 축하합니다. 아닌가요? 걱정할 필요는 없습니다. 의지력(끈기)과 열정에 관한 다른 책들을 살펴보죠.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;의지력의 재발견&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;로이 바우마이스터, 존 티어니는 “의지력의 재발견”에서 자기 절제를 위해 필요한 의지력은 고갈되는 자원임을 알려줍니다. 의지력에는 생각 조절, 감정 조절, 충동 조절, 수행 조절(인내심)과 같은 범주가 있는데, 감정 통제, 유혹 참기, 스트레스, 반복된 결정(선택)으로 인해 의지력을 사용하게 되면 결국 고갈된다고 합니다. 의지력을 충전하기 위해서는 식사(포도당 흡수), 휴식, 잠이 필요합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;의지력은 충전, 고갈을 반복하는 자원이지만 장기간의 훈련으로 강화할 수 있다고 합니다. 의지력을 강화하기 위한 훈련들은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;매일 곧은 자세 연습&lt;/li&gt;



&lt;li&gt;정돈하는 습관&lt;/li&gt;



&lt;li&gt;체력 단련&lt;/li&gt;



&lt;li&gt;작은 성취&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;의지력이 강해지면 고갈되는 속도가 느려지고, 의지력이 필요한 어떤 행동이 습관이 되면 더이상 의지력을 소진할 필요가 없습니다. 아직 의지력이 약하다 하더라도 사용할 수 있는 전략들이 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;중요한 일이나 결정은 아침 또는 점심 식후에 진행하기&lt;/li&gt;



&lt;li&gt;유혹 피하기&lt;/li&gt;



&lt;li&gt;유혹에 대한 선제적 예방조치 (세이렌 앞에서 몸을 묶은 오디세우스처럼; 예를 들면, 시간을 낭비하는 특정 웹사이트 접근 차단하기)&lt;/li&gt;



&lt;li&gt;일을 미루지 않기&lt;/li&gt;



&lt;li&gt;모니터링하기&lt;/li&gt;



&lt;li&gt;대안을 남기지 않기 (한 가지 일을 위해 시간을 정해놓고 작업하기, 해당 작업을 하기 싫다면 다른 일도 하지 않기)&lt;/li&gt;



&lt;li&gt;동기 부여를 위해 스스로에게 사소한 보상 자주 하기&lt;/li&gt;



&lt;li&gt;고귀한 생각(목표)에 집중하기&lt;/li&gt;



&lt;li&gt;습관화하기&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;결국 좋은 &lt;strong&gt;습관&lt;/strong&gt;을 들이는 것이 중요합니다. 좋은 습관을 만들면 의지력 고갈 없이 중요한 일들(대학원생의 경우 공부, 연구, 논문 쓰기 등)을 할 수 있습니다. Robert Boice도 “Professors as Writers”에서 꾸준한 논문 쓰기 습관이 학자에게 매우 중요하다고 강조하였습니다. 좋은 습관을 통해 의지력을 아껴 쓰면 스스로 절제할 수 있게 됩니다. 내면의 절제는 타인에 대한 친절함으로 이어지기에 의지력이 강한 사람은 이타적이라고 합니다. 여러분도 대학원에서 좋은 습관을 만들고 의지력을 키워가시길 바랍니다. 이번엔 열정에 대해 알아보겠습니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;strong&gt;열정의 배신&lt;/strong&gt;&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;칼 뉴포트는 “열정의 배신 (So good they can’t ignore you)”에서 열정을 따르지 말라고 합니다. 열정보다 일이 먼저입니다. 일에 대한 열정은 흔하지 않습니다. 열정을 갖는 데는 시간이 걸리죠. 따라서 열정이 없는 상태에서 열정을 따르려 하지 말고 먼저 다양한 일을 접해보는 것이 중요합니다. 일을 잘하면 열정은 부수적으로 생긴다고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 때 &lt;strong&gt;실력&lt;/strong&gt;이 중요하다고 강조합니다. 영문 제목에 나온 것처럼 아무도 여러분을 무시하지 못하게 실력으로 승부하라고 합니다. 세상이 자신에게 무엇을 해줄 것인지가 아니라 자신이 세상에 무엇을 줄 것인지 고민하는 장인 마인드를 가지시기 바랍니다. 이는 무엇을 줄까 고민하라는 &lt;a href=&quot;https://pkgpl.org/2021/09/04/삶의-의미/&quot;&gt;빅터 프랭클의 글&lt;/a&gt;과도 일치합니다. 애덤 그랜트도 “기브 앤 테이크”에서 지혜롭게 주는 사람이 성공한다고 했습니다. 승진보다는 &lt;strong&gt;자율성&lt;/strong&gt;을 추구하시기 바랍니다. 자율성이 커지면 행복도와 참여도, 성취감이 높아지고, 따라서 열정도 커진다고 합니다. 또한 가치있는 &lt;strong&gt;소명&lt;/strong&gt;을 가지고 일할 때 행복하다고 합니다. 실력, 자율성, 소명 – 결국 내적 동기 부여를 위한 &lt;a href=&quot;https://pkgpl.org/2021/09/03/자율성-숙련-목적/&quot;&gt;자율성, 숙련, 목적&lt;/a&gt;과 동일한 내용입니다. 저자는 창의성을 발휘할 수 있고 영향력있고 자율성이 높은, 희소하고 가치 있는 기술과 관련된 직업이 좋은 직업이라고 합니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;정리&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;정리해보면, 열정과 의지력이 중요하지만, 열정은 처음부터 가지고 있는 것이 아니라 실력이 향상되면 생기는 것이고, 의지력은 고갈되는 자원으로 강화하려면 장기간의 훈련이 필요합니다. 학부 공부를 통해 몇 가지 세부 전공을 탐색해본 후 대학원 연구실을 결정했다면 해당 분야에서 &lt;a href=&quot;https://pkgpl.org/2021/09/02/의식적인-연습-deliberate-practice/&quot;&gt;의식적인 연습&lt;/a&gt;을 통해 실력을 키워가는 것이 바람직합니다. 실력이 향상되어 &lt;a href=&quot;https://pkgpl.org/2021/09/01/전문가에-이르는-길/&quot;&gt;전문가&lt;/a&gt;에 가까워짐에 따라 자율성과 열정도 커지게 됩니다. 자신의 돈벌이를 위해서만 일할 것이 아니라 세상에 좋은 영향을 끼치기 위해, 가치있는 것을 주기 위해 연구하고 일하는 사람이 되시길 바랍니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>포트란과 런타임 다형성 (runtime polymorphism)</title><link>https://pkgpl.org/2021/10/08/%ed%8f%ac%ed%8a%b8%eb%9e%80%ea%b3%bc-%eb%9f%b0%ed%83%80%ec%9e%84-%eb%8b%a4%ed%98%95%ec%84%b1-runtime-polymorphism/</link><guid isPermaLink="true">https://pkgpl.org/2021/10/08/%ed%8f%ac%ed%8a%b8%eb%9e%80%ea%b3%bc-%eb%9f%b0%ed%83%80%ec%9e%84-%eb%8b%a4%ed%98%95%ec%84%b1-runtime-polymorphism/</guid><pubDate>Thu, 07 Oct 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;포트란에서의 객체지향프로그래밍 다형성과 관련하여 &lt;a href=&quot;https://pkgpl.org/2014/07/12/fortran_function_overloading/&quot;&gt;함수 오버로딩&lt;/a&gt;과 &lt;a href=&quot;https://pkgpl.org/2014/07/13/fortran_operator_overloading/&quot;&gt;연산자 오버로딩&lt;/a&gt;에 대해 글을 올린 적이 있습니다. 함수 오버로딩은 다른 함수를 같은 이름으로 사용하는 것으로, 이를 통해 하나의 함수 이름으로 다른 인수(argument)를 사용하는 것과 같은 효과를 나타낼 수 있습니다. 연산자 오버로딩은 함수를 이용해 기존 연산자의 기능을 재정의하거나 새로운 연산자를 만드는 기능이었죠. 런타임 다형성은 하나의 함수에 서로 다른 인수를 사용하는 기능으로, 상속 및 오버라이딩과 관련이 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;함수 오버로딩에서도 하나의 함수 이름으로 다른 인수를 사용하는 것과 같은 효과를 낼 수 있다고 하였는데, 실제로는 인수에 따라 다른 함수들을 정의하고 같은 이름으로 사용한 것인 반면에, 런타임 다형성을 이용하면 하나의 함수만 정의하고 서로 다른 인수를 사용할 수 있습니다. 이 때 인수들은 아무 인수나 되는 것은 아니고 서로 상속 관계에 있어야 합니다. 코드를 살펴보겠습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-syntaxhighlighter-code &quot;&gt;&lt;pre tabindex=&quot;0&quot; class=&quot;brush: plain; title: ; notranslate&quot; title=&quot;&quot;&gt;

module m_hero
    type:: hero_t
    contains
        procedure::speak =&amp;gt; speak_hero
    end type 

    type,extends(hero_t):: ironman_t
    contains
        procedure:: speak =&amp;gt; speak_ironman
    end type

    type,extends(hero_t):: spiderman_t
    contains
        procedure:: speak =&amp;gt; speak_spiderman
    end type

contains

    subroutine speak_hero(hero)
    class(hero_t):: hero
    print*,&apos;I am a hero.&apos;
    end subroutine

    subroutine speak_ironman(hero)
    class(ironman_t):: hero
    print*,&apos;I am Iron Man.&apos;
    end subroutine

    subroutine speak_spiderman(hero)
    class(spiderman_t):: hero
    print*,&quot;I&apos;m Peter.&quot;
    end subroutine

    subroutine who_are_you(hero)
    class(hero_t):: hero
    call hero%speak()
    end subroutine

end module
&lt;/pre&gt;&lt;/div&gt;


&lt;p class=&quot;wp-block-paragraph&quot;&gt;위 코드에서 &lt;code&gt;ironman_t&lt;/code&gt;와 &lt;code&gt;spiderman_t&lt;/code&gt;는 &lt;code&gt;hero_t&lt;/code&gt;를 상속합니다. 모두 각자의 &lt;code&gt;speak&lt;/code&gt; 메소드를 가지고 있는데, 서로 다른 &lt;code&gt;type&lt;/code&gt;이지만 다음과 같이 &lt;code&gt;who_are_you&lt;/code&gt; 서브루틴의 인수로 사용할 수 있습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-syntaxhighlighter-code &quot;&gt;&lt;pre tabindex=&quot;0&quot; class=&quot;brush: plain; title: ; notranslate&quot; title=&quot;&quot;&gt;

program test_runtime_polymorphism1
    use m_hero
    type(hero_t):: hero
    type(ironman_t):: ironman
    type(spiderman_t):: spiderman

    call who_are_you(hero)
    call who_are_you(ironman)
    call who_are_you(spiderman)
end program
&lt;/pre&gt;&lt;/div&gt;


&lt;p class=&quot;wp-block-paragraph&quot;&gt;실행 결과는 예상대로 다음과 같습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;I am a hero.&lt;br&gt;I am Iron Man.&lt;br&gt;I’m Peter.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이번에는 &lt;code&gt;ihero&lt;/code&gt;라는 변수 값에 따라 &lt;code&gt;hero&lt;/code&gt;들 중 한 명이 달려가 사람들을 구해야 한다고 생각해봅시다(모두 &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;save_people&lt;/code&gt; 메소드를 가지고 있다고 합시다). 아래와 같이 구현할 수 있습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-syntaxhighlighter-code &quot;&gt;&lt;pre tabindex=&quot;0&quot; class=&quot;brush: plain; title: ; notranslate&quot; title=&quot;&quot;&gt;

program test_runtime_polymorphism2_not_good
    use m_hero
    type(ironman_t):: ironman
    type(spiderman_t):: spiderman
    integer:: ihero = 1

    select case (ihero)
    case (1)
        call who_are_you(ironman)
        !call ironman%run()
        !call ironman%save_people()
    case (2)
        call who_are_you(spiderman)
        !call spiderman%run()
        !call spiderman%save_people()
    end select
end program
&lt;/pre&gt;&lt;/div&gt;


&lt;p class=&quot;wp-block-paragraph&quot;&gt;그러나 위 코드는 중복이 많습니다. &lt;code&gt;Hulk&lt;/code&gt;, &lt;code&gt;Black Widow&lt;/code&gt;, &lt;code&gt;Thor&lt;/code&gt; 등 새로운 avenger가 올 때마다 코드가 여러 줄씩 늘어나게 됩니다. 아름답지 않습니다! 포인터를 이용하면 &lt;code&gt;hero_t&lt;/code&gt; 클래스 변수가 자식 &lt;code&gt;type&lt;/code&gt;을 가리키도록 할 수 있습니다.&lt;/p&gt;


&lt;div class=&quot;wp-block-syntaxhighlighter-code &quot;&gt;&lt;pre tabindex=&quot;0&quot; class=&quot;brush: plain; title: ; notranslate&quot; title=&quot;&quot;&gt;

program test_runtime_polymorphism2_better
    use m_hero
    class(hero_t),pointer:: hero
    type(ironman_t),target:: ironman
    type(spiderman_t),target:: spiderman
    integer:: ihero = 1

    select case (ihero)
    case (1)
        hero =&amp;gt; ironman
    case (2)
        hero =&amp;gt; spiderman
    end select

    call who_are_you(hero)
    !call hero%run()
    !call hero%save_people()
end program
&lt;/pre&gt;&lt;/div&gt;


&lt;p class=&quot;wp-block-paragraph&quot;&gt;아름답습니다! 유지 보수하기 훨씬 좋아졌습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Stack overflow로 인한 Segmentation fault 해결하기</title><link>https://pkgpl.org/2021/10/07/stack-overflow%eb%a1%9c-%ec%9d%b8%ed%95%9c-segmentation-fault-%ed%95%b4%ea%b2%b0%ed%95%98%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2021/10/07/stack-overflow%eb%a1%9c-%ec%9d%b8%ed%95%9c-segmentation-fault-%ed%95%b4%ea%b2%b0%ed%95%98%ea%b8%b0/</guid><pubDate>Thu, 07 Oct 2021 06:20:51 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;포트란, C와 같은 컴파일 언어 사용시 함수나 서브루틴 내에서 선언하는 변수는 기본적으로 메모리의 stack이라는 정적 할당 영역에 저장하게 됩니다. 만약 함수나 서브루틴 내에서 선언한 배열의 크기가 커지면 시스템의 stack 크기를 넘어갈 수 있고(stack overflow) 이 경우 잘못된 메모리 주소를 참조하는 segmentation fault 에러가 발생하게 됩니다. Stack overflow를 방지하는 세 가지 방법을 살펴보겠습니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;직접 allocate&lt;/strong&gt;: 배열을 필요에 따라 함수나 서브루틴 내에서 할당하고 해제하는 방식으로 코드를 수정해줍니다. 이 경우 stack 대신 heap이라는 동적 할당 영역을 사용하므로 stack overflow가 발생하지 않습니다. 그러나 코드를 수정해야 하므로 제 경우 2번이나 3번 방식을 선호합니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;시스템 stack 크기 증가&lt;/strong&gt;: 리눅스에서 &lt;code&gt;ulimit -s unlimited&lt;/code&gt; 명령을 이용해 stack 크기를 무한히 크게 만들 수 있습니다.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;컴파일 옵션&lt;/strong&gt;: 컴파일시 크기가 큰 배열은 stack 대신 heap 공간을 사용하도록 옵션을 추가합니다. ifort에는 &lt;code&gt;-heap-arrays [size]&lt;/code&gt;, gfortran에는 &lt;code&gt;-fmax-stack-var-size=n&lt;/code&gt; 옵션이 있습니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>디지털 미디어와 깊이 읽기</title><link>https://pkgpl.org/2021/09/07/%eb%94%94%ec%a7%80%ed%84%b8-%eb%af%b8%eb%94%94%ec%96%b4%ec%99%80-%ea%b9%8a%ec%9d%b4-%ec%9d%bd%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/07/%eb%94%94%ec%a7%80%ed%84%b8-%eb%af%b8%eb%94%94%ec%96%b4%ec%99%80-%ea%b9%8a%ec%9d%b4-%ec%9d%bd%ea%b8%b0/</guid><pubDate>Mon, 06 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;h2 class=&quot;wp-block-heading&quot;&gt;생각하지 않는 사람들&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;니콜라스 카는 “생각하지 않는 사람들(The Shallows)”에서 인터넷 사용으로 인한 두뇌 변화에 대해 이야기합니다. 인터넷에서는 빠르게 움직이는 작은 정보 조각들이 흘러다닙니다. 이러한 환경은 많은 주제를 폭넓게 탐구하는데에는 적합하지만 주제를 피상적인 수준에서만 탐구하게 만듭니다. 인터넷 사용으로 인해 뇌는 더 산만해지도록 훈련받습니다. 정보를 빨리 효율적으로 처리하기는 하지만 지속적인 집중은 어려워집니다. 인터넷 사용 시간 증가로 출판물을 읽는 시간은 감소하고, 그에 따라 기존의 인쇄 매체를 읽는데 필요한 선형적 사고, 깊이 생각하는 능력이 사라지고 있습니다. 웹을 많이 이용할수록 긴 글에 집중하기 어려워집니다. ‘스압(스크롤 압박) 주의’, ‘tl;dr (too long; didn’t read)’ 같은 단어들은 긴 글에 대한 거부감을 나타내죠. 마셜 매클루언은 “&lt;a href=&quot;https://pkgpl.org/2021/09/06/미디어의-이해-인간의-확장/&quot;&gt;미디어의 이해&lt;/a&gt;“에서 우리가 사용하는 도구가 증폭시키는 우리의 기능(능력)은 결국 마비된다고 했습니다. 소프트웨어가 더 똑똑해질수록 사용자는 더 멍청해지게 됩니다.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;다시, 책으로&lt;/h2&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;매리언 울프도 “다시, 책으로(Reader, Come Home)”에서 디지털 미디어 사용으로 인한 깊이 읽기 능력 상실에 대해 이야기합니다. 깊이 읽기는 “&lt;a href=&quot;https://pkgpl.org/2021/09/05/독서의-기술과-논문-읽기/&quot;&gt;독서의 기술&lt;/a&gt;“에서 이야기하는 분석 독서와 관련이 있습니다. 인쇄 미디어를 깊이 읽기 위해서는 진실을 분별하고 분석적, 비판적으로 생각하고 공감하고 이해하기 위해 인지적 인내가 필요합니다. 반면에, 디지털 미디어는 즉각성, 빠른 전환, 끊임 없는 주의 환기, 몰입 보다는 정보 얻기, 공감 쇠퇴와 같은 특성을 가집니다. 너무 많은 정보로 인지 과부하가 발생하게 되고 우리는 단순화, 압축, 선별과 같이 심층 처리 없이 정보를 처리하게 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;어떤 미디어에 노출된 시간이 길수록 미디어의 행동 유도 특성이 이용자에게 더 큰 영향을 미치게 되는데, 요즘 사람들이 가장 많이 사용하는 미디어들은 스마트폰, 인터넷과 같은 디지털 미디어들이죠. 많은 아날로그 미디어들이 디지털로 증발되어가는 시대에 디지털 미디어를 잘 다루는 능력도 중요합니다. 하지만, 대학원에서 연구하는 학생들의 입장에서 집중하고, 깊이 읽고, 생각하는 능력의 쇠퇴는 치명적일 수 있습니다. 인터넷이 널리 사용되기 시작한지 20년 정도 되었고, 스마트폰은 널리 사용되기 시작한지 10년 정도 되었으므로 이 문제는 앞으로 더 심각해질 수 있습니다. 니콜라스 카는 깊이 읽는 능력이 소수 엘리트만의 능력이 될 가능성이 크다고 했습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;해결책은 마셜 매클루언이 이야기한 것처럼 디지털 미디어 사용 시간을 줄이고 인쇄 미디어를 읽는 시간을 늘리는 것입니다. 관련된 내용을 칼 뉴포트는 “디지털 미니멀리즘”, 매리언 울프는 ‘양손잡이 뇌’라고 표현했습니다. 책을 읽되 전자책이 아닌, 아날로그 책을 읽고, 논문을 읽을 때도 스크린 상에서 읽는 것이 아니라 인쇄된 논문을 읽읍시다. 종이 사용과 환경 보호의 관점에서는 안 좋지만 전문가는 자신의 정신적 기술을 연마할 책임이 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>미디어의 이해 – 인간의 확장</title><link>https://pkgpl.org/2021/09/06/%eb%af%b8%eb%94%94%ec%96%b4%ec%9d%98-%ec%9d%b4%ed%95%b4-%ec%9d%b8%ea%b0%84%ec%9d%98-%ed%99%95%ec%9e%a5/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/06/%eb%af%b8%eb%94%94%ec%96%b4%ec%9d%98-%ec%9d%b4%ed%95%b4-%ec%9d%b8%ea%b0%84%ec%9d%98-%ed%99%95%ec%9e%a5/</guid><pubDate>Sun, 05 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;마셜 매클루언은 “미디어의 이해”에서 미디어가 인간에게 미치는 영향에 대해 이야기하고 있습니다. 이 때 미디어는 인간 감각을 확장한 모든 것을 의미합니다. 일반적으로 생각하는 라디오, 텔레비전, 영화 뿐 아니라 피부를 확장한 의복과 집, 다리를 확장한 바퀴, 자동차, 비행기, 말을 확장한 문자 등 다양한 기술들을 모두 미디어라 할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;미디어를 이용해 자신을 확장하게 되면 인간의 감각 비율에 변화가 생기게 되고 확장된 감각은 ‘마비’ 또는 절단 됩니다. 연못에 비친 자신의 모습을 보고 지각이 마비되었던 나르시스처럼 자신을 확장한 미디어에 사로잡혀 마비되는 것이지요. 길을 잘 찾기 위해 네이게이션을 사용하며 길 찾기 능력이 사라지고, 전화번호를 잊지 않기 위해 핸드폰을 사용하며 전화번호를 기억하는 능력이 사라지고, 멀리 가기 위해 자동차를 타면서 장거리를 걷고 뛰는 능력이 사라집니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;미디어에는 주어진 경험 패턴에 순응하게 만들고 사람들에게 자신의 전제 조건들을 주입시키는 힘을 가지고 있습니다. ‘미디어가 메시지다’라고 할 때 메시지는 이러한 미디어로 인한 인간 변화를 의미합니다. 진지한 예술가는 자신의 감각 변화에 예민하기에 이러한 미디어의 영향을 피할 수 있지만, 일반적인 사람들은 미디어의 힘을 이해해도 미디어 사용으로 인한 감각 변화를 막을 수 없습니다. 유일한 해결책은 다른 미디어입니다. 예를 들어, 텔레비전에 대항하려면 인쇄물을 해독제로 사용해야 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학원에서 연구를 통해 전문가가 되고자 하는 학생들은 미디어와 관련하여 다음 두 가지 측면에 주의를 기울일 필요가 있다고 생각합니다.&lt;br&gt;1. &lt;a href=&quot;https://pkgpl.org/2021/09/07/디지털-미디어와-깊이-읽기/&quot;&gt;현재 디지털 미디어로 인해 자신이 어떠한 영향을 받고 있는지&lt;/a&gt;&lt;br&gt;2. 미래 자신이 개발할 기술(미디어)이 자신과 다른 사람들에게 어떠한 영향을 끼칠 것인지&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>독서의 기술과 논문 읽기</title><link>https://pkgpl.org/2021/09/05/%eb%8f%85%ec%84%9c%ec%9d%98-%ea%b8%b0%ec%88%a0%ea%b3%bc-%eb%85%bc%eb%ac%b8-%ec%9d%bd%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/05/%eb%8f%85%ec%84%9c%ec%9d%98-%ea%b8%b0%ec%88%a0%ea%b3%bc-%eb%85%bc%eb%ac%b8-%ec%9d%bd%ea%b8%b0/</guid><pubDate>Sat, 04 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;모티머 애들러는 “How to read a book” (번역본 “독서의 기술”, “생각을 넓혀주는 독서법”)에서 독서의 네 가지 수준에 대해 알려줍니다.&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;초급 독서&lt;br&gt;초급 독서는 단순히 글자를 읽는 수준입니다.&lt;/li&gt;



&lt;li&gt;점검 독서&lt;br&gt;빠르게 책의 내용을 파악하는 수준으로 골라 읽기, 표면 읽기라고 할 수 있습니다.&lt;/li&gt;



&lt;li&gt;분석 독서&lt;br&gt;철저하게 깊이 읽기입니다.&lt;/li&gt;



&lt;li&gt;신토피칼 독서&lt;br&gt;하나의 주제에 대한 여러 권의 책을 관련지어 읽습니다.&lt;/li&gt;
&lt;/ol&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;모든 책을 이렇게 읽을 필요는 없습니다. 자신에게 중요한 책만 분석해가면서 읽으면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;분석 독서&lt;/strong&gt;는 다시 3단계로 나눌 수 있습니다. 1단계는 구조 파악 단계입니다.&lt;br&gt;1. 책을 분류&lt;br&gt;2. 구상과 플롯 – 전체를 몇 문장으로 요약합니다.&lt;br&gt;3. 개요 파악&lt;br&gt;4. 저자의 의도 파악 – 해결하려는 문제를 분명히 합니다.&lt;br&gt;&lt;br&gt;2단계는 내용 해석 단계입니다.&lt;br&gt;5. 저자와 타협 – 키워드를 이해하고 저자가 사용하고 있는 용어의 의미를 파악합니다.&lt;br&gt;6. 저자가 전달하고 싶은 것은 무엇인가? – 저자의 명제와 중요 문장을 파악합니다.&lt;br&gt;7. 저자의 논증 발견 – 귀납법, 연역법 등 논증 방법과 가정 및 전제를 파악합니다.&lt;br&gt;8. 저자의 해결 검토 – 저자가 해결한 문제와 해결하지 않은 문제를 판별합니다.&lt;br&gt;&lt;br&gt;3단계는 저자에게 찬성하거나 반론을 제시하는 단계입니다. 이 때 어떤 점이 부족한지 분명히 합니다. 예를 들면, 저자의 지식이 부족한지, 지식에 오류가 있는지, 논리성이 결여된 것은 아닌지, 분석이나 설명이 불완전한 것은 아닌지 분명히 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;신토피칼 독서&lt;/strong&gt;도 단계를 나눌 수 있습니다.&lt;br&gt;0. 먼저 준비 작업으로 연구 분야를 조사하여 읽고자 하는 문헌표를 작성하고 문헌표의 문헌들을 점검합니다.&lt;br&gt;1. 1단계에서는 문헌들 사이에서 관련 깊은 곳을 발견합니다.&lt;br&gt;2. 저자들마다 같은 용어를 다른 방식으로 사용했을 수 있으므로 자신의 용어 사용 방식을 정합니다.&lt;br&gt;3. 명제를 세우고 여러 가지 질문을 던집니다.&lt;br&gt;4. 질문에 대한 저자들의 대답을 정리하고 논점을 명확히 합니다.&lt;br&gt;5. 질문과 논점을 정리하고 논고를 분석합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;논문을 읽을 때에도 위의 수준들을 적용할 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;점검 독서&lt;/strong&gt;: 여러 논문들 중 자신에게 필요한 논문을 찾을 때 사용하게 됩니다. 제목과 초록, 그림 등을 보면서 자신이 읽을만한 논문인지 파악합니다.&lt;br&gt;&lt;strong&gt;분석 독서&lt;/strong&gt;: 자신의 연구에 중요한 논문을 찾았다면 분석 독서의 방법을 적용할 수 있습니다. 과학 기술 논문의 구조는 정해져 있고 초록에 핵심 내용이 요약되어 있으므로 분석 독서의 1단계는 금방 넘어갈 수 있고, 2단계와 3단계에 집중합니다. 논문을 심사할 때에는 3단계에서 파악한 내용을 바탕으로 심사 의견을 남길 수 있습니다.&lt;br&gt;&lt;strong&gt;신토피칼 독서&lt;/strong&gt;: 자신의 연구 주제를 정했다면 해당 주제와 관련된 논문들을 모아서 신토피칼 독서 방법을 적용하게 됩니다. 문헌표 작성시 인터넷 검색을 이용할 수도 있는데, 보통 관련 논문의 서론과 참고 문헌 목록에서 필요한 논문들을 찾을 수 있습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>삶의 의미</title><link>https://pkgpl.org/2021/09/04/%ec%82%b6%ec%9d%98-%ec%9d%98%eb%af%b8/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/04/%ec%82%b6%ec%9d%98-%ec%9d%98%eb%af%b8/</guid><pubDate>Fri, 03 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;빅터 프랭클은 “죽음의 수용소에서”라는 책에서 유대인 강제 수용소 경험과 삶의 의미에 대해 들려줍니다. 자신의 삶의 의미를 찾는다면 강제 수용소 생활도 견딜 수 있다고 합니다. 우리는 가치 있는 목표를 추구함으로써 자신의 삶에 보다 깊은 의미를 부여할 수 있습니다. 이 때 중요한 것은 ‘우리가 삶으로부터 무엇을 기대하는가’가 아니라 ‘삶이 우리로부터 무엇을 기대하는가’입니다. ‘무엇을 받을까’가 아니라 ‘무엇을 줄까’를 고민하라는 것이지요. 우리는 자신의 삶에 대해 책임을 짐으로써만 삶의 질문에 대답할 수 있다고 합니다. 빅터 프랭클이 제안하는 삶의 의미를 찾는 세 가지 방식은 다음과 같습니다. &lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;무엇인가를 창조하거나 어떤 일을 함으로써&lt;/li&gt;



&lt;li&gt;어떤 일을 경험하거나 어떤 사람을 만남으로써(사랑)&lt;/li&gt;



&lt;li&gt;피할 수 없는 시련에 대해 어떤 태도를 취하기로 결정함으로써&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;전문가, 장인은 무엇인가를 창조하거나 어떤 일을 함으로써 삶의 의미를 찾을 수 있을 것입니다. 전문가가 되기 위해 대학원에 진학한 여러분, 장차 사회에 무엇을 줄 수 있을지 고민해보세요. 가치 있는 목적은 &lt;a href=&quot;https://pkgpl.org/2021/09/03/자율성-숙련-목적/&quot;&gt;내적 동기의 필수 요소&lt;/a&gt;이기도 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;봉사나 타인 사랑으로 자신을 잊을수록 우리는 더 인간다워지며 자신을 더 잘 실현하게 된다고 합니다. 성공과 행복, 쾌락을 목표로 삼지 말라고 합니다. 이런 것들은 어떤 행위의 부산물로 찾아오는 것이지 그 자체가 목적이 아닙니다. 먼 미래의 행복을 위해 현재 대학원에서의 시간을 희생한다고 생각하지 말고, 지금 배우고 성장해가는 과정 중에 행복하시길 바랍니다. 소유하는 삶이 아닌, &lt;a href=&quot;https://pkgpl.org/2018/12/31/책-소유냐-존재냐-에리히-프롬/&quot;&gt;존재하는 삶&lt;/a&gt;을 살아가시길 바랍니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>자율성, 숙련, 목적</title><link>https://pkgpl.org/2021/09/03/%ec%9e%90%ec%9c%a8%ec%84%b1-%ec%88%99%eb%a0%a8-%eb%aa%a9%ec%a0%81/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/03/%ec%9e%90%ec%9c%a8%ec%84%b1-%ec%88%99%eb%a0%a8-%eb%aa%a9%ec%a0%81/</guid><pubDate>Thu, 02 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;다니엘 핑크는 “드라이브”라는 책에서 전문가에게 필요한 내적 동기, 내재적 보상에 대해 알려줍니다. 당근과 채찍이라는 외적 보상은 보통 창의성에 해가 되는 반면에, 내재 동기는 창의성을 유도한다고 합니다. 내적 동기를 위한 필수 3요소는 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;자율성: 자기 주도적 동기 부여로, 자신의 삶을 주도하겠다는 욕구입니다. 무엇을(업무) 언제(시간) 어떻게(기술) 누구와 함께(팀) 할 것인지 선택할 수 있다면 자율성이 높다고 할 수 있습니다. &lt;a href=&quot;https://pkgpl.org/2021/10/09/%ec%a0%84%eb%ac%b8%ea%b0%80%ec%97%90-%ec%9d%b4%eb%a5%b4%eb%8a%94-%ea%b8%b8/&quot;&gt;드라이퍼스 모델&lt;/a&gt;에서 볼 수 있는 것처럼 초보자는 규칙을 따라야 하기 때문에 자율성이 거의 없지만 보통 실력이 향상될수록 자율성이 증가하게 됩니다. 물론 자유에는 책임도 따릅니다.&lt;/li&gt;



&lt;li&gt;숙련: 중요한 무언가를 더욱 잘하고 싶다는 욕구로, 몰입에 이르는 길입니다. 일의 즐거움 자체가 보상이 됩니다. 숙련을 위해서는 성장형 마음가짐이 필요하고 &lt;a href=&quot;https://pkgpl.org/2021/10/10/%ec%9d%98%ec%8b%9d%ec%a0%81%ec%9d%b8-%ec%97%b0%ec%8a%b5-deliberate-practice/&quot;&gt;의식적인 연습&lt;/a&gt;이라는 힘든 과정을 견디기 위한 투지, 의지가 필요합니다. 점근선과 같이 완전한 숙련에 도달하는 것은 불가능하지만 숙련을 추구하는 데 즐거움이 존재합니다.&lt;/li&gt;



&lt;li&gt;목적: &lt;a href=&quot;https://pkgpl.org/2021/09/04/삶의-의미/&quot;&gt;의미있는 삶&lt;/a&gt;을 위한 욕구, 자신보다 더 큰 무언가를 위해 일을 하고 싶다는 욕구입니다. 자신보다 위대하고 영원한 무언가에 속해 있다는 느낌이 들지 않는다면 진정으로 탁월한 삶을 이끌 수 없다고 합니다(미하이 칙센트미하이).&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 책에서 외재 동기에 의해 일하는 사람은 X 유형, 내재 동기로 일하는 사람은 I 유형으로 분류합니다. “&lt;a href=&quot;https://pkgpl.org/2018/12/31/책-소유냐-존재냐-에리히-프롬/&quot;&gt;소유냐 존재냐&lt;/a&gt;”에 나오는 소유형 인간, 존재형 인간과 통한다고 볼 수 있겠습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;(꽤 소박한) 일정 수준을 넘긴 후에는 돈이 많다고 더 행복해지지 않습니다. 자신에게 중요한 무언가를 하고, 그 무언가를 잘하고, 또 자신보다 큰 대의를 위해 노력할 때 우리는 가장 풍요롭다고 합니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>의식적인 연습 deliberate practice</title><link>https://pkgpl.org/2021/09/02/%ec%9d%98%ec%8b%9d%ec%a0%81%ec%9d%b8-%ec%97%b0%ec%8a%b5-deliberate-practice/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/02/%ec%9d%98%ec%8b%9d%ec%a0%81%ec%9d%b8-%ec%97%b0%ec%8a%b5-deliberate-practice/</guid><pubDate>Wed, 01 Sep 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;안데르스 에릭슨은 “1만 시간의 재발견 (Peak)”이라는 책에서 의식적인 연습(deliberate practice)에 대해 설명하고 있습니다. 의식적인 연습은 특정 기술의 전문성을 획득하기 위한 연습으로, 단순한 연습에 비해 훨씬 목적 의식이 강하고 용의주도하며 집중적인 연습입니다. 의식적인 연습은 다음과 같은 특성들이 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;다른 사람들이 이미 방법을 알고 있고, 효과적 훈련 기법이 수립되어 있는 기술을 연마하는데 사용합니다.&lt;/li&gt;



&lt;li&gt;편하게 여기는 컴포트존을 벗어난 지점에서 진행됩니다. 현재의 능력을 살짝 넘어서는 작업을 지속적으로 시도합니다.&lt;/li&gt;



&lt;li&gt;명확하고 구체적인 목표가 있고, 훈련 성과를 가시적으로 확인할 수 있습니다.&lt;/li&gt;



&lt;li&gt;신중하고 계획적입니다. 온전히 집중하고 의식적으로 행동합니다.&lt;/li&gt;



&lt;li&gt;피드백이 존재하고 그에 따라 행동을 바꿉니다.&lt;/li&gt;



&lt;li&gt;효과적인 심적 표상(mental model)을 만들어내고 심적 표상에 의존합니다.&lt;/li&gt;



&lt;li&gt;기존에 습득한 기술의 특정 부분을 집중적으로 개선합니다. 이를 위해서는 교사나 코치가 초보자에게 정확한 기본 기술을 가르쳐주는 것이 중요합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;실력 향상을 위해서는 올바른 연습을 충분한 기간에 걸쳐 수행해야 하며 시간을 단축시켜주는 지름길은 없습니다. 의식적인 연습에서는 지식보다 행동, 기술에 집중합니다. ‘무엇을 아는가’보다 ‘무엇을 할 수 있는가’에 초점을 맞추는거죠. 지식은 기술을 익히며 자연스럽게 얻게 됩니다. 노력의 대부분은 교사가 내준 과제를 하며 혼자 하는 연습에 들어갑니다. 만약 교사 없이 연습하려면 집중(Focus)하고 피드백(Feedback)을 받아 수정(Fix)하는 과정을 반복해야 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학원 생활에 의식적인 연습을 적용한다면, 전공 지식 쌓기, 논문 쓰기, 프로그래밍, 특정 프로그램 다루기 등 각 전공에서 필요한 기술별로 적용해야겠죠. 연구 능력이나 창의성 향상과 같이 목표가 모호한 경우에는 구체적으로 성과를 확인할 수 있도록 다른 접근이 필요할 듯 합니다.&lt;br&gt;의식적인 연습에는 빠른 피드백이 중요한데, 현실적으로 학생들이 지도교수님께 각각의 기술들에 대해 매번 빠르게 피드백을 받기는 어렵습니다. 지도교수님께도 피드백을 받되, 스스로도 피드백을 받고 수정할 수 있는 환경을 구축하는 것이 좋습니다.&lt;br&gt;전공 지식 쌓기 같은 경우 전공 서적에 연습 문제가 있다면 풀어보며 스스로 피드백을 얻을 수 있습니다.&lt;br&gt;논문 쓰기의 경우 자신의 글과 출판된 논문의 글을 비교하며 피드백을 받을 수 있습니다. 학술지에 자주 논문을 제출하면 그만큼 자주 피드백을 받을 수 있겠죠. 단, 피드백이 기분 좋지 않은 경우도 많을겁니다.&lt;br&gt;프로그래밍의 경우에는 애자일 방법론에서 사용하는 테스트주도 개발이 유용할 듯 합니다.&lt;br&gt;전공 연구에 필요한 특정 프로그램을 다룰 경우에는 프로그램의 기능을 하나씩 이용해 필요한 작업을 실행해가며 피드백을 얻을 수 있습니다.&lt;br&gt;이렇게 피드백을 통해 하나씩 수정해가는 과정을 꾸준히 반복하다보면 어느새 실력이 향상되어 있을 것입니다. 조급해하지 맙시다. 천재도 전문가 수준에 도달하기 위해서는 많은 연습이 필요다하고 합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학원을 졸업하고 전문가가 된다고 해서 의식적인 연습이 끝나는 것은 아닙니다. 전문가는 끊임없이 연습하고 기술을 연마할 방법을 모색하는 사람입니다. 훈련을 멈추면 능력이 사라지기 시작하기 때문이죠. 많은 경우 어떤 기술이나 능력을 비범한 수준으로 발전시킨 사람들은 다른 영역에서는 오히려 뒤쳐지는 모습을 보인다고 합니다. 여러분의 교수님이 전공 외의 다른 부분에서 좀 모자라보여도 이해해주세요^^&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>전문가에 이르는 길</title><link>https://pkgpl.org/2021/09/01/%ec%a0%84%eb%ac%b8%ea%b0%80%ec%97%90-%ec%9d%b4%eb%a5%b4%eb%8a%94-%ea%b8%b8/</link><guid isPermaLink="true">https://pkgpl.org/2021/09/01/%ec%a0%84%eb%ac%b8%ea%b0%80%ec%97%90-%ec%9d%b4%eb%a5%b4%eb%8a%94-%ea%b8%b8/</guid><pubDate>Tue, 31 Aug 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;앤디 헌트는 프로그래머를 위한 “실용주의 사고와 학습”이라는 책에서 드라이퍼스 모델이라는, 기술 습득과 통달에 관한 연구를 소개하고 있습니다. 드라이퍼스 모델에 따르면 초보자에서 전문가에 이르는 과정은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;초보자&lt;/li&gt;



&lt;li&gt;고급입문자&lt;/li&gt;



&lt;li&gt;중급자&lt;/li&gt;



&lt;li&gt;숙련자&lt;/li&gt;



&lt;li&gt;전문가&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;초보자&lt;/strong&gt;는 해당 기술 영역에서 사전 경험이 거의 없는 사람으로, 일하기 위해서는 정해진 규칙이 필요한 사람을 말합니다.&lt;br&gt;&lt;strong&gt;고급 입문자&lt;/strong&gt;는 고정된 규칙에서 조금씩 벗어나기 시작하지만, 문제 해결에 어려움을 느끼고 아직 큰 그림은 잘 모르는 사람입니다.&lt;br&gt;&lt;strong&gt;중급자&lt;/strong&gt;는 문제 영역에서 개념적 모델을 만들고 활용할 수 있습니다. 문제를 스스로 해결하고 새로운 문제를 해결할 방법을 찾아내기도 하죠. 그러나 자신을 돌아보고 잘못을 스스로 교정할 수 있는 능력은 아직 부족한 상태입니다.&lt;br&gt;&lt;strong&gt;숙련자&lt;/strong&gt;는 이전에 잘못했던 일을 스스로 교정할 수 있습니다. 다른 사람의 경험으로부터 배울 수도 있습니다. 경험이 풍부하고 뭔가가 잘 안 될 때 무엇을 바꿔야 해결할 수 있는지도 압니다. 중급자보다는 전문가에 가깝습니다.&lt;br&gt;&lt;strong&gt;전문가&lt;/strong&gt;는 어떤 분야든 지식과 정보의 근원으로 늘 더 나은 방법과 수단을 찾습니다. 적절한 맥락에서 써먹을 수 있을만큼 방대한 경험을 가지고 있고, 직관적으로 세부사항 중에서 중요한 것과 그렇지 않은 것을 가려낼 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;이 모델은 기술 및 분야별로 적용되는 모델로, 한 분야에서 전문가가 된다고 해서 다른 분야에서도 전문가가 되는 것은 아닙니다. 하지만, 한 분야에서 전문가가 되고 나면 다른 분야에서 전문성을 얻기가 훨씬 쉬워집니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;무술 수련에서도 수, 파, 리라고 유사한 개념이 있습니다. ‘수’는 가르침을 받은대로 따라하는 단계, ‘파’는 수련의 의미와 목적을 되새겨보고 더 깊이 이해하고 흡수하는 단계입니다. ‘리’는 가르침을 넘어서고 경험을 초월하는 단계로, 더이상 학생이 아니며 새로운 방법을 창출해낼 수 있습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;박사과정에 진학한 학생은 전문가가 되기 위한 길에 들어섰다고 생각할 수 있습니다. 석사과정을 초보자에서 고급 입문자가 되기 위한 단계(수)라고 한다면 박사과정은 중급자를 거쳐 숙련자가 되기 위한 단계(파)라고 할 수 있겠네요. 전문가(리)가 되기 위해서는 박사 졸업후에도 몇 년의 경험이 더 필요합니다. 1만 시간의 법칙을 적용해보자면 1년에 250일씩, 하루 4시간의 의식적인 연습을 한다고 했을 때 10년의 기간이 필요합니다(물론 1만 시간이 절대적인 값은 아닙니다).&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://pkgpl.org/2021/10/10/%ec%9d%98%ec%8b%9d%ec%a0%81%ec%9d%b8-%ec%97%b0%ec%8a%b5-deliberate-practice/&quot;&gt;의식적인 연습&lt;/a&gt;은 쉽지 않지만 이를 통해 일을 잘 하게 되면 자율성이 커지고 일 자체로부터 내적인 보상도 얻을 수 있습니다. 자신이 잘 하는 일에 몰입하며 행복감을 느끼게 됩니다. 꾸준히 노력하여 자신의 전문 기술로 사회를 더 좋게 만드는데 기여하는 훌륭한 전문가가 되시길 바랍니다(&lt;a href=&quot;https://pkgpl.org/2021/10/11/%ec%9e%90%ec%9c%a8%ec%84%b1-%ec%88%99%eb%a0%a8-%eb%aa%a9%ec%a0%81/&quot;&gt;자율성, 숙련, 목적&lt;/a&gt;).&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>연구실 도커 기본 이미지 pkgpl_base</title><link>https://pkgpl.org/2021/06/24/%ec%97%b0%ea%b5%ac%ec%8b%a4-%eb%8f%84%ec%bb%a4-%ea%b8%b0%eb%b3%b8-%ec%9d%b4%eb%af%b8%ec%a7%80-pkgpl_base/</link><guid isPermaLink="true">https://pkgpl.org/2021/06/24/%ec%97%b0%ea%b5%ac%ec%8b%a4-%eb%8f%84%ec%bb%a4-%ea%b8%b0%eb%b3%b8-%ec%9d%b4%eb%af%b8%ec%a7%80-pkgpl_base/</guid><pubDate>Wed, 23 Jun 2021 22:30:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;탄성파탐사 연구실에서 연구할 때 많이 사용하는 라이브러리들을 설치해놓은 도커 이미지를 공개해두었습니다. &lt;a href=&quot;https://hub.docker.com/r/pkgpl/pkgpl_base&quot;&gt;도커 허브&lt;/a&gt;에서 이미지를 받거나, &lt;a href=&quot;https://github.com/pkgpl/pkgpl_base&quot;&gt;깃허브&lt;/a&gt;에서 도커 파일을 받을 수도 있지만, &lt;a href=&quot;https://pkgpl.org/2021/06/23/docker와-github를-이용한-소프트웨어-연구-환경-구축/&quot;&gt;Docker와 GitHub를 이용한 소프트웨어 연구 환경 구축&lt;/a&gt;에서 설명한 &lt;a href=&quot;https://github.com/pkgpl/project_template&quot;&gt;연구 프로젝트 템플릿&lt;/a&gt;을 통해 이용하는 것을 추천합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;설치된 주요 라이브러리들은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;탄성파 자료 처리 관련
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Seismic Unix&lt;/li&gt;



&lt;li&gt;Madagascar&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;수치 연산 관련&lt;ul&gt;&lt;li&gt;nvcc&lt;/li&gt;&lt;li&gt;gcc/gfortran&lt;/li&gt;&lt;li&gt;python&lt;/li&gt;&lt;li&gt;numpy&lt;/li&gt;&lt;li&gt;numba&lt;/li&gt;&lt;/ul&gt;
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;mpi4py&lt;/li&gt;



&lt;li&gt;mkl&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;딥러닝 관련 (horovod 도커 이미지 사용)
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;pytorch&lt;/li&gt;



&lt;li&gt;tensorflow&lt;/li&gt;



&lt;li&gt;mxnet&lt;/li&gt;



&lt;li&gt;horovod&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;기타 머신러닝 관련
&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;scikit-learn&lt;/li&gt;



&lt;li&gt;pandas&lt;/li&gt;



&lt;li&gt;jupyterlab&lt;/li&gt;



&lt;li&gt;matplotlib&lt;/li&gt;



&lt;li&gt;bokeh&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Docker와 GitHub를 이용한 소프트웨어 연구 환경 구축</title><link>https://pkgpl.org/2021/06/23/docker%ec%99%80-github%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%86%8c%ed%94%84%ed%8a%b8%ec%9b%a8%ec%96%b4-%ec%97%b0%ea%b5%ac-%ed%99%98%ea%b2%bd-%ea%b5%ac%ec%b6%95/</link><guid isPermaLink="true">https://pkgpl.org/2021/06/23/docker%ec%99%80-github%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%86%8c%ed%94%84%ed%8a%b8%ec%9b%a8%ec%96%b4-%ec%97%b0%ea%b5%ac-%ed%99%98%ea%b2%bd-%ea%b5%ac%ec%b6%95/</guid><pubDate>Tue, 22 Jun 2021 23:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;소프트웨어를 이용한 연구와 수업을 위해 도커와 깃허브를 이용한 연구 프로젝트 템플릿을 만들어서 공개했습니다. 도커를 이용하면 소프트웨어와 관련된 라이브러리를 설치하고 환경을 설정하는 과정을 쉽게 만들 수 있고, 깃과 깃허브를 이용하면 도커 설정 파일과 프로그래밍 소스 코드를 안전하게 관리할 수 있습니다. 도커 사용 경험이 없는 연구자들이 도커를 쉽게 사용할 수 있도록 프로젝트 템플릿에 도커 관련 리눅스 스크립트들을 추가하였습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;a href=&quot;https://github.com/pkgpl/project_template&quot;&gt;프로젝트 템플릿&lt;/a&gt;은 깃허브 계정을 만들고 Fork하면 됩니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;사용 방법은 &lt;a href=&quot;https://kseg.jams.or.kr/po/volisse/sjPubsArtiPopView.kci?soceId=INS000002518&amp;amp;artiId=SJ0000000564&amp;amp;sereId=SER000000001&amp;amp;submCnt=1&quot;&gt;리눅스 컨테이너와 버전 관리 시스템을 이용한 소프트웨어 연구 환경 구축&lt;/a&gt; 논문이나 &lt;a href=&quot;https://youtu.be/qpf4fycdklo&quot;&gt;유튜브&lt;/a&gt;에서 확인할 수 있습니다.&lt;/p&gt;



&lt;blockquote class=&quot;wp-block-quote is-layout-flow wp-block-quote-is-layout-flow&quot;&gt;
&lt;p class=&quot;wp-block-paragraph&quot;&gt;소프트웨어 기술 발달에 따라 점점 더 많은 과학자와 공학자들이 연구를 위해 컴퓨터 소프트웨어와 프로그래밍 도구들을 사용하고 있다. 소프트웨어를 이용한 연구에서는 환경 설정, 재현성 및 소스 코드 손실과 같은 문제들이 발생할 수 있다. 이 해설에서는 리눅스 컨테이너와 버전 관리 시스템을 사용하여 이러한 문제를 방지하는 방법에 대해 조사하였다. 연구 프로젝트 단위로 클라우드 저장소를 통해 코드를 관리하고 리눅스 컨테이너에 연구 환경을 구축하면 위의 문제들을 방지하고 협동 연구를 더 쉽게 만들 수 있다. 리눅스 컨테이너 사용경험이 없는 연구자들을 위해 컨테이너 생성과 실행에 필요한 스크립트를 포함한 연구 프로젝트 템플릿 저장소를 공개하였다.&lt;/p&gt;
&lt;cite&gt;//리눅스 컨테이너와 버전 관리 시스템을 이용한 소프트웨어 연구 환경 구축 – 초록&lt;/cite&gt;&lt;/blockquote&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Git과 GitHub를 이용한 소스 코드 버전 관리</title><link>https://pkgpl.org/2021/06/20/git%ea%b3%bc-github%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%86%8c%ec%8a%a4-%ec%bd%94%eb%93%9c-%eb%b2%84%ec%a0%84-%ea%b4%80%eb%a6%ac/</link><guid isPermaLink="true">https://pkgpl.org/2021/06/20/git%ea%b3%bc-github%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ec%86%8c%ec%8a%a4-%ec%bd%94%eb%93%9c-%eb%b2%84%ec%a0%84-%ea%b4%80%eb%a6%ac/</guid><pubDate>Sat, 19 Jun 2021 22:00:00 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;대학원에서 연구를 위해 또는 수업을 위해 프로그래밍을 사용하는 경우가 있습니다. 프로그래밍 언어를 이용해 직접 프로그램을 개발할 경우 소스 코드를 관리해주는 프로그램을 버전 관리 시스템이라고 합니다. 버전 관리 시스템을 이용하면 소스 코드 변경 사항을 기록하여 필요할 경우 이전 상태로 되돌릴 수 있고, 실수로 코드를 지워도 복구가 가능합니다. 대학원생들에게 다양한 버전 관리 시스템들 중 깃(&lt;a href=&quot;https://git-scm.com&quot;&gt;Git&lt;/a&gt;)을 추천합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;주요 Git 명령어들&lt;/strong&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Git에서 주로 사용하는 명령줄(Command line) 명령어들은 아래와 같습니다. 명령줄이 익숙하지 않은 학생들은 &lt;a href=&quot;https://git-scm.com/downloads&quot;&gt;GUI 프로그램&lt;/a&gt;을 이용해도 됩니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;git init: 현재 디렉토리를 git 저장소로 만들어줍니다.&lt;/li&gt;



&lt;li&gt;git add &amp;lt;files&amp;gt;: 파일들(새 파일 또는 수정한 파일)의 변경 사항을 추적하겠다고 git에게 알려줍니다.&lt;/li&gt;



&lt;li&gt;git commit: 앞에서 추적하기로 한 변경 사항들을 실제로 기록합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;git status: 현재 저장소 상황을 보여줍니다. 추적 중인 파일들 중 어떤 파일들이 변경되었는지 알 수 있습니다.&lt;/li&gt;



&lt;li&gt;git diff: 어떤 내용들이 변경되었는지 확인합니다.&lt;/li&gt;



&lt;li&gt;git log: 그동안의 commit 내역을 확인합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;git clone &amp;lt;remote&amp;gt;: 원격 저장소가 있을 경우 원격 저장소를 현재 컴퓨터에 복사합니다.&lt;/li&gt;



&lt;li&gt;git pull: 원격 저장소에서 최신 변경 사항을 가지고 옵니다.&lt;/li&gt;



&lt;li&gt;git push: 현재 저장소에서 commit한 변경 사항을 원격 저장소에 기록합니다.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;소스 코드에 주요 변경 사항이 있을 때마다 git add, git commit 명령을 실행합니다. 위의 명령어들은 일단 변경 사항을 저장하기 위한 명령어들이고 문제가 생겼을 때 복구하기 위한 명령어들이나 branch(가지 치기) 기능과 관련된 명령어들도 여러 가지가 있습니다. 평소에는 add, commit 명령으로 소스 코드 변경 사항을 잘 기록해두고 다른 명령어들은 필요할 때 찾아서 사용하면 됩니다(&lt;a href=&quot;https://git-scm.com/book/ko/v2&quot;&gt;한글판 Pro Git 책&lt;/a&gt;).&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;원격 저장소가 필수는 아니지만 사용중인 컴퓨터 전체에 문제가 생겼을 경우에는 git으로도 소스 코드를 복구할 수 없기 때문에 중요한 코드라면 별도의 컴퓨터에 원격 저장소를 만들어두는 것이 좋습니다. 원격 저장소로 사용하기 좋은 클라우드 서비스들이 몇 가지 있는데 그중 깃허브(&lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;)를 가장 많이 사용합니다. GitHub를 사용하면 다른 사람과 공동으로 작업하기도 좋습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;GitHub에 저장소를 만들고 작업중인 컴퓨터에서 clone하면 GitHub 저장소가 자동으로 원격 저장소로 등록되기 때문에 컴퓨터에서 코드를 수정하고 add, commit한 후 push해서 GitHub 저장소를 업데이트할 수 있습니다. 이미 컴퓨터에 git 저장소가 있을 경우에는 GitHub에 새로운 저장소를 만들고 작업중인 컴퓨터에서 GitHub 저장소를 원격 저장소로 등록해주면 됩니다. 이 때 필요한 명령은 GitHub에서 새로운 저장소를 만들면 자세히 설명해줍니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;GitHub를 이용하면 작업중인 컴퓨터와 GitHub 두 군데에 소스 코드를 백업하는 셈입니다. 여러 대의 컴퓨터에서 작업하더라도 GitHub를 통해 소스 코드를 쉽게 동기화할 수 있습니다. 프로그래밍이 본인의 연구에서 중요하다면 꼭 버전 관리 시스템을 사용합시다. git add/commit/push를 기억합시다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>GPU를 이용한 병렬 처리/전산 유체 역학 시뮬레이션 성능 향상</title><link>https://pkgpl.org/2020/11/18/gpu%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%eb%b3%91%eb%a0%ac-%ec%b2%98%eb%a6%ac-%ec%a0%84%ec%82%b0-%ec%9c%a0%ec%b2%b4-%ec%97%ad%ed%95%99-%ec%8b%9c%eb%ae%ac%eb%a0%88%ec%9d%b4%ec%85%98-%ec%84%b1%eb%8a%a5/</link><guid isPermaLink="true">https://pkgpl.org/2020/11/18/gpu%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%9c-%eb%b3%91%eb%a0%ac-%ec%b2%98%eb%a6%ac-%ec%a0%84%ec%82%b0-%ec%9c%a0%ec%b2%b4-%ec%97%ad%ed%95%99-%ec%8b%9c%eb%ae%ac%eb%a0%88%ec%9d%b4%ec%85%98-%ec%84%b1%eb%8a%a5/</guid><pubDate>Wed, 18 Nov 2020 07:00:46 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;본 연구실에서는 파동 전파 모델링을 위해 병렬 프로그래밍을 사용하고 있습니다. 최근 GPU 성능 향상에 따라 GPU를 이용한 파동 전파 모델링과 완전 파형 역산도 진행하고 있습니다. 그동안 진행해 왔던 GPU 관련 과제들은 다음과 같습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;2014-2019 자원개발특성화대학사업 – 산학협력 연구단 석유가스 물리탐사&lt;/li&gt;



&lt;li&gt;2015-2016 한국지질자원연구원 – GPU를 이용한 파동 전파 모델링 기술 개발, GPU를 이용한 속도 모델링 기술 개발&lt;/li&gt;



&lt;li&gt;2016 부산과학기술기획평가원 – 범용 그래픽 처리장치와 OpenACC를 이용한 병렬 컴퓨팅 성능 향상&lt;/li&gt;



&lt;li&gt;2017-2019 한국지질자원연구원 – 다중 GPU 기반 고성능 역시간 구조보정 성능 비교 연구&lt;/li&gt;



&lt;li&gt;2019-2020 국방과학연구소 – 저주파 수중음향 전달특성 및 고속화 성능 분석&lt;/li&gt;
&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;병렬 프로그래밍 기술은 탄성파 탐사 분야 뿐 아니라 물리학, 기계, 조선이나 화학 공학의 전산 유체 시뮬레이션 분야에서도 중요하게 사용되는 기술입니다. 특히 GPU 계산은 CPU를 이용한 계산보다 빠르고 효율적이기 때문에 대학/연구소/기업 등에서 연산 성능 향상 및 비용 절감을 위해 수요가 점점 증가하고 있습니다. 그러나 안타깝게도 부산 지역에 GPU 프로그래밍을 하는 사람이 많지 않기 때문에 GPU 병렬 프로그래밍 도입에 어려움을 겪는 사례들이 있습니다. &lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;올해 여름에 부산대학교 조선해양공학과 교수님으로부터 쇄빙선에 가해지는 빙하중을 시뮬레이션하는 프로그램을 GPU에서 빠르게 돌아가도록 만들어달라는 제안을 받고 방학 기간 동안 작업을 진행했습니다. 부산대에서 OpenMP와 MPI를 이용해 클러스터 컴퓨터에서 돌아가도록 개발한 프로그램을 자체적으로 GPU용으로 바꿨는데 성능이 안 나와서 본 연구실에서 GPU 프로그램의 성능을 향상시키는 작업을 수행했습니다. 그 결과 클러스터 컴퓨터에서 CPU 56 코어를 사용해 8시간 30분 정도 걸리던 벤치마킹 모델 시뮬레이션 작업이 GPU 최적화를 통해 Nvidia Tesla V100 GPU 카드 한 장을 사용했을 때 30분 정도로 단축되었습니다. 여러 장의 GPU를 사용할 수 있도록 개선하여 GPU 카드 네 장을 사용하면 10분 정도에 결과를 얻을 수 있습니다. 해당 연구는 최근 대한조선학회에 발표했습니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;현재 대학원 수업에서 병렬 프로그래밍을 다루기는 하지만 컴퓨터 관련 학과가 아니다보니 GPU 성능 최적화에 대해 깊이 다루지는 않습니다. 평소 컴퓨터와 프로그래밍에 관심이 있고 고성능 병렬 프로그래밍에 대해 배우고 싶다면, 본 연구실에 들어와서 병렬 연산 쪽으로 연구하는 것도 좋겠네요. 병렬 프로그래밍에서 주로 다루는 언어는 Fortran/C/C++/CUDA 이니 해당 언어 사용 경험이 있다면 더 좋습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>책: 실용주의 프로그래머 – 앤드류 헌트, 데이비드 토머스</title><link>https://pkgpl.org/2019/02/08/%ec%b1%85-%ec%8b%a4%ec%9a%a9%ec%a3%bc%ec%9d%98-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%a8%b8-%ec%95%a4%eb%93%9c%eb%a5%98-%ed%97%8c%ed%8a%b8-%eb%8d%b0%ec%9d%b4%eb%b9%84%eb%93%9c-%ed%86%a0%eb%a8%b8/</link><guid isPermaLink="true">https://pkgpl.org/2019/02/08/%ec%b1%85-%ec%8b%a4%ec%9a%a9%ec%a3%bc%ec%9d%98-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%a8%b8-%ec%95%a4%eb%93%9c%eb%a5%98-%ed%97%8c%ed%8a%b8-%eb%8d%b0%ec%9d%b4%eb%b9%84%eb%93%9c-%ed%86%a0%eb%a8%b8/</guid><pubDate>Fri, 08 Feb 2019 02:09:04 GMT</pubDate><content:encoded>
&lt;p class=&quot;wp-block-paragraph&quot;&gt;‘실용주의 프로그래머’는 전문 프로그래머들을 위한 조언들이 담긴 책입니다. 제가 대학원생 때 읽고 책의 조언들 중 몇 가지를 직접 실천해보면서 많은 도움을 얻었습니다. 총 70가지의 조언들이 담겨 있는데 제가 실천했던 조언들 중 몇 가지만 살펴보겠습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;&lt;strong&gt;11. DRY (Don’t Repeat Yourself) – 반복하지 마라.&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;12. 재사용하기 쉽게 만들라.&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;21. 명령어 셸의 힘을 사용하라.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;연구하면서 반복적으로 하는 작업들이 있습니다. 대학원생 때 반복적으로 하던 작업들 중 이진 파일로 된 탄성파 자료나 속도모델 등에서 trace나 profile을 추출하는 작업, 지하 영상에 미분이나 라플라시안 필터를 적용하는 작업, 깊이에 따라 속도가 선형으로 증가하는 속도모델을 만드는 작업 등이 있었습니다. 그때 그때 코드를 새로 작성하거나 예전에 사용했던 코드를 수정해서 작업했었는데 이러한 반복 작업을 없애기 위해 명령어 셸에서 옵션만 바꿔가며 쉽게 재사용할 수 있는 프로그램들을 작성했었습니다. 그리고 그런 프로그램들을 모아 gpl 라이브러리라고 이름을 붙였죠. 주로 당시 사용하던 포트란 프로그래밍 언어로 프로그램들을 작성했는데, 명령어 셸에서 사용할 수 있도록 option parser도 만들고 파일 입출력도 많이 다루면서 프로그래밍 연습을 할 수 있었습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;&lt;strong&gt;22. 하나의 에디터를 잘 사용하라.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;리눅스 Command line 상에서 프로그래밍을 했기 때문에 당시 사용할 수 있는 에디터로 &lt;a href=&quot;https://www.vim.org&quot;&gt;Vim&lt;/a&gt;과 &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;가 있었습니다. 둘 중 어느 것을 사용할까 비교해보다가 결국 어디에나 설치되어 있는 Vi(Vim)를 사용하기로 했고, 각종 명령어와 plugin들을 이용해 Vim 고급 사용법을 익혔습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;&lt;strong&gt;23. 언제나 소스코드 관리 시스템을 사용하라.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;당시에는 Mercurial을 선택해서 사용하다가 몇 년 전부터는 Git만 사용하고 있습니다.&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;&lt;strong&gt;28. 텍스트 처리 언어를 하나 익혀라.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;당시 포트란과 C 언어만 사용하고 있었는데, 이 책을 읽은 후 Ruby, Perl, Python 중 프로그래머를 행복하게 하자는 철학을 내세웠던 Ruby를 선택해서 공부하고 사용했었습니다. Ruby를 배워놓았던 것이 도움이 돼서 나중에 Ruby와 Seismic Unix를 이용해 Muting/Interpolation 스크립트도 작성할 수 있었습니다. 참고로 지금은 Ruby는 사용하지 않고, 과학/공학 라이브러리가 많은 Python을 주로 사용합니다.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;위의 조언들 외에도&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;&lt;li&gt;20. 지식을 일반 텍스트로 저장하라.&lt;/li&gt;&lt;li&gt;29. 코드를 작성하는 코드를 작성하라.&lt;/li&gt;&lt;li&gt;36. 모듈간의 결합도를 최소화하라.&lt;/li&gt;&lt;li&gt;49. 소프트웨어를 테스트하라.&lt;/li&gt;&lt;li&gt;61. 수작업 절차를 사용하지 말라.&lt;/li&gt;&lt;li&gt;68. 문서가 애초부터 전체의 일부가 되게 하고, 나중에 집어넣으려고 하지 말라.&lt;/li&gt;&lt;/ul&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;등 다양한 조언들을 실천해보면서 프로그래밍 실력을 향상시킬 수 있었습니다. 우리가 전문 프로그래머는 아니지만 주로 프로그래밍을 이용해 연구를 수행하고 있으니 프로그래밍에 대해 공부하는 것도 많은 도움이 됩니다. 단, 이것 자체가 연구는 아니니 연구하는 중에 틈틈이 연습해보는 것이 좋겠죠.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category><category>Computer</category></item><item><title>책: 소유냐 존재냐 – 에리히 프롬</title><link>https://pkgpl.org/2018/12/31/%ec%b1%85-%ec%86%8c%ec%9c%a0%eb%83%90-%ec%a1%b4%ec%9e%ac%eb%83%90-%ec%97%90%eb%a6%ac%ed%9e%88-%ed%94%84%eb%a1%ac/</link><guid isPermaLink="true">https://pkgpl.org/2018/12/31/%ec%b1%85-%ec%86%8c%ec%9c%a0%eb%83%90-%ec%a1%b4%ec%9e%ac%eb%83%90-%ec%97%90%eb%a6%ac%ed%9e%88-%ed%94%84%eb%a1%ac/</guid><pubDate>Mon, 31 Dec 2018 08:39:42 GMT</pubDate><content:encoded>&lt;p&gt;우리는 자본주의 사회에 살고 있습니다. 자본주의 사회는 빚과 소비가 있어야 돌아가는 사회로, 생산자들은 곳곳에서 광고와 뉴스 등을 통해 사람들에게 필요한 또는 불필요한 재화와 서비스의 소비를 부추기고 있습니다. 자본주의 사회에서는 많이 벌어서 많이 소유하고 많이 소비하는 것이 행복한 삶이라는 것을 전제로 하고 있고, 각종 미디어의 영향에서 자유로울 수 없는 우리들은 별다른 생각 없이 위의 전제를 받아들이며 살아가는 경우가 많습니다. 하지만 이 전제는 잘못되었고 그에 따라 많은 사람들이 인간 소외로 고통을 겪고 있습니다. 인류 역사에 자본주의가 등장한 것은 얼마 되지 않았지만 우리는 자본주의에 너무 익숙해진 나머지 자본주의 생활 양식이 아닌 다른 생활 양식이 있다는 사실을 생각하지 못하고 살아갈 때가 많습니다. 책을 읽을 때의 장점 중 하나가 이렇게 평소 삶 속에서 생각하지 못하던 것들을 새롭게 깨달을 수 있다는 점입니다.&lt;/p&gt;
&lt;p&gt;에리히 프롬은 이 책에서 많이 소유하는 것을 추구하는 삶 뿐 아니라 풍요롭게 존재하는 것을 추구하는 삶도 있다는 것을, 그러한 삶이 더 가치 있는 삶임을 일깨워줍니다. 자본주의의 소유하는 삶은 탐욕적으로 자신의 소유(재산, 명예, 권력 등)를 늘리고, 남들과 비교하여 자신이 우월하다는 데에서 행복을 발견하는 삶입니다. 반면에 존재하는 삶은 소유물에 집착하지 않는 삶, 기쁨에 차서 자신의 능력을 생산적, 능동적으로 사용하고, 사랑하고 나누며 베푸는 삶입니다. 소유하는 삶은 자신의 소유물로 자신의 가치를 매기고 소유물의 노예가 되는 삶이지만 존재하는 삶은 존재의 절대적 가치를 아는 삶입니다. 존재하는 삶이라고 해서 소유가 전혀 없는 것은 아니지만 존재하는 삶을 사는 사람은 자신의 소유물에 대해 집착하지 않고 소유로부터 자유롭습니다.&lt;/p&gt;
&lt;p&gt;두 가지 생활 양식이 학생들의 실생활에서는 어떻게 나타날까요? 소유하는 삶에 길들여진 학생은 강의를 들을 때 잘 암기하여 좋은 성적을 거두는데 중점을 두지만, 존재하는 삶을 사는 학생은 강의 내용을 통해 새로운 생각을 하며 성장하는데 중점을 둡니다. 소유하는 삶의 학생은 책을 읽을 때 소설의 줄거리를 파악하고 철학 서적의 주요 사항을 뒤따라 암기하는데 중점을 두지만, 존재하는 삶을 사는 학생은 소설을 통해 인간의 본성을 통찰하고 철학 서적의 사상을 비판적으로 읽습니다. 소유하는 삶에서는 보다 많이 아는 것이 중요하지만, 존재하는 삶에서는 보다 깊이 아는 것이 중요합니다. 소유하는 삶에서 사랑이란 사랑의 대상을 구속하고 지배하여 소유하는 것이지만, 존재하는 삶에서의 사랑은 사랑의 대상을 배려하고 알고자 하며 소생시키고 생동감을 증대시키는 과정입니다.&lt;/p&gt;
&lt;p&gt;우리 물리탐사 연구실이 존재하는 삶을 실천할 수 있는 공동체가 되길 바랍니다. 책 뒷부분에 가면 인간 성격 변화에 관한 거시적인 이야기가 나오지만 우리는 우선 작게 연구실에서 실천할 수 있는 부분을 생각해봅시다. 수업을 들을 때 시험 잘 보고 좋은 성적을 얻는 것도 중요하지만 수업을 통해 스스로가 성장하는데 중점을 둡시다. 연구하고 논문을 쓸 때 실적을 늘리는데 중점을 둘 것이 아니라 연구를 통해 새로운 것을 발견/발명하는 기쁨을 누리고 논문을 통해 사회에 기여한다는 생각으로 논문을 씁시다. 다른 사람과 경쟁해서 이기기 위해서가 아니라 어제의 나와 경쟁해서 더 성장하기 위해 노력합시다. 교수님 말이라고 절대적으로 받아들이지 말고 교수님도 틀릴 수 있으니 자신의 생각과 의견을 이야기합시다. 서로를 가족같이 여기고 자신이 좀 더 아는 것을 나누며 서로의 성장을 도웁시다. 연구실에서 보내는 시간을 학위를 위해 희생하는 시간이 아닌, 그 자체로 보람되고 행복한 시간으로 만들어갑시다. 연구실 생활을 통해 우리 모두의 존재가 좀 더 풍성해지길 바랍니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Books</category></item><item><title>rsfio module</title><link>https://pkgpl.org/2017/02/28/rsfio-module/</link><guid isPermaLink="true">https://pkgpl.org/2017/02/28/rsfio-module/</guid><pubDate>Tue, 28 Feb 2017 09:16:41 GMT</pubDate><content:encoded>&lt;p&gt;포트란 언어에서 사용할 수 있는 RSF 파일(&lt;a href=&quot;http://www.ahay.org/wiki/Guide_to_RSF_file_format&quot;&gt;Madagascar RSF file format&lt;/a&gt;) 입출력 모듈을 &lt;a href=&quot;https://github.com/pkgpl/rsfio&quot;&gt;github&lt;/a&gt;에 공개했습니다. 참고로 &lt;a href=&quot;http://www.ahay.org/wiki/Main_Page&quot;&gt;Madagascar&lt;/a&gt; 패키지에서도 포트란 API를 제공합니다. 위의 모듈은 Madagascar 없이도 RSF 파일을 사용할 수 있도록 만들었습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Fortran config parser</title><link>https://pkgpl.org/2017/02/27/fortran-config-parser/</link><guid isPermaLink="true">https://pkgpl.org/2017/02/27/fortran-config-parser/</guid><pubDate>Mon, 27 Feb 2017 07:43:43 GMT</pubDate><content:encoded>&lt;p&gt;포트란 언어에서 사용할 수 있는 configuration file parser 모듈을 &lt;a href=&quot;https://github.com/pkgpl/cfgio&quot;&gt;github&lt;/a&gt;에 공개했습니다.&lt;/p&gt;
&lt;p&gt;다음과 같은 configuration 파일에서 변수들을 읽어들일 수 있는 모듈입니다. 사용법은 &lt;a href=&quot;https://github.com/pkgpl/cfgio&quot;&gt;github&lt;/a&gt;에 올렸습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[DEFAULTS]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;../include&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;use_abs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Section 1]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;nmax&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;30&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# comment 1
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;vmin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1.0&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;freqs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5.0, 10.0, 30.0, 50.0&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;amps&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;0.0, 1.0, 1.0, 0.0&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;../text&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[Section 2]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;use_abs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;; comment 2
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;my&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$(Section 1:path)/file.txt&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>거꾸로 수업 4학기</title><link>https://pkgpl.org/2016/10/16/%ea%b1%b0%ea%be%b8%eb%a1%9c-%ec%88%98%ec%97%85-4%ed%95%99%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2016/10/16/%ea%b1%b0%ea%be%b8%eb%a1%9c-%ec%88%98%ec%97%85-4%ed%95%99%ea%b8%b0/</guid><pubDate>Sun, 16 Oct 2016 05:18:31 GMT</pubDate><content:encoded>&lt;h3 aria-level=&quot;2&quot; id=&quot;거꾸로-수업과의-만남&quot;&gt;거꾸로 수업과의 만남&lt;/h3&gt;
&lt;p&gt;2015년 2월 말, 개강을 한 주 앞두고 마음이 무거웠다. 강의에서 보게 될 일부 학생들의 멍한 눈빛과 조는 모습이 눈 앞에 아른거렸다. 그동안 조는 학생들보다는 열심히 듣는 학생들이 더 많았고 강의 평가도 나쁘지 않았지만 내 무미건조한 말투 때문에 잠과 사투를 벌일 학생들을 생각하니 마음이 아팠다. 그 때 하나님의 은혜로 ‘플립러닝’이란 단어가 생각났다. 그게 무엇인지는 몰랐다. 이전 학기에 대학교육개발원에서 플립러닝 교수법 강의가 있어서 가보고 싶었지만 강의 시간과 겹쳐서 못 갔었는데 그 때 생각이 난 것이다. 그래서 인터넷을 찾아보고 2014년 봄에 방송했던 KBS의 &lt;a href=&quot;http://www.kbs.co.kr/special/s_page/2016special/edufor21/index.html#season1&quot;&gt;21세기 교육혁명 미래교실을 찾아서&lt;/a&gt; 프로그램도 봤다. 거꾸로 교실 관련 책도 두 권 주문해서 읽으며 당장 모든 학부 강의에 거꾸로 수업을 도입하기로 했다.&lt;/p&gt;
&lt;h3 id=&quot;거꾸로-수업&quot;&gt;거꾸로 수업&lt;/h3&gt;
&lt;p&gt;기존의 수업은 학교에서 강의를 듣고 집에 가서 숙제를 하는 방식이었다. 강의는 보통 선생님이 앞에서 설명하고 학생들은 조용히 듣는 방식이다. 학생들이 질문을 할 수도 있지만 질문하는 학생은 많지 않다. 집에서 숙제를 할 때에는 강의 자료나 책 등을 참고하는데 이 때 선생님의 도움을 받기는 어렵다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%97%AD%EC%A7%84%ED%96%89_%EC%88%98%EC%97%85&quot;&gt;거꾸로 수업&lt;/a&gt;에서는 집에서 강의를 듣거나 읽는다. 수업 시간에는 숙제, 토의와 같은 활동을 하면서 수시로 친구들과 대화하고 선생님께 질문하여 도움을 받을 수 있다.&lt;/p&gt;
&lt;p&gt;‘서울대에서는 누가 A+를 받는가’라는 책에서 인용한 연구를 보면 학생은 강의를 들으며 머리를 별로 쓰지 않는다. 따라서 질문할 것도 별로 없다. 반면에 스스로 공부를 하거나 숙제를 할 때에는 머리를 많이 사용하게 되고 질문할 것도 많아진다. 거꾸로 수업에서는 학생들에게 질문이 생겼을 때 선생님이 옆에서 도와줄 수 있다.&lt;/p&gt;
&lt;h3 id=&quot;수업-준비&quot;&gt;수업 준비&lt;/h3&gt;
&lt;p&gt;거꾸로 수업을 위해서는 학생들이 집에서 예습을 해올 수 있도록 미리 동영상을 만들어 인터넷에 올려야 했다. 적당한 교재가 있다면 동영상이 필수는 아니지만 학생들이 빠르게 예습해올 수 있도록 매 시간 강의의 핵심 내용만 담아 짧게는 10분에서 길게는 30분 정도 길이의 동영상을 만들어 올렸다. 짧은 동영상이지만 제작에는 몇 시간씩 걸린다. 동영상도 중요하지만 더 중요한 것은 수업 시간을 어떻게 채울 것인가이다. 강의 없이 두 시간을 채워야 한다. 수업을 위해 학생들이 토의할 수 있는 질문들과 풀 문제들, 동영상에서 생략된 내용을 채워줄 토의를 준비해야 했는데, 수업 준비하느라 흰머리가 많이 늘어난 듯 하다. 그렇게 2015년 두 학기는 수업 준비와 과제 채점만 하다가 다 보냈다. 올해 1학기에는 작년에 만들었던 동영상을 그대로 사용할 수 있어서 비교적 수월했지만 2학기에는 강의 과목 변경으로 인해 또 두 과목의 동영상을 새로 제작중이다.&lt;/p&gt;
&lt;p&gt;고맙게도 대부분의 학생들이 수업 전에 동영상을 보고 왔다. 학생들 중에는 동영상을 보며 몇 장씩 필기를 해오는 학생들도 있었다. 나중에 설문조사를 해보니 동영상이 길지 않아 아무 때나 스마트폰으로 간편히 볼 수 있고, 동영상을 미리 보지 않으면 수업 시간에 조원들에게 피해를 끼치게 되기 때문에 열심히 보고 왔다고 했다.&lt;/p&gt;
&lt;h3 id=&quot;수업-진행&quot;&gt;수업 진행&lt;/h3&gt;
&lt;p&gt;수업 진행 방식은 강의에 따라 약간씩 달라지지만 크게 내가 제시하는 질문에 대한 학생들의 조별 토의와 문제 풀이로 나뉜다. 조별 토의는 강의실 구조상 한 책상에 앉은 두세 명이 한 조가 되어 진행한다. 조는 보통 내가 지정해주지는 않고 학생들이 알아서 앉도록 한다. 제시하는 질문들은 동영상 내용을 이해했는지 기본 개념을 묻는 질문과 응용이 필요한 질문들이다. 이 때 학생들은 짝을 지어 대화, 토론, 논쟁하는 하브루타 방식으로 공부하게 된다. 학생들은 주요 개념들을 직접 설명하면서 더 잘 이해하고 기억하게 된다. 나는 학생들이 서로 설명하고 토의할 때 학생들 사이를 지나다니며 질문을 받고 대답해준다. 예전 강의식 수업에 비하면 학생들의 질문이 크게 늘었다. 조에 따라 활발히 토론하는 조도 있고 말이 별로 없는 조도 있지만, 현재 학생들의 토의를 평가에 넣지는 않고 있다. 대부분의 학생들이 토의에 열정적으로 참여한다. 토의 후에는 몇몇 학생들에게 토의 내용을 발표하도록 시켜서 바로 이해했는지 확인 후 다음 질문으로 넘어간다. 중요한 개념과 관련된 질문의 경우 발표하는 학생에게 소크라테스식 문답법으로 꼬리에 꼬리를 물고 질문을 던지고 설명해주기도 한다. 학생들 한 명 한 명 이름을 불러 질문하다 보니 내 수업을 처음 듣는 학생들 이름도 금방 기억할 수 있어서 좋다. 평소에 학생들이 토론하는 모습을 관찰하게 되니 학생들이 추천서를 써달라고 왔을 때 쓸 말이 있어서 좋았다.&lt;/p&gt;
&lt;p&gt;문제 풀이는 조별 또는 개인 과제로 제출하도록 해서 평가에 반영한다. 개인 과제 제출시에도 베끼지는 말되, 옆 친구들과 적극적으로 토의하며 풀도록 한다. 과제는 되도록이면 수업 시간이 끝나기 전에 마쳐서 제출하도록 하지만 수업 시간중에 다 못해서 나중에 제출하더라도 감점은 없다. 학과에 컴퓨터실이 있어서 과목에 따라 컴퓨터실에서 수업을 진행하며 컴퓨터로 풀어야 하는 과제들을 내주기도 한다.&lt;/p&gt;
&lt;p&gt;거꾸로 수업을 하게 되면서 학생들은 서로 말을 많이 하게 되었다. 그에 따라 조는 학생이 없어졌다. 드물게 몇 주에 한 번 조는 학생을 발견하는 경우도 있지만 예전에 거의 매시간 몇 명씩 봤던 것에 비하면 없는 것이나 마찬가지다. 그래서 수업 시간도 이전에 학생들이 많이 졸던 9시, 1시로 잡고 있다. 조별 토의를 통해 편입학한 학생들이 기존 학생들과 쉽게 친해지는 장점도 있었다.&lt;/p&gt;
&lt;p&gt;‘어떻게 공부할 것인가’라는 책의 ‘인출 연습’ 개념을 도입하여 토의 내용에 이전 수업 내용과 관련된 질문을 넣기도 한다. 퀴즈와 시험 범위는 처음부터 누적이다. 과목에 따라 학기중 두 세번 정도 학생들이 마인드맵을 이용해 배운 내용을 정리하고 직접 시험 문제를 출제해보도록 해준다. 학생들이 작성해서 제출한 내용은 스캔해서 모든 학생들에게 공개하며 좋은 문제가 있으면 중간 또는 기말 시험에 그대로 출제하기도 한다.&lt;/p&gt;
&lt;h3 id=&quot;수업-결과&quot;&gt;수업 결과&lt;/h3&gt;
&lt;p&gt;앞에 거꾸로 수업으로 얻게된 장점들을 몇 가지 적었는데, 가장 큰 단점은 수업 준비에 많은 시간과 노력이 필요하다는 점이다. ‘조벽 교수의 명강의 노하우&amp;amp;노와이’에서 준비에 시간이 많이 걸리는 교수법은 좋지 않다고 했다. 새로 동영상을 제작하는데는 시간이 오래 걸리지만 앞으로 동일한 수업을 반복하게 되면 수업 준비 시간이 짧아지게 될 것이다.&lt;/p&gt;
&lt;p&gt;현재 네 학기째 학부 수업을 거꾸로 수업으로 진행중이다(대학원 수업은 강의식 수업과 거꾸로 수업의 활동이 혼합된 형태). 강의 경력이 짧아서 학생들의 학업 성취도가 향상되었는지는 알 수 없다. 하지만 학생들의 강의 만족도는 높아졌다. 수업을 열심히 들었던 한 학생은 대학교육개발원의 &lt;a href=&quot;http://ctl.pknu.ac.kr/ctl/ur/material_view_form.acl?CMN_SEQ_NO=1222&amp;amp;SCH_VALUE=&amp;amp;display=10&amp;amp;start=1&quot;&gt;명강의 에세이 공모전&lt;/a&gt;에 내 강의에 관한 글을 써서 상을 받았다. 고맙게도 학생들이 작년 두 학기 강의 평가를 잘 해줘서 단과대학 우수강의교수상을 받았다. 앞으로도 개선해야 할 점들이 많지만 이전의 강의식 수업으로 돌아갈 수는 없을 듯 하다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item><item><title>속도 프로파일과 탄성파 트레이스 추출하여 그리기</title><link>https://pkgpl.org/2016/10/15/%ec%86%8d%eb%8f%84-%ed%94%84%eb%a1%9c%ed%8c%8c%ec%9d%bc%ea%b3%bc-%ed%83%84%ec%84%b1%ed%8c%8c-%ed%8a%b8%eb%a0%88%ec%9d%b4%ec%8a%a4-%ec%b6%94%ec%b6%9c%ed%95%98%ec%97%ac-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2016/10/15/%ec%86%8d%eb%8f%84-%ed%94%84%eb%a1%9c%ed%8c%8c%ec%9d%bc%ea%b3%bc-%ed%83%84%ec%84%b1%ed%8c%8c-%ed%8a%b8%eb%a0%88%ec%9d%b4%ec%8a%a4-%ec%b6%94%ec%b6%9c%ed%95%98%ec%97%ac-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</guid><pubDate>Sat, 15 Oct 2016 05:36:17 GMT</pubDate><content:encoded>&lt;p&gt;속도모델에서 프로파일을 추출하여 깊이에 따라 속도 그림을 그려보겠습니다. 이진 형식의 속도파일에서 텍스트 파일로 프로파일을 추출한 후 그리는 방법과 이진 속도파일을 직접 읽어서 그리는 방법을 살펴보겠습니다. 참고로, 탄성파 공통송신원모음 등에서 트레이스를 추출하여 그리는 과정 또한 동일합니다.&lt;/p&gt;
&lt;h3 aria-level=&quot;2&quot; id=&quot;텍스트-파일로-추출하여-그리기&quot;&gt;텍스트 파일로 추출하여 그리기&lt;/h3&gt;
&lt;p&gt;바이너리 파일에서 프로파일 또는 트레이스를 추출하기 위해 &lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt; 라이브러리의 &lt;code&gt;gplTracePick&lt;/code&gt; 프로그램을 사용하겠습니다. 이차원 단면(속도모델, 공통송신원모음 등)에서 세로 방향 트레이스를 추출할 때 사용하는 프로그램입니다. (가로방향 트레이스는 &lt;code&gt;gplHTracePick&lt;/code&gt; 프로그램을 이용하면 됩니다.) 이 프로그램을 그냥 실행하면 아래와 같은 도움말이 나옵니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


%%sh # 이 글을 쓰고 있는 jupyter notebook에서 shell 명령을 실행하기 위한 magic command입니다.
gplTracePick # 실제 터미널상에서 실행하는 명령어

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt; Gpl trace picker
 Required parameters:
     [i] n1=            : # of grids in fast dimension
     [s] fin=           : input binary file
     [s] fout=          : output binary file
     [i] pick=          : (=first), first pick (1~n2)
 Optional parameters:
     [i] last=first     : last pick (pick~n2)
     [i] step=1         : pick step
     [f] d1=1.0         : grid size
     [i] n2=calc        : # of grids in slow dimension
     [s] type=f         : data type [ifdcz]
     [s] otype=a        : output type [ab] (ascii/binary)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;위에서 &lt;code&gt;n1&lt;/code&gt;, &lt;code&gt;fin&lt;/code&gt;, &lt;code&gt;fout&lt;/code&gt;, &lt;code&gt;pick&lt;/code&gt;은 프로그램 실행시 필수적으로 넣어줘야 하는 값입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;n1&lt;/code&gt;은 세로 방향(fast dimension) 격자수&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fin&lt;/code&gt;은 입력 파일 이름&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fout&lt;/code&gt;은 출력 파일 이름&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pick&lt;/code&gt;은 추출하고자하는 가로 방향(slow dimension) 격자 번호입니다. 격자 번호는 1번부터 시작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Marmousi 속도모델(nx=576, ny=188, h=0.016 km)에 대해 1.6 km 지점(격자번호 101)에서 시작하여 3.2 km 간격(200개 격자 간격)으로 3개의 속도 프로파일을 추출한다면 아래와 같이 실행할 수 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


%%sh
gplTracePick n1=188 d1=0.016 fin=marm16km.bin fout=vel_profile.txt pick=101 step=200 last=501

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt; n2=         576


     n1=188
     d1=0.016
     fin=marm16km.bin
     fout=vel_profile.txt
     pick=101
     step=200
     last=501
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;그 때 결과물은 아래와 같습니다. 첫 번째 열은 깊이 정보, 두 번째부터 네 번째 열까지는 추출한 속도 프로파일 정보입니다(1.6 km, 4.8 km, 8.0 km).&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;

%%sh
head vel_profile.txt
&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;   0.00000000       1.50000012       1.50000012       1.50000012    
   1.60000008E-02   1.50000012       1.50000012       1.50000012    
   3.20000015E-02   1.50000012       1.65800011       1.59800005    
   4.80000004E-02   1.66200006       1.66200006       1.60200012    
   6.40000030E-02   1.66600013       1.66600013       1.60600019    
   8.00000057E-02   1.67000008       1.73999715       1.69000006    
   9.60000008E-02   1.67400002       1.74399781       1.69400012    
  0.112000003       1.67800009       1.61800003       1.69800007    
  0.128000006       1.78200006       1.70200002       1.63200009    
  0.144000009       1.78600013       1.70600009       1.63600004    
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;텍스트 파일로 추출한 결과는 &lt;a href=&quot;https://pkgpl.org/2014/07/27/gnu-quick-plot-gnuqp/&quot;&gt;gnuplot&lt;/a&gt;과 같은 프로그램을 이용해 빠르게 확인해볼 수 있습니다. 여기서는 파이썬의 Matplotlib을 이용하여 위의 속도 프로파일을 그려보겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

trc=np.loadtxt(&quot;vel_profile.txt&quot;)

h=0.016
fs=&apos;large&apos;

plt.figure(figsize=[15,5])
for i,ix in enumerate([100,300,500]):
    plt.plot(trc[:,0],trc[:,i+1],label=&quot;{0} km&quot;.format(ix*h))

plt.legend(loc=&quot;upper left&quot;,fontsize=fs)
plt.xlabel(&quot;Depth (km)&quot;,fontsize=fs)
plt.ylabel(&quot;Velocity (km/s)&quot;,fontsize=fs)

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&amp;lt;matplotlib.text.Text at 0x10cc66c88&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-16-plot_velocity_profiles_and_seismic_traces_10_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;이진-파일을-직접-읽어서-그리기&quot;&gt;이진 파일을 직접 읽어서 그리기&lt;/h3&gt;
&lt;p&gt;이번에는 파이썬에서 이진 형식의 속도모델 파일을 직접 읽어서 그려보겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


nx=576
ny=188
vel=np.fromfile(&quot;marm16km.bin&quot;,dtype=np.float32)
vel.shape=(nx,ny)

h=0.016
fs=&apos;large&apos;
depth=np.arange(ny)*h

plt.figure(figsize=[15,5])
for ix in [100,300,500]:
    plt.plot(depth,vel[ix,:],label=&quot;{0} km&quot;.format(ix*h))

plt.legend(loc=&quot;upper left&quot;,fontsize=fs)
plt.xlabel(&quot;Depth (km)&quot;,fontsize=fs)
plt.ylabel(&quot;Velocity (km/s)&quot;,fontsize=fs)

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;matplotlib.text.Text at 0x10d13dd30&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-16-plot_velocity_profiles_and_seismic_traces_13_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;p&gt;참고로, 파이썬은 배열 인덱스가 0번부터 시작하기 때문에 가로방향 100, 300, 500번 속도 프로파일을 가져다가 그렸습니다(&lt;code&gt;gplTracePick&lt;/code&gt;을 이용하는 앞의 예제에서는 101, 301, 501번 격자 위치에서 추출했죠).&lt;/p&gt;
&lt;h3 id=&quot;탄성파-트레이스-그리기&quot;&gt;탄성파 트레이스 그리기&lt;/h3&gt;
&lt;p&gt;공통송신원모음에서 탄성파 트레이스를 추출하여 그리는 과정은 속도모델에서 프로파일을 추출하여 그리는 경우와 동일합니다. 아래는 샘플 개수가 723개, 샘플링 간격 4 ms, 트레이스가 96개인 공통송신원모음 파일(marm3000.bin)에서 31번째와 61번째 트레이스를 그리는 예제입니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


ntr=96
ns=723
dt=0.004
trc=np.fromfile(&quot;marm3000.bin&quot;,dtype=np.float32)
trc.shape=(ntr,ns)

fs=&apos;large&apos;
time=np.arange(ns)*dt

plt.figure(figsize=[15,5])
for itr in [30,60]:
    plt.plot(time,trc[itr,:],label=&quot;trace {0}&quot;.format(itr+1))
plt.legend(loc=&quot;upper left&quot;,fontsize=fs)
plt.xlabel(&quot;Time (s)&quot;,fontsize=fs)
plt.ylabel(&quot;Amplitude&quot;,fontsize=fs)
plt.xlim([0,ns*dt])

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;(0, 2.892)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-16-plot_velocity_profiles_and_seismic_traces_16_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>속도모델 그림 그리기</title><link>https://pkgpl.org/2016/10/13/%ec%86%8d%eb%8f%84%eb%aa%a8%eb%8d%b8-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2016/10/13/%ec%86%8d%eb%8f%84%eb%aa%a8%eb%8d%b8-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</guid><pubDate>Thu, 13 Oct 2016 11:28:18 GMT</pubDate><content:encoded>&lt;p&gt;두 가지 방법으로 2차원 속도모델을 그려보겠습니다. 첫 번째 방법은 SU의 &lt;code&gt;psimage&lt;/code&gt;를 이용하는 방법, 두 번째는 python의 matplotlib을 이용하는 방법입니다.&lt;/p&gt;
&lt;h2 id=&quot;psimage로-그리기&quot;&gt;psimage로 그리기&lt;/h2&gt;
&lt;p&gt;첫 번째 방법부터 보겠습니다. &lt;code&gt;psimage&lt;/code&gt;는 쉘에서 사용하는 명령어이지만, &lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt; 라이브러리의 &lt;a href=&quot;https://pkgpl.org/2016/10/09/탄성파-자료처리-그림-그리기/&quot;&gt;psplot&lt;/a&gt; 모듈을 이용하면 python 명령을 통해 간편하게 속도모델을 그릴 수 있습니다. Marmousi 속도모델을 그림으로 그려보겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


from gpl.psplot import plot

nx=576
ny=188
h=0.016
fin=&quot;marm16km.drt&quot;

opt = &quot;n1={0} d1={1} d2={1} d1num=1 lbeg=1.5 lend=5.5&quot;.format(ny,h,h)
plot.velocity(&quot;marm16km.png&quot;, fin, opt)

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;psimage label1=&quot;Depth (km)&quot; legend=1 d2s=0.5 lheight=1.0 lstyle=&quot;vertright&quot; label2=&quot;Distance (km)&quot; height=1.0 labelsize=8 lwidth=0.1 d1s=0.5 width=2.65  n1=188 d1=0.016 d2=0.016 d1num=1 lbeg=1.5 lend=5.5 &amp;lt; marm16km.drt &amp;gt; marm16km.eps

// adding velocity unit (km/s)

// fixing bounding box

// converting .eps to .png ..
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-13-plot_seismic_velocity-marm16km.png&quot; alt=&quot;vel&quot;&gt;(marm16km.png)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;velocity_color&lt;/code&gt;를 이용해 컬러로 그릴 수도 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


plot.velocity_color(&quot;marm16km_color.png&quot;,fin,opt)

&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;psimage label1=&quot;Depth (km)&quot; ghls=&quot;0.33,0.5,1&quot; bps=24 bhls=&quot;0.67,0.5,1&quot; d1s=0.5 lwidth=0.1 whls=&quot;0,0.5,1&quot; legend=1 d2s=0.5 lheight=1.0 lstyle=&quot;vertright&quot; label2=&quot;Distance (km)&quot; height=1.0 labelsize=8 width=2.65  n1=188 d1=0.016 d2=0.016 d1num=1 lbeg=1.5 lend=5.5 &amp;lt; marm16km.drt &amp;gt; marm16km_color.eps

// adding velocity unit (km/s)

// fixing bounding box

// converting .eps to .png ..
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-13-plot_seismic_velocity-marm16km_color.png&quot; alt=&quot;vel&quot;&gt;(marm16km_color.png)&lt;/p&gt;
&lt;h2 id=&quot;matplotlib으로-그리기&quot;&gt;Matplotlib으로 그리기&lt;/h2&gt;
&lt;p&gt;두 번째 방법은 python의 matplotlib 라이브러리를 이용하는 방법입니다. 이를 위해서는 코드에서 numpy를 이용해 속도모델을 읽어들인 후에 matplotlib으로 그립니다. 속도모델을 그리는 부분은 함수로 작성하였는데, 필요에 따라 수정해서 사용하면 되겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

def plot_vel(vel, h, figsize=[15,4], unit=&apos;km/s&apos;, xticks=None, yticks=None, cticks=None, cmap=&apos;gray_r&apos;, fontsize=20):
    xmax=(vel.shape[0]-1)*h
    ymax=(vel.shape[1]-1)*h

    plt.figure(figsize=figsize)
    plt.imshow(vel.transpose(),extent=(0,xmax,ymax,0),cmap=cmap)

    # x,y labels
    plt.xlabel(&apos;Distance (km)&apos;,fontsize=fontsize)
    plt.ylabel(&apos;Depth (km)&apos;,fontsize=fontsize)

    # x,y ticks, tick labels
    plt.tick_params(labelsize=fontsize)
    plt.gca().xaxis.tick_top()
    plt.gca().xaxis.set_label_position(&quot;top&quot;)
    xticks and plt.xticks(xticks)
    yticks and plt.yticks(yticks)

    # colorbar
    cb=plt.colorbar(shrink=1.0,pad=0.01,aspect=10,ticks=cticks)
    plt.clim([vel.min(),vel.max()])
    cb.set_label(unit,fontsize=fontsize)
    ct=plt.getp(cb.ax,&apos;ymajorticklabels&apos;)
    plt.setp(ct,fontsize=fontsize)

# 속도모델 읽기
vel=np.fromfile(fin,dtype=np.float32)
vel.shape=(nx,ny)

yticks=[0,1,2] # y축 ticks
cticks=[2,3,4,5] # colorbar ticks
plot_vel(vel,h,yticks=yticks,cticks=cticks)

&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-13-plot_seismic_velocity_11_0.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;

# 컬러로 그리고(cmap=&apos;jet&apos;) 파일로 저장하기
plot_vel(vel,h,xticks=[0,3,6,9],cmap=&apos;jet&apos;)
plt.savefig(&quot;vel.png&quot;,bbox_inches=&apos;tight&apos;)
&lt;/pre&gt;
&lt;figure class=&quot;lineno-container&quot;&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-13-plot_seismic_velocity_12_0.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;p&gt;결과물로 저장한 &lt;code&gt;vel.png&lt;/code&gt; 파일은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images/2016-10-13-plot_seismic_velocity-vel.png&quot; alt=&quot;vel&quot;&gt;(vel.png)&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Matplotlib을 이용한 탄성파 자료처리 그림 그리기</title><link>https://pkgpl.org/2016/10/10/matplotlib%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%83%84%ec%84%b1%ed%8c%8c-%ec%9e%90%eb%a3%8c%ec%b2%98%eb%a6%ac-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2016/10/10/matplotlib%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-%ed%83%84%ec%84%b1%ed%8c%8c-%ec%9e%90%eb%a3%8c%ec%b2%98%eb%a6%ac-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</guid><pubDate>Mon, 10 Oct 2016 09:35:05 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://pkgpl.org/2016/10/09/탄성파-자료처리-그림-그리기/&quot;&gt;이전 글&lt;/a&gt;에서는 SU 명령어들을 이용해 탄성파 자료처리 결과 확인용 그림을 그리는 방법을 살펴보았습니다. 이번에는 Python의 &lt;a href=&quot;http://matplotlib.org/&quot;&gt;Matplotlib&lt;/a&gt;을 이용하여 그린 그림 예제들을 보겠습니다. 그림은 &lt;a href=&quot;https://pkgpl.org/2015/09/15/ipython-processing/&quot;&gt;IPython Processing&lt;/a&gt; 모듈을 이용해 그렸으며, 그릴 때 사용한 코드는 &lt;a href=&quot;https://github.com/pkgpl/IPythonProcessing/blob/master/pkprocess/pkplot.py&quot;&gt;github&lt;/a&gt;에서 볼 수 있습니다.&lt;/p&gt;
&lt;h3 aria-level=&quot;2&quot; id=&quot;속도모델-구조보정-영상&quot;&gt;속도모델, 구조보정 영상&lt;/h3&gt;
&lt;p&gt;우선, 다음과 같이 이진파일로부터 2차원 속도모델과 구조보정 결과를 그릴 수 있습니다. 기본적으로 속도모델은 컬러, 구조보정 영상은 흑백으로 그리도록 했지만, 필요에 따라 코드를 수정해서 색상을 바꿀 수 있습니다. 색상을 바꾸고 싶을 경우 &lt;a href=&quot;http://matplotlib.org/api/pyplot_api.html?highlight=imshow#matplotlib.pyplot.imshow&quot;&gt;&lt;code&gt;imshow&lt;/code&gt;&lt;/a&gt; 함수의 &lt;a href=&quot;http://scipy-cookbook.readthedocs.io/items/Matplotlib_Show_colormaps.html&quot;&gt;&lt;code&gt;cmap&lt;/code&gt;&lt;/a&gt; 인자를 이용하면 됩니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;

%matplotlib inline
from pkprocess import *
import numpy as np

vel = np.fromfile(&quot;marm16km.drt&quot;, dtype=np.float32)

nx = 576
nz = 188
h = 0.016
vel.shape = (nx, nz)

plot_vel(vel, h)
&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_4_0.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


plot_mig(vel,h)

&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_5_0.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;공통송신원-모음-스펙트럼&quot;&gt;공통송신원 모음, 스펙트럼&lt;/h3&gt;
&lt;p&gt;그리고 SU 파일로부터 공통송신원 모음이나 F-X, F-K 스펙트럼을 그릴 수 있습니다. 공통송신원 모음은 Wiggle trace 또는 이미지로 그릴 수 있고, 이미지 색상은 &lt;a href=&quot;http://scipy-cookbook.readthedocs.io/items/Matplotlib_Show_colormaps.html&quot;&gt;&lt;code&gt;cmap&lt;/code&gt;&lt;/a&gt;으로 조절 가능합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


su = read_su(&quot;marm3000.su&quot;)

plot_wiggle(su, perc=97)

&lt;/pre&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;min=-616.05078125 max=613.4453125
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_8_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


plot_image(su, perc=97)

&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;min=-616.05078125 max=613.4453125&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_9_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


plot_image(su, perc=97, cmap=&apos;bwr&apos;)

&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;min=-616.05078125 max=613.4453125&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_10_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


specfx(su)

&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dt=0.004, fmax=125.0&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_11_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


specfk(su)

&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dt=0.004, fmax=125.0&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dx=0.025, kmax=20.0&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-11-plot_seismic_processing_matplotlib-output_12_1.png&quot; alt=&quot;png&quot;&gt;&lt;/p&gt;
&lt;p&gt;위의 그림들 모두 &lt;a href=&quot;http://matplotlib.org/&quot;&gt;Matplotlib&lt;/a&gt;으로 그렸으므로, 수정이 필요할 경우 &lt;a href=&quot;http://matplotlib.org/&quot;&gt;Matplotlib 문서&lt;/a&gt;를 참고하여 수정해서 사용하시면 되겠습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>탄성파 자료처리 그림 그리기</title><link>https://pkgpl.org/2016/10/09/%ed%83%84%ec%84%b1%ed%8c%8c-%ec%9e%90%eb%a3%8c%ec%b2%98%eb%a6%ac-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</link><guid isPermaLink="true">https://pkgpl.org/2016/10/09/%ed%83%84%ec%84%b1%ed%8c%8c-%ec%9e%90%eb%a3%8c%ec%b2%98%eb%a6%ac-%ea%b7%b8%eb%a6%bc-%ea%b7%b8%eb%a6%ac%ea%b8%b0/</guid><pubDate>Sun, 09 Oct 2016 04:32:51 GMT</pubDate><content:encoded>&lt;p&gt;탄성파 자료처리 결과 그림을 쉽게 그리는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;p&gt;탄성파 자료처리를 하다 보면 결과물을 그림으로 확인해야 하는 경우가 많습니다. 특별히 노력해서 그려야 하는 그림도 있지만 속도모델, 공통송신원모음 등 대부분의 그림은 거의 비슷한 명령으로 그릴 수 있습니다. 개인적으로 논문이나 발표자료에 넣을 그림을 그릴 때 &lt;a href=&quot;http://www.cwp.mines.edu/cwpcodes/&quot;&gt;Seismic Un*x&lt;/a&gt;(SU)를 많이 이용하는데, 몇 가지 자주 그리는 그림들을 쉽게 그릴 수 있도록 파이썬 모듈을 만들었습니다. 모듈은 &lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt;라이브러리에 포함되어 있습니다. 최근 python 3 용으로 수정하였습니다.&lt;/p&gt;
&lt;p&gt;먼저 속도모델을 예로 들어보겠습니다. 그림을 그리기 위한 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


from gpl.psplot import plot

vel=&quot;marm16km.drt&quot;
opt=&quot;n1=188 d1=0.016 d2=0.016 d1num=1 d2num=2&quot;

plot.velocity_color(&quot;vel_color.png&quot;,vel,opt)

&lt;/pre&gt;
&lt;p&gt;위 코드는 &lt;code&gt;gpl.psplot&lt;/code&gt; 모듈에서 &lt;code&gt;plot&lt;/code&gt;을 가져오고, &lt;code&gt;marm16km.drt&lt;/code&gt; 파일로부터 &lt;code&gt;opt&lt;/code&gt; 문자열의 옵션을 이용하여 &lt;code&gt;vel_color.png&lt;/code&gt; 파일을 생성하는데, 컬러로 된 속도모델 그림으로 만들라는 코드입니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;velocity_color&lt;/code&gt;는 그림 종류를 지정하는 명령인데, 현재 다음과 같은 명령들을 지원합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;velocity(target, source, option, unit=”km/s”)&lt;/li&gt;
&lt;li&gt;velocity_color(target, source, option, unit=”km/s”)&lt;/li&gt;
&lt;li&gt;gradient(target, source, option)&lt;/li&gt;
&lt;li&gt;gradient_color(target, source, option)&lt;/li&gt;
&lt;li&gt;migration(target, source, option)&lt;/li&gt;
&lt;li&gt;contour(target, source, option)&lt;/li&gt;
&lt;li&gt;seismogram(target, source, option)&lt;/li&gt;
&lt;li&gt;spectrum(target, source, option)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위의 명령들은 SU를 이용해 해당 그림을 그리라는 명령으로, &lt;code&gt;contour&lt;/code&gt;만 &lt;code&gt;pscontour&lt;/code&gt;를 사용하고 나머지는 &lt;code&gt;psimage&lt;/code&gt;를 사용합니다. 입력 파일이 SU 파일이라면 &lt;code&gt;supscontour&lt;/code&gt; 또는 &lt;code&gt;supsimage&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;p&gt;인자들 중 &lt;code&gt;target&lt;/code&gt;은 출력 파일, &lt;code&gt;source&lt;/code&gt;는 입력 파일, &lt;code&gt;option&lt;/code&gt;은 그림 그릴 때 사용할 옵션입니다. 그림 종류에 따라 기본적으로 몇 가지 옵션이 들어가있는데, &lt;code&gt;n1, d1, d2&lt;/code&gt;와 같이 입력 파일에 따라 달라지는 옵션을 &lt;code&gt;option&lt;/code&gt;에 넣어주면 됩니다. 그리고 기본 옵션을 덮어쓰고 싶은 경우에도 &lt;code&gt;option&lt;/code&gt;에 추가해줍니다.&lt;/p&gt;
&lt;p&gt;속도모델의 단위는 기본적으로 &lt;code&gt;km/s&lt;/code&gt;로 지정해 놓았는데, 필요에 따라 바꿔서 사용할 수 있습니다. &lt;code&gt;g/cc&lt;/code&gt;로 바꾸면 밀도 모델을 그릴 수도 있겠죠. &lt;code&gt;migration&lt;/code&gt;은 snapshot을 그릴 때 사용할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;SU 명령은 기본적으로 eps 파일을 생성합니다. &lt;code&gt;target&lt;/code&gt;을 eps 외의 다른 파일(png, tiff, jpg 등)로 지정하면&lt;a href=&quot;http://www.imagemagick.org/&quot;&gt;ImageMagick&lt;/a&gt;의 &lt;code&gt;convert&lt;/code&gt; 명령을 이용해 eps 파일을 변환합니다.&lt;/p&gt;
&lt;p&gt;따라서 본 모듈의 모든 기능을 이용하려면 &lt;a href=&quot;https://www.python.org/&quot;&gt;Python&lt;/a&gt;, &lt;a href=&quot;http://www.cwp.mines.edu/cwpcodes/&quot;&gt;SU&lt;/a&gt;, &lt;a href=&quot;http://www.imagemagick.org/&quot;&gt;ImageMagick&lt;/a&gt;이 필요합니다.&lt;/p&gt;
&lt;p&gt;터미널에서 위의 코드를 실행했을 때 나오는 메시지는 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;
&lt;div class=&quot;highlight&quot;&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;highlight&quot;&gt;&lt;code&gt;psimage height=1.0 width=2.65 d2s=0.5 lwidth=0.1 lstyle=&quot;vertright&quot; lheight=1.0
label2=&quot;Distance (km)&quot; ghls=&quot;0.33,0.5,1&quot; bps=24 whls=&quot;0,0.5,1&quot; legend=1
bhls=&quot;0.67,0.5,1&quot; labelsize=8 label1=&quot;Depth (km)&quot; d1s=0.5  n1=188 d1=0.016
d2=0.016 d1num=1 d2num=2 &amp;lt; marm16km.drt &amp;gt; vel_color.eps

psimage: bclip=5.5 wclip=1.5

// adding velocity unit (km/s)

// fixing bounding box
Original:  %%BoundingBox: 66 41 353 207
Updated:   %%BoundingBox: 85 104 324 202

// converting .eps to .png ..

&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;내용을 살펴보면 다음 순서로 실행됩니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SU의 &lt;code&gt;psimage&lt;/code&gt; 명령을 이용해 속도모델 eps 파일을 생성합니다. 옵션은 컬러 속도모델에 맞춰서 들어갑니다. 참고로, 그림 크기는 Geophysics 논문 기준에 맞춘 것입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;km/s&lt;/code&gt;라는 단위를 넣어줍니다(&lt;a href=&quot;https://pkgpl.org/2015/01/05/postscript-language-editing/&quot;&gt;postscript 수정&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;그림 여백을 조절합니다(&lt;a href=&quot;https://pkgpl.org/2015/01/05/postscript-bounding-box/&quot;&gt;bounding box 수정&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;eps 파일을 png 파일로 수정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;그리고, 결과물인 &lt;code&gt;vel_color.png&lt;/code&gt;은 다음과 같습니다. &lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-vel_color.png&quot; alt=&quot;output&quot;&gt;(vel_color.png)&lt;/p&gt;
&lt;p&gt;아래 코드와 다른 그림 예시를 올리니 필요한 그림에 해당하는 명령을 사용하시면 되겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot; class=&quot;brush: python; title: ; notranslate&quot; title=&quot;&quot;&gt;


from gpl.psplot import plot

vel=&quot;marm16km.drt&quot;
opt=&quot;n1=188 d1=0.016 d2=0.016 d1num=1 d2num=2&quot;

plot.velocity(&quot;vel.png&quot;,vel,opt+&quot;lbeg=1.5 lend=5.5 lfnum=1.5&quot;)
plot.velocity_color(&quot;vel_color.png&quot;,vel,opt)
plot.velocity_color(&quot;density_color.png&quot;,vel,opt,unit=&quot;g/cc&quot;)
plot.gradient(&quot;grad.png&quot;,vel,opt)
plot.gradient_color(&quot;grad_color.png&quot;,vel,opt)
plot.migration(&quot;mig.png&quot;,vel,opt)
plot.contour(&quot;contour.png&quot;,vel,opt)

seismo=&quot;marm3000.su&quot;
opt2=&quot;f2=0 d2=0.025 d1s=0.5 d2s=0.5&quot;
plot.seismogram(&quot;seismo.png&quot;,seismo,opt2)

spec=&quot;marm3000fx.su&quot;
plot.spectrum(&quot;spec.png&quot;,spec,opt2)

&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-vel.png&quot; alt=&quot;output&quot;&gt;(vel.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-vel_color.png&quot; alt=&quot;output&quot;&gt;(vel_color.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-density_color.png&quot; alt=&quot;output&quot;&gt;(density_color.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-grad.png&quot; alt=&quot;output&quot;&gt;(grad.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-grad_color.png&quot; alt=&quot;output&quot;&gt;(grad_color.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-mig.png&quot; alt=&quot;output&quot;&gt;(mig.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-contour.png&quot; alt=&quot;output&quot;&gt;(contour.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i0.wp.com/pkgpl.github.io/images//2016-10-10-plot_seismic_processing_results-seismo.png&quot; alt=&quot;output&quot;&gt;(seismo.png)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pkgpl.org/media/seismic-processing-spec.png&quot; alt=&quot;output&quot;&gt;(spec.png)&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Muting scripts</title><link>https://pkgpl.org/2015/09/15/muting-scripts/</link><guid isPermaLink="true">https://pkgpl.org/2015/09/15/muting-scripts/</guid><pubDate>Tue, 15 Sep 2015 04:32:56 GMT</pubDate><content:encoded>&lt;p&gt;SU 파일 뮤팅 스크립트를 공개하였습니다. SU 파일을 손으로 뮤팅할 때 모든 shot gather를 뮤팅하는 것이 아니라 건너 뛰면서 뮤팅한 후 건너뛴 부분은 interpolation하도록 만들었습니다. 해상 스트리머 탐사 자료에 사용할 수 있습니다. &lt;a href=&quot;https://github.com/pkgpl/MutingScripts&quot;&gt;Github&lt;/a&gt;에서 받을 수 있습니다.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고 문헌&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Kim, A., D. Ryu, W. Ha, and C. Shin, 2015, An efficient first arrival picking procedure for marine streamer data, Geosystem Engineering,  18(5), 251-258.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>IPython Processing</title><link>https://pkgpl.org/2015/09/15/ipython-processing/</link><guid isPermaLink="true">https://pkgpl.org/2015/09/15/ipython-processing/</guid><pubDate>Tue, 15 Sep 2015 04:27:12 GMT</pubDate><content:encoded>&lt;p&gt;학부 탄성파 자료 처리 수업에서 사용하기 위한 파이썬 패키지입니다. 기존의 공개된 Matlab 패키지를 파이썬으로 변환하였습니다. 간단한 2차원 자료 처리(time processing)가 가능합니다.&lt;/p&gt;
&lt;p&gt;육상, 해상 자료 처리 예제와 함께 공개하였고, &lt;a href=&quot;https://github.com/pkgpl/IPythonProcessing&quot;&gt;Github&lt;/a&gt;에서 받으실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고 문헌&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;하완수, 2015, 대화식 탄성파 자료 처리 수업을 위한 파이썬 패키지 개발, 한국자원공학회지, 52(4), 414-421.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>SU 파일 입출력을 위한 포트란 라이브러리</title><link>https://pkgpl.org/2015/03/12/su-%ed%8c%8c%ec%9d%bc-%ec%9e%85%ec%b6%9c%eb%a0%a5%ec%9d%84-%ec%9c%84%ed%95%9c-%ed%8f%ac%ed%8a%b8%eb%9e%80-%eb%9d%bc%ec%9d%b4%eb%b8%8c%eb%9f%ac%eb%a6%ac/</link><guid isPermaLink="true">https://pkgpl.org/2015/03/12/su-%ed%8c%8c%ec%9d%bc-%ec%9e%85%ec%b6%9c%eb%a0%a5%ec%9d%84-%ec%9c%84%ed%95%9c-%ed%8f%ac%ed%8a%b8%eb%9e%80-%eb%9d%bc%ec%9d%b4%eb%b8%8c%eb%9f%ac%eb%a6%ac/</guid><pubDate>Thu, 12 Mar 2015 06:18:08 GMT</pubDate><content:encoded>&lt;p&gt;포트란 사용자들이 Seismic Un*x의 SU 파일을 읽고, 수정하고, 쓸 수 있도록 하는 입출력 라이브러리를 작성하여 공개하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/pkgpl/SUIO&quot;&gt;Github&lt;/a&gt;에서 받으실 수 있습니다.&lt;/p&gt;
&lt;p&gt;매뉴얼은 &lt;a href=&quot;http://suio.readthedocs.io&quot;&gt;ReadTheDocs&lt;/a&gt;를 참고하세요.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고문헌&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;하완수, 2015, SU 파일 입출력을 위한 포트란 라이브러리 개발, 한국자원공학회지, 52(1), 81-90.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Postscript language editing</title><link>https://pkgpl.org/2015/01/05/postscript-language-editing/</link><guid isPermaLink="true">https://pkgpl.org/2015/01/05/postscript-language-editing/</guid><pubDate>Mon, 05 Jan 2015 03:37:04 GMT</pubDate><content:encoded>&lt;p&gt;Postscript로 만들어진 .ps 또는 .eps 파일은 &lt;a title=&quot;Postscript bounding box&quot; href=&quot;https://pkgpl.org/2015/01/05/postscript-bounding-box/&quot;&gt;앞의 글&lt;/a&gt;에서 보셨던 것처럼, 일반적인 text 편집기로 편집할 수 있는 ascii 파일입니다. 파일의 내용은 출력물을 만들어내는 postscript 언어죠. 따라서 postscript 언어를 알면 eps 그림 파일도 마음대로 편집할 수 있습니다. Postscript language를 배우고 싶으신 분은 &lt;a href=&quot;http://www.adobe.com/products/postscript/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adobe site&lt;/a&gt;에 가셔서 매뉴얼을 받아보시면 됩니다. 여기서는 &lt;a title=&quot;Postscript bounding box&quot; href=&quot;https://pkgpl.org/2015/01/05/postscript-bounding-box/&quot;&gt;앞의 글&lt;/a&gt;에서 만들었던 파일에서 legend unit의 위치를 바꾸는 법만 살펴보도록 하겠습니다. 앞에서 보았던 그림은 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; class=&quot;alignnone size-full wp-image-1107&quot; src=&quot;https://pkgpl.org/media/eps_bbox_after.jpg&quot; alt=&quot;eps_bbox_after&quot; width=&quot;435&quot; height=&quot;176&quot;&gt;&lt;/p&gt;
&lt;p&gt;위 그림에서 오른쪽 끝에 있는 “m/s”를 legend(scale bar) 위로 옮겨봅시다. 결과는 다음과 같습니다.(옮긴 후 bounding box도 바꿔줬습니다.)&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; class=&quot;alignnone size-full wp-image-1106&quot; src=&quot;https://pkgpl.org/media/eps_unit.jpg&quot; alt=&quot;eps_unit&quot; width=&quot;419&quot; height=&quot;177&quot;&gt;&lt;/p&gt;
&lt;p&gt;위의 결과를 얻기 위해서는 .eps 파일을 열어서 ‘m/s’라는 문자열을 찾아 지워줍니다. 파일 끝에서 약간 앞에 두 개가 있을겁니다. 그런 후 아래의  코드를 .eps 파일 끝부분의 ‘showpage’ 명령 앞에 넣어줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;%%%%% changed the position of unit
GS
270 190 TR
NP
/Helvetica findfont 8 scalefont setfont
0 0 0 setrgbcolor
21.96 -6.462 M
(m/s) SW exch -0.5 mul
exch -0.5 mul RM (m/s) SH
S
GR
%%%%%&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;%%%%%는 comment이고, ‘m/s’라는 문자열의 위치는 ‘GS’ 아래에 있는 두 개의 숫자(x좌표, y좌표)로 조정합니다. 그림 크기에 따라 위치는 달라집니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Postscript bounding box</title><link>https://pkgpl.org/2015/01/05/postscript-bounding-box/</link><guid isPermaLink="true">https://pkgpl.org/2015/01/05/postscript-bounding-box/</guid><pubDate>Mon, 05 Jan 2015 03:28:24 GMT</pubDate><content:encoded>&lt;p&gt;SU(Seismic Un*x)에 있는 psimage로 Marmousi 속도모델을 그리면 다음과 같습니다.(그림 겉부분의 회색은 그림에 포함되어 있지 않은 부분으로, 경계를 표시하기 위해 넣었습니다.)&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; class=&quot;alignnone size-full wp-image-1108&quot; src=&quot;https://pkgpl.org/media/eps_bbox_before.jpg&quot; alt=&quot;eps_bbox_before&quot; width=&quot;487&quot; height=&quot;305&quot;&gt;&lt;/p&gt;
&lt;p&gt;여기서 사용한 명령은 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;psimage par=&apos;../marm8m.txt&apos; label1=&quot;Depth (km)&quot; label2=&quot;Offset (km)&quot; labelsize=8 height=1.0 width=2.4 legend=1 lstyle=vertright lwidth=0.1 lheight=1 units=&quot;m/s&quot; &amp;lt; ../marm8m.drt &amp;gt; marm.eps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 때, psimage는 그림 주위로 지나치게 넓은 공간을 만들어 줍니다. Bounding box 정보가 정확하지 않기 때문이죠. 이 상태로는 eps 파일을 다른 그림파일로 변환하여 paper에 넣거나 power point 발표자료에 넣기에 좋지 않습니다(물론 자르기 crop 기능을 이용할 수도 있기는 하죠).&lt;/p&gt;
&lt;p&gt;이 공간을 없애기 위해서는 아래 명령을 이용합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;strong&gt;&lt;code&gt;gs -sDEVICE=bbox -dNOPAUSE -dBATCH marm.eps&lt;/code&gt;&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;그럼 다음과 같은 결과를 보여줍니다.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;GPL Ghostscript 8.63 (2008-08-01)&lt;br&gt;
Copyright (C) 2008 Artifex Software, Inc.  All rights reserved.&lt;br&gt;
This software comes with NO WARRANTY: see the file PUBLIC for details.&lt;br&gt;
Loading NimbusSanL-Regu font from /usr/share/fonts/default/Type1/n019003l.pfb… 2656772 1085343 2641408 1357198 2 done.&lt;br&gt;
Loading NimbusSanL-Bold font from /usr/share/fonts/default/Type1/n019004l.pfb… 2673436 1178370 2661504 1363393 2 done.&lt;br&gt;
&lt;strong&gt;%%BoundingBox: 87 107 327 200&lt;/strong&gt;&lt;br&gt;
%%HiResBoundingBox: 87.695997 107.509005 326.645990 199.601994&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;위의 결과에서 마지막 두 줄에 나온 것이 흰 공간을 없앤 bounding box의 크기입니다. 둘 중 하나를 쓰시면 됩니다. 네 개의 숫자는 각각 왼쪽 아래 x좌표, 왼쪽 아래 y좌표, 오른쪽 위 x좌표, 오른쪽 위 y좌표를 의미합니다. Eps 파일을 텍스트 편집기로 열어서 %%BoundingBox 라고 써진 줄을 찾아 bounding box 크기를 위의 정보로 고쳐주면 아래와 같은 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; class=&quot;alignnone size-full wp-image-1107&quot; src=&quot;https://pkgpl.org/media/eps_bbox_after.jpg&quot; alt=&quot;eps_bbox_after&quot; width=&quot;435&quot; height=&quot;176&quot;&gt;&lt;/p&gt;
&lt;p&gt;또는 SU에 있는 psbbox 라는 프로그램을 이용할 수도 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;psbbox llx=87 lly=107 urx=327 ury=200 &amp;lt; marm.eps &amp;gt;marmfx.eps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a title=&quot;Geophysical Prospecting Library&quot; href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;Gpl&lt;/a&gt;에 있는 fixbbox 프로그램은 위의 과정을 자동으로 실행하는 Python 프로그램으로,&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;fixbbox &amp;lt;input eps file&amp;gt; &amp;lt;output eps file&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;과 같이 실행할 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Fortran option parser</title><link>https://pkgpl.org/2014/09/29/fortran-option-parser/</link><guid isPermaLink="true">https://pkgpl.org/2014/09/29/fortran-option-parser/</guid><pubDate>Mon, 29 Sep 2014 14:55:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt;에서 사용하기 위해 개발한 포트란 option parser를 소개합니다. Option parser는 command line option들을 분석해서 프로그램에서 사용할 수 있도록 변수로 저장해주는 역할을 합니다. 리눅스나 맥에서 명령을 실행할 때&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;$ gcc -c -o main.e main.c
$ tar -zxvf file.tgz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같은 유닉스 표준 형태의 옵션이 있고,&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;$ suximage n1=101 d1=0.5 perc=99 &amp;lt; file.su
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같이 &lt;a href=&quot;http://www.cwp.mines.edu/cwpcodes/&quot;&gt;Seismic Un*x&lt;/a&gt;나 &lt;a href=&quot;http://www.ahay.org&quot;&gt;Madagascar&lt;/a&gt; 등에서 사용하는 형태의 옵션도 있는데, 지금 소개해드리는 option parser는 두 번째 형태의 옵션을 지원합니다. Option parser는 한 번 작성한 프로그램의 재사용을 위해 매우 유용한 기능입니다. 우선 테스트 프로그램을 통해 사용 예를 살펴본 후 자세한 사용법을 보겠습니다.&lt;/p&gt;
&lt;h2&gt;테스트 프로그램&lt;/h2&gt;
&lt;p&gt;다음의 테스트 프로그램은 다양한 종류의 변수를 command line option으로부터 읽어서 출력하는 프로그램입니다.&lt;br&gt;
지원하는 자료형은 integer, single precision real, double precision real, logical, character입니다(complex는 아직까지 필요가 없어서 안 넣었습니다). 단일 변수 뿐 아니라 각각의 배열도 지원합니다. 필수 입력 옵션과 기본값을 가진 옵션을 구분하여, 필수 입력 옵션들 중 하나라도 command line option에 없을 경우 도움말을 출력하고 프로그램을 종료합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;        program test_optparse
        use gpl_optparse
        implicit none
        integer,parameter:: mxlen=100,mxstr=100
        integer:: i,io,ia(mxlen)
        integer:: j,ni,nf,nb,nd,ns
        real:: f,fo,fa(mxlen)
        logical:: b,bo,ba(mxlen)
        real(kind=8):: d,d_o,da(mxlen)
        character(len=mxstr) :: s,so,sa(mxlen)

        ! required parameters
        call from_par(&apos;i&apos;,i,&apos;integer number&apos;)
        call from_par(&apos;f&apos;,f,&apos;float: single precision real number&apos;)
        call from_par(&apos;d&apos;,d,&apos;double precision&apos;)
        call from_par(&apos;b&apos;,b,&apos;boolean/logical&apos;)
        call from_par(&apos;s&apos;,s,&apos;string&apos;)

        ! optional parameters
        call from_par(&apos;io&apos;,io,1,&apos;1&apos;,&apos;optional integer&apos;)
        call from_par(&apos;fo&apos;,fo,1.0,&apos;1.0&apos;,&apos;optional float&apos;)
        call from_par(&apos;do&apos;,d_o,1.0d0,&apos;1.0d0&apos;,&apos;optional double&apos;)
        call from_par(&apos;bo&apos;,bo,.true.,&apos;T&apos;,&apos;optional boolean&apos;)
        call from_par(&apos;so&apos;,so,&apos;&apos;,&apos;empty&apos;,&apos;optional string&apos;)

        ! array, required parameters
        call from_par(&apos;ia&apos;,ia,ni,&apos;integer array&apos;)
        call from_par(&apos;fa&apos;,fa,nf,&apos;float array&apos;)
        call from_par(&apos;da&apos;,da,nd,&apos;double array&apos;)
        call from_par(&apos;ba&apos;,ba,nb,&apos;boolean array&apos;)
        call from_par(&apos;sa&apos;,sa,ns,&apos;string array&apos;)

        call help_par()
        !call report_par()
        
        print*,&apos;i=&apos;,i
        print*,&apos;f=&apos;,f
        print*,&apos;d=&apos;,d
        print*,&apos;b=&apos;,b
        print*,&apos;s=&apos;,trim(s)
        print*,&apos;&apos;
        print*,&apos;ia=&apos;,ia(1:ni)
        print*,&apos;fa=&apos;,fa(1:nf)
        print*,&apos;ba=&apos;,ba(1:nb)
        print*,&apos;da=&apos;,da(1:nd)
        print*,&apos;sa=&apos;,(trim(sa(j))//&apos;_&apos;,j=1,ns)
        print*,&apos;&apos;
        print*,&apos;io=&apos;,io
        print*,&apos;fo=&apos;,fo
        print*,&apos;do=&apos;,d_o
        print*,&apos;bo=&apos;,bo
        print*,&apos;so=&apos;,so
        end program
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;실행 결과&lt;/h2&gt;
&lt;p&gt;위의 프로그램을 컴파일하여 아래와 같이 실행하면 변수들이 제대로 입력된 것을 확인할 수 있습니다. 문자열의 경우 문자열을 둘러싼 따옴표는 제거하고 변수에 저장합니다. 배열은 쉼표를 기준으로 배열의 원소를 나눕니다. 기본값을 가지고 있는 변수의 경우 command line option에 있으면 주어진 값을 저장하고 없으면 기본값을 저장합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;$ ./test_optparse s=test.dat i=2 f=2.5 d=3.0 b=T ia=1,2,3,4 fa=1.0,2.0,3.0,4.0 da=1.,2.,3. ba=T,F,T sa=st,&apos;ri&apos;,&quot;ng&quot; io=5 so=&quot;gpl&quot;
 i=           2
 f=   2.50000000    
 d=   3.0000000000000000     
 b= T
 s=test.dat
 
 ia=           1           2           3           4
 fa=   1.00000000       2.00000000       3.00000000       4.00000000    
 ba= T F T
 da=   1.0000000000000000        2.0000000000000000        3.0000000000000000     
 sa=st_ri_ng_
 
 io=           5
 fo=   1.00000000    
 do=   1.0000000000000000     
 bo= T
 so=gpl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;만약 기본값이 없는 필수 옵션 중 하나라도 command line option에 빠져있다면 다음과 같이 도움말을 표시하고 프로그램을 종료합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;$ ./test_optparse 
 Required parameters:
     [i] i=             : integer number
     [f] f=             : float: single precision real number
     [d] d=             : double precision
     [b] b=             : boolean/logical
     [s] s=             : string
     [I] ia=            : integer array
     [F] fa=            : float array
     [D] da=            : double array
     [B] ba=            : boolean array
     [S] sa=            : string array
 Optional parameters:
     [i] io=1           : optional integer
     [f] fo=1.0         : optional float
     [d] do=1.0d0       : optional double
     [b] bo=T           : optional boolean
     [s] so=empty       : optional string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 도움말에서 i=integer, f=real, d=real(kind=8), b=logical, s=character(len=?)을 의미하고, 각각의 대문자는 배열을 의미합니다.&lt;/p&gt;
&lt;h2&gt;사용법&lt;/h2&gt;
&lt;p&gt;그럼 실제 모듈의 사용법을 알아보겠습니다. 모듈은 &lt;code&gt;use gpl_optparse&lt;/code&gt; 또는 간편하게 &lt;code&gt;use gpl&lt;/code&gt;로 불러올 수 있습니다. 가장 중요한 &lt;code&gt;from_par&lt;/code&gt; 서브루틴은 다음과 같이 세 가지 방식으로 사용할 수 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;call from_par(&apos;parname&apos;,variable,&apos;help message&apos;) !! 필수 옵션
call from_par(&apos;parname&apos;,variable_arr,len_arr,&apos;help message&apos;) !! 필수 배열
call from_par(&apos;parname&apos;,variable,default,&apos;default message&apos;,&apos;help message&apos;) !! 기본값이 있는 변수
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Command line option은 &lt;code&gt;parname=value&lt;/code&gt; 형태로 입력 받게 됩니다. 위의 서브루틴들에서 &lt;code&gt;&apos;parname&apos;&lt;/code&gt;은 이 때 사용되는 이름이고, &lt;code&gt;value&lt;/code&gt;는 &lt;code&gt;variable&lt;/code&gt;에 저장됩니다. ’help message’는 도움말 출력시 보여주는 변수 설명입니다.&lt;/p&gt;
&lt;p&gt;배열의 경우 &lt;code&gt;parname=value1,value2,value3&lt;/code&gt;과 같은 형태로 입력받고, 입력받은 값은 &lt;code&gt;variable_arr&lt;/code&gt;에 저장됩니다. 이 때 입력받은 원소는 &lt;code&gt;len_arr&lt;/code&gt; 개입니다.&lt;/p&gt;
&lt;p&gt;기본값이 있는 변수의 경우 &lt;code&gt;default&lt;/code&gt;는 기본값이고, &lt;code&gt;&apos;default message&apos;&lt;/code&gt;는 도움말 출력시 기본값을 보여주기 위한 문자열입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pkgpl.org/2014/07/12/fortran_function_overloading/&quot;&gt;함수 오버로딩을&lt;/a&gt; 사용하였기 때문에 정수, 실수 등의 자료형에 상관없이 위의 서브루틴들을 이용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;기타 사용할 수 있는 서브루틴들과 함수는 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;call help_par()
call help_header(&apos;msg before the parameter help msg&apos;)
call help_footer(&apos;msg after the parameter help msg&apos;)
call force_help()

call report_par()

if(given_par(&apos;parname&apos;)) call do_something()
call from_parfile(&apos;parfile.txt&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;에서 &lt;code&gt;help_par&lt;/code&gt;는 도움말 출력을 위한 서브루틴입니다. 도움말과 관련된 서브루틴들로는 도움말을 보강하기 위한 &lt;code&gt;call help_header(&apos;msg&apos;)&lt;/code&gt;, &lt;code&gt;call help_footer(&apos;msg&apos;)&lt;/code&gt;, 필수 옵션이 주어졌는지와 무관하게 도움말을 출력하기 위한 &lt;code&gt;call force_help()&lt;/code&gt;가 있습니다. &lt;code&gt;report_par&lt;/code&gt;는 입력받은 변수들을 출력해서 확인하기 위한 서브루틴입니다. 이 외에도 옵션이 주어졌는지 확인하기 위한 &lt;code&gt;logical function given_par(&apos;parname&apos;)&lt;/code&gt; 함수, 옵션들을 저장해놓은 텍스트파일로부터 옵션들을 읽어들이기 위한 &lt;code&gt;call from_parfile(&apos;parfile.txt&apos;)&lt;/code&gt;와 같은 명령이 있습니다.&lt;/p&gt;
&lt;p&gt;참고로, command line option에 &lt;code&gt;par=parfile.txt&lt;/code&gt;와 같은 옵션이 있으면 &lt;code&gt;parfile.txt&lt;/code&gt;에서 먼저 변수를 읽은 후 command line option을 읽습니다. &lt;code&gt;parfile.txt&lt;/code&gt;에 주어진 변수가 command line option에 다시 나오면 command line에 주어진 값을 사용합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gpl_optparse&lt;/code&gt; 모듈의 소스코드는 &lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt;의 &lt;a href=&quot;https://github.com/pkgpl/gpl&quot;&gt;GitHub&lt;/a&gt;에서 받으실 수 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Polymorphic Fortran &amp; C</title><link>https://pkgpl.org/2014/07/28/polymorphic-fortran-c/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/28/polymorphic-fortran-c/</guid><pubDate>Mon, 28 Jul 2014 13:30:31 GMT</pubDate><content:encoded>&lt;h1 aria-level=&quot;2&quot;&gt;포트란 함수 오버로딩과 중복&lt;/h1&gt;
&lt;p&gt;앞서 &lt;a title=&quot;포트란과 함수 오버로딩&quot; href=&quot;https://pkgpl.org/2014/07/12/fortran_function_overloading/&quot;&gt;포트란 함수 오버로딩에 관한 글&lt;/a&gt;을 올렸습니다. 포트란 모듈과 인터페이스를 이용하면 서로 다른 자료형을 인자로 받는 함수나 서브루틴이라도 같은 이름으로 사용할 수가 있었습니다. 그런데, 동적 자료형을 지원하는 언어와 달리, 포트란에서는 자료형별로 서브루틴들을 따로 만든 후에 같은 이름으로 호출하였습니다. 동적 자료형 언어에서는 함수 자체를 한 번만 작성하면 되지요. 여기에서 포트란 코드 작성에 중복이 발생하게 됩니다. 이러한 중복을 제거하기 위해 파이썬으로 만든 스크립트가 polyfc (Polymorphic Fortran &amp;amp; C)입니다. 예전에 &lt;a href=&quot;https://github.com/drewmccormack/forpedo&quot;&gt;Forpedo&lt;/a&gt;에서 아이디어를 얻었는데, Forpedo를 사용하려니 좀 복잡해서 Python 연습도 할 겸 &lt;a title=&quot;Geophysical Prospecting Library&quot; href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot;&gt;gpl&lt;/a&gt;용으로 만들었습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;예제&lt;/h1&gt;
&lt;p&gt;이해하기 쉽게 예제를 살펴보겠습니다. 배열의 내용을 출력하는 서브루틴을 작성하려고 합니다. 배열은 integer, real, real(kind=8), complex, complex(kind=8) 다섯 종류의 자료형을 지원하려고 합니다. 그럼 서브루틴을 자료형에 따라 총 5개를 작성해야 하는데, 선언부만 다르고 나머지는 동일하거나 거의 비슷하게 됩니다. 그래서 일종의 템플릿 서브루틴을 만들고, 필요한 부분만 바꿔가며 서브루틴을 복제하려고 합니다. 그러면 거의 비슷한 코드를 중복해서 작성하는 수고를 덜 수 있겠죠. 아래는 polyfc에 입력으로 들어가는 템플릿 파일입니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module polyfc_example

!@interface print_array
contains
!@template print_array ifdcz
    subroutine print_array_&amp;lt;name&amp;gt;(arr)
    &amp;lt;type&amp;gt;,intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
!@end
end module
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;포트란 주석을 이용하여 인터페이스가 들어갈 부분과 템플릿 부분을 표시하고, 자료형에 따라 바뀌어야 하는 부분은 &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;으로 표시하였습니다. 이 외에 필요할 경우 &lt;code&gt;&amp;lt;kind&amp;gt;&lt;/code&gt;와 &lt;code&gt;&amp;lt;esize&amp;gt;&lt;/code&gt;도 지원합니다. 바뀌며 들어가는 부분은 다음 표를 보면 알 수 있습니다.&lt;/p&gt;
&lt;table tabindex=&quot;0&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center;&quot;&gt;Name&lt;/th&gt;
&lt;th style=&quot;text-align:left;&quot;&gt;Fortran type&lt;/th&gt;
&lt;th style=&quot;text-align:left;&quot;&gt;C type&lt;/th&gt;
&lt;th style=&quot;text-align:left;&quot;&gt;Fotran kind&lt;/th&gt;
&lt;th style=&quot;text-align:center;&quot;&gt;esize&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;i&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;integer&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;int&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=4)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;f&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;real&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;float&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=4)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;d&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;real(kind=8)&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;double&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=8)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;c&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;complex&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;float complex&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=4)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;z&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;complex(kind=8)&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;double complex&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=8)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;b&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;logical&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(not supported)&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(kind=4)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;s&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;character(len=*)&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;char&lt;/td&gt;
&lt;td style=&quot;text-align:left;&quot;&gt;(len=*)&lt;/td&gt;
&lt;td style=&quot;text-align:center;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;그래서 &lt;code&gt;polyfc input.f90 &amp;gt; output.f90&lt;/code&gt;과 같이 실행했을 때 얻게 되는 파일은 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;! This file was generated from pfc.example.f90 by Polyfc at Mon Jul 28 22:12:32 2014.
! Do not edit this file directly.

module polyfc_example

    interface print_array
        module procedure print_array_i
        module procedure print_array_f
        module procedure print_array_d
        module procedure print_array_c
        module procedure print_array_z
    end interface print_array

contains

    subroutine print_array_i(arr)
    integer,intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
 
    subroutine print_array_f(arr)
    real,intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
 
    subroutine print_array_d(arr)
    real(kind=8),intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
 
    subroutine print_array_c(arr)
    complex,intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
 
    subroutine print_array_z(arr)
    complex(kind=8),intent(in):: arr(:)
    integer i
    do i=1,size(arr)
        print*, i, arr(i)
    enddo
    end subroutine
 
end module
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자동으로 작성하면 손으로 복사했을 경우 생길 수 있는 오류도 피할 수 있겠죠. 단, 코드에 버그가 있을 때에는 output 파일에서 버그가 있는 곳을 찾아 input 파일의 해당 위치를 고쳐줘야 합니다.&lt;/p&gt;
&lt;p&gt;참고로, polyfc 이름이 의미하듯, C도 지원합니다. 단, C에서는 &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt;과 &lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt;만 지원합니다. 물론 인터페이스도 지원하지 않습니다. C에서는 아래와 같은 방식으로 사용 가능합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;//@template ifdczbs
void abc_&amp;lt;name&amp;gt;(&amp;lt;type&amp;gt; def)
{
    ...
}
//@end
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>GNU Quick Plot (gnuqp)</title><link>https://pkgpl.org/2014/07/27/gnu-quick-plot-gnuqp/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/27/gnu-quick-plot-gnuqp/</guid><pubDate>Sun, 27 Jul 2014 14:25:06 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.gnuplot.info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gnuplot&lt;/a&gt;은 리눅스에서 텍스트파일에 저장된 값을 빠르게 그림으로 그려주는 프로그램입니다. 다양한 기능을 가지고 있지만, 제 경우에는 주로 수치해석 후 결과 확인용으로 씁니다.&lt;br&gt;
gnuplot으로 그림을 그릴 때에는 command line 상에서 &lt;code&gt;gnuplot&lt;/code&gt;이라고 치고 들어가서 gnuplot 명령어들을 이용하여 그림을 그리고 &lt;code&gt;q&lt;/code&gt;를 입력하여 빠져나옵니다.&lt;br&gt;
그런데 간단히 결과를 확인해보기 위해서 gnuplot에 들어가서&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;p &apos;file1&apos; w l,&apos;file1&apos; u 1:3 w l,&apos;file1&apos; u 1:4 w p
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또는&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;set grid
set xrange[:10]
set log y
p &apos;file1&apos; w l,&apos;file2&apos; w l,&apos;file3&apos; w l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;과 같이 매번 치려니 귀찮다는 생각이 들었습니다. 그래서 gnuqp (GNU Quick Plot)를 만들었습니다. 이 script를 사용하면 command line 상에서 바로 gnuplot 명령어를 사용하여 그림을 그릴 수 있습니다. 사용 방법은 아래와 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Usage :
gnuqp [options] filename1 [u 1:2] [w l], filename2 [u 1:2] [w l], filename3 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;실행파일 이름, 몇 가지 setting 관련 옵션들, 이후에는 gnuplot의 plot 명령어를 입력합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Required parameters :
filename1
Empty filename[2,3,...] will be replaced by the filename1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 번째 위치부터는 파일명을 생략하면 첫 번째 파일명으로 대체합니다. 하나의 파일에서 여러 column들을 그릴 때 편리합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Optional parameters :
u 1:2   : columns you want to plot
w [lp..]: line style- line, point, dot or impulse ..etc (default: w l)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;plot 명령어의 옵션들 중에는 using (columns)과 with (line style)만 지원합니다. 그 외의 명령은 제가 잘 안 써서요^^.&lt;br&gt;
위의 옵션을 주지 않았을 때 기본적으로 &lt;code&gt;with line&lt;/code&gt; 옵션으로 그립니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;-p      : do not run gnuplot. just print the gnuplot command
-c      : no comma seperation - the arguments are filenames seperated with a blank- use with glob pattern
-l       : set logscale y
-g      : set grid
-x[:10] : set xrange [:10]
-y[1:5] : set yrange [1:5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 옵션들은 gnuplot의 setting을 간편하게 하기 위해 만들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-p&lt;/code&gt; 옵션을 붙이면 gnuplot의 명령어만 출력하고 그림은 안 그립니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-c&lt;/code&gt; 옵션을 붙이면 파일들을 기본 옵션(with line)으로 그립니다. 이 때 파일명들 사이의 “,”를 생략하고 파일명만 씁니다. command line상에서 glob pattern을 이용하여 여러 그림을 그릴 수 있도록 하기 위한 옵션입니다. 예를 들면, 다음과 같은 경우죠.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;./gnuqp.py -p -c file.00*
-&amp;gt; p &apos;file.0010&apos; w l,&apos;file.0020&apos; w l,&apos;file.0030&apos; w l,&apos;file.0040&apos; w l,&apos;file.0050&apos; w l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;나머지 gnuplot setting들은 위의 설명으로 충분할 것이라 생각합니다.&lt;br&gt;
앞에 예를 들었던 명령어들을 gnuqp를 이용하여 실행한다면 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;(gnuplot)
p &apos;file1&apos; w l,&apos;file1&apos; u 1:3 w l,&apos;file1&apos; u 1:4 w p
(q)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;는 &lt;code&gt;gnuqp file1, u 1:3, u 1:4 wp&lt;/code&gt;,&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;(gnuplot)
set grid
set xrange[:10]
set log y
p &apos;file1&apos; w l,&apos;file2&apos; w l,&apos;file3&apos; w l
(q)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;는 &lt;code&gt;gnuqp file1, file2, file3 -g -l -x[:10]&lt;/code&gt;와 같이 실행할 수 있습니다. gnuqp는 &lt;a title=&quot;Geophysical Prospecting Library&quot; href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gpl&lt;/a&gt;에 포함되어 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>SConstruct 사용법</title><link>https://pkgpl.org/2014/07/27/sconstruct_basic/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/27/sconstruct_basic/</guid><pubDate>Sun, 27 Jul 2014 13:30:18 GMT</pubDate><content:encoded>&lt;p&gt;SConstruct은 &lt;a title=&quot;Makefile 사용법&quot; href=&quot;https://pkgpl.org/2014/07/12/makefile_basic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Makefile&lt;/a&gt;과 비슷한 역할을 하는, Python script입니다. 따라서 Python이라는 언어의 강력한 기능들을 그대로 가져다 쓸 수 있다는 장점이 있습니다. Makefile을 make라는 명령어로 실행하듯이, SConstruct는 scons라는 명령어로 실행합니다. SConstruct file의 작성법은 &lt;a title=&quot;Makefile 사용법&quot; href=&quot;https://pkgpl.org/2014/07/12/makefile_basic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Makefile&lt;/a&gt;이나 &lt;a title=&quot;Rakefile 사용법&quot; href=&quot;https://pkgpl.org/2014/07/26/rakefile_basic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rakefile&lt;/a&gt;의 작성법과는 차이가 있습니다. 작성법을 살펴보기 전에 먼저 ‘Environment’와 ‘Builder’라는 개념에 대해 살펴보겠습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;Environments&lt;/h1&gt;
&lt;p&gt;Makefile에서는 기본적으로 Shell의 환경변수들을 가져다가 썼습니다. 물론 PATH 환경변수도 가지고 오기 때문에 compiler의 절대경로를 써주지 않아도 알아서 잘 compile을 했었습니다.&lt;br&gt;
반면에, scons는 기본적으로 Shell의 환경변수들을 가져오지 않습니다. scons를 설치할 때 기본적인 compiler들(gcc, gfortran 등)은 알아서 찾아내기 때문에 보통은 문제가 없지만 특정한 compiler(icc, ifort 등)를 사용하고 싶은 경우 compile 관련 환경변수(construction variables)에 절대경로를 지정해주거나 Shell의 환경변수를 가지고 옵니다. Shell의 환경변수들을 전부 가지고 오고 compiler로 ifort를 사용할 경우 script에 다음과 같이 써줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;import os
DefaultEnvironment(ENV=os.environ, FORTRAN=&apos;ifort&apos;,
    FORTRANFLAGS=&apos;-assume byterecl -O2&apos;, LINK=&apos;ifort&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;scons에는 위에 사용한 Default Environment외에도 사용자가 마음대로 Environment를 만들 수 있습니다. 아래와 같이 쓸 경우 myEnv라는 새로운 Environment를 만들어 사용할 수 있습니다. 이런 식으로 여러 개의 Environment들을 만들어 필요에 따라 같은 프로그램도 옵션을 바꿔가며 compile할 수 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;import os
DefaultEnvironment(ENV=os.environ, FORTRAN=&apos;ifort&apos;,
    FORTRANFLAGS=&apos;-assume byterecl -O2&apos;, LINK=&apos;ifort&apos;)
myEnv=Environment(ENV=os.environ, CFLAGS=&apos;-O3&apos;,
    FORTRANFLAGS=&apos;-O1&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 환경 설정 내용을 이후에 사용하기 위해 &lt;code&gt;myenv.py&lt;/code&gt;라는 파일에 저장해두었다고 가정 하겠습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;Builders&lt;/h1&gt;
&lt;p&gt;scons는 기본적으로 많이 사용되는 프로그램들의 compile 방법들을 알고 있습니다. Compile하는 object를 builder라고 하는데, c/c++, fortran, java, TeX, LaTeX, tar, zip 등 다수의 builder들이 존재합니다. 따라서 원하는 builder에 알맞은 target과 source 이름만 넣어주면 scons가 알아서 compile합니다. 필요한 변수(옵션)들은 해당 Environment에서 가지고 옵니다. 기본적인 작성법은 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Program(&apos;target1.e&apos;, &apos;source1.f&apos;)
myEnv.Program(&apos;target2.e&apos;, &apos;source2.c&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;첫 번째 줄은 ‘source1.f’라는 파일로부터 ‘target1.e’ 라는 파일을 생성하는 명령입니다. 이 때 필요한 변수들은 Default Environment에서 가지고 옵니다. 두 번째 줄은 ‘source2.c’라는 파일로부터 ‘target2.e’라는 파일을 생성하는 명령이고, 필요한 변수는 &lt;code&gt;myEnv&lt;/code&gt;라는 Environment에서 가지고 옵니다. 위에서 &lt;code&gt;Program&lt;/code&gt;이라는 명령은 source code에 해당하는 builder를 불러오는 역할을 하죠. 지금까지의 SConstruct script와 실행 결과를 살펴볼까요?&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;from myenv import *
Program(&apos;target1.e&apos;,&apos;source1.f&apos;)
myEnv.Program(&apos;target2.e&apos;,&apos;source2.c&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;scons&lt;/code&gt;라고 실행하면,&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
ifort -o source1.o -c -assume byterecl -O2 source1.f
gcc -o source2.o -c -O3 source2.c
ifort -o target1.e source1.o
gcc -o target2.e source2.o
scons: done building targets.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같은 화면을 얻게 됩니다. 복잡한 내용은 빼고 실행 결과만 보고 싶을 경우 &lt;code&gt;scons -Q&lt;/code&gt; 라고 실행하면 결과를 다음과 같이 보여줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;ifort -o source1.o -c -assume byterecl -O2 source1.f
gcc -o source2.o -c -O3 source2.c
ifort -o target1.e source1.o
gcc -o target2.e source2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 실행 결과를 보면 source file의 확장자에 따라 필요한 compiler를 사용하고 필요한 환경변수들을 가져다가 사용했음을 알 수 있습니다. 특정 Compiler가 사용하는 환경변수는 &lt;a href=&quot;http://www.scons.org/documentation.php&quot;&gt;scons user manual&lt;/a&gt;에서 찾아볼 수 있습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;예제&lt;/h1&gt;
&lt;p&gt;그럼 &lt;a title=&quot;Makefile 사용법&quot; href=&quot;https://pkgpl.org/2014/07/12/makefile_basic/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞에서 살펴보았던 예제&lt;/a&gt; – &lt;code&gt;main.f, sub1.f, sub2.f&lt;/code&gt; 는 어떻게 compile하는지 살펴보겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;from myenv import *
Program(&apos;main.e&apos;,[&apos;main.f&apos;,&apos;sub1.f&apos;,&apos;sub2.f&apos;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 source file이 여러 개인 경우 source file들을 list로 묶어줍니다. 다른 방법으로 아래와 같이 쓸 수도 있습니다. Split이라는 함수는 문자열을 나눠서 list로 만들어줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;from myenv import *
obj=Split(&apos;main.f sub1.f sub2.f&apos;)
Program(&apos;main.e&apos;,obj)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Makefile이나 Rakefile에 비해 상당히 간단하죠? 실행 결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;ifort -o main.o -c -assume byterecl -O2 main.f
ifort -o sub1.o -c -assume byterecl -O2 sub1.f
ifort -o sub2.o -c -assume byterecl -O2 sub2.f
ifort -o main.e main.o sub1.o sub2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또 앞의 Makefile, Rakefile 예제들과는 달리 clean 이라는 target이 없습니다. scons -c 라고 실행하면 scons는 compile 과정에서 새로 생긴 파일들을 알아서 지워줍니다. 실행 결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed main.o
Removed sub1.o
Removed sub2.o
Removed main.e
scons: done cleaning targets.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;물론 특정 target만 만들고 싶을 때는 &lt;code&gt;scons main.o&lt;/code&gt;와 같이 실행하여 하나의 target만 만들 수도 있습니다. &lt;code&gt;main.o&lt;/code&gt;라는 target은 script 내에서 지정해준 적이 없지만 확장자 규칙에 따라 compile 중에 생기는 파일이기 때문에 앞에서와 같이 실행하면 알아서 만들어줍니다. 또한, 많은 경우 dependency도 알아서 check해줍니다.&lt;/p&gt;
&lt;p&gt;만약 &lt;code&gt;Program()&lt;/code&gt;에서 target을 생략하고 source만 적어주면 list의 첫 번째 source file 이름을 기준으로 target file 이름을 만들어 줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Program([&apos;main.f&apos;,&apos;sub.f&apos;]) ## -&amp;gt; target=&apos;main&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;http://www.scons.org&quot;&gt;SCons Homepage&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;예전에 다른 블로그에 올렸던 글인데, 이곳에 복사해둡니다.&lt;/em&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Unit number 자동 할당</title><link>https://pkgpl.org/2014/07/27/unit-number-%ec%9e%90%eb%8f%99-%ed%95%a0%eb%8b%b9/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/27/unit-number-%ec%9e%90%eb%8f%99-%ed%95%a0%eb%8b%b9/</guid><pubDate>Sat, 26 Jul 2014 15:56:35 GMT</pubDate><content:encoded>&lt;p&gt;포트란에서 파일을 열 때 파일에 번호(Logical unit number)를 할당하고 그 번호를 이용하여 파일 내용을 읽거나 파일에 출력을 하게 됩니다. 리눅스에서 다음 세 번호는 기본적으로 할당이 되어(입출력 스트림이 열려) 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;0: stderr
5: stdin
6: stdout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;나머지 4바이트 정수 자료형으로 표현할 수 있는 양의 정수값은 사용자가 파일에 할당하여 사용할 수 있습니다 (컴파일러마다 범위는 차이가 있습니다). 보통은 사용하는데 문제가 없지만 하나의 프로그램에서 여러 개의 파일을 열 경우 앞에서 다른 파일에 할당하여 사용중인 번호를 피해 새로운 번호를 찾아야 합니다. 사용중인 번호를 피하기 위해 앞의 코드를 살펴본다든지, 파일 입출력 서브루틴을 위해 새로운 번호를 전달해줄 경우 귀찮다는 생각이 들게 됩니다. 예를 들면 다음과 같은 경우죠.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;subroutine write_a_number(un, filename, n)
integer,intent(in):: un, n
character(len=*),intent(in):: filename
open(un,file=trim(filename))
write(un,*) n
close(un)
end subroutine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이럴 때 inquire함수를 사용하면 특정 번호가 사용중인지 알 수 있고, 따라서 새로운 번호도 자동으로 찾을 수 있습니다. 아래 서브루틴과 함수는 &lt;a href=&quot;https://pkgpl.org/2014/07/26/geophysical-prospecting-library/&quot; title=&quot;Geophysical Prospecting Library&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gpl&lt;/a&gt;의 포트란 모듈(module_base)에서 복사하였습니다. 파일 번호는 99번부터 10번까지만 사용하게 만들었습니다. 동시에 그 이상의 파일을 열 일은 없다고 생각하고 만들었는데, 많은 파일을 열어야 할 경우 do loop 범위를 조정하면 되겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;subroutine assign_un(un)
integer, intent(out) :: un
logical :: oflag
integer :: i
do i=99,10,-1
    inquire(unit=i,opened=oflag)
    if(.not.oflag) then
        un=i
        return
    endif
enddo
stop &quot;Error: Logical unit assignment&quot;
end subroutine

logical function un_opened(un) result(val)
integer,intent(in):: un
inquire(unit=un,opened=val)
end function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 서브루틴을 사용하면 앞에서 살펴본 &lt;code&gt;write_a_number&lt;/code&gt; 서브루틴을 다음과 같이 고칠 수 있습니다. 서브루틴의 인터페이스가 좀 더 간단해졌고, 앞으로는 서브루틴을 사용할 때 파일 번호에 대해 고민할 필요가 없겠죠. 자동화의 간단한 예가 되겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;subroutine write_a_number_new(filename, n)
integer,intent(in):: n
character(len=*),intent(in):: filename
integer:: un
call assign_un(un)
open(un,file=trim(filename))
write(un,*) n
close(un)
end subroutine
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Geophysical Prospecting Library</title><link>https://pkgpl.org/2014/07/26/geophysical-prospecting-library/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/26/geophysical-prospecting-library/</guid><pubDate>Sat, 26 Jul 2014 14:58:25 GMT</pubDate><content:encoded>&lt;h1 aria-level=&quot;2&quot;&gt;GPL (Geophysical Prospecting Library)&lt;/h1&gt;
&lt;p&gt;이 라이브러리는 제가 개인적으로, 대부분 직접 작성하여 사용하는 프로그램들이나 스크립트들을 모아놓은 라이브러리입니다. 연구를 위해 실용적으로 사용하는 잡동사니들의 모음으로, 반복되는 작업들을 자동화하는데 초점을 맞추고 작성한 라이브러리입니다. 내용은 수치해석 프로그래밍을 편리하게 하기 위한 포트란 모듈과 C 함수들, 컴파일을 쉽게 하기 위한 스크립트, 파일 수정 및 부분 추출 등을 위한 프로그램들, 결과 확인 및 논문 그림 그리기를 위한 스크립트들 등이 있습니다. 주로 포트란으로 작성하였고, 그 외에 프로그래밍 연습도 할 겸 C, 파이썬, 루비 등의 언어를 사용하였습니다.&lt;/p&gt;
&lt;p&gt;라이브러리 정리 및 간단한 문서화를 위해 블로그를 통해 라이브러리의 기능을 하나 둘씩 공개하려고 합니다. 홈페이지를 방문해주신 누군가에게 도움이 되기를 바랍니다. 코드는 &lt;a href=&quot;https://github.com/pkgpl/gpl&quot;&gt;GitHub&lt;/a&gt;를 통해 공개하겠습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;설치 방법&lt;/h1&gt;
&lt;h2&gt;설치 전에&lt;/h2&gt;
&lt;p&gt;gpl을 제대로 사용하기 위해서는 Fortran 및 C 컴파일러가 필요하고, Python (2.7)과 Ruby (1.9) 인터프리터가 필요합니다. 모든 gpl 기능을 원활히 사용하기 위해서는 탄성파 자료처리 패키지인 &lt;a href=&quot;http://www.cwp.mines.edu/cwpcodes/&quot;&gt;Seismic Un*x&lt;/a&gt;와 &lt;a href=&quot;http://www.ahay.org&quot;&gt;Madagascar&lt;/a&gt;, Python의 &lt;a href=&quot;http://www.numpy.org&quot;&gt;Numpy&lt;/a&gt; 및 &lt;a href=&quot;http://matplotlib.org&quot;&gt;Matplotlib&lt;/a&gt; 라이브러리, &lt;a href=&quot;http://www.scons.org&quot;&gt;SConstruct&lt;/a&gt; 그리고 &lt;a href=&quot;http://www.gnuplot.info&quot;&gt;Gnuplot&lt;/a&gt;과 &lt;a href=&quot;http://www.imagemagick.org&quot;&gt;ImageMagick&lt;/a&gt;이 필요합니다.&lt;/p&gt;
&lt;h2&gt;설치&lt;/h2&gt;
&lt;p&gt;1. &lt;a href=&quot;https://github.com/pkgpl/gpl&quot;&gt;GitHub&lt;/a&gt;에서 파일을 받습니다.&lt;br&gt;
2. &lt;code&gt;path_to_gpl/gpl/compiler.py&lt;/code&gt;에서 Fortran과 C compiler 관련 설정을 해줍니다.&lt;br&gt;
3. &lt;code&gt;make install&lt;/code&gt;을 실행합니다.&lt;br&gt;
4. &lt;code&gt;~/.bash_profile&lt;/code&gt; (Mac에서는 &lt;code&gt;~/.profile&lt;/code&gt;)에 &lt;code&gt;path_to_gpl/etc/env.sh&lt;/code&gt;의 내용을 추가해줍니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Rakefile 사용법</title><link>https://pkgpl.org/2014/07/26/rakefile_basic/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/26/rakefile_basic/</guid><pubDate>Sat, 26 Jul 2014 14:37:29 GMT</pubDate><content:encoded>&lt;h1 aria-level=&quot;2&quot;&gt;Rakefile 기본 사용법&lt;/h1&gt;
&lt;p&gt;Rakefile은 &lt;a href=&quot;https://pkgpl.org/2014/07/12/makefile_basic/&quot; title=&quot;Makefile 사용법&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Makefile&lt;/a&gt;과 비슷한 역할을 하는, Ruby script입니다. 따라서 Ruby라는 언어의 강력한 기능들을 그대로 가져다 쓸 수 있다는 장점이 있습니다. 단, Ruby를 알아야 제대로 사용할 수 있겠죠. Makefile을 &lt;code&gt;make&lt;/code&gt;라는 명령어로 실행하듯이, Rakefile은 &lt;code&gt;rake&lt;/code&gt;라는 명령어로 실행합니다. Rakefile 작성법을 Makefile 작성법과 비교하며 살펴보도록 하겠습니다. Makefile의 기본적인 작성법은&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Target: Dependency list
[Tab] Command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;였죠. Rakefile도 유사합니다. 단, Ruby syntax를 사용하죠. 기본적인 작성법은 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;task :name = [:prereq1, :prereq2] do
    Command
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Makefile에서 Target에 해당하는 것이 Rakefile의 task입니다. 잘 살펴보면 task라는 함수명과 Hash, Block 두 개의 argument로 이루어진 구조라는 것을 알 수 있습니다. Hash의 key는 target이 되고 value는 prerequisites (dependency list)가 됩니다. Block은 실행해야 할 명령들로 이루어집니다. 특별히 compile하는 경우와 같이 파일을 작성하는 task의 경우에는&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;file &quot;name&quot; = [&quot;prereq1&quot;, &quot;prereq2&quot;] do
    Command
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같이 file task를 사용합니다. Command 부분에서 &lt;code&gt;name&lt;/code&gt; 또는 dependency list (prereq1, prereq2, … )를 사용하고 싶을 때는&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;file &quot;name&quot; = [&quot;prereq1&quot;, &quot;prereq2&quot;] do |t|
    sh &quot;f77 -o #{t.name} #{t.prerequisites.join(&apos; &apos;)}&quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;과 같이 사용하여 &lt;code&gt;f77 -o name prereq1 prereq2&lt;/code&gt;와 같은 결과를 얻을 수도 있습니다.&lt;/p&gt;
&lt;p&gt;그럼 &lt;a href=&quot;https://pkgpl.org/2014/07/12/makefile_basic/&quot; title=&quot;Makefile 사용법&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞에서 만들었던 Makefile&lt;/a&gt;과 같은 기능을 하는 Rakefile을 만들어 비교해 보겠습니다. 앞에서 만들었던 Makefile은 다음과 같고,&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;# target: dependency list
# [tab] command
F77=gfortran

all: main

main: main.o sub1.o sub2.o
    $(F77) -O2 -o main main.o sub1.o sub2.o
main.o: main.f
    $(F77) -O2 -c main.f
sub1.o: sub1.f
    $(F77) -O2 -c sub1.f
sub2.o: sub2.f
    $(F77) -O2 -c sub2.f
clean:
    rm main main.o sub1.o sub2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이에 해당하는 Rakefile은 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;f90=&apos;gfortran&apos;
 
task :default =&amp;gt; [&apos;main.e&apos;]
file &apos;main.e&apos; =&amp;gt; [&apos;main.o&apos;,&apos;sub1.o&apos;,&apos;sub2.o&apos;] do |t|
    sh &quot;#{f90} -o #{t.name} main.o sub1.o sub2.o&quot;
end
 
file &apos;main.o&apos; =&amp;gt; [&apos;main.f&apos;] do
    sh &quot;#{f90} -c main.f&quot;
end
file &apos;sub1.o&apos; =&amp;gt; [&apos;sub1.f&apos;] do
    sh &quot;#{f90} -c sub1.f&quot;
end
file &apos;sub2.o&apos; =&amp;gt; [&apos;sub2.f&apos;] do
    sh &quot;#{f90} -c sub2.f&quot;
end
 
require &apos;rake/clean&apos;
CLEAN.include(&apos;*.o&apos;)
CLOBBER.include(&apos;main.e&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;task :default&lt;/code&gt; 부분은 Makefile에서 &lt;code&gt;all&lt;/code&gt; 이라는 target을 지정해서 사용했던 것과 같은 역할을 합니다. 단, Rakefile에서는 default task가 맨 처음에 나올 필요가 없습니다. 파일 내 아무데나 나와도 잘 인식합니다. 중간 부분은 Makefile과 매우 유사하므로 특별한 설명이 필요 없겠죠? 뒤에 있는 clean task는 rake에 이미 지정되어 있는 task입니다. 사용하기 위해서는 &lt;code&gt;rake/clean&lt;/code&gt;을 불러옵니다. &lt;code&gt;rake clean&lt;/code&gt;을 실행하면 &lt;code&gt;CLEAN&lt;/code&gt;에 포함된 파일들을 지워주고 &lt;code&gt;rake clobber&lt;/code&gt;를 실행하면 &lt;code&gt;CLOBBER&lt;/code&gt;와 &lt;code&gt;CLEAN&lt;/code&gt;에 지정된 파일들을 모두 지워줍니다. 위에서 볼 수 있는 것처럼, 최종 결과 파일만 &lt;code&gt;CLOBBER&lt;/code&gt;에 포함시키고 중간에 생성되는 파일들은 &lt;code&gt;CLEAN&lt;/code&gt;에 포함시키면 편리하게 사용할 수 있습니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;확장자 규칙&lt;/h1&gt;
&lt;p&gt;Makefile에서는 확장자 규칙을 이용해 편리하게 compile할 수 있었죠? Rakefile에도 같은 기능이 있습니다. 비교해볼까요?&lt;/p&gt;
&lt;h3&gt;Makefile&lt;/h3&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;# $^ : dependency list
# $@ : target

F77=ifort
FFLAG=-assume byterecl -O2
TARGET=main
OBJECTS=main.o sub1.o sub2.o

all: $(TARGET)

$(TARGET): $(OBJECTS)
    $(F77) -o $@ $^

.SUFFIXES: .o .f
%.o: %.f
    $(F77) ${FFLAG} -c $^

clean:
    rm $(TARGET) $(OBJECTS)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rakefile&lt;/h3&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;F90=&apos;ifort&apos;
FFLAG=&apos;-assume byterecl -O2&apos;
TARGET=&apos;main.e&apos;
SRC=FileList[&apos;*.f&apos;]
OBJ=SRC.ext(&apos;o&apos;)
 
task :default =&amp;gt; TARGET
file TARGET =&amp;gt; OBJ do
    sh &quot;#{F90} -o #{TARGET} #{OBJ}&quot;
end
rule &apos;.o&apos; =&amp;gt; &apos;.f&apos; do |t|
    sh &quot;#{F90} #{FFLAG} -c #{t.source}&quot;
end
 
require &apos;rake/clean&apos;
CLEAN.include(&apos;*.o&apos;)
CLOBBER.include(&apos;main.e&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rakefile에서는 &lt;code&gt;rule&lt;/code&gt;이라는 함수가 Makefile의 확장자법칙과 같은 역할을 합니다. &lt;code&gt;FileList&lt;/code&gt; 명령은 glob pattern (여기서는 &lt;code&gt;‘*.f’&lt;/code&gt;)을 받아들여서 해당하는 파일들의 목록을 만들어주고, &lt;code&gt;FileList&lt;/code&gt; 객체의 &lt;code&gt;ext&lt;/code&gt; method는 목록에 있는 파일들의 확장자를 원하는 확장자로 바꿔서 새로운 FileList를 만들어줍니다. 앞에서 dependency list를 불러올 때 &lt;code&gt;t.prerequisites.join(&apos; &apos;)&lt;/code&gt;이라고 사용했었는데 여기서는 &lt;code&gt;t.source&lt;/code&gt;라고 사용했습니다. 앞의 방법은 전체 dependency list를 문자열로 만들어주고(‘ ‘을 이용하여 각각을 합치죠), 뒤의 방법은 dependency list의 첫 번 째 항목만 문자열로 만들어줍니다. 위의 예에서는 dependency list에 &lt;code&gt;‘.o’&lt;/code&gt;에 해당하는 &lt;code&gt;‘.f’&lt;/code&gt; 파일 하나만 있으니까 &lt;code&gt;t.source&lt;/code&gt;라고 사용해도 무관하겠죠?&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;작업 설명&lt;/h1&gt;
&lt;p&gt;Makefile에 없고 Rakefile에만 있는 기능 중 하나로, task에 설명을 달 수 있는 기능이 있습니다. task 또는 file task 바로 윗 줄에&lt;br&gt;
&lt;code&gt;desc &quot;description&quot;&lt;/code&gt;&lt;br&gt;
이라고 설명을 추가해주면 &lt;code&gt;rake -T&lt;/code&gt;라고 실행했을 때 설명과 함께 task 목록을 보여줍니다. Rakefile을 직접 보지 않고도 안에 무슨 task가 있는지 확인할 수 있는 유용한 기능이죠^^&lt;/p&gt;
&lt;p&gt;더 자세한 내용은 다음 &lt;a href=&quot;http://docs.seattlerb.org/rake/&quot;&gt;site&lt;/a&gt;를 참고하세요.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;예전에 다른 블로그에 올렸던 글인데, 이곳에 복사해둡니다.&lt;/em&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>포트란과 연산자 오버로딩</title><link>https://pkgpl.org/2014/07/13/fortran_operator_overloading/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/13/fortran_operator_overloading/</guid><pubDate>Sat, 12 Jul 2014 15:03:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://pkgpl.org/2014/07/12/fortran_function_overloading/&quot;&gt;함수 오버로딩&lt;/a&gt;과 마찬가지로, &lt;a href=&quot;http://ko.wikipedia.org/wiki/연산자_오버로딩&quot;&gt;연산자 오버로딩도&lt;/a&gt; 객체지향 프로그래밍의 다형성과 관련된 개념입니다. 포트란 90에서 연산자 오버로딩을 사용하는 방법을 살펴보겠습니다. 아래 코드는 이차원 좌표 자료형과 두 개의 점을 더하는 함수 예제입니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module point2d_op

type point
    real x, y
end type

contains

    type(point) function add(p1, p2) result(p)
    type(point), intent(in):: p1, p2
    p%x=p1%x+p2%x
    p%y=p1%y+p2%y
    end function

end module

program test_point2d_op
use point2d_op
type(point):: p1,p2,p3

p1%x=1.0 ; p1%y=2.0
p2%x=3.0 ; p2%y=4.0

&lt;strong&gt;p3=add(p1,p2)&lt;/strong&gt;

print*, p3%x,p3%y
end program
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;새로운 자료형을 정의했으니 새로운 자료형에 대응하는 더하기 연산도 따로 정의할 필요가 있습니다. 그런데 &lt;code&gt;p3=add(p1,p2)&lt;/code&gt;와 같이 쓰는 것보다는 &lt;code&gt;p3=p1+p2&lt;/code&gt;로 쓰는 것이 더 직관적이고 이해하기 쉽겠죠. 이 때 사용하는 것이 연산자 오버로딩입니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;연산자 오버로딩&lt;/h1&gt;
&lt;p&gt;포트란에서는 &lt;code&gt;interface&lt;/code&gt;문을 사용하여 이미 존재하는 연산자를 오버로드 하거나 새로운 연산자를 정의할 수 있습니다. 아래 예제는 &lt;code&gt;+&lt;/code&gt; 연산자를 오버로드 하는 예제입니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module point2d_op

type point
    real x, y
end type

&lt;strong&gt;interface operator (+) 
    module procedure:: add 
end interface&lt;/strong&gt;

contains

    type(point) function add(p1, p2) result(p)
    type(point), intent(in):: p1, p2
    p%x=p1%x+p2%x
    p%y=p1%y+p2%y
    end function

end module

program test_point2d_op
use point2d_op
type(point):: p1,p2,p3

p1%x=1.0 ; p1%y=2.0
p2%x=3.0 ; p2%y=4.0

&lt;strong&gt;p3 = p1 + p2&lt;/strong&gt;

print*, p3%x,p3%y
end program
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;수학 연산자를 오버로딩할 때에는 수학적 정의에 합당하도록 또는 이해하기 쉽도록 정의하는 것이 좋습니다. 위의 &lt;code&gt;add&lt;/code&gt; 함수를 &lt;code&gt;-&lt;/code&gt; 연산자에 오버로딩하는 것도 가능하나 그렇게 되면 프로그래밍할 때 문제가 발생하겠죠.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;새로운 연산자 정의&lt;/h1&gt;
&lt;p&gt;연산자를 오버로드하지 않고 새로 정의할 수도 있습니다. 새로 정의하는 연산자는 &lt;code&gt;.name.&lt;/code&gt;과 같이 &lt;code&gt;&apos;.&apos;&lt;/code&gt;으로 시작해서 &lt;code&gt;&apos;.&apos;&lt;/code&gt;으로 끝나야 합니다. 아래 예제는 &lt;code&gt;add&lt;/code&gt; 함수를 &lt;code&gt;.add.&lt;/code&gt; 연산자로 정의한 경우입니다. &lt;code&gt;p3=add(p1,p2)&lt;/code&gt; 대신 &lt;code&gt;p3=p1.add.p2&lt;/code&gt;와 같이 사용한 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module point2d_op

type point
    real x, y
end type

&lt;strong&gt;interface operator (.add.) 
    module procedure:: add 
end interface&lt;/strong&gt;

contains

    type(point) function add(p1, p2) result(p)
    type(point), intent(in):: p1, p2
    p%x=p1%x+p2%x
    p%y=p1%y+p2%y
    end function

end module

program test_point2d_op
use point2d_op
type(point):: p1,p2,p3

p1%x=1.0 ; p1%y=2.0
p2%x=3.0 ; p2%y=4.0

&lt;strong&gt;p3 = p1 .add. p2&lt;/strong&gt;

print*, p3%x,p3%y
end program
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>포트란과 함수 오버로딩</title><link>https://pkgpl.org/2014/07/12/fortran_function_overloading/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/12/fortran_function_overloading/</guid><pubDate>Sat, 12 Jul 2014 14:07:02 GMT</pubDate><content:encoded>&lt;h1 aria-level=&quot;2&quot;&gt;포트란과 객체지향 프로그래밍&lt;/h1&gt;
&lt;p&gt;포트란이라 하면 옛날 언어라고 생각하기 쉬운데, 포트란 언어도 시대의 흐름에 따라 계속 발전해 오고 있습니다. 특히, 2003버전부터는 클래스와 상속 등을 지원하는 객체지향 프로그래밍 언어라 할 수 있습니다. 안타깝게도, 한글로 된 포트란 서적이 별로 없고, 출판된 것도 95버전까지밖에 안 나와 있어서 앞으로 블로그에서 몇 가지 객체지향 프로그래밍과 관련된 기능들을 소개하고자 합니다.&lt;/p&gt;
&lt;h2&gt;포트란과 함수 오버로딩&lt;/h2&gt;
&lt;p&gt;함수 오버로딩이란 같은 이름의 서브프로그램(서브루틴, 함수, 메소드 등)이 인자에 따라 다른 기능을 하는 것을 말합니다. 객체지향 프로그래밍의 다형성과 관련된 개념인데, 포트란에서는 90버전에 도입된 &lt;code&gt;interface&lt;/code&gt;문을 이용하여 적용 가능합니다.&lt;/p&gt;
&lt;p&gt;아래 예제는 2차원 좌표라는 자료형을 정의하고 좌표들 사이의 거리를 구하는 함수를 구현한 예제입니다. 자료형을 정의할 때 single precision 자료형 &lt;code&gt;point_sp&lt;/code&gt;와 double precision 자료형 &lt;code&gt;point_dp&lt;/code&gt; 두 가지를 정의했고, 따라서 함수도 single precision용 &lt;code&gt;distance_sp&lt;/code&gt;와 double precision용 &lt;code&gt;distance_dp&lt;/code&gt; 두 가지를 정의했습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module point2d

type point_sp
    real x, y
end type

type point_dp
    real(kind=8):: x,y 
end type

contains

    real function distance_sp(p1, p2) result(dist)
    type(point_sp), intent(in):: p1, p2
    dist=sqrt((p1%x-p2%x)**2+(p1%y-p2%y)**2)
    end function

    real(kind=8) function distance_dp(p1, p2) result(dist)
    type(point_dp), intent(in):: p1, p2
    dist=dsqrt((p1%x-p2%x)**2+(p1%y-p2%y)**2)
    end function 

end module

program test_point2d
use point2d
type(point_sp):: s1,s2
type(point_dp):: d1,d2
real:: dist_s
real(kind=8):: dist_d

s1%x=0.0 ; s1%y=0.0
s2%x=3.0 ; s2%y=4.0

d1%x=0.0d0 ; d1%y=0.0d0
d2%x=3.0d0 ; d2%y=4.0d0

&lt;strong&gt;dist_s=distance_sp(s1,s2)
dist_d=distance_dp(d1,d2)&lt;/strong&gt;

print*, dist_s, dist_d
end program

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 예제에서 두 개의 함수가 하는 일은 같지만, 정적 자료형 언어의 특성상 자료형에 따라 두 개의 함수를 정의해야 했습니다. 이 프로그램은 간단해서 별 문제가 없지만, 프로그램이 복잡해지면 이렇게 같은 기능의 다른 함수들로 인해 인터페이스가 복잡해지게 됩니다. 같은 기능의 함수들을 single/double과 같은 자료형에 상관없이 같은 이름으로 사용할 수 있다면 프로그래밍 인터페이스가 좀 더 단순해지겠죠. 위의 모듈에 아래의 interface 구문을 넣으면 &lt;code&gt;distance_sp&lt;/code&gt; 함수와 &lt;code&gt;distance_dp&lt;/code&gt; 함수를 모두 &lt;code&gt;distance&lt;/code&gt;라는 이름으로 사용할 수 있습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;interface distance
    module procedure:: distance_sp
    module procedure:: distance_dp
end interface
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 선언해 놓으면 두 함수의 인자가 두 개의 &lt;code&gt;point_sp&lt;/code&gt;와 두 개의 &lt;code&gt;point_dp&lt;/code&gt;로 다르기 때문에 인자의 자료형을 가지고 어떤 함수를 사용해야하는지 판단할 수 있게 됩니다. 만약 두 함수의 인자가 동일하다면 &lt;code&gt;interface&lt;/code&gt;문을 사용할 수 없습니다. 아래는 함수 오버로딩을 사용하도록 수정한 예제입니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;module point2d

type point_sp
    real x, y
end type

type point_dp
    real(kind=8):: x,y 
end type

&lt;strong&gt;interface distance
    module procedure:: distance_sp
    module procedure:: distance_dp
end interface&lt;/strong&gt;

contains

    real function distance_sp(p1, p2) result(dist)
    type(point_sp), intent(in):: p1, p2
    dist=sqrt((p1%x-p2%x)**2+(p1%y-p2%y)**2)
    end function

    real(kind=8) function distance_dp(p1, p2) result(dist)
    type(point_dp), intent(in):: p1, p2
    dist=dsqrt((p1%x-p2%x)**2+(p1%y-p2%y)**2)
    end function 

end module

program test_point2d
use point2d
type(point_sp):: s1,s2
type(point_dp):: d1,d2
real:: dist_s
real(kind=8):: dist_d

s1%x=0.0 ; s1%y=0.0
s2%x=3.0 ; s2%y=4.0

d1%x=0.0d0 ; d1%y=0.0d0
d2%x=3.0d0 ; d2%y=4.0d0

&lt;strong&gt;dist_s=distance(s1,s2)
dist_d=distance(d1,d2)&lt;/strong&gt;

print*, dist_s, dist_d
end program

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자료형에 상관없이 &lt;code&gt;distance&lt;/code&gt;라는 함수를 이용하여 거리를 계산하고 있음을 알 수 있습니다. 물론 위에서 &lt;code&gt;distance_sp&lt;/code&gt;와 &lt;code&gt;distance_dp&lt;/code&gt;도 사용 가능합니다. 함수 오버로딩을 사용한다고 프로그램의 실행 속도가 빨라지지는 않습니다. 하지만 서브프로그램들의 인터페이스를 단순화하여 프로그래밍을 좀 더 편하게 할 수 있다는 장점이 있습니다.&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>Makefile 사용법</title><link>https://pkgpl.org/2014/07/12/makefile_basic/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/12/makefile_basic/</guid><pubDate>Sat, 12 Jul 2014 13:09:28 GMT</pubDate><content:encoded>&lt;p&gt;Makefile의 기초적인 사용법을 알아봅시다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;Makefile이 필요한 경우&lt;/h1&gt;
&lt;p&gt;먼저, 다음과 같이 3개의 source 파일이 있을 때 컴파일하는 과정을 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;첫 번째 파일: main.f&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;       implicit none
       print *, &apos;main&apos;
       call sub1()
       call sub2()
       end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 번째 파일: sub1.f&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;       subroutine sub1()
       print*, &apos;sub1&apos;
       end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세 번째 파일: sub2.f&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;       subroutine sub2()
       print*, &apos;sub2&apos;
       end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;main.f 파일에서 sub1.f와 sub2.f에 있는 subroutine들을 불러오는 매우 간단한 프로그램입니다. 여기서는 하나의 파일 안에 subroutine을 다 넣는 것이 더 편하지만, Makefile 연습을 위해 세 개의 파일로 나누어 놓았습니다.&lt;br&gt;
이렇게 세 개의 파일을 가지고 실행 파일을 만들기 위한 명령은 다음과 같죠.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;f77 -c -O2 -o main.o main.f
f77 -c -O2 -o sub1.o sub1.f
f77 -c -O2 -o sub2.o sub2.f
f77 -o main main.o sub1.o sub2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 명령에서 &lt;code&gt;-c&lt;/code&gt; 옵션은 source code를 가지고 object file을 생성하라는 의미입니다. 각각의 source file들에 대해 object file을 생성하고 나중에 링크시켜서 실행파일을 만듭니다. &lt;code&gt;-O2&lt;/code&gt;는 compile 할 때 optimization level 을 2로 하라는 의미, &lt;code&gt;-o 파일명&lt;/code&gt; 은 output file을 &lt;code&gt;-o&lt;/code&gt; 다음에 나오는 파일명으로 만들라는 의미입니다. 마지막 줄에서 세 개의 objective file들을 링크시켜서 &lt;code&gt;main&lt;/code&gt; 이라는 실행파일을 생성합니다. 실행 파일의 실행 결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;$ ./main
main
sub1
sub2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;잘 실행됩니다. 그런데 만약 sub1.f 파일을 수정했다면 어떻게 해야할까요? 다시 컴파일하기 위해서는&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;f77 -c -O2 -o sub1.o sub1.f
f77 -o main main.o sub1.o sub2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;라고 수정한 파일만 다시 컴파일한 후, 다른 object file들과 링크시켜서 실행파일을 만들어야겠죠. 좀 귀찮습니다. 자동으로 할 수 있으면 좋겠죠. shell script를 하나 만들어서 처음의 컴파일 명령 4줄을 다 써 넣으면 자동으로 실행할 수 있습니다. 하지만, 그렇게 되면 sub1.f 파일을 고쳤을 때 main.f와 sub2.f 파일까지 새로 컴파일하게 됩니다. 프로그램이 간단할 때는 큰 문제가 없지만, 프로그램이 크고 복잡해지면 컴파일 시간이 오래 걸린다는 문제가 생기게 됩니다. Source code 내용에 따라서 특정 code는 다른 code보다 먼저 컴파일해야만 하는 경우도 생길 수 있습니다. 이런 경우에 편리하게 쓸 수 있는 프로그램이 바로 make입니다. make는 실행했을 때 현재 디렉토리에 있는 Makefile 이라는 파일을 찾아 build 작업을 수행합니다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;Makefile 작성법&lt;/h1&gt;
&lt;p&gt;Makefile의 작성법은&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;Target: Dependency list
[Tab] Command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;와 같습니다. Target은 만들고 싶은 대상, Dependency list는 Target을 만들기 전에 먼저 만들어져야 할 대상들, Command는 Target을 만드는 방법(command line 명령어)입니다. 한 가지 주의할 점은 Command 앞에는 Tab이 들어가야 한다는거죠. 그럼 위의 세 파일을 컴파일하기 위한 기초적인 Makefile을 살펴보겠습니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;# target: dependency list
# [tab] command
F77=gfortran

all: main

main: main.o sub1.o sub2.o
    $(F77) -O2 -o main main.o sub1.o sub2.o
main.o: main.f
    $(F77) -O2 -c main.f
sub1.o: sub1.f
    $(F77) -O2 -c sub1.f
sub2.o: sub2.f
    $(F77) -O2 -c sub2.f
clean:
    rm main main.o sub1.o sub2.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;F77=gfortran&lt;/code&gt; 이라고 먼저 선언을 했습니다. 여기서 &lt;code&gt;F77&lt;/code&gt;은 매크로(일종의 변수)입니다. 이런식으로 선언을 해두면 뒤에 &lt;code&gt;$(F77)&lt;/code&gt;과 같이 필요할 때 불러서 쓸 수 있습니다. 컴파일러를 바꿀 때 &lt;code&gt;gfortran&lt;/code&gt; 대신에 &lt;code&gt;f77&lt;/code&gt; 이나 &lt;code&gt;ifort&lt;/code&gt; 등으로 바꿔주면 되겠죠.&lt;/p&gt;
&lt;p&gt;다음에 나오는게 &lt;code&gt;all&lt;/code&gt; 이라는 Target입니다. Dependency list에는 &lt;code&gt;main&lt;/code&gt;이 있고 Command는 없네요. Command line에서 make를 실행하면 현재 디렉토리에 있는 Makefile을 찾아 제일 처음에 나오는 Target만 실행합니다. &lt;code&gt;make target1&lt;/code&gt;과 같이 실행하면 Makefile내에서 &lt;code&gt;target1&lt;/code&gt; 이라는 Target을 찾아 실행합니다. 따라서 맨 처음 Target을 &lt;code&gt;all&lt;/code&gt; 이라고 지정해두고 Dependency list에 자신이 만들고 싶은 Target들을 적어두면 make만 쳐서 원하는 Target들을 한 번에 만들 수 있겠죠. 전체적인 compile 과정은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;제일 처음에 나오는 &lt;code&gt;all&lt;/code&gt; 이라는 Target을 만나서 Dependency list를 확인한다. &lt;code&gt;main&lt;/code&gt;이라는 Dependency를 찾았다.&lt;/li&gt;
&lt;li&gt;Dependency를 만족하기 위해 &lt;code&gt;main&lt;/code&gt;이라는 Target을 찾는다. 그리고 &lt;code&gt;main&lt;/code&gt;의 Dependency list – &lt;code&gt;main.o, sub1.o, sub2.o&lt;/code&gt; 를 찾았다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main.o&lt;/code&gt;라는 Target을 찾아서 Dependency &lt;code&gt;main.f&lt;/code&gt;를 찾고 현재 디렉토리에 &lt;code&gt;main.o&lt;/code&gt; 파일이 없거나 &lt;code&gt;main.o&lt;/code&gt; 파일의 수정 시간이 &lt;code&gt;main.f&lt;/code&gt; 파일의 수정시간보다 이전일 때 &lt;code&gt;gfortran -O2 -c main.f&lt;/code&gt; 라는 Command를 실행한다. 그렇지 않은 경우에는 아무 것도 실행하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main.o&lt;/code&gt;가 잘 만들어졌으면 다시 &lt;code&gt;main&lt;/code&gt; 이라는 Target으로 넘어가 &lt;code&gt;sub1.o&lt;/code&gt;, &lt;code&gt;sub2.o&lt;/code&gt;라는 Dependency를 같은 방법으로 만족하고 돌아온다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;의 Dependency 세 개가 다 만족되었으면 &lt;code&gt;gfortran -O2 -o main main.o sub1.o sub2.o&lt;/code&gt; 라는 Command를 실행하여 &lt;code&gt;main&lt;/code&gt;이라는 Target을 만든다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;이라는 Target이 만들어졌으면 &lt;code&gt;all&lt;/code&gt;이라는 Target으로 돌아간다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;all&lt;/code&gt;의 Dependency가 다 만족되었지만, Command가 없으므로 make가 끝난다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;clean&lt;/code&gt;이라는 Target은 처음에 나오지도 않고 다른 Target의 Dependency 에도 들어가지 않으니 실행이 안 됩니다. 명령줄에서 make clean이라고 실행했을 때만 실행이 되죠. &lt;code&gt;clean&lt;/code&gt;은 Dependency list가 비어있으니까 make clean이라고 실행하면 해당하는 Command를 항상 실행하게 됩니다. 보통 make로 생성된 파일들을 지우기 위해 &lt;code&gt;clean&lt;/code&gt;이라는 Target을 만듭니다.&lt;/p&gt;
&lt;p&gt;여기까지만 배우고 끝내기에는 아쉽습니다. Makefile에는 강력한 기능들이 많기 때문이죠. 몇 개만 더 살펴봅시다.&lt;/p&gt;
&lt;h1 aria-level=&quot;2&quot;&gt;확장자 규칙&lt;/h1&gt;
&lt;p&gt;아래의 Makefile은 compiler과 compile option이 약간 바뀐 것 말고는 위의 Makefile과 같은 기능을 합니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;# $^ : dependency list
# $@ : target

F77=ifort
FFLAG=-assume byterecl -O2
TARGET=main
OBJECTS=main.o sub1.o sub2.o

all: $(TARGET)

$(TARGET): $(OBJECTS)
    $(F77) -o $@ $^

.SUFFIXES: .o .f
%.o: %.f
    $(F77) ${FFLAG} -c $&amp;lt;

clean:
    rm $(TARGET) $(OBJECTS)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Command 위치에서 &lt;code&gt;$^&lt;/code&gt;는 Dependency list를 자동으로 입력해줍니다. 또한 &lt;code&gt;$@&lt;/code&gt;는 Target 이름을 자동으로 입력해줍니다.&lt;/p&gt;
&lt;pre tabindex=&quot;0&quot;&gt;&lt;code&gt;.SUFFIXES: .o .f
%.o: %.f
    $(F77) ${FFLAG} -c $&amp;lt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;는 확장자 규칙으로, &lt;code&gt;.SUFFIXES: .o .f&lt;/code&gt; 는 &lt;code&gt;.o&lt;/code&gt; 라는 확장자와 &lt;code&gt;.f&lt;/code&gt;라는 확장자를 특별히 중요하게 생각하라는 뜻입니다. 그 아래에 나오는 내용은 &lt;code&gt;.o&lt;/code&gt; 확장자를 가진 Target에 대해 &lt;code&gt;.f&lt;/code&gt; 파일을 이용한 Dependency 와 Command를 자동으로 생성해주는 기능을 합니다. 따라서 처음의 Makefile에 있었던 &lt;code&gt;main.o, sub1.o, sub2.o&lt;/code&gt; 라는 Target과 Dependency, Command를 자동으로 만들어줍니다. 한 가지 주의할 점은, 확장자 규칙에서는 앞서 나왔던 &lt;code&gt;$^&lt;/code&gt;가 아닌, &lt;code&gt;$&amp;lt;&lt;/code&gt;를 사용한다는 점입니다. &lt;code&gt;$&amp;lt;&lt;/code&gt;는 확장자 규칙에서만 사용되며, 타겟보다 나중에 변경된 종속 항목들을 의미합니다. Build 과정이 복잡할 때 Makefile은 큰 힘을 발휘합니다.&lt;/p&gt;
&lt;p&gt;더 자세한 내용을 알고 싶으신 분들은 &lt;a href=&quot;http://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make.html&quot;&gt;임대영님의 GNU Make 강좌&lt;/a&gt;를 참고하세요.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;예전에 다른 블로그에 올렸던 글인데, 이곳에 복사해둡니다.&lt;/em&gt;&lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Computer</category></item><item><title>환영합니다</title><link>https://pkgpl.org/2014/07/12/welcome/</link><guid isPermaLink="true">https://pkgpl.org/2014/07/12/welcome/</guid><pubDate>Sat, 12 Jul 2014 12:32:36 GMT</pubDate><content:encoded>&lt;p&gt;탄성파 탐사 연구실을 찾아주신 분들을 환영합니다.&lt;/p&gt;
&lt;p&gt;단순히 연구실 소개만 하는 홈페이지가 아니라 방문자에게 조금이라도 유익한 홈페이지로 만들고자 블로깅을 시작합니다. 물리탐사 전공자 뿐 아니라 수치해석을 다루는 다른 전공자들에게도 참고가 될 수 있도록 주로 프로그래밍과 관련된 글들을 올릴 생각입니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;em&gt;The LORD bless you and keep you;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;the LORD make his face shine on you and be gracious to you;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;the LORD turn his face toward you and give you peace.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
</content:encoded><dc:creator>plusha</dc:creator><category>Uncategorized</category></item></channel></rss>