Linux에서는 프로세스 실행 시 필요한 메모리를 바로 할당하는 것이 아니라 메모리를 주었다는 것을 저장하는 Memory Commit 정책을 가지고 있다. 실제 메모리 할당은 프로세스가 실행되면서 메모리가 필요할 때 이루어진다.
그리고 Linux는 Overcommit를 허용하는데, 이는 커밋된 메모리가 실제 가용 메모리보다 더 큰 것을 뜻한다. Overcommit 덕분에 메모리 사용량이 큰 프로세스가 있어도 실행될 수가 있다. 그런데 Overcommit이 된 상태에서 프로세스에게 실제 메모리 할당이 되면 가용 메모리보다 더 큰 메모리를 할당할 수도 있는데, 이 때 OOM(Out Of Memory)이 발생하기 때문에 Overcommit은 OOM의 주요 원인으로 손꼽힌다.
OOM Killer과 OOM Score
OOM이 발생하면 메모리 확보를 위해 프로세스를 강제로 종료 시키는 OOM Killer가 실행된다. OOM Killer이 프로세스를 종료할 때 당연히 무작위로 종료하는 것은 아니고, OOM Score에 따라서 종료될 프로세스가 결정된다. OOM Score은 0~1000 사이의 값을 가지고, 값이 클 수록 종료 우선순위가 높아진다. 따라서 OOM Killer는 OOM Score이 높은 순서대로 프로세스를 종료한다.
OOM Score은 oom_badness()를 통해 계산된다. Heuristic하게 계산되는 점수인 만큼 시간이 지나면서 점수 계산 방법이 여러 번 바뀌었던 것 같은데 현재는 기본적으로 메모리 사용량이 높을 수록 OOM Score이 높아진다.
oom_score_adj 값은 OOM Score 조정 값이다. OOM Score를 계산하는 oom_badness()를 보면 마지막에 adj이 OOM Score에 더해지는 것을 볼 수 있다. oom_score_adj 값이 -1000이면 OOM Score LONG_MIN 값을 가져서 종료되지 않는다.
따라서 하나의 머신에서 서버를 포함한 여러 개의 프로세스가 실행되어 있는데, OOM이 발생해도 OOM Killer가 서버 프로세스를 종료하지 않도록 하기 위해서는 서버 프로세스의 oom_score_adj 값을 -1000으로 바꾸면 된다.
모델과 토크나이저에 대해서 push_to_hub()메소드를 이용하여 바로 모델을 업로드하는 방법이 있습니다. 이 방법을 이용하면 원격 저장소 생성까지 한 후에 업로드를 해줍니다.
from transformers import AutoTokenizer, AutoModelForCausalLM
print("model loading...")
# Model & Tokenizer loading
tokenizer = AutoTokenizer.from_pretrained("sshleifer/tiny-gpt2")
model = AutoModelForCausalLM.from_pretrained("sshleifer/tiny-gpt2")
# Repository 생성 & model upload
REPO_NAME = YOUR_REPO_NAME # ex) 'my-bert-fine-tuned'
AUTH_TOKEN = YOUR_OWN_TOKEN # <https://huggingface.co/settings/token>
## Upload to Huggingface Hub
model.push_to_hub(
REPO_NAME,
use_temp_dir=True,
use_auth_token=AUTH_TOKEN
)
tokenizer.push_to_hub(
REPO_NAME,
use_temp_dir=True,
use_auth_token=AUTH_TOKEN
)
위 코드를 통해 모델을 업로드할 때, 권한을 위한 토큰값이 필요합니다.
Huggingface 홈페이지에 로그인한 후 오른쪽 상단 프로필 > Settings > Access Tokens을 누르거나 로그인 후에 링크를 클릭하면 바로 토큰을 관리할 수 있는 페이지가 나타납니다. 페이지 상단을 보면 User Access Tokens부분이 있는데, 여기서 New token을 눌러 토큰을 생성할 수 있습니다. 이 때, Role을 read로 하면 권한 에러가 발생하므로 write로 설정해야합니다.
이렇게 생성된 토큰값을 AUTH_TOKEN의 값으로 이용하면 됩니다.
2. CLI 이용
다음은 CLI환경에서 모델을 업로드하는 방법입니다. 우선 아래 코드를 이용해 모델과 토크나이저가 model 디렉토리에 저장되어 있다고 하겠습니다.
from transformers import AutoTokenizer, AutoModelForCausalLM
print("model loading...")
# Model & Tokenizer loading
tokenizer = AutoTokenizer.from_pretrained("sshleifer/tiny-gpt2")
model = AutoModelForCausalLM.from_pretrained("sshleifer/tiny-gpt2")
tokenizer.save_pretrained("./model")
model.save_pretrained("./model")
이후 이용법은 깃허브에 파일을 올리는 것과 동일합니다.
다만 모델의 용량이 큰 것은 수십GB에 이르기 때문에 용량이 큰 파일도 업로드 할 수 있도록 git lfs(Large File Storage)를 설치합니다. 설치가 완료되면 user.email과 user.name을 huggingface 계정의 이메일과 이름으로 설정해줍니다.
마지막으로 transformers 패키지를 설치하면 같이 설치되는 huggingface-hub 패키지를 이용하는 방법이 있는데, 이를 이용하면 코드 상에서 모델 업로드 뿐만 아니라 더 많은 작업을 수행할 수 있습니다. 주의할 점은 ipynb파일에서만 작업이 가능한 점입니다.
먼저 아래 코드로 huggingface 계정과 연동시킬 수 있는데, 위의 과정과 마찬가지로 토큰값이 필요합니다.
from huggingface_hub import notebook_login
notebook_login()
create_repo()와 delete_repo()를 이용하면 원격 저장소를 생성하고, 삭제할 수 있습니다.
from huggingface_hub import create_repo
# Repository 생성
create_repo(name=REPO_NAME)
# Repository 삭제
delete_repo(name=REPO_NAME
아래 코드를 이용하면 Repository 객체를 생성할 수 있습니다. 여기서 첫 번째 인자는 생성할 로컬 저장소 이름이고, 두 번째 인자는 연동할 원격 저장소 이름입니다. 코드를 실행하면 객체가 생성되면서 원격 저장소의 파일들이 로컬 저장소에 복사되고, 객체를 이용해서 원격 저장소와 관련된 작업들을 할 수 있습니다.
from huggingface_hub import Repository
repo = Repository(LOCAL_DIR_NAME, clone_from=NAMESPACE/REPO_NAME)
그리고 upload_file()를 이용하면 add, commit, push 작업 없이 바로 하나의 파일을 업로드할 수도 있습니다. 여기서는 굳이 로컬 저장소에 있지 않은 파일도 업로드가 가능합니다. path_in_repo 인자값은 원격 저장소에 저장되는 파일의 이름입니다.
from huggingface_hub import upload_file, delete_file
# 파일을 직접 업로드
upload_file(
LOCAL_FILE_PATH,
path_in_repo=REPO_FILE_PATH,
repo_id=NAMESPACE/REPO_NAME,
)
delete_file()를 이용하면 원격 저장소의 파일을 바로 삭제할 수도 있습니다.
# 파일 삭제
delete_file(
REPO_FILE_PATH,
repo_id=NAMESPACE/REPO_NAME,
)
P Stage2 이후로 후기를 작성하지 않았는데, 과정이 종료되었으니 마지막으로 그동안 밀린 후기를 써보려고 한다.
이번 후기에는 P Stage3, 4와 기업 채용 연계(기업 네트워킹)에 관한 내용을 담아보려고 한다.
P Stage3
: P Stage3에서는 MRC Task를 선택했다. 프로젝트 이름은 MRC이지만 사실상 Open-Domain QA에 가까웠다.
먼저 문제 해결을 위해서는 두 가지 과정을 거쳐야 했는데, 주어진 질문(query)에 대해 유사한 문서를 찾고(retrieval), 문서 내에서 정답을 찾는 과정(extraction)으로 진행되었다.
문서 내에서 정답을 찾는 것도 중요했지만 유사한 문서를 잘못 찾으면 답도 잘못 나오기 때문에 유사한 문서를 찾는 것이 매우 중요했다.
강의 등에서 최근에는 DPR과 같이 dense embedding을 이용한 retrieval 방법이 sprase retrieval 방법보다 성능이 더 좋아지고 있다는 것을 듣고 시도해보았으나 성능이 너무 안 좋게 나왔다. 그래서 결국 sparse embedding을 사용을 했었다.
P Stage3부터 팀 단위로 프로젝트가 진행되다보니까 문제가 더욱 어려워진 느낌이 들었다.
개인적으로 어떻게 성능을 개선시켜할지 잘 떠오르지가 않았고, 막상 떠올라도 어떻게 구현을 해야되는지 어려운 점이 많았다.
P Stage4
: P Stage4에서는 수식인식 Task를 선택했다. 사실상 OCR 문제였는데, 사진 속 수식을 인식하고 이를 latex 문법으로 변환하는 문제였다.
수식인식 문제도 크게 수식 부분을 찾는 detection 부분과 수식을 인식하는 recognition 부분으로 나눌 수 있었다. 이번 스테이지에서는detection이 수행된 부분을데이터셋으로 주어져서 recognition부분만 다루면 됐었다.
하지만 P Stage4는 개인적인 사정이 있어서 제대로 참여하지 못했다ㅠㅠ
기업 네트워킹
: 아마 부스트캠프에 관심을 가지는 분들은 대부분 "기업 채용 연계"인 "기업 네트워킹"에 관심이 있기 때문이라고 생각한다.
나 역시도 지원을 하기 전에 어떤 기업들이 채용 연계에 참여하는지, 또 실제로 얼만큼 채용이 이루어질지 많이 궁금했다.
채용 연계에 참여한 기업 리스트는 알려드릴 수 없지만 20개 이상의 기업이 참여했고, 예상보다 많은 기업이 채용 연계에 참여한다고 생각했다. 그 중에는 우리가 아는 큰 기업들도 많았고, 인공지능 스타트업으로 유명한 기업들도 있었다.
채용을 어떻게 진행하는지는 기업마다 달랐는데, 대부분은 부스트캠프 전형을 따로 만들거나 개별 컨택을 통해 채용 연계가 이루어졌다.
다만 채용 연계가 진행된다 해도 코테/과제 => 면접 과 같이 일반 채용과 비슷하게 전형이 진행되는 듯 했다.
나는 채용 연계에 참여를 하지 않았기 때문에 자세한 내용을 알지는 못하지만 생각보다 많은 채용 공고가 올라오고, 뽑는 인원도 꽤 많았던 것 같아서 부스트캠프에서 열심히 한다면 좋은 기업에 취업할 수 있지 않을까 생각한다.
지금 생각해봤을 때, 부스트캠프에 참여한 것이 매우 좋은 기회였다고 생각한다. 현재는 산업기능요원으로 군복무를 하고 있는데, 이 역시 부스트캠프 덕분이라고 생각한다.
아마 2기부터는 1기에서의 진행을 바탕으로 교육 과정을 수정해서 더욱 완성도 있는 교육이 이루어질 것 같고, 아마 취업 연계 등도 더 활발히 이루어지지 않을까 생각을 한다.
문제에 따르면 논문 $n$편 중, $h$번 이상 인용된 논문이 $h$편 이상이고, 나머지 논문이 $h$번 이하 인용되었다면 $h$의 최댓값을 H-Index라고 한다.
예를들어 인용수가 [3, 0, 6, 1, 5]라고 하면, H-index는 3이 된다.
H-Index를 구하기 위해 정렬을 먼저 하면 [0, 1, 3, 5, 6]가 되는데 3까지는 $h$번 이상 인용된 논문의 수가 $h$이상이고 5부터는 $h$번 이상 인용된 논문의 수가 $h$보다 작게된다.
이렇게 $h$번 이상 인용된 논문의 수가 $h$보다 작게되는 원소를 찾으면 최종 H-Index의 범위는 (이전 원소 값) ~ (현재 원소 값)사이에 위치하게 된다. 따라서 (현재 원소 값)부터 (이전 원소 값)에 대하여 for문을 돌고, $h$번 이상 인용된 논문의 수가 $h이상이 되는 값이 나오면 그 값이 바로 H-Index가 된다.
def solution(citations):
# len(citations) : 1 <= n <= 1000
answer = 0
citations.sort() # O(nlogn)
max_h = -1
for i in range(len(citations)):
h = citations[i]
n_h_over = len(citations) - i
if n_h_over >= h:
max_h = h
else:
for h in range(citations[i], max_h-1, -1):
if n_h_over >= h:
max_h = h
return max_h
return max_h
요즘 부스트캠프 AI Tech 2기를 모집한다는 소식이 있어가지고 합격후기 조회수가 많이 늘어난 것 같다.
2기는 1기에 비해 커리큘럼이 바뀐 부분이 많아 보였는데 간단하게 살펴본 것들을 써보고자 한다.
먼저 U Stage가 8주에서 5주로 줄어들었다.
그래프, 특강 주차가 사라지고 최적화 강의는 프로젝트 부분으로 이동한 것 같았다.
따라서 강의는 기초개념과 CV, NLP에 대해서만 이루어지는 것으로 보였다.
그리고 P stage도 많이 바뀐 것 같은데 정형데이터, DKT와 같은 프로젝트가 없어지고
CV와 NLP 프로젝트 중 하나를 선택하고, 데이터 구축과 배포 프로젝트가 의무적으로 추가되었다.
1기에 비해 CV, NLP에 중점을 두고 전체적인 pipeline을 경험까지 할 수 있도록 구성을 변경한 것 같다.
나중에 엔지니어로서 채용연계를 노리시는 분이 있다면 서비스 배포까지 경험할 수 있는 거 같아서 상당히 좋은 기회일 것 같다.
그 다음으로 P Stage2가 끝난지 3주정도 됐는데 많이 늦었지만 P Stage2 후기를 작성하고자 한다.
P Stage2에서는 NLP task를 경험해보고 싶어서 KLUE를 선택했다.
트랜스포머 기반 언어모델들을 모아서 라이브러리로 만든 huggingface를 처음 써봐서 프로젝트 초반에는 이것에 익숙해지느라 시간을 좀 많이 쏟았던 것 같다.
그리고 baseline 코드에서는 학습부분이 huggingface의 trainer를 기반으로 작성되어 있는데, trainer를 쓰면 직접 코드를 수정하기가 어려워서 학습 부분 코드를 작성했는데, 여기서도 시간이 좀 걸렸다.
그리고 일단 먼저 entity를 감싸는 special token을 추가해보기로 했는데,문제를 어떤 식으로 접근해야되나 많이 막막했다. 그러던 중에 다른 캠퍼분이 공유해주신 R-BERT 내용을 보고 entity vector들의 평균을 이용하는 식으로 접근을 하기로 하였다.
모델이나 하이퍼파라미터 등은피어세션이나 토론게시판 등 다른 캠퍼분들을 많은 도움을 받았고 성능도 많이 올릴 수 있었다.
예상보다 다양한 시도는 못 해봐서 아쉬움은 있었는데 그래도 P Stage1보다는 등수가 올라서 만족스러웠다.