☁ 뭉게뭉게 클라우드

[AWS SageMaker / HuggingFace] 허깅페이스와 LoRA를 사용하여 단일 Amazon SageMaker GPU에서 대규모 언어 모델(LLM) 훈련하기 | 인턴

우주수첩 2023. 11. 10. 09:14
728x90

 

어짜피 이렇게 팽 당한 과제 아까우니까 공부한거라도 적어두려고 합니당

 

모르면 이전 포스트 슝:

2023.11.09 - [🏝️ 멋찐넘 AWS/🚨 ERR] - [슬기로운 인턴생활 | AWS SageMaker & HuggingFace] The requested resource studio ... is not available in this region

 

 

정확하게는 어떤걸 하고 싶었냐면 Fine tunning을 함으로써 모델의 성능과 정확도를 더 올리고 싶었다죠

 

그래서 AWS 기술 블로그에 나와있는

 

 

 

허깅페이스와 LoRA를 사용하여 단일 Amazon SageMaker GPU에서 대규모 언어 모델(LLM) 훈련하기

를 진행하였답니당

 

허깅페이스가 저는 좀 생소했는데 이 칭구가 말이죠

 

사람들이 만든 모델들을 올려서 무료로 공유하는 사이트란 말이에요

 

긍까 AI 모델 코드 공유에 집중된 깃허브 같은 그런 머 ㅇㅅㅇ....

 

그래서 Hugging Face에 BLOOMZ-7B라는 Text Generation 모델이 오픈 되어있는데, 이 모델을 사용하면서 LoRA와 int8 양자화를 통해 fin tuning을 진행하는!!!!

 

그런 과제를 하고 있었어여.

 

 

사용했던 모델인 BLOOMZ-7B에 관한 정보는 하단의 Url을 확인해주세용

 

 

 

 

여튼

 

 

 

AWS의 기술 블로그와 해당 내용을 담은 깃허브 노트북을 보면서 fine tunning릏 진행합니다!

 

 

 


 

 

# 예상 비용 및 실행 환경 조건

 

  • NVIDIA A10G GPU가 탑재된 SageMaker ml.g5.2xlarge 사용
    $1.515/hour, 예상 시간 = 5.7 시간

 

해봐야 10달러 이내로 모델을 돌리고 너만의 FineTunning을 진행할 수 있어!! 

 

라고 했지만 

 

 

야무지게 기대를 깨 버린 인턴이 여기 잇꾸요.

 


 

# SageMaker 사양

 

SageMaker Studio

도메인 : QuickSetupDomain-생략
사용자 프로필 : hjkim
사용 인스턴스 : ml.g5.2xlarge
사양 : 2 vCPU + 8GiB
서비스 한도 증가 요청 필요
    ml.g5.2xlarge for endpoint usage
    ml.g5.2xlarge for training job usage
사용 모델 : bigscience/bloomz-7b1

 

sagemaker 서비스 한도 증가 요청을 해야하는 두 가지 usage가 있어서 이 칭구를 해줘야지 돌려볼 수 있답니다.

 

 


 

 

# 사용 Dataset

 

datasets 라이브러리에 있는 samsum Dataset

 

 


 

# 실행 환경 설정

 

깃허브에있는 파일들을 복붙을 하고

 

깃허브와 같은 구조로

 

폴더를 생성해 주시면 된답니다!

 

 


 

 

# Installing

 

 

!pip install "transformers==4.26.0" "datasets[s3]==2.9.0" sagemaker py7zr --upgrade --quiet

 

다르게 install 하면

 

notebook 8-bit training is not supported yet

 

이 오류 납니다.

 

제가 그래써여

 

다시 저 코드 복사해서 올바르게 다운바드면 사라지는 오류랍니당

 

 


 

# HuggingFace Model parameter

huggingface_estimator = HuggingFace(
    entry_point          = 'run_clm.py',      # train script
    source_dir           = 'scripts',         # directory which includes all the files needed for training
    instance_type        = 'ml.g5.2xlarge', # instances type used for the training job
    instance_count       = 1,                 # the number of instances used for training
    base_job_name        = job_name,          # the name of the training job
    role                 = role,              # IAM role used in training job to access AWS resources, e.g. S3
    volume_size          = 300,               # the size of the EBS volume in GB
    transformers_version = '4.26',            # the transformers version used in the training job
    pytorch_version      = '1.13',            # the pytorch_version version used in the training job
    py_version           = 'py39',            # the python version used in the training job
    hyperparameters      =  hyperparameters
)

 

  • entry_point : 파일의 훈련 작업에서 실행되는 스크립트 파일.
    • 해당 파일에서 모델 훈련 및 다른 작업을 수행하는 python 코드가 포함되어있음.
    • sagemaker에서 모델 훈련을 시작하면 entry_point로 지정된 파이썬 파일이 실행된다.
  • source_dir : 훈련 작업에 필요한 모든 파일을 포함하는 디렉토리의 경로를 지정. 현재 코드에서는 ‘script’ 디렉토리로 설정
  • instance_type : 훈련 작업에 사용할 Sagemaker 인스턴스 유형 지정
  • instance_count : 훈련 작업에 사용할 인스턴스의 개수를 지정, 현재 1개
  • base_job_name : 훈련 작업의 기본 이름 설정
  • role : IAM 역할으 지정하여 훈련 작업에서 aWS 리소스에 엑세스 할 수 있도록 함.
  • volume _size : EBS(Elastic Block Stroe) 볼륨 크기를 지정. 현재 300gb
  • transformer_version : 사용할 hugging_face transformers 라이브러리의 버전을 지정. 현재 4.26
  • pytorch_veraion : 사용할 pytorch 버전을 지정. 현재 py39
  • hyperparamaters : 훈련 스크립트에 전달할 하이퍼 파라미터 설정을 정의. 모델 훈련 중 사용

 


 

# run_clm.py

 

실질적으로 hugginface model이 실행하는 파일

 

 구성 메소드

1. main

2. parse_arge

3. training_functions(args)

 

 

Main

def main():
    args, _ = parse_arge()
    training_function(args)

if __name__ == "__main__":
    main()

 

parse_arge

def parse_arge():
    """Parse the arguments."""
    parser = argparse.ArgumentParser()
    # add model id and dataset path argument
		# 모델 식별자를 지정하는 문자열 인수 : default에 기본 모델 id 값을 설정
    parser.add_argument(
        "--model_id",
        type=str,
        default="bigscience/bloomz-7b1",

        help="Model id to use for training.",
    )
		# 데이터셋 경로를 지정하는 문자열 인수 | 기본 값 : lm_dataset -> 훈련 데이터를 포함하는 디렉토리
    parser.add_argument("--dataset_path", type=str, default="lm_dataset", help="Path to dataset.")
    #훈련에 사용할 에폭 수 지정, 기본값은 3
		parser.add_argument("--epochs", type=int, default=3, help="Number of epochs to train for.")
    #훈련 중 각 디바이스에 할당되는 배치 크기 지정. 디바이스마다 몇개의 데이터 포인트를 처리할지 설정
		parser.add_argument(
        "--per_device_train_batch_size",
        type=int,
        default=1,
        help="Batch size to use for training.",
    )
		# 학습률 지정 부동소수점. 모델 업데이트의 크기를 조정하는 하이퍼 파라미터
    parser.add_argument("--lr", type=float, default=5e-5, help="Learning rate to use for training.")
    # 훈련과정에서 사용할 난수 시드를 지정하는 정수 인수. 무작위성을 제어하고 재현성을 확보하는데 사용
		parser.add_argument("--seed", type=int, default=42, help="Seed to use for training.")
		#graident checkingpoint 사용 여부 . 메모리 사용ㅇ을 줄이고 훈련 속도를 향상 시키는 기술.
    parser.add_argument(
        "--gradient_checkpointing",
        type=bool,
        default=True,
        help="Path to deepspeed config file.",
    )
		#Bfloat16을 사용할지 여부. 반정밀도 부동소수점 표현. 모델의 훈련 가속화 가능. 현재 CPU 디바이스의 기능을 확인하여 자동으로 설정 가능.
    parser.add_argument(
        "--bf16",
        type=bool,
        default=True if torch.cuda.get_device_capability()[0] == 8 else False,
        help="Whether to use bf16.",
    )
    args = parser.parse_known_args()
		#명령줄에서 제공된 인수들을 파싱하고 그 결과를 반환
    return args

 

 

training_function(args)

def training_function(args):
    # set seed
    set_seed(args.seed)

    dataset = load_from_disk(args.dataset_path)
    # load model from the hub
		# 허깅페이스 모델 허브에서 모델을 로드. 
    model = AutoModelForCausalLM.from_pretrained(
        args.model_id,
        use_cache=False if args.gradient_checkpointing else True,  # this is needed for gradient checkpointing
        device_map="auto",
				#모델을 8bit 정밀도로 로드
        load_in_8bit=True,
    )
    # create peft config
		#모델에 대한 PEFT 설정을 생성. 모델의 훈련 과정을 조정하고 최적화를 진행
    model = create_peft_config(model)

    # Define training args
    output_dir = "/tmp"
		# 훈련에 대한 다양한 인수 설정 . 
    training_args = TrainingArguments(
        output_dir=output_dir,
        overwrite_output_dir=True,
        per_device_train_batch_size=args.per_device_train_batch_size,
        bf16=args.bf16,  # Use BF16 if available
        learning_rate=args.lr,
        num_train_epochs=args.epochs,
        gradient_checkpointing=args.gradient_checkpointing,
        gradient_accumulation_steps=2,
        # logging strategies
        logging_dir=f"{output_dir}/logs",
        logging_strategy="steps",
        logging_steps=10,
        save_strategy="no",
        optim="adafactor",
    )

    # Create Trainer instance
    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=dataset,
        data_collator=default_data_collator,
    )

    # Start training
    trainer.train()

    # merge adapter weights with base model and save
    # save int 8 model
    trainer.model.save_pretrained(output_dir)
    # clear memory
    del model 
    del trainer
    # load PEFT model in fp16
    peft_config = PeftConfig.from_pretrained(output_dir)
    model = AutoModelForCausalLM.from_pretrained(
        peft_config.base_model_name_or_path,
        return_dict=True,
        torch_dtype=torch.float16,
        low_cpu_mem_usage=True,
        load_in_8bit=False
    )
    model = PeftModel.from_pretrained(model, output_dir)
    model.eval()
    # Merge LoRA and base model and save
    merged_model = model.merge_and_unload()
    merged_model.save_pretrained("/opt/ml/model/")

    # save tokenizer for easy inference
    tokenizer = AutoTokenizer.from_pretrained(args.model_id)
    tokenizer.save_pretrained("/opt/ml/model/")
    
    # copy inference script
    os.makedirs("/opt/ml/model/code", exist_ok=True)
    shutil.copyfile(
        os.path.join(os.path.dirname(__file__), "inference.py"),
        "/opt/ml/model/code/inference.py",
    )
    shutil.copyfile(
        os.path.join(os.path.dirname(__file__), "requirements.txt"),
        "/opt/ml/model/code/requirements.txt",
        
    )

 

 

 


 

 

결론적으로 마지막에 왜 그런지 모르겠지만 data set이 이상하다는 오류를 마주하고

 

해결할 방법을 찾지 못해 멍때리던 중

 

엄청난 인스턴스사양(지금거 4배 정도...)로 모델을 돌리고 있던 인턴을 발견해버리신 팀장님에 의해

 

과제가 끝까지 진행되지 못하고 마무리 되었지만

 

 

언제 또 Sage Maker를, AWS를 과금 걱정 덜하게 써 볼 수 있겠는가. 또, Hugging Face라는 걸 미리 알게 된 것도,

 

모델을 돌려 볼 수 있었던 기회도 너무 좋았고  재미써따 ㅎㅎㅎㅎㅎㅎㅎ

 

 


 

관련  URL

 

 

(AWS 기술 블로그) 허깅페이스와 LoRA를 사용하여 단일 Amazon SageMaker GPU에서 대규모 언어 모델(LLM) 훈련하기 : https://aws.amazon.com/ko/blogs/tech/train-a-large-language-model-on-a-single-amazon-sagemaker-gpu-with-hugging-face-and-lora/

 

허깅페이스와 LoRA를 사용하여 단일 Amazon SageMaker GPU에서 대규모 언어 모델(LLM) 훈련하기 | Amazon Web

이 글은 AWS Machine Learning Blog에 게시된 Train a Large Language Model on a single Amazon SageMaker GPU with Hugging Face and LoRA by Philipp Schmid, Doug Kelly, and Robert Fisher을 한국어로 번역 및 편집하였습니다. 원문은 허깅

aws.amazon.com

 

BLOOMZ-7B 모델 : https://huggingface.co/bigscience/bloomz-7b1

 

bigscience/bloomz-7b1 · Hugging Face

Accuracy on Winogrande XL (xl) validation set self-reported 55.800 Accuracy on XWinograd (en) test set self-reported 66.020 Accuracy on XWinograd (fr) test set self-reported 57.830 Accuracy on XWinograd (jp) test set self-reported 52.870 Accuracy on XWinog

huggingface.co

 

git hub : https://github.com/huggingface/notebooks/blob/5ef609e9078e6248d73f28106e60ddafa9359db1/sagemaker/24_train_bloom_peft_lora/sagemaker-notebook.ipynb

 

 

 

 

728x90