매직코드
article thumbnail

랭체인을 공부하게 된 이유

chat gpt의 상용화로 언어모델에 대한 관심이 높아지면서 자연스럽게 LLM을 공부하고자 하는 마음이 생겼다.

특히 인터넷상에서 검색할 수 있는 것들을 학습하여 어떤 대답이든 척척 내어놓는 모습을 보면서

개인적으로 보유하거나 회사 차원에서 보유하고 있는 데이터를 학습시켜 검색을 한다면 업무의 효율성이 올라갈 것 같았다.

개인적인 데이터를 사용하는 경우에는 오픈소스로 나와있는 언어모델을 호출해서 사용하면 되지만,

회사에서 사용하고자 하는 경우 민감한 데이터의 유출이 이루어지면 안되기 때문에 로컬에서 랭체인을 사용한 챗봇을 만들려면 어떻게 하면 좋을지 궁금해졌다.

 

이 주제를 시도하게 된 이유

openAI에서 chat gpt를 발표한 이후 많은 사람들의 관심이 Chat으로 넘어가게 되었다.

지금까지는 텍스트로만 질문하여 텍스트로 답변을 받는 방식으로 chat gpt를 써왔는데 gpt가 코드로도 답변을 해주는 만큼 데이터 입력과 설명을 잘 하면 코드작성에서 끝나지 않고 모델학습까지 한번에 해결해주지 않을까? 싶었다.

 

AI쪽으로 지식이 없는 사용자가 원하는 데이터를 넣고, Chat 형식으로 "분석해줘"라고 요구사항을 입력했을 때, 데이터 전처리부터 모델학습까지 자동적으로 진행하고 결과를 보여준다면 chat gpt를 사용하는 것 처럼 일반인들도 머신러닝, 딥러닝에 좀 더 쉽게 접근하고 이용할 수 있을 것 같았다. (이 프로젝트를 하면서 한편으로는 데이터 사이언티스트의 역할이 LLM+LangChain으로 대체되지 않을까...? 라는 생각도 있었다...)

 

접근 및 해결과정

> 모델 선정

처음에는 openai를 사용하지 않으려고 최근에 오픈된 Llama2 모델을 사용하려고 했지만 한국어가 잘 지원되지 않아 openai의 LLM모델을 api로 연결해서 사용하기로 했다. openAI에서 지원하는 다양한 모델들 중에서 Chat 모델인 gpt3.5-turbo를 처음에 썼었는데 생각보다 성능이 낮았고, Chat 모델이다보니 LangChain으로 연결했을 때 모든 결과가 대화형으로 나와서 모델학습을 진행하기에 메모리를 과하게 사용하는 경향이 있었다. 따라서 일반 LLM 모델인 'text-davinci-003'모델을 선택했다.

 

> 데이터 input

LLM모델에 csv데이터를 넣는 방법을 찾다보니 LangChain을 알게되었다. LLM모델이 언어모델이다보니 csv보다는 pdf를 넣어보는 레퍼런스가 많았는데 다행히 LangChain을 통해서 csv 파일을 LLM 모델에 넣는 방법을 LangChain 공식문서에서 찾을 수 있었다.

 

> 데이터 전처리 및 모델학습 자동화

(prompt설정)LLM으로 가장 많이 사용하는 Chat 형식은 text 형식으로 질문에 답해주거나 가지고 있는 데이터를 요약하는 정도였지만 내가 만들고자 하는 것은 데이터 전처리도 해야하고 모델학습도 진행해야한다. 그래서 prompt를 잘 작성하는게 가장 중요한 부분이었다. 같은 말을 하더라도 어떤 영어단어를 선택하느냐에 따라 과정이 많이 바뀌고 동일한 prompt여도 실행을 할 때마다 다른 결과를 보여주는 문제도 있었기 때문에 일관성 있게 동일하거나 비슷한 과정을 거쳐 결과를 낼 수 있도록 작성하려고 노력했다.

(코드저장)사용자에 대해서는 머신러닝을 아예 모르는 일반인을 대상으로 했지만, 머신러닝을 배우고자 하는 사람도 사용할 수 있기 때문에 자동화 과정에서 사용했던 코드를 사용자도 볼 수 있도록 코드를 저장할 수 있도록 했다.

 

 

실습코드

import warnings
warnings.filterwarnings(action='ignore')

# data
import os
import pandas as pd

# model
from langchain import OpenAI

# prompt
from langchain import PromptTemplate

# agent
from langchain.agents import create_pandas_dataframe_agent
from langchain.agents import AgentType
# openAI 설정
OPENAI_API_KEY = "본인 계정 api키 작성"
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY

api를 통해 llm을 사용하려면 돈을 지불해야하기 때문에 openai계정에 결제정보를 입력하고난 후에 불러와야한다.

과금하는 방식이기 때문에 평소에 코드 쓰는 것 처럼 막 돌려보기 말고 신중하게 돌려볼것!

 

데이터 전처리

# data
file_path = './data.csv'
df = pd.read_csv(file_path)

# model(text-davinci-003)
model = OpenAI(temperature=0)

# agent
agent = create_pandas_dataframe_agent(model,
                                      df,
                                      verbose=True,
                                      return_intermediate_steps=True,
                                     )

간단하게 실습할 예정이었기 때문에 타이타닉 데이터를 사용했다.

titanic.csv
0.06MB

 

return_intermediate_steps 파라미터를 통해 agent가 수행하는 Thought, Action, Action Input, Observation에 대한 내용을 기억하게 할 수 있다. 혹시 모델학습 자동화가 된다면 agent가 사용한 코드를 따로 뽑을 수 있을까 싶어서 찾아보다가 알게된 파라미터다. 나중에 python_code.py파일로 뽑을 수 있지만 사람이 직접 작성한것처럼 예쁘게 나오지 않아서 실질적으로 코드를 돌리는 수준까지는 어렵겠지만 한줄한줄 어떻게 수행했는지 확인하는데는 도움이 될 수 있을 것 같다.

 

# prompt
prompt_template = PromptTemplate.from_template("You are a data scientist who conducts data preprocessing and model learning. Don't indent when you write code." # 역할지정
                                               "Before starting the all process, please set random_seed with import random, random.seed() as {random_seed} for the consistency." # 시드지정
                                               "Use pandas library to preprocess the data." # 판다스 사용
                                               "When processing missing values, please process missing values as {missing_values}." # 결측치처리 방법 설정
                                               "If data column's dtype is float or int format, please use {scaler}." # 스케일링 설정
                                               "If data column's dtype is 'O' format, please use {encoder}. if you don't have object columns, don't do this." # 인코딩 설정
                                               "Save df as preprocessing.csv file at same directory, index=False." # 전처리 완료된 데이터 저장
                                              )

formatted = prompt_template.format(random_seed='100',
                                   missing_values='0',
                                   scaler='MinMaxScaler',
                                   encoder='LabelEncoder',
                                  )

answer = agent(formatted)

prompt에 사용한 중괄호{}는 사용자가 직접 입력할 수 있도록하는 변수를 표시한다.

prompt 문장을 하나하나 해석해보자면 아래와 같다.

 

You are a data scientist who conducts data preprocessing and model learning. Don't indent when you write code.

너는 데이터전처리와 모델학습을 수행하는 데이터사이언티스다. 코드를 작성할 때 들여쓰기를 하지 마라.

 

Before starting the all process, please set random_seed with import random, random.seed() as {random_seed} for the consistency.

모든 과정을 시작하기 전에 random_seed를 설정해라. 설정하는 코드는 import random, random.seed() as {random_seed}다.

코드의 formatted를 보면 random_seed는 100으로 설정했다.

 

Use pandas library to preprocess the data.

전처리를 할 때는 pandas를 사용해라. (이 설정을 넣어준 이유는 Dataframe전처리하는데 어떨때는 numpy를 쓰고 어떨때는 pandas를 사용하는데 나는 마지막에 csv파일로 저장하기 편하게 하려고 pandas를 이용하게 했다.)

 

When processing missing values, please process missing values as {missing_values}

결측치처리를 할 때, 결측값은 {missing_values}로 채워라.

코드의 formatted를 보면 missing_values는 0으로 설정했다.

 

If data column's dtype is float or int format, please use {scaler}.

float나 int형의 컬럼이 있으면 {scaler}를 사용해라.

코드의 formatted를 보면 scaler는 MinMaxScaler로 설정했다.

 

If data column's dtype is 'O' format, please use {encoder}. if you don't have object columns, don't do this.

object 컬럼이 있으면 {encoder}를 사용해라. 만약 object컬럼이 없으면 안해도 된다.

코드의 formatted를 보면 encoder LabelEncoder로 설정했다.

 

Save df as preprocessing.csv file at same directory, index=False.

전처리 완료된 df를 preprocessing.csv파일로 (현재디렉토리와)같은 디렉토리에 저장해라. index=False다.

 

 

길고 긴 Thought와 Action 끝에 전처리를 완료하여 완료된 df를 df.csv로 저장했다.

다음에는 저장할 파일명도 같이 넣어줄까 싶다.

 

코드확인

# 코드저장
# .py저장 --> 모든 코드를 저장
py_code = []
for i in range(len(answer['intermediate_steps'])):
    a = answer['intermediate_steps'][i][0].tool_input
    py_code.append(a)
    
with open('preprocessing.py', 'w') as f:
    for item in py_code:
        f.write(item + '\n')

전처리할 때 agent의 생각들을 보면 많은 코드들이 나온다.

그 중에서 Action Input에서 사용한 python 코드들을 모두 저장해봤다.

 

코드가 짧은 편이라서 예쁘게 나온 것 같으면서도 import 위치가 중간중간 들어가 있는 문제와

위에서 실행했던 코드가 에러때문에 한번 더 실행이 되면서 중복으로 작성된 문제를 발견할 수 있다.

이를 해결하기 위해서 중복된 코드를 지워보기도 하고 맨 마지막 코드만 불러와보기도 했는데, Chain을 돌릴 때마다 결과가 다르게 나와서 일관성 있는 코드를 뽑아내기 어려웠다. 하지만 이 부분은 계속 시도해보면 잘 뽑을 수 있을 것 같다.

 

코드를 뽑는 방법을 알아낸것이 아까우니 어떻게든 사용해보자 싶어서 나중에 streamlit으로 구현할 때 하나의 Action이 지나갈 때 마다 어떤 코드를 사용했는지 확인할 수 있게 하려고 한다.

 

간단한 모델학습

# data
file_path = './preprocessing.csv'
df = pd.read_csv(file_path)

# model(text-davinci-003)
model = OpenAI(temperature=0.1)

# agent
agent = create_pandas_dataframe_agent(model,
                                      df,
                                      verbose=True,
                                      return_intermediate_steps=True,
                                     )

# 기준 템플릿
prompt_template = PromptTemplate.from_template("You are a data scientist who conducts model learning." # 역할지정
                                               "preprocessing is done. you don't need do preprocessing. Do only model training. Don't indent when you write code." # 환경설명
                                               "Target columns is {target}." # 타겟설정
                                               "set np.random.seed(100) random.seed(100)." # 시드고정  
                                               "Traning classification model." # 모델 설정
                                               "print best metirc result and parameter values." # 결과
                                               "Save best model as best_model.pkl file in same directory." # 모델 저장
                                              )

formatted = prompt_template.format(target='Survived')
agent(formatted)

 

전처리 완료한 데이터를 넣을 수 있도록 한 다음 prompt를 작성했다.

preprocessing is done.

you don't need do preprocessing.

Do only model training.

Don't indent when you write code.

라는 문구를 넣어서 전처리를 하지 않고 모델학습만 수행할 수 있도록 했다.

 

모델은 간단한 모델부터 automl까지 모두 수행하긴 하는데 target를 지정하지 않으면 종종 이상한 컬럼을 label로 잡기도 하고 분류모델을 사용해야하는데 회귀모델을 사용하곤 한다. 그래서 사용자로부터 target을 받아올 수 있도록 했다.

target을 받아오니 확실히 사용해야할 모델을 잘 고른다.

 

 

타이타닉 데이터로 0.80 정도의 정확도가 나온 것을 보니 어느정도 잘 작동한다고 볼 수 있다.

 

prompt에서 모델설정 부분을 "Traning the model using h2o automl."로 수정하면 H2O를 이용한 Automl도 수행할 수 있다.

다만 H2O는 y값이 숫자면 자동으로 회귀모델을 사용하고, 문자면 자동으로 분류모델을 사용하기 때문에 H2O를 통해 AutoML을 사용하고자 한다면 데이터전처리를 좀 더 해줘야 한다.

 

보완할 점

> 전처리와 모델학습을 따로 수행

원래 계획은 전처리부터 모델학습까지 한번에 자동화 해주는 서비스를 만드는 것이었는데, Chain을 연결하는 부분에 있어서 너무 복잡했던건지 모델성능이 부족한건지 10번을 시도하면 8~9번은 에러가 나고 1~2번정도만 Final answer를 내주었다.

계속 사용하기에는 불안정하다고 판단하여 Chain을 이용하여 전처리를 하고, 전처리 한 데이터를 저장하여 모델학습할 때 다시 넣어주는 방식으로 진행했다.

 

> agent, prompt, tool 사용

LangChain 공식문서를 보면 agent는 tool을 통해서 좀 더 세밀하게 조정할 수 있을것 같은데 tool에대한 이해도가 낮기도 하고,

예제로 나와있는 체인종류나 모델종류는 내가 사용하고자하는 체인과 모델하고는 달라서 세부적인 코드가 변경되어 사용하기 어려운 점이 있었다. 그래서 지금은 prompt에 모든 설정을 text로 넣어서 결과값이 나오게 했는데, tool을 이용하면 좀 더 안정적으로 이용할 수 있을 것 같다.

 

> 웹 시각화

streamlit를 이용해 일반인도 사용할 수 있도록 웹으로 만들예정이다.

 

 

profile

매직코드

@개발법사

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!