태그 : FastTrack

  • FastTrack을 활용한 Domain adaptive language model fine-tuning

    By 권용근

    Introduction

    이번 글에서는 Backend.AI의 MLOps 플랫폼인 FastTrack을 이용하여 공급망(Supply chain) 및 무역 관련 도메인에 특화된 언어모델을 학습시키고, 평가하는 방법에 대해 설명합니다. 해당 언어모델을 위한 Base model로는 공급망 및 무역 도메인 데이터 세트를 통해 continual-pretrained된 gemma-2-2b-it 모델을 사용하였습니다. 사용처에 따라 Question Answering task에 특화된 모델을 학습시키기 위해 웹에서 직접 수집, 가공한 도메인 데이터 세트를 학습 가능한 질문과 답변으로 구성되는 포맷(이하 Q/A task)으로 변환하여 사용하였습니다.

    AI를 개발하는 과정에서는 데이터 전처리, 학습, 검증, 배포, 추론과 같은 단계를 거쳐야 합니다. 래블업의 FastTrack을 사용하면 위와 같은 각각의 단계를 하나의 파이프라인으로 구성할 수 있고, 파이프라인 구성에 따라 특정 단계를 건너뛰거나 단계별 자원량을 다르게 설정하는 등 손쉽게 커스터마이징 할 수 있습니다.

    Concept of Domain Adaptation

    본격적인 모델 학습에 들어가기 앞서, Domain Adaptation이라는 과정이 필요합니다. 생소하신 분들을 위해 짧게 설명하자면, Domain Adaptation이란 사전 학습된 모델을 특정 도메인에 적합하도록 개선하는 프로세스를 말합니다. 오늘날 우리가 접하는 대다수의 일반적인 언어모델들은 특정 분야에 전문적인 지식을 가지도록 만들어지지 않았습니다. 대부분의 모델은 일반적인 도메인에서의 데이터 세트를 사용하여 다음 토큰을 잘 예측할 수 있도록 학습한 뒤, 전반적인 사용 방향에 맞게 fine-tune 되어 만들어집니다. 그러나 전문 도메인에서 사용될 목적으로 모델을 만든다면, 일반적인 데이터 세트를 사용하여 학습시키는 것은 충분치 않습니다. 예를 들어, 범용적인 도메인에서 학습된 모델은 "이 영화가 매우 훌륭했다"와 같은 일반적인 문장의 맥락을 잘 파악할 수 있지만, "법원이 채무자의 자산을 압류하도록 명령했다"와 같은 법률 도메인의 문장은 제대로 해석하지 못할 수 있습니다. 이는 모델이 각 도메인에서 사용되는 특수한 용어와 표현을 학습하지 않았기 때문입니다. 또 다른 예시로, 어떠한 Q/A task가 주어졌다면 일반적인 데이터로는 Q/A task를 구현할 수 없을 가능성이 있습니다. 제대로 된 Q/A task를 처리하기 위해서는 Q/A task에 특화된 데이터 세트로 사전 학습된 언어 모델을 fine-tune하는 식으로 '특정한 도메인의 데이터'를 넣어주어야 하기 때문이죠. 이러한 fine-tuning 과정은 모델이 작업의 뉘앙스를 더 잘 이해하여 사용자의 domain-specific한 질문에 대해 효과적으로 답변할 수 있도록 합니다.

    이번 글에서는 공급망(Supply Chain Management, 이하 SCM) 및 무역 도메인에 특화된 모델을 개발하는 과정을 다룹니다. 위 그림에서 볼 수 있듯이, "영화"나 "여행" 같은 일반 도메인 용어와 "항공화물운송장", "대금결제인"과 같은 SCM 도메인 용어 사이에는 현격한 차이가 있습니다. 이러한 차이를 좁히기 위해 SCM과 무역 도메인에서의 데이터 세트를 활용하여, 해당 도메인에 대한 모델의 이해도를 높이고, 맥락을 더욱 정확하게 파악할 수 있도록 조정하는 것이 우리가 오늘 달성해볼 목표입니다. 정리하면, Domain Adaptation은 본질적으로 서로 다른 도메인 간의 격차를 해소, 새로운 맥락에서 모델이 더 나은 성능을 발휘할 수 있도록 돕는 과정이라고 할 수 있습니다.

    Train model from scratch vs DAPT

    그렇다면 처음부터 해당 도메인의 데이터 세트를 통해 학습(Train model from scratch)하면 되지 않을까요? 물론 가능하지만, 여러가지 한계점이 존재합니다. 만약 처음부터 해당 도메인의 데이터 세트를 통해 학습하게 되면, 해당 도메인에서의 지식은 물론 일반적인 도메인에서의 지식조차 없는 상황이기 때문에 더 많은 데이터 세트와 학습이 요구될 수 있습니다. 일반적인 도메인에서의 딥러닝을 위한 데이터 세트를 수집하는 것도 어렵지만, 특정 도메인에 국한된 양질의 데이터를 수집하는 것은 더욱 어려운 일입니다. 데이터를 수집했다 치더라도, 모델 학습에 맞게 전처리하는 과정에서 많은 시간과 비용이 발생하게 되죠. 따라서 모델을 처음부터 학습시키는 것은 해당 도메인의 데이터 세트를 충분히 확보하고 있고, 자원을 충분히 보유한 기업에 더 적합한 방법이라고 할 수 있습니다.

    만약 domain-adaptive 한 model을 개발하고 싶은데 아주 많은 데이터 세트를 확보하지 못했거나, 자원이 충분하지 않다면 어떻게 해야 할까요? 이런 경우 선택할 수 있는 방법이 Domain-Adaptive Pre-Training (DAPT)입니다. DAPT란, 이미 일반적인 도메인을 통해 충분히 학습된 모델을 특정 도메인의 데이터 세트로 continual pretraining (지속 학습)하여 도메인에 특화된 모델을 개발하는 과정을 말합니다. 이 방법은 일반적인 도메인에 대한 지식을 이미 보유하고 있는 모델을 추가로 학습시키는 방법이기 때문에, 모델을 처음부터 학습시키는 방법에 비해 상대적으로 적은 비용과 데이터 세트를 요구합니다.

    Development environment Setup

    1. 모델 학습에 앞서, 필요한 패키지들을 설치합니다.
    pip install bitsandbytes==0.43.2
    pip install deepspeed==0.14.4
    pip install transformers==4.43.3
    pip install accelerate==0.33.0
    pip install flash-attn==1.0.5
    pip install xforms==0.1.0
    pip install datasets==2.20.0
    pip install wandb
    pip install evaluate==0.4.2
    pip install vertexai==1.60.0
    pip install peft==0.12.0
    pip install tokenizers==0.19.1
    pip install sentencepiece==0.2.0
    pip install trl==0.9.6
    pip install bitsandbytes==0.43.2
    pip install deepspeed==0.14.4
    pip install transformers==4.43.3
    pip install accelerate==0.33.0
    pip install flash-attn==1.0.5
    pip install xforms==0.1.0
    pip install datasets==2.20.0
    pip install wandb
    pip install evaluate==0.4.2
    pip install vertexai==1.60.0
    pip install peft==0.12.0
    pip install tokenizers==0.19.1
    pip install sentencepiece==0.2.0
    pip install trl==0.9.6
    
    1. 모듈 가져오기
    import os
    import json
    from datasets import load_from_disk, Dataset,load_dataset
    import torch
    from transformers import AutoTokenizer, AutoModelForCausalLM, Gemma2ForCausalLM, BitsAndBytesConfig, pipeline, TrainingArguments
    from peft import LoraConfig, get_peft_model
    import transformers
    from trl import SFTTrainer
    from dotenv import load_dotenv
    import wandb
    from huggingface_hub import login
    

    Dataset preparation

    데이터 세트는 fine-tuning의 목적에 따라 다르게 준비되어야 합니다. 이 글에서는 무역 영역에 대한 질문에 효과적으로 답변할 수 있는 모델을 학습하는 것을 목표로 하기 때문에, 웹 크롤링을 통해 자체적으로 수집한 데이터 세트를 사용합하기로 결정했습니다. 데이터 세트는 무역 자격증 시험 데이터 세트, 무역 용어-정의 데이터 세트, 무역 강의 스크립트 데이터 세트의 세 가지 유형으로 분류됩니다.

    1. 무역 자격증 시험 데이터 세트

    질문: 다음 중 우리나라 대외무역법의 성격에 대한 설명으로 거리가 먼 것을 고르시오. 1. 우리나라에서 성립되고 이행되는 대외무역행위는 기본적으로 대외무역법을 적용한다. 2. 타 법에서 명시적으로 대외무역법의 적용을 배제하면 당해 법은 특별법으로서 대외무역법보다 우선 적용된다. 3. 대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다. 4. 관계 행정기관의 장은 해당 법률에 의한 물품의 수출·수입 요령 그 시행일 전에 지식경제부 장관이 통합하여 공고할 수 있도록 제출하여야 한다. 정답: 대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다. 질문: ...

    1. 무역 용어 정의 데이터 세트
    {
      "term": "(계약 등을) 완전 무효화하다, 백지화하다, (처음부터) 없었던 것으로 하다(Rescind)",
      "description": "계약을 파기, 무효화, 철회, 취소하는 것; 그렇지 않았음에도 불구하고 계약을 시작부터 무효인 것으로 선언하고 종결짓는 것."
    }
    
    
    1. 무역 강의 스크립트 데이터 세트

    예전에는 전자상거래 셀러가 엑셀에다가 입력을 해서 수출신고 데이터를 업로드 해서 생성을 했잖아요 그리고 대량으로 전송하는 셀러는 api를 통해서 신고를 했습니다 그런데 그 수출신고 정보의 원천정보를 뭐냐면 쇼핑몰에서 제공하는 판매 주문정보입니다 그래서 그 쇼핑몰에 직접 저희가 연계를 해서 판매 주문 정보를 가져올 수 있게끔 새 서비스를 만들었어요 그래서 API 연계된 쇼핑몰들이 있는데 그게 현재 5개가 연결되어 있는데 쇼피 쇼피파이 라자다 라쿠텐 q10이 있고요 아마존하고 위치도 연계 예정에 있습니다 그래서 셀러는 ...

    Q/A 작업에 알맞은 모델을 만들려면 데이터 세트를 질의응답 형식으로 변환해야 합니다. 첫 번째 데이터 세트인 무역 자격증 시험 데이터 세트와 두 번째 데이터 세트인 무역 용어 정의 데이터 세트는 간단한 코드를 사용하여 변환할 수 있지만, 세번째 데이터 세트인 무역 강의 스크립트 데이터 세트를 확인해 보면 대화 형식의 데이터를 직접 변환하기 어려워 보입니다. 이 경우에는 대화형 스크립트에서 대규모 언어 모델(LLM)을 활용하여 Q/A 쌍을 추출하는 접근 방식을 사용할 수 있습니다. 프롬프트와 그 결과는 다음과 같습니다.

    Prompt

    summary: {summary}
    Instruction: 다음 summary를 기반으로 질문과 해당 답변을 추출하세요.
    출력 형식은 JSON으로, 각 질문과 답변을 객체로 묶어 'qa_pairs'라는 배열 안에 넣어야 합니다.
    'questions' key에는 요약에서 도출된 질문 목록이 포함되어야 하며, 'answers' key에는 각 질문에 대한 해당 답변 목록이 포함되어야 합니다:
    출력 예시:
    {{"qa_pairs": [{{"question": "Question1", "answer": "Answer1"}},{{"question": "Question2", "answer": "Answer2"}},{{"question": "Question3", "answer": "Answer3"}},]...}}
    Output:
    

    Output

    {"qa_pairs":
      [
        {"question": "전자상거래 무역 플랫폼은 어떤 서비스를 제공하나요?", "answer": "판매 주문 관리, 창고 관리, 수출입 통관, 배송 관리 등 전자상거래 업무를 위한 다양한 서비스를 제공합니다"},
        {"question": "쇼핑몰과의 API 연계를 통해 무엇을 간소화할 수 있나요?", "answer": "판매 주문 정보를 자동으로 가져와 수출신고를 간소화할 수 있습니다"},
        {"question": "창고 관리 기능은 어떤 것을 관리할 수 있나요?", "answer": "자가 창고, 위촉 창고, 해외 풀필먼트 센터 등을 관리할 수 있습니다"},
        {"question": "수출입 통관 서비스는 어떤 기능을 제공하나요?", "answer": "미국 세관과 연동된 수출입 통관 서비스를 통해 미국 수출 시 수입 신고를 간편하게 처리할 수 있습니다"},
        {"question": "배송 관리 기능은 어떤 서비스를 지원하나요?", "answer": "우체국 EMS, DHL 등 개별 배송과 함께 해외 현지 라스트 마일 배송까지 지원합니다"}
      ]
    }
    

    이제 간단한 코드를 사용하여 각 데이터 세트를 Q/A 데이터 집합으로 변환할 준비가 된 것 같습니다. 아래의 코드를 사용하여 각 데이터 세트를 Q/A 형식으로 변환해 보겠습니다.

    import os
    import json
    import re
    from datasets import Dataset, concatenate_datasets, load_from_disk
    
    def replace_dot_number(text):
        result = re.sub(r'\.(\d+)\.', r'. \1.', text)
        return result
    
    def read_json(path):
        with open(path, 'r', encoding='utf-8') as f:
            return json.load(f)
    
    def write_json(data, path):
        with open(path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False)
    
    def dataset_maker(data:list) -> Dataset:
        return Dataset.from_list(data)
    
    def save_dataset(dataset, save_path):
        dataset.save_to_disk(save_path)
    
    def exam_qa_formatter():
        data = []
        root = 'dataset/exam_data'
        for file in sorted(os.listdir(root)):
            file_path = os.path.join(root, file)
            content = read_json(file_path)['fixed_text']
            question_list = content.split('질문:')[1:]
            for question in question_list:
                try:
                    question_and_options = replace_dot_number(question.split('정답:')[0]).strip()
                    answer = question.split('정답:')[1].strip()
                    data.append({"context": replace_dot_number(question), "question":question_and_options, "answer":answer})
    
                except Exception as e:
                    pass
        return data
    
    def description_to_term_formattter(kor_term, eng_term, description):
        context = f"{kor_term}: {description}"
        question = f"설명: '{description}' 이 설명에 해당하는 무역 용어는 무엇인가요?"
        answer = kor_term if eng_term is None else f"{kor_term}, {eng_term}"
        return context, question, answer
    
    def term_to_description(kor_term, eng_term, description):
        context = f"{kor_term}: {description}"
        question = f"'{kor_term}({eng_term})' 이라는 무역 용어는 어떤 의미인가요?" if eng_term is not None else f"'{kor_term}' 이라는 무역 용어는 어떤 의미인가요?"
        answer = description
        return context, question, answer
        
    def term_qa_formatter():
        data = []
        root = 'dataset/term_data'
        for file in os.listdir(root):
            file_path = os.path.join(root, file)
            term_set = read_json(file_path)
            if file == 'terms_data_2.json':
                term_set = [item for sublist in term_set for item in sublist]
            for pair in term_set:
                eng_term = pair.get('eng_term', None)
                if 'term' in pair.keys():
                    kor_term = pair['term']
                else:
                    kor_term = pair['kor_term']
                description = pair['description']
                context_1, question_1, answer_1 = description_to_term_formattter(kor_term, eng_term, description)
                context_2, question_2, answer_2 = term_to_description(kor_term, eng_term, description)
                data_1 = {"context": context_1, "question": question_1, "answer": answer_1} 
                data_2 = {"context": context_2, "question": question_2, "answer": answer_2} 
                data.append(data_1)
                data.append(data_2)
        return data
    
    def transcript_qa_formatter():
        data = []
        root = 'dataset/transcript_data/success'
    
        for file in sorted(os.listdir(root)):
            file_path = os.path.join(root, file)
            for line in open(file_path):
                line = json.loads(line)
                context = line['context']
                output = line['json_output']
    
                qa_pairs = json.loads(output)['qa_pairs']
                for pair in qa_pairs:
                    question = pair['question']
                    answer = pair['answer']
                    if type(answer) == list:
                        answer = answer[0]
                    data.append({"context": context, "question": question, "answer": answer})
        return data
    
    ###### Term dataset
    {'context': 'APEC 경제위원회(Economic Committee (EC)): 개별위원회나 실무그룹이 추진하기 어려운 여러분야에 걸친 이슈에 대한 분석적 연구작업을 수행하기 위해 결성된 APEC 기구,',
     'question': "설명: '개별위원회나 실무그룹이 추진하기 어려운 여러분야에 걸친 이슈에 대한 분석적 연구작업을 수행하기 위해 결성된 APEC 기구,' 이 설명에 해당하는 무역 용어는 무엇인가요?",
     'answer': 'APEC 경제위원회(Economic Committee (EC))'}
    
    ###### Transcript dataset
    {'context': '수입 신고는 일반적으로 입항 후에 하는 것이 원칙이며, 보세 구역에서 5부 10장을 작성하여 신고합니다',
     'question': '수입 신고는 언제 하는 것이 원칙인가요?',
     'answer': '수입 신고는 일반적으로 입항 후에 하는 것이 원칙입니다.'}
    
    ###### Exam dataset
    {'context': ' 다음 중 우리나라 대외무역법의 성격에 대한 설명으로 거리가 먼 것을 고르시오. 1. 우리나라에서 성립되고 이행되는 대외무역행위는 기본적으로 대외무역법을 적용한다. 2. 타 법에서 명시적으로 대외무역법의 적용을 배제하면 당해 법은 특별법으로서 대외무역법보다 우선 적용된다. 3. 대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다. 4. 관계 행정기관의 장은 해당 법률에 의한 물품의 수출·수입 요령 그 시행일 전에 지식경제부 장관이 통합하여 공고할 수 있도록 제출하여야  한다.정답: 대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다.',
     'question': '다음 중 우리나라 대외무역법의 성격에 대한 설명으로 거리가 먼 것을 고르시오. 1. 우리나라에서 성립되고 이행되는 대외무역행위는 기본적으로 대외무역법을 적용한다. 2. 타 법에서 명시적으로 대외무역법의 적용을 배제하면 당해 법은 특별법으로서 대외무역법보다 우선 적용된다. 3. 대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다. 4. 관계 행정기관의 장은 해당 법률에 의한 물품의 수출·수입 요령 그 시행일 전에 지식경제부 장관이 통합하여 공고할 수 있도록 제출하여야  한다.',
     'answer': '대외무역법은 국내법으로서 국민의 국내 경제생활에 적용되는 법률이기 때문에 외국인이 국내에서 행하는 무역행위는 그 적용 대상이 아니다.'}
    
    # Exam dataset
    Dataset({
        features: ['context', 'question', 'answer'],
        num_rows: 1430
    })
    
    # Term dataset
    Dataset({
        features: ['context', 'question', 'answer'],
        num_rows: 15678
    })
    
    # Transcript dataset
    Dataset({
        features: ['context', 'question', 'answer'],
        num_rows: 8885
    })
    
    # Concatenated dataset 
    Dataset({
        features: ['context', 'question', 'answer'],
        num_rows: 25993
    })
    

    Q/A 형식의 데이터 세트와 합쳐진 데이터 세트(학습 데이터 세트)는 위와 같습니다. 약 26,000개의 Q/A 쌍이 학습에 사용될 것으로 예상됩니다.

    이제 fine-tuning을 위한 데이터 세트가 준비되었습니다. 이 데이터 세트가 실제로 모델에 어떻게 입력되는지 확인해 보겠습니다.

    <bos><start_of_turn>user
    Write a hello world program<end_of_turn>
    <start_of_turn>model
    

    huggingface 웹사이트에서는 채팅 템플릿 형식과 모델의 프롬프트 형식 정의에 대한 정보가 포함된 gemma-2b-it의 모델 카드를 찾을 수 있습니다(gemma-2-2b-it). 즉, gemma에게 질문을 하려면 모델이 이해할 수 있는 형식의 프롬프트를 만들어야 하는 것이죠.

    대화의 시작은 <start_of_turn>으로 표시되며, 대화의 끝은 <end_of_turn>으로 표시됩니다. 화자는 사용자 및 모델로 지정되어 있음을 알 수 있습니다. 따라서 모델에게 질문을 할 때 프롬프트의 형식은 위와 같은 형식이어야 합니다.

    def formatting_func(example):
        prompt_list = []
        for i in range(len(example['question'])):
            prompt_list.append("""<bos><start_of_turn>user
        다음 질문에 대답해주세요:
        {}<end_of_turn>
        <start_of_turn>model
        {}<end_of_turn><eos>""".format(example['question'][i], example['answer'][i]))
            return prompt_list  
    

    이 문서에서는 Q/A 데이터 세트를 사용하여 모델을 학습시키는 데 중점을 두고 있으므로 '이런 종류의 질문에는 이렇게 대답해야 한다'는 식으로 접근하여 모델을 학습시킬 것입니다. 앞서 언급한 채팅 템플릿을 고려하면 위와 같은 형식으로 코드를 작성할 수 있습니다. 이때, 채팅 템플릿에 토큰이 명시적으로 포함되어 있지 않더라도 모델은 구분 기호 이상으로 더 많은 콘텐츠를 생성하려고 시도할 수 있습니다. 이 때 모델이 답변만 제공하고 턴을 종료하도록 하기 위해 토큰을 추가해줍니다.

    <bos><start_of_turn>user
    다음 질문에 대답해주세요:
    '(관세)감축률(Reduction Rate)' 이라는 무역 용어는 어떤 의미인가요?<end_of_turn>
    <start_of_turn>model
    관세를 감축하는 정도를 말함. 예를 들어 200%p에 관세감축률이 50%를 적용하면 감축 후 관세는 100%p가 됨. 극단적인 경우로 관세감축률이 100%이면 모든 관세는 감축 후에는 0%p가 됨.<end_of_turn><eos>
    

    실제 학습에서는 위와 같은 예시가 input으로 들어가게 됩니다. 이제 학습을 위한 데이터 세트 준비를 마쳤습니다.

    Training

    학습 코드는 아주 간단합니다. SFTTrainer를 사용하며, base model로는 이전에 SCM & 무역 데이터 세트를 통해 continual-pretrained 된 모델을 gemma-2-2b-it 모델을 사용합니다.

    model_id = "google/gemma-2-2b-it"
    output_dir = 'QA_finetune/gemma-2-2b-it-lora128'
    tokenizer = AutoTokenizer.from_pretrained(model_id, token=access_token)
    
    model = AutoModelForCausalLM.from_pretrained(
                # "google/gemma-2-2b-it",
                "yonggeun/gemma-2-2b-it-lora128-merged",
                device_map="auto",
                torch_dtype=torch.bfloat16,
                token=access_token,
                attn_implementation="eager", # attn_implementation,
                cache_dir="./models/models",
            )
    
    
    def formatting_func(example):
        prompt_list = []
        for i in range(len(example['question'])):
            prompt_list.append("""<bos><start_of_turn>user
    다음 질문에 대답해주세요:
    {}<end_of_turn>
    <start_of_turn>model
    {}<end_of_turn><eos>""".format(example['question'][i], example['answer'][i]))
        return prompt_list   
    
    
    def train(data):  
        valid_set = data["test"]
        valid_set.save_to_disk('QA_finetune/valid_set/gemma-2-2b-it-lora128')
    
        lora_config = LoraConfig(
            r=256,
            lora_alpha=32,
            lora_dropout=0.05,
            bias="none",
            target_modules=["q_proj", "o_proj", "k_proj", "v_proj", "gate_proj", "up_proj", "down_proj"],
            task_type="CAUSAL_LM",
        )
    
        training_args = TrainingArguments(
            per_device_train_batch_size=2,
            warmup_steps=2,
            logging_steps=1, 
            gradient_accumulation_steps=4,
            # num_train_epochs=3,
            num_train_epochs=3,  
            learning_rate=2e-4,
            save_steps=100,
            fp16=False,
            bf16=True,
            output_dir=output_dir,
            push_to_hub=True,
            report_to="wandb"
        )
    
        trainer = SFTTrainer(
            model=model,
            tokenizer=tokenizer,
            train_dataset=data['train'],
            args=training_args,
            formatting_func=formatting_func,
            peft_config=lora_config,
            max_seq_length=max_length,
            packing= False,
        )
    
        model.config.use_cache = False
    
        print("Training...")
        trainer.train()
        print("Training done!")
    

    Evaluation

    훈련이 성공적으로 완료되면 필수적으로 모델의 성능을 평가해야 합니다. 이 글에서는 특정 도메인에서의 Question Answering 성능을 평가하는 데 중점을 두었기 때문에 일반적인 모델의 벤치마크에 사용되는 것과는 다른 지표가 필요했습니다. 이 글에서는 SemScore와 Truthfulness를 활용하여 모델을 평가했습니다.

    SemScore: 대상 응답과 모델 응답 간의 의미적 텍스트 유사성을 기반으로 하는 평가 방법입니다.(SemScore)

    Evaluating Truthfulness: 이 방법은 LLM에 모델 응답과 답변을 제공한 다음 1에서 5까지의 척도로 진실성을 측정하는 방식입니다.(Truthfulness)

    Fasttrack pipeline

    이제 FastTrack에서 모델 학습에 사용될 파이프라인을 만들어보겠습니다. 파이프라인은 FastTrack에서 사용하는 작업 단위입니다. 각 파이프라인은 최소 실행 단위인 태스크(Task)의 묶음으로 표현될 수 있습니다. 하나의 파이프라인에 포함되는 여러 개의 태스크는 서로 의존 관계를 가질 수 있으며, 이 의존성에 따라 순차적으로 실행이 보장됩니다.

    Create Pipeline

    위 그림에서 파란색 '+' 버튼을 찾아 새 파이프라인을 만듭니다.

    파이프라인을 생성하면 파이프라인의 이름과 설명, 사용할 데이터 저장소의 위치, 그리고 파이프라인에서 공통적으로 적용할 환경변수 등을 선택할 수 있습니다. 필요한 정보를 입력한 후 하단의 "Save" 버튼을 클릭하여 파이프라인을 생성합니다.

    Drag and create task

    새 파이프라인이 만들어지면 작업 템플릿에 새 작업을 추가할 수 있습니다. Custom Task를 클릭해서 아래 작업 공간으로 끌고오면, task가 새롭게 생성됩니다.

    Enter information

    작업을 만들 때는 위와 같이 작업 실행에 필요한 정보를 입력해야 합니다. 태스크 이름과 설명을 이해하기 쉽게 작성하고, 단일 노드 또는 다중 노드 중 하나를 선택합니다. 본 문서에서는 단일 노드 훈련을 수행하므로 단일 노드를 선택하겠습니다.

    다음으로 명령어를 작성해야 합니다. 명령은 기본적으로 세션을 실행하는 명령어입니다. 실행할 스크립트가 오류 없이 작동할 수 있도록 마운트된 V-folder의 디렉터리를 정확하게 지정해야 합니다. 학습에 필요한 대부분의 패키지는 이미 세션에 설치되어 있지만, 추가 패키지를 설치해야 하거나 버전 문제가 있는 경우에는 패키지를 다시 설치해야 할 수 있습니다. 이 경우 requirements.txt 파일에서 필요한 패키지를 지정하고 설치 후 다른 스크립트를 실행할 수 있습니다.

    Resource configuration

    다음은 세션, 리소스 및 V-folder 설정입니다.

    본 글에서는 Pytorch 기반으로 코드를 작성하였지만, Pytorch 이외에도 Tensorflow, Triton server 등의 환경을 선택할 수 있습니다.

    FastTrack의 장점 중 하나는 리소스를 최대한 효율적으로 활용할 수 있다는 점입니다. 하나의 리소스 그룹 내에서도 여러 세션에 리소스를 분할하여 resource utilization rate를 극대화할 수 있습니다.

    데이터 세트 준비의 경우 별도의 GPU 연산이 필요하지 않기 때문에 GPU 리소스를 할당하지 않아도 괜찮습니다. 이를 통해 최소한의 리소스로 코드를 실행할 수 있으며, 이 시간 동안 다른 세션에 GPU 리소스를 할당할 수 있어 GPU 리소스가 유휴 상태로 남는 상황을 방지할 수 있습니다. 또한 병렬적으로 모델 학습이 필요한 경우(예: 10FGPU가 가용하고 각 훈련 세션에 5FGPU씩 필요한 경우) 모델을 병렬로 학습시킬 수 있죠. 이렇게 하면 리소스 낭비를 줄이고 학습 시간을 단축할 수 있습니다.

    준비한 데이터 세트와 학습 코드가 작성되어 있는 V-folder를 올바르게 선택합니다.

    Duplicate or delete task

    작업 블록의 우측 상단 미트볼 메뉴 아이콘 (⋯)을 누르면 생성된 작업을 복제하거나 삭제할 수 있습니다.

    FastTrack에서는 이와 같이 생성된 여러 개의 작업 사이 순서를 정할 수 있습니다. 이는 작업들 간의 의존성을 추가하는 과정입니다. 경우에 따라 여러개의 작업이 끝난 뒤에 다음 작업이 실행되도록 설정할 수도 있습니다. 이 경우에는 작업들 간의 의존성에 따라 모든 작업이 끝나기 전까지 다음 작업이 진행되지 않습니다. 완성된 예시는 위와 같습니다. 이번 글에서는 dataset preparation - fine-tuning - evaluation 순서로 작업을 진행합니다.

    각 작업이 올바르게 정의되었다면 'Run'을 클릭하여 파이프라인을 실행합니다.

    FastTrack 화면 좌측에서 생성했던 파이프라인들을 확인할 수 있습니다. 클릭하면 파이프라인 작업 세션에서 현재 실행 중인 작업 및 실행했던 작업들을 모니터링 할 수 있습니다.

    Monitoring jobs

    위와 같은 화면을 통해 작업을 모니터링 할 수 있습니다. 각 작업은 지정된 순서대로 진행되며, 이전 작업이 완료되면 다음 작업을 위한 세션을 시작하기 위해 리소스가 할당되고, 작업이 완료되면 세션이 종료됩니다. 필요한 경우 작업을 건너뛸 수 있는 옵션도 있습니다. 일례로, 위의 이미지에서는 dataset preparation 작업을 건너뛰고 fine-tuning 작업이 실행되고 있는 것을 볼 수 있습니다. 건너뛴 작업은 분홍색, 실행되고 있는 작업은 하늘색, 실행 예정인 작업은 노란색으로 나타납니다.

    Log checking

    빨간 네모로 강조되어 있는, 각 작업의 이름 옆의 파란색 버튼을 클릭하면 각 작업의 로그를 확인할 수 있습니다. 이를 통해 트레이닝 진행 상황을 직접 모니터링할 수 있습니다. 로그는 터미널과 동일한 결과로, 위의 화면과 같이 나타납니다. 학습이 잘 이뤄지고 있는 것을 확인할 수 있죠. 파이프라인 실행이 성공적으로 완료되면 결과를 확인할 수 있습니다. 본 문서에서는 평가 결과를 플로팅하여 /home/work/XaaS/train/QA_finetune/truthfulness_result.png 로 저장하도록 구성했습니다. (Backend.AI의 V-folder는 /home/work/~ 가 기본 디렉토리 구조입니다.)

    학습을 마친 뒤, 해당 경로에 결과 이미지가 생성된 모습입니다.

    Result checking

    위와 같이 파이프라인이 성공적으로 실행된 모습을 작업 이름의 왼쪽에서 확인할 수 있습니다.

    Result

    이제 모델을 Fine-tuning 한 결과를 gemma-2-2b-it와 비교하여 확인해보겠습니다.

    1. SemScore (목표 응답과 모델 응답 간의 의미론적 텍스트 유사성, 1.00 is the best)

    | Base Model | Trained Model | |------------|---------------| | 0.62 | 0.77 |

    학습된 모델의 SemScore가 증가했습니다(0.62 -> 0.77). 이 결과는 학습된 모델이 목표 응답과 의미적으로 더 유사한 출력을 생성할 수 있음을 나타냅니다. 즉, 학습된 모델이 의도한 목표 응답에 더 가깝고 의미적으로 더 일관된 응답을 생성하는 능력이 향상되었다는 것입니다. 결과적으로 학습된 모델의 전반적인 성능과 신뢰성이 크게 향상되었다고 할 수 있습니다.

    1. Truthfulness 학습된 모델은 고득점 사례는 증가하고 저득점 사례는 감소하는 경향을 보입니다. 낮은 점수(1, 2점) (1,111 -> 777), 높은 점수(4, 5점) (108 -> 376) 이는 모델이 진실에 가까운 도메인 정보를 식별하는 능력이 향상되고, 훈련이 효과적이었다는 것을 나타냅니다.

    Truthfulness result

    Conclusion

    이번 글에서는 Backend.AI의 MLOps 플랫폼인 FastTrack을 활용하여 특정 domain에 특화된 모델을 학습하는 Pipeline을 구축해보았습니다. FastTrack의 모든 기능을 활용하지 않고 일부 기능만을 사용했음에도 자원을 유연하게 활용하고, Task 설정을 자유롭게 하여 학습 시간을 단축하고, 자원 활용율을 끌어올릴 수 있었습니다. 또한 독립적인 실행 환경에서 안정적으로 학습을 시킬 수 있었으며, Pipeline Job의 실행 정보를 모니터링할 수 있어 학습이 진행되는 동안 각 파이프라인의 자원 사용량 및 실행 횟수를 파악할 수 있었습니다. 이 글에서 다룬 내용 이외에도 FastTrack은 스케줄링, 병렬 모델 학습과 같은 추가적인 기능들을 다양하게 지원하고 있습니다. 아래 첨부된 래블업 블로그 게시글에서 각각 강지현님과 강정석님이 작성하신 FastTrack의 다른 기능들에 대한 더 많은 정보를 확인할 수 있습니다.

    FastTrack의 모든 기능을 활용하지는 못했지만, 자원의 유연한 활용, 자유로운 task 설정 등을 통해 학습 시간을 단축하고 자원의 utilization rate를 높일 수 있었습니다. 또한 독립적인 실행환경에서 안정적인 학습이 가능하고, Pipeline Job 실행 정보를 통해 각 파이프라인에서의 자원 사용량, 실행 횟수 등을 파악할 수 있었습니다. 이외에도 FastTrack에서는 스케줄링, 병렬 모델 학습 등 많은 기능을 지원합니다. 아래의 문서들에서 FastTrack에 대한 더 많은 정보를 확인할 수 있습니다.

    Backend.AI MLOps 플랫폼 FastTrack을 소개합니다.

    FastTrack 길라잡이: 모델 학습 결과 알림 받기

    26 September 2024

  • FastTrack 길라잡이: 모델 학습 결과 알림 받기

    By 강정석

    이제는 클래식이 되어버린 AlexNet부터 오늘날 뜨거운 관심을 받고 있는 여러 거대 언어 모델(이하 LLM)들까지, 우리는 필요에 맞게 다양한 모델을 학습하고 평가합니다. 그러나 현실적으로 모델을 여러 번 실행해 보고 경험이 쌓이기 전까지 우리는 학습이 언제 종료될지 가늠하기 어렵습니다.

    Backend.AI의 뛰어난 스케줄링은 GPU의 유휴 시간을 최소화하고 우리가 잠든 사이에도 모델 학습이 실행될 수 있도록 하였습니다. 그렇다면 더 나아가서, 우리가 잠든 사이에 학습이 완료된 모델의 결과를 전달받을 수 있다면 어떨까요? 이번 글에서는 FastTrack의 신기능과 Slack을 활용하여 모델 학습 결과를 메시지로 수신하는 방법을 다뤄보도록 하겠습니다.

    이 글은 Backend.AI FastTrack 24.03.3 버전을 기준으로 작성되었습니다.

    들어가기에 앞서

    본문은 Slack App 및 Bot을 생성하는 방법을 다루지 않습니다. 자세한 내용은 공식 문서를 참고하는 것을 권장합니다.

    파이프라인 생성하기

    모델 학습에 사용할 파이프라인(Pipeline)을 만들어 보도록 하겠습니다. 파이프라인은 FastTrack에서 사용하는 작업 단위입니다. 각 파이프라인은 최소 실행 단위인 태스크(Task)의 묶음으로 표현될 수 있습니다. 하나의 파이프라인에 포함되는 여러 개의 태스크는 서로 의존 관계를 가질 수 있으며, 이 의존성에 따라 순차적으로 실행됨이 보장됩니다. 각 태스크마다 자원 할당량을 설정할 수 있어 전체 자원을 유연하게 관리할 수 있습니다.

    파이프라인에 실행 명령이 전달되면 해당 시점의 상태를 그대로 복제하여 실행되는데, 이러한 단위를 파이프라인 잡(Pipeline Job)이라고 합니다. 하나의 파이프라인에서 여러 개의 파이프라인 잡이 실행될 수 있으며, 하나의 파이프라인 잡은 하나의 파이프라인으로부터 생성됩니다.

    파이프라인 생성 버튼

    파이프라인 목록 상단에 위치한 파이프라인 생성 버튼("+")을 클릭합니다.

    파이프라인 생성하기

    파이프라인의 이름과 설명, 사용할 데이터 저장소의 위치, 그리고 파이프라인에서 공통적으로 적용할 환경변수와 파이프라인 초기화 방법 등을 선택할 수 있습니다. slack-pipeline-0이라는 이름을 입력한 후 하단의 "Create" 버튼을 클릭하여 파이프라인을 생성합니다.

    태스크 생성하기

    태스크 끌어오기

    새 파이프라인이 생성된 것을 볼 수 있습니다. 이제 태스크를 추가해 보도록 하겠습니다. 상단의 태스크 템플릿 목록(Task templates)에 있는 "Custom Task" 블럭을 마우스로 끌어와서 하단 작업 공간에 놓습니다.

    태스크가 수행할 동작 입력하기

    우측에 태스크의 세부사항을 입력할 수 있는 작업창이 나타납니다. model-training-task라는 이름을 주어 태스크의 역할을 나타낼 수 있으며, 모델 학습을 진행하기 위하여 pytorch:1.11-py38-cuda11.3 이미지를 사용하도록 설정합니다. 실제 모델 학습은 오랜 시간을 소요하므로 이번 예시에서는 아래와 같이 간단한 명령을 수행하도록 합니다.

    # 3초 동안 동작을 중지시킴으로써 실행 시간이 증가합니다.
    sleep 3
    # 파이프라인 전용 폴더에 `result.txt` 파일을 생성합니다. 학습이 완료된 모델의 정확도라고 가정합니다.
    echo "0.$RANDOM" > /pipeline/outputs/result.txt
    

    태스크 생성하기 (1)

    마지막으로 태스크에 할당할 자원량을 입력한 후 하단의 "Save" 버튼을 클릭하여 태스크를 생성합니다.

    또다른 태스크 끌어오기

    모델 학습 태스크가 작업 공간에 생성된 것을 확인할 수 있습니다. 이번에는 앞에서 저장한 result.txt 파일로부터 수치를 읽어와 Slack으로 알림을 보내는 태스크를 만들기 위하여 다시 "Custom Task" 블럭을 하단 작업 공간에 가져옵니다.

    태스크 단위 환경변수 `SLACK_TOKEN` 입력하기

    이번 태스크는 slack-alarm-task라고 이름을 설정하고, 아래와 같은 스크립트를 입력하여 Slack에 알림을 보내는 동작을 수행하도록 합니다.

    pip install slack-sdk
    python -c '
    import os
    from pathlib import Path
    from slack_sdk import WebClient
    SLACK_BOT_TOKEN = os.environ.get("SLACK_TOKEN")
    JOB_ID = os.environ.get("BACKENDAI_PIPELINE_JOB_ID")
    def main():
        result = Path("/pipeline/input1/result.txt").read_text()
        client = WebClient(token=SLACK_BOT_TOKEN)
        client.chat_postMessage(
            channel="#notification",
            text="Pipeline job({}) finished with accuracy {}".format(JOB_ID, result),
        )
    if __name__ == "__main__":
        main()
    '
    

    위 코드는 SLACK_TOKEN, BACKENDAI_PIPELINE_JOB_ID라는 이름의 두 환경변수를 활용하고 있습니다. BACKENDAI_* 형태의 환경변수는 Backend.AI 및 FastTrack 시스템에서 자동으로 추가하는 값들로, 그중 BACKENDAI_PIPELINE_JOB_ID는 각 태스크가 실행되고 있는 파이프라인 잡의 고유 식별자를 나타냅니다.

    또 하나의 환경변수인 SLACK_TOKEN는 태스크 단위 환경 변수로 추가된 값으로, 이 기능을 활용하면 코드 변경 없이 다양한 값을 관리 및 변경할 수 있습니다.

    태스크 생성하기 (2)

    slack-alarm-task 태스크에도 알맞은 자원을 할당해 준 후 하단의 "Save" 버튼을 클릭하여 태스크를 생성합니다.

    태스크 의존성 추가하기

    태스크 의존성 추가하기

    이제 작업 공간에는 두 개의 태스크(model-training-taskslack-alarm-task)가 존재합니다. 이때 slack-alarm-taskmodel-training-task이 종료된 후 실행되어야 하므로 두 태스크 간 의존성을 추가해야 합니다. 먼저 실행되어야 할 태스크(model-training-task)의 하단에서 나중에 실행되어야 할 태스크(slack-alarm-task)의 상단까지 마우스를 끌어다 놓습니다.

    파이프라인 실행하기

    파이프라인 실행하기 (1)

    의존성이 추가되어 model-training-task에서 slack-alarm-task 방향으로 뻗는 화살표가 연결된 것을 볼 수 있습니다. 이제 파이프라인을 실행하기 위하여 우측 상단의 "Run" 버튼을 클릭합니다.

    파이프라인 실행하기 (2)

    파이프라인을 실행하기에 앞서 파이프라인의 간단한 요약을 검토할 수 있습니다. 2개의 태스크가 존재하는 것을 다시 한번 확인한 후 하단의 "Run" 버튼을 클릭합니다.

    파이프라인 실행하기 (3)

    파이프라인이 성공적으로 실행되어 파이프라인 잡이 생성되었습니다. 하단의 "OK"를 클릭하면 파이프라인 잡의 정보를 볼 수 있습니다.

    파이프라인 잡

    파이프라인 잡이 정상적으로 생성되었습니다. 모델 학습(model-training-task)이 완료된 후 slack-alarm-task가 실행 중인 것을 확인할 수 있습니다.

    Slack 알림받기

    Slack 알림 (1)

    Slack 알림 (2)

    파이프라인 잡 실행 결과가 Slack을 통해 사용자에게 전달된 것을 확인할 수 있습니다. 이제 우리는 편한 마음으로 잠들 수 있게 되었습니다.

    30 May 2024

  • 23.09: 2023년 9월 업데이트

    By 래블업 주식회사

    23.09: 2023년 9월 업데이트

    2023년 하반기 Backend.AI의 주요 릴리즈인 23.09 가 출시되었습니다. 23.09 에서는 생성AI 의 개발, 파인튜닝 및 운영 자동화 기능이 대폭 강화되었습니다. 워크로드에 따라 자동으로 AI 모델을 스케일링, 로드밸런싱하고 다양한 GPU/NPU 지원을 확장하였으며 한 대의 노드는 물론 100~2천대 이상의 노드들을 관리할 때의 안정성도 증가하였습니다. 개발팀은 최선을 다해 마지막 비트까지 짜내기 위해 노력하고 있습니다. 지난 23.03 7월 업데이트 이후 개선된 주요 내용들은 다음과 같습니다.

    Backend.AI Core & UI

    • Backend.AI 모델 서비스 (Model Service) 기능이 정식 출시되었습니다. 이제 LLM과 같은 거대 모델의 학습 뿐만 아니라 추론 서비스를 위한 환경까지 Backend.AI 를 통해 더욱 효율적으로 준비할 수 있습니다. 자세한 내용은 Backend.AI Model Service 미리 보기 블로그를 참고하시기 바랍니다.
    • OpenID SSO(Single Sign-On) 를 사용하여 Backend.AI에 로그인 할 수 있는 기능이 추가되었습니다.
    • 커널 이미지가 지원하는 경우, 컴퓨팅 세션에서 sudo 명령을 패스워드 없이 사용하도록 설정 가능합니다.
    • HAProxy를 이용하지 않은 Redis Sentinel 를 지원합니다. 이를 테스트하기 위해 install-dev.sh 파일에 --configure-ha 설정을 추가했습니다.
    • Backend.AI Manager 와 Agent 간의 RPC 채널을 인증 및 암호화 통신이 가능하도록 기능을 추가하였습니다.
    • Backend.AI Manager 의 CLI 로그 기능이 개선되었습니다.
    • Backend.AI Agent 가 NAT 환경 아래에 놓여 있을 경우 Manager 가 RPC 연결을 할 수 없는 문제를 수정하였습니다.
    • Raft 알고리즘 라이브러리인 riteraft-py가 앞으로 raftify 로 개명되어 개발됩니다.
    • 다음의 신규 Storage Backend 들을 지원합니다.
      • VAST Data
      • KT Cloud NAS (Enterprise 전용)

    Backend.AI FastTrack

    • 다양한 이기종 가속기 지원을 위한 UI 를 개선하였습니다.
    • 이제 VFolder 삭제시 저장소 이름이 아닌 독립된 고유 ID 값을 이용합니다.
    • Django 버전이 4.2.5 로, Node.js 버전이 20 으로 업그레이드 되었습니다.
    • 미리 설정된 형태로 파이프라인을 생성해주는 파이프라인 템플릿 기능이 추가되었습니다.
    • 파이프라인 전용 폴더가 삭제되었을 경우 FastTrack UI상에 비활성화된 것으로 표시됩니다.
    • 파이프라인 삭제 과정이 개선되었습니다.
    • 태스크(세션)별 접근 가능한 BACKENDAI_PIPELINE_TASK_ID 환경변수가 추가되었습니다.
    • 태스크(세션)별 실제 실행 시간이 표시됩니다.

    Contribution Academy

    특별히 지난 기간에는 NIPA 에서 주관하는 2023 오픈소스 컨트리뷰선 아카데미를 통해 주니어 개발자 멘티분들의 다음과 같은 코드 기여들이 있었습니다.

    • SSH/SFTP 접속 예제를 클립보드에 복사하는 버튼을 생성하였습니다.
    • 기존에 사용되던 WebUI의 여러 Lit 엘리멘트를 React 로 리팩토링 하였습니다.
    • 다양한 테스트 코드들을 작성했습니다.
    • 정상적으로 동작하지 않던 환경변수 및 메시지 오류들을 발견하고 수정했습니다.

    Backend.AI 는 하루가 다르게 변하는 AI 생태계에서 다양한 환경을 지원함과 동시에 더욱 강력하고 사용자 친화적인 환경을 제공하고자 끊임없이 발전하고 있습니다. 앞으로의 행보에도 많은 기대 부탁드립니다!
    Make your AI accessible with Backend.AI!

    26 September 2023

  • 23.03: 2023년 7월 업데이트

    By 래블업 주식회사

    23.03: 2023년 7월 업데이트

    Backend.AI 23.03 및 22.09의 지속적 업데이트 내용을 정리합니다. 개발팀은 최선을 다해 마지막 비트까지 짜내기 위해 노력하고 있습니다.

    이번 업데이트에서 가장 중요한 변경사항은 다음과 같습니다:

    • 스토리지 관리성 강화: VFolder v3 아키텍처 적용으로 사용자 및 프로젝트별 스토리지 용량 관리 기능(Quota)을 추가하였습니다.
    • NVIDIA 호환성 확장: CUDA v12 및 NVIDIA H100 시리즈를 지원합니다.
    • 하드웨어 호환성 확장: 퓨리오사에이아이(FuriosaAI) 사의 WARBOY 가속기를 지원합니다.

    Backend.AI Core & UI

    • CUDA v12 및 NVIDIA H100 시리즈를 지원합니다.
    • 퓨리오사에이아이(FuriosaAI) 사의 첫 번째 NPU인 WARBOY 가속기를 지원합니다.
    • VFolder v3 아키텍처 적용으로 사용자 및 프로젝트별 스토리지 용량 관리 기능(Quota)을 추가하였습니다.
      • 단, Directory Quota를 지원하는 스토리지에 한정합니다.
    • 멀티노드 클러스터 세션 생성이 실패하는 오류를 수정하였습니다.
    • PULLING 상태의 연산 세션이 PREPARING 상태로 잘못 표기되는 오류를 수정하였습니다.
    • 다수의 스토리지에 동일한 이름의 폴더를 보유할 경우 해당 이름의 데이터 폴더 복제 시 CLONING 상태가 제대로 표기되지 않는 오류를 수정하였습니다.
    • 커널 이미지에 zsh 패키지가 설치되어 있는 경우 연산 세션의 웹 터미널이 zsh를 기본 쉘로 사용하도록 개선하였습니다.
    • (관리) 스토리지 프록시 및 이벤트 버스의 건강 상태를 알 수 있는 기능을 추가하였습니다.

    Backend.AI FastTrack

    • 태스크별 multi-node 클러스터 모드 설정 기능을 추가하였습니다.
    • .env에 설정한 환경변수가 프론트엔드에 적용되지 않는 오류를 수정하였습니다.
    • 모바일 브라우저로 접속할 경우 out-of-date로 인식하는 오류를 수정하였습니다.
    • 태스크별 에러가 발생할 경우 원인 메시지를 보여주는 필드를 추가하였습니다.
    • 기타 에디터 관련 문제를 개선하였습니다.

    Backend.AI 는 하루가 다르게 변하는 AI 생태계에서 다양한 환경을 지원함과 동시에 더욱 강력하고 사용자 친화적인 환경을 제공하고자 끊임없이 발전하고 있습니다. 앞으로의 행보에도 많은 기대 부탁드립니다!
    Make your AI accessible with Backend.AI!

    31 July 2023

  • 23.03: 2023년 5월 업데이트

    By 래블업 주식회사

    Backend.AI 23.03 및 22.09의 지속적 업데이트 내용을 정리합니다. 개발팀은 최선을 다해 마지막 비트까지 짜내기 위해 노력하고 있습니다.

    이번 업데이트에서 가장 중요한 변경사항은 다음과 같습니다:

    • 하드웨어 호환성 확장: 리벨리온(Rebeillons) 사의 ATOM 가속기 유휴 상태 검사 및 Dell EMC 스토리지 백엔드를 지원하여 하드웨어 호환성을 확장했습니다.
    • 고속 업로드 강화: SFTP 기능을 도입하여 스토리지로의 고속 업로드를 지원합니다.
    • 개발환경 향상: 로컬 Visual Studio Code에서 원격 SSH 모드로 세션을 접속할 수 있도록 하여 개발환경을 향상했습니다.
    • 관리 용이성 증가: 관리자용 사용자 인터페이스 개선으로 AI 가속기 설정 및 자원 그룹 관리 용이성을 높였습니다.

    Backend.AI Core & UI

    • ATOM 가속기의 유휴 상태 검사를 지원하도록 추가하였습니다.
    • 스토리지로 직접 고속 업로드를 지원하는 SFTP 기능을 도입하였습니다.
    • 관리자 설정에 따라 주기적으로 비밀번호 업데이트를 강제 실행하는 기능을 추가하였습니다.
    • 업로드 전용 세션(SYSTEM) 탭을 추가하였습니다.
    • 허용되는 세션 타입에 Inference 타입을 추가하였습니다.
    • 로컬 Visual Studio Code에서 원격 SSH 모드로 세션 접속 기능을 추가하였습니다.
    • 폴더 탐색기에서 폴더 업로드를 지원하도록 하였습니다.
    • 세션 생성시 할당된 공유자원(shared memory)양을 표시하도록 개선하였습니다.
    • Dell EMC 스토리지 백엔드 지원을 추가하였습니다.
    • 컨테이너 메모리 사용량 측정의 정확도를 개선하였습니다.
    • 하나의 연산 노드에서 여러 개의 agent를 동시 실행할 수 있도록 개선하였습니다.
    • 관리자용으로 프로젝트/자원 그룹명 필터를 추가하였습니다.
    • 관리자용으로 GPU를 포함한 다양한 AI 가속기를 자원 프리셋/정책에서 설정할 수 있도록 사용자 인터페이스를 추가하였습니다.
    • 관리자용으로 GPU를 포함한 다양한 가속기의 할당과 현재 사용량을 표시하는 인터페이스를 제공하였습니다.
    • 관리자용으로 자원 그룹의 공개 여부를 설정할 수 있는 사용자 인터페이스를 제공하였습니다.
    • 관리자용으로 세션 별 idle-checks 값 확인할 수 있는 사용자 인터페이스를 제공하였습니다.
    • CLI에서 vfolder 업로드 시 재귀 옵션을 추가하였고, 상대 경로 처리를 개선하였습니다.
    • CLI에서 특정 세션 종료 시 의존성이 걸려있는 세션을 한번에 종료할 수 있는 재귀 옵션을 추가하였습니다.
    • 개발자용으로 기존의 cuda-mock 플러그인을 대체하는 새로운 mock-accelerator 플러그인을 추가하였습니다.
    • 개발자용으로 스토리지 프록시의 내부 모니터링을 위한 상태 및 통계 확인 API를 추가하였습니다.

    Backend.AI FastTrack

    • 파이프라인 모듈 추가 시 vfolder를 이름으로 검색할 수 있도록 개선하였습니다.
    • 파이프라인 실행 후 성공/실패를 쉽게 알 수 있도록 표시를 추가하였습니다.

    Backend.AI Forklift

    • 버그 수정 및 안정성을 개선하였습니다.
    • 빌드 작업 내역 삭제 기능을 지원합니다.
    • 빌드 작업 목록의 pagination을 지원합니다.

    Backend.AI 는 하루가 다르게 변하는 AI 생태계에서 다양한 환경을 지원함과 동시에 더욱 강력하고 사용자 친화적인 환경을 제공하고자 끊임없이 발전하고 있습니다. 앞으로의 행보에도 많은 기대 부탁드립니다!
    Make your AI accessible with Backend.AI!

    31 May 2023

  • 23.03: 2023년 3월 업데이트

    By 래블업 주식회사

    23.03: 2023년 3월 업데이트

    2023년을 맞이하여 Backend.AI의 첫 major 릴리즈인 23.03.0 버전이 발표되었습니다. 일부 기능은 후속 업데이트로 지속해서 선보일 예정입니다.

    특히 이번 업데이트에서는:

    • 새로운 연산 세션 유형으로 '추론(inference)' 서비스를 지원합니다.
    • 새로운 스토리지 폴더 유형으로 '모델(model)' 관리를 지원합니다.
    • 사용자 및 프로젝트 단위의 스토리지 용량 관리를 지원합니다.
    • FastTrack의 파이프라인 버전 관리 및 UI가 크게 개선되었습니다.

    Backend.AI Core & UI (23.03)

    • 모델 관리 및 추론 세션 관리 기능을 추가하였습니다.
      • 보다 고도화된 추론 엔드포인트 관리 및 네트워크 라우팅 계층은 후속 업데이트로 추가될 예정입니다.
    • 코드베이스가 Python 3.11 기반으로 업데이트되었습니다.
    • 프론트엔드에 React 구성요소들을 도입하고 Relay를 활용하여 보다 빠르고 반응성 높은 UI를 소개할 수 있는 기반을 준비하였습니다.
    • 설치 환경으로 Ubuntu 22.04부터 기본으로 사용하는 cgroup v2를 정식 지원합니다.
    • 사용자 및 프로젝트 단위의 스토리지 용량 관리를 위해 vfolder 구조를 v3로 업데이트하였습니다.
    • 커널과 세션을 이제 별도의 데이터베이스 테이블로 다루고, 상태 전이 추적 과정이 전반적으로 더 적은 데이터베이스 부하로 작동하도록 개선하였습니다.
    • 세션 실행 시 에이전트가 이미지 다운로드하는 과정의 진행상황을 표시하도록 개선하였습니다.
    • CUDA 11.7 이상 환경에서 컨테이너별 GPU 사용량 표시를 개선하였습니다.
    • 각 리소스그룹 내에서 사용자 및 프로젝트별로 스케줄링 우선순위(priority)를 지정할 수 있습니다.
    • 사용자 계정 보호를 위해 일회용 비밀번호(TOTP) 기반 2FA (이중인증, two-factor authentication) 로그인을 지원합니다.
    • 사용자가 직접 SSH keypair를 등록해 세션 접속이 가능하도록 지원합니다.
    • Graphcore IPU 와 Rebellions ATOM 장치에 대응하는 사용자 인터페이스를 지원합니다.

    Backend.AI Forklift (23.03)

    • Dockerfile 템플릿 및 고급 편집 기능을 추가하였습니다.
    • 추론용 컨테이너 이미지 작성을 지원합니다.
    • Harbor 레지스트리와 연동할 수 있도록 이미지 관리 기능을 확장하였습니다.

    Backend.AI FastTrack (23.03)

    • FastTrack UI 상에서 스토리지 폴더 내용을 바로 확인할 수 있습니다.
    • Core와의 세션 상태 동기화 방식을 이벤트 기반으로 개선하였습니다.
    • 파이프라인 스케줄의 최대 반복 횟수를 설정할 수 있습니다.
    • Task 실행에 실패할 경우 파이프라인 job이 대기하지 않고 자동으로 취소됩니다.
    • 파이프라인 버전 관리가 추가되었습니다. 파이프라인의 형상 이력을 추적할 수 있으며, 특정 시점의 내용을 불러와 이어서 작업을 진행할 수 있습니다.
    • 코드 에디터를 통해 YAML 형태의 파이프라인을 직접 수정할 수 있습니다.

    개발 및 연구 프레임워크 지원

    • TensorFlow 2.12, PyTorch 1.13 지원
    • NGC (NVIDIA GPU Cloud) TensorFlow 22.12 (tf2), NGC PyTorch 22.12, NGC Triton 22.08 지원
    • Google Colab과 동일한 라이브러리 및 패키지들을 제공하는 python-ff:23.01 이미지 추가

    위에 나열한 것 외에도 많은 버그 수정과 내부적인 개선 사항들이 포함되어 있습니다.
    앞으로도 더 많은 기능이 찾아올 예정입니다!

    31 March 2023

  • Backend.AI MLOps 플랫폼 FastTrack을 소개합니다.

    By 강지현

    이번 글에서는 Backend.AI의 MLOps 플랫폼인 FastTrack을 소개합니다. FastTrack을 사용하면 데이터 전처리, 학습, 검증, 배포, 그리고 추론과 같은 각각의 단계를 하나의 파이프라인으로 구성할 수 있습니다. 특히 FastTrack에서는 파이프라인을 구성할 때에 사용자가 각 단계를 손쉽게 커스터마이징 가능합니다. 이번 포스팅에서는 MLOps 플랫폼이 왜 필요한지와 함께 Backend.AI FastTrack 의 탄생 배경, 그리고 FastTrack 이 가지는 특장점을 함께 소개합니다.

    MLOps 플랫폼의 대두

    지난 몇 년간 IT 산업 뿐만 아니라, 디지털 트랜스포메이션이 일어난 대부분의 산업에서는 AI를 도입해 산재되어 있던 데이터로 유의미한 예측을 도출해 빠르게 변하는 시장에 대응할 수 있도록 각고의 노력을 기울여왔습니다. 이 과정에서 AI를 잘 활용하기 위해서는 모델 학습, 최적화에서 끝나는 것이 아니라, 데이터 I/O를 고려한 하드웨어 도입, 모델 버전 관리 등과 같이 다양한 단계에 대한 대응이 필요하게 되었습니다. 여기서 나온 개념이 MLOps(Machine Learning Operations) 입니다. MLOps에 대한 자세한 내용은 래블업 기술 블로그에서 다루고 있는 MLOps 시리즈 에서 확인하실 수 있으니, FastTrack 소개글을 보기에 앞서 MLOps 개념이 생소하신 분들께서는 위의 글을 훑어보시는 것을 추천합니다.

    FastTrack의 역사

    래블업은 DevOps 파이프라인 수요에 대응하고자 2019년 Backend.AI 파이프라인 기능을 베타 릴리즈로 추가했습니다. 복잡한 파이프라인 생성 및 관리 과정을 단순화하고, 중간에 두 경로 이상으로 나누어지는 단방향 파이프라인을 운영하는 기능을 개발 및 테스트로 공개하였습니다. 그러나, MLOps 개념의 대두와 함께 AirFlow, MLFlow, KubeFlow 등의 다양한 파이프라인 솔루션들이 보급됨에 따라 저희는 파이프라인 기능을 정식 기능으로 개발하는 대신, 오픈소스 파이프라인 도구들을 통합하고 지원하는 쪽으로 개발 방향을 선회했습니다.

    한편 AI 개발 파이프라인은 점차 복잡해지고, 유저들의 다양한 요구들을 오픈소스 MLOps 파이프라인 도구들이 채워줄 수 없음이 명확해진 시점에서 저희는 Backend.AI의 파이프라인 기능을 다시 되살리기로 했습니다. Backend.AI 파이프라인 기능의 재활성화 및 프로토타이핑 과정에서, 유저들의 요청을 바로 반영할 수 있도록 본체에 완전히 통합된 파이프라인 대신 Backend.AI 클러스터와 함께 동작하지만 독립적으로 동작하는 MLOps 파이프라인 솔루션으로 개발 방향이 변경되었습니다.

    이렇게 다양한 역사를 밟아온 래블업의 AI/MLOps 솔루션은 공항이나 물류 등에서 통과 및 통관 절차를 빨리 처리해주는 과정을 부르는 FastTrack Lane에서 힌트를 얻은 FastTrack으로 명명하였으며, Backend.AI 22.09와 함께 첫 정식 버전을 테스트 중입니다.

    FastTrack이란?

    FastTrack 이란 Backend.AI 클러스터를 기반으로 여러 개의 작업단위들을 사용자가 목적에 맞게 커스터마이징 하고, DAG(Directed Acyclic Graph)형태로 실행될 수 있도록 돕는 머신러닝 워크플로우 플랫폼입니다. 머신러닝 파이프라인의 각 단계에 대응하는 세션을 선,후 관계를 통해 실행할 수 있게 되면 사용자는 데이터 전처리, 학습, 검증, 배포, 모니터링, 최적화 등과 같은 각 단계를 필요에 따라 결합해 하나의 워크플로우로 다룰 수 있습니다. 다시 말해 기존 Backend.AI 클러스터에서 사용자가 일일이 수동으로 생성해야 했던 세션을 워크플로우로 구성하여 단계가 끝날 때마다 자동으로 스케줄링 해주기 때문에 사용자는 보다 편리하게 모델을 구축, 재사용할 수 있습니다.

    FastTrack 구조와 특징

    FastTrack에서는 워크플로우 템플릿을 파이프라인(Pipeline), 실행 대상인 워크플로우를 파이프라인 잡(Pipeline Job)으로 구분하고, 워크플로우 안의 작업단위를 태스크(Task), 실행 대상인 작업단위를 태스크 인스턴스(Task instance)로 구분합니다. 아래의 구조도와 함께 FastTrack에서 어떻게 단계별 작업이 진행되는지 설명합니다.

    파이프라인(Pipeline)

    파이프라인은 태스크들의 각각의 정보와 관계를 모아둔 집합체로, DAG(Directed Acyclic Graph) 구조를 갖습니다. AI 워크플로우를 만들기 위해서는 파이프라인을 생성하면 되는데, 이 때 학습이 잘 되고 있는지 등을 아티팩트(artifact)로 확인할 수 있도록 FastTrack에서는 Backend.AI 클러스터에 파이프라인 전용 폴더를 자동생성합니다. 또한 FastTrack에서는 드래그-앤-드랍(Drag and drop)과 같은 인터페이스로 사용자가 손쉽게 태스크 간 관계를 수정할 수 있고, 변경 결과를 즉시 도식화된 플로우로 확인 및 YAML 파일로 확인할 수 있어 매우 편리합니다. 또한 파이프라인은 YAML 파일로 관리되기 때문에 내보내기나 불러오기가 용이하여 사용자간 공유도 손쉽게 할 수 있습니다.

    파이프라인 잡(Pipeline Job)

    파이프라인 잡의 경우 생성된 파이프라인 정보를 기반으로 만들어지는 실제 개체로, 실행이 되는 동안에는 수정이 불가하다는 특성을 갖습니다. FastTrack GUI에서는 작업단위가 실행되는 것을 각 작업단위에 대응하는 노드의 색상으로 확인할 수 있습니다. 또한 파이프라인과 마찬가지로, 구성하고 있는 태스크 인스턴스의 정보와 관계를 YAML 형태로 관리합니다. 모든 태스크 인스턴스가 종료되면, 파이프라인 잡의 상태도 성공 또는 실패로 표시됩니다.

    태스크(Task)

    파이프라인을 이루는 최소 실행단위로, 용도 별로 자원 할당이 가능합니다. 가령 모델 학습만을 위한 태스크의 경우, 전처리 용과 달리 많은 GPU 자원을 집중할당하여 자원을 보다 효율적으로 사용할 수 있습니다. 또한 실행환경도 각각 지정할 수 있습니다. Backend.AI 클러스터에서 지원하는 이미지를 기준으로 TensorFlow, PyTorch, Python 3.x, NGC TensorFlow, NGC PyTorch 등과 같은 이미지를 도커 빌드과정 없이 그대로 사용할 수 있습니다. 또한 필요에 따라 Backend.AI 클러스터에서 생성한 가상폴더(Virtual Folder)를 태스크 별로 마운트할 수 있습니다.

    태스크 인스턴스(Task Instance)

    태스크 인스턴스는 파이프라인 잡이 생성될 때 파이프라인을 구성하는 태스크 정보를 바탕으로 생성되는 실제 개체라고 볼 수 있습니다. 즉 AI 워크플로우를 실행하는 것은 파이프라인 잡을 구성하는 태스크 인스턴스가 지정된 선,후 관계에 맞게 실행이 된다는 것을 의미합니다. 태스크 인스턴스는 현재 Backend.AI 클러스터의 세션(Session)과 1:1 대응이 되어 세션 상태와 태스크 인스턴스의 상태가 동일시 되고 있으나, 추후 세션 외에도 다양한 실행 단위로 확장될 예정입니다.

    마치며

    지금까지 Backend.AI MLOps 플랫폼인 FastTrack에 대한 소개와 함께 MLOps 에 대해 다뤄보았습니다. 현재 Backend.AI FastTrack의 경우 22.09 버전이 릴리즈 되었으며, 추후 파이프라인 버저닝, 파이프라인 간 의존 관계 추가, 태스크 자원 사용 최적화, GitHub 기반 모델/데이터 스토어 지원 등과 같은 다양한 사용자 편의 기능을 개발 및 제공할 예정입니다. 누구나, 언제 어디서든 AI 모델을 개발, 사용할 수 있게 하자는 래블업의 모토에 맞게, FastTrack을 이용하면 누구나 손쉽게 자동화된 모델 구축을 할 수 있도록 만들어가겠습니다. 앞으로의 행보에도 많은 관심 부탁드립니다.

    29 November 2022

도움이 필요하신가요?

내용을 작성해 주시면 곧 연락 드리겠습니다.

문의하기

Headquarter & HPC Lab

서울특별시 강남구 선릉로100길 34 남영빌딩 4층, 5층

© Lablup Inc. All rights reserved.