경작 25일차 Hugging Course 5

한정화·2023년 2월 25일
0

#230225 토

3장에서는 Hugging Face Hub에서 자신이 원하는 데이터셋을 가져와 fine-tuning하는 방법에 대해 알아보았다. 그런데 원하는 데이터셋이 hub에 없거나 데이터셋이 너무 커 RAM의 용량이 부족할 때, 혹은 그래서 다른 데이터셋을 Hub에 푸쉬해 사용하려고 할 때엔 어떻게 해야할까? 이와 관련된 내용들에 대해 알아보자.

  1. Hub에 없는 데이터셋을 로드하는 방법
  2. datasets 라이브러리로 데이터셋 처리하기
  3. 데이터셋이 너무 커 RAM의 용량이 부족할 때

1. Hugging Face Hub에 없는 데이터셋 로드하기

1) 깃허브에 있는 local dataset

!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz
!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz

wget은

2)


2. datasets 라이브러리로 데이터셋 처리하기

허깅코스에서는 예시 데이터셋으로 UC Irvine Machine Learning Repository의 Drug Review Dataset을 사용하였다. 약물을 복용한 환자들의 후기, 호전 상태, 만족도 등급이 정리되어있다.

1) wget, unzip

!wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip"
!unzip drugsCom_raw.zip

2) 데이터셋 로드

우선 datasets 라이브러리를 사용해 데이터셋을 가져온다.

from datasets import load_dataset

data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"}
drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t")

무작위로 샘플 몇 개를 가져와 데이터셋의 특징을 살펴보자.

drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000))  #shuffle로 무작위로 가져옴 
drug_sample[:3]  #샘플 3개 

출력결과 :

{'Unnamed: 0': [87571, 178045, 80482],
 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'],
 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'],
 'review': ['"like the previ...Aleve works!"',
  '"I have taken ...s."',
  '"I have been ta ...er a few days."'],
 'rating': [9.0, 3.0, 10.0],
 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'],
 'usefulCount': [36, 13, 128]}

3) processing

그러면 이 데이터셋을 학습에 적절하게 처리해보자.

  • 우선 2)에서 확인하였듯 condition이 대문자와 소문자가 섞여있으므로 소문자로 통일해보자.
def lowercase_condition(example):  #데이터셋의 각 딕셔너리의 condition의 문자열을 소문자로 변환한 딕셔너리를 반환 
    return {"condition": example["condition"].lower()}

drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None) #람다 함수 
drug_dataset = drug_dataset.map(lowercase_condition)

condition에 문자열이 포함되어있지 않고 None인 경우 소문자 변환 함수를 적용할 수 없어 에러가 나기 때문에, 람다 함수를 사용해 None인 경우를 필터링해야 한다. 람다 함수는 map이나 filter 작업을 정의할 수 있는 좋은 친구이다~

  • 짧은 리뷰는 무의미해므로 제거하자.
    우선 각 리뷰별 단어 수를 세어 데이터셋의 딕셔너리에 새로운 키로 추가해주자.
def compute_review_length(example):   #데이터셋의 각 딕셔너리에 review_legth라는 새로운 키를 추가한 딕셔너리를 반환 
    return {"review_length": len(example["review"].split())}
    
drug_dataset = drug_dataset.map(compute_review_length)

다음으로 람다 함수를 이용해 글자수가 너무 적은 리뷰는 filtering 해준다.

drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30)  #람다함수를 이용해 filtering
print(drug_dataset.num_rows)

3. 데이터셋이 너무 커 RAM의 용량이 부족할 때

1) 대용량 데이터셋 가져오기

일단 데이터셋이 너무 커 RAM의 용량이 부족한 문제를 해결하는 방법에 대해 알아보려면 대용량 데이터셋을 가져오는 것부터 시작해야한다. 허깅코스에서는 예시로 Pile은 EleutherAI의 Pile이라는 english utterance 데이터셋을 사용하였다. Pile은 무려 825GB의 용량을 가지고 있다고 한다. (세상에)

!pip install zstandard
from datasets import load_dataset

data_files = "https://the-eye.eu/public/AI/pile_preliminary_components/PUBMED_title_abstracts_2019_baseline.jsonl.zst"
pubmed_dataset = load_dataset("json", data_files=data_files, split="train")

2) memory-mapping

데이터셋을 메모리가 매핑된 파일로 처리하면 RAM과 시스템 storage를 매핑해줘서 데이터셋을 완전히 로드하지 않아도 데이터셋의 각 요소에 접근하고 작업할 수 있다.

  • 현재 메모리 사용량 체크
!pip install psutil
import psutil  #프로세스의 메모리 사용량을 체크해줌 

print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB")  #바이트를 메가바이트로 변환

출력 결과 :

RAM used: 5678.33 MB
  • 데이터셋 크기 체크
print(f"Number of files in dataset : {pubmed_dataset.dataset_size}")
size_gb = pubmed_dataset.dataset_size / (1024 ** 3)
print(f"Dataset size (cache file) : {size_gb:.2f} GB")

출력 결과 :

Number of files in dataset : 20979437051
Dataset size (cache file) : 19.54 GB

일반적으로 작업을 위해서는 데이터셋 크기의 5~10배 많은 RAM이 필요하다. 따라서 두 결과를 비교했을 때 메모리 매핑이 필요하다.

  • 메모리 매핑

0개의 댓글