LLM으로 계정 과목 자동 추천 시스템 만들기

cola·2024년 9월 17일

프로젝트 개요

회계에서 계정 과목이란 돈에 대해서 이름을 붙이는 것이다. 그런데 계정 과목이라는 것이 양도 많고 헷갈려서 LLM을 통해서 상황에 맞는 계정 과목을 추천해주면 좋겠다고 생각했다.

데이터 수집

먼저 어떤 회계 기준과 지원하는 계정 과목의 범위를 정해야한다. 국제회계기준(IFRS)에서 다루는 핵심적인 계정 과목들로 범위를 정했다.

https://www.ifrs-gaap.com/ifrs-chart-accounts
위 사이트에서 데이터를 복붙후 파이썬으로 파싱하여 전체 리스트를 csv로 추출하였다.
계정 과목은 "자산 > 부동산"과 같은 식으로 계층 구조를 가지기에 '>'로 계층 구조를 표현하였다.

title
"Assets > Property, plant and equipment > Land and Land Improvements"
"Assets > Property, plant and equipment > Buildings"
"Assets > Property, plant and equipment > Machinery and Equipment"
"Assets > Property, plant and equipment > Fixtures and fittings"
...

예시 데이터 수집

수집 방안

어떤 방식으로 LLM 학습을 진행할지 고민이 많았는데 결론적으로는 chatgpt를 이용해서 각 라벨에 대해서 예시 데이터를 받아서 input data로 사용하고 라벨을 output으로 사용하기로 했다.

"Assets > Property, plant and equipment > Buildings" 이라는 라벨이 있으면 gpt를 통해 예시들을 받아 온다.

"I buy a new office building"라는 예시가 있다고 하면 학습에서 입력으로 사용되고 출력은 "Assets > Property, plant and equipment > Buildings"이 되는 것이다.

추가 고민했던 사항

pdf로 학습을 하려 했으나, pdf 선정이 어렵고 데이터 추출도 어렵다. 어렵게 추출했다 하더라도 원하는 데이터 포맷으로 변환 하고 데이터 증강을 해야하기에 번거로운 문제가 있었다.

chatgpt에서 IFRS에 대해서 몇가지 질문을 했었는데 IFRS에 대해서 잘 알고 있음을 확인해서 chatgpt를 통해 수집한 데이터의 신뢰성에 큰 문제가 없을 것으로 판단했다.

사용 프롬프트

너는 회계사야. ifrs 회계 규칙에 따라서 조언을 해줘야해.

내가 어떤 회계 계정 과목을 말하면, 그 예시에 해당하는 문장을 알려줘야해.

알려줄때는 '내가~' 형태의 예시를 알려줘야해.

내가 회계 계정 과목을 말하면 100가지의 예시를 json 배열에 담아줘. 한줄로 출력해줘.

단 영어로 알려줘야해.
예시에 금액에 대한 부분은 포함되지 않도록 해줘.
문장의 동사는 다양할 수록 좋아

여러 프롬프트들을 시도하다 최종적으로 사용한 프롬프트이다.
원하는 데이터 분포를 만들기 위해 프롬프트를 튜닝하는 것도 생각보다 어려웠다.

데이터 수집 노가다 ON

라벨 109에 대해서 chatgpt한테 말하고 나온 결과 복붙하고를 반복해서 1시간 반정도 걸렸다... (사람이 할 짓이 못됨)

다음에 동일한 작업을 한다고 하면 돈을 조금 내더라도 api 연동을 하는게 정신 건강에 좋을 것 같다

중간중간 chatgpt 사용량 제한이 걸리면 시크릿 탭으로 가거나 다른 pc로 진행했다.

파인튜닝

베이스 모델 선정

gemma 모델은 파라미터 개수에 따라서 2b, 7b로 나뉘고, 베이스 모델과 질의 응답에 최적화하여 사전 학습된 it가 붙은 모델이 있다.

gpu가 한정적이므로 7b는 엄두도 못내고 2b 모델을 사용하였다.

gemma 2b 베이스 모델을 가지고 삽질을 했는데 데이터 양이 적어서 그런지 도무지 성능이 안나와서 결과적으로 gemma 2b it 모델을 사용했고 성능 향상에 큰 영향을 주었다.

학습 환경

캐글에서 제공해주는 Telsa P100 16GB를 사용했다

무료 크레딧을 활용해서 클라우드 GPU를 사용하려 했으나 NCloud는 신청서를 내야하고, Azure는 유료계정 전환이 필요해서 접었다... ~~

QLoRA

전체 코드는 https://www.kaggle.com/code/hellqq21321/train-account-title-recommendation

def generate_prompt(example):
    prompt_list = []
    for i in range(len(example['example'])):
        prompt_list.append(r"""<bos><start_of_turn>user
Recommend me which account title can i use in the case:

{}<end_of_turn>
<start_of_turn>model
{}<end_of_turn><eos>""".format(example['example'][i], example['title'][i]))
    return prompt_list

학습에 사용하는 프롬프트 포멧을 만드는 코드로 처음에 <eos>토큰을 끝에 안붙여 줘서 결과가 뒤에 주렁주렁 이상한게 붙어서 나왔다. eos 토큰은 프롬프트의 끝을 나타낸다.

lora_config = LoraConfig(
    r=6,
    lora_alpha = 8,
    lora_dropout = 0.05,
    target_modules=["q_proj", "o_proj", "k_proj", "v_proj", "gate_proj", "up_proj", "down_proj"],
    task_type="CAUSAL_LM",
)

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16
)

BASE_MODEL = "google/gemma-2b-it"

model = AutoModelForCausalLM.from_pretrained(BASE_MODEL, device_map="auto", quantization_config=bnb_config)
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, add_special_tokens=True)
tokenizer.padding_side = 'right'

주어진 GPU 리소스에서 학습을 진행하기 위해 QLoRA를 사용하였다. 양자해서 불러와서 학습을 진행하는데도 GPU램을 10GB 이상 잡아먹고, 실제 추론할때는 양자화 되지 않은 베이스 모델과 추가로 학습된 어뎁터를 가지고 사용하기에 베이스 모델 용량이 커서 15GB 정도가 사용되였다.

max_steps = 2000
loggin_steps = max_steps // 10

trainer = SFTTrainer(
    model=model,
    train_dataset=train_data,
    max_seq_length=512,
    args=TrainingArguments(
        output_dir="outputs",
#        num_train_epochs = 1,
        max_steps=max_steps,
        per_device_train_batch_size=1,
        gradient_accumulation_steps=4,
        optim="paged_adamw_8bit",
        warmup_steps=0.03,
        learning_rate=2e-4,
        fp16=True,
        logging_steps=loggin_steps,
        push_to_hub=False,
        report_to='none',
    ),
    peft_config=lora_config,
    formatting_func=generate_prompt,
)
trainer.train()

ADAPTER_MODEL = "lora_adapter"
trainer.model.save_pretrained(ADAPTER_MODEL)

max_step을 2000으로 잡아서 42분 가량이 학습에 소요 되었다.
실제 서비스에 모델을 활용할 정도의 성능을 얻기에 max_step 2000은 사실 많지 않은 횟수이기에 성능을 더 높이려면 더 많은 데이터와 더 많은 max_step이 필요하다.

결과물


쿼리에 대해서 원하는데로 결과가 잘 나옴을 확인 했다. 도파민 max

느낀점

finetuning은 학습에 드는 리소스가 많이 든다.

2b 모델 양자화 해서 돌리는데도 16GB 이상의 GPU가 필요했고 램 부족으로 배치 사이즈를 크게 할 수도 없었다. 학습하는데도 시간이 많이 들어서 실제 사용하려면 좋은 GPU를 여러대 사용해야 할텐데 비용이 만만치 않겠다.

실무에서 사용한다고 하면 프롬프트 엔지니어링, 프롬프트 체이닝, RAG와 같은 다른 기법들을 먼저 사용해보고 최후에 수단으로 쓰는게 좋을 것 같다고 생각이 들었다. 온라인으로 업데이트가 가능하고 비용도 적게 드는 RAG가 대부분의 케이스에서 활용성이 더 좋을 것 같다.

데이터 수집은 어려워

대용량 모델을 학습하기 위해서는 양질의 데이터가 대량으로 필요한데 데이터 구하는게 제일 힘들었다. 이러한 이유 때문인지 파인튜닝을 할때 생성형 AI를 쓰는 케이스가 많고, 생성형 AI의 중요도가 높다고 느꼈다. 생성형 모델이 발달하면 더 양질의 데이터를 만들 수 있고, 그 데이터로 좋은 모델을 만드는게 가능해졌다.

결론

결과물이 괜찮게 나오는게 너무 신기했고 파인튜닝의 프로세스에 대해서 알게되고 직접 해봐서 좋은 경험이었다.


레퍼런스

코드

참고한 자료

0개의 댓글