전체 글 thumbnail list [LLM] 4. 효율적인 GPU 사용, 분산 학습, LoRA, QLoRA 단일 GPU 효율적으로 사용하기 GPU 자원은 한정되어 있기 때문에, 언제든 GPU 메모리를 효율적으로 사용하는 방법을 탐구해야 한다. 이번에는 GPU 메모리 사용 효율화를 위한 방법인 그레이디언트 누적 / 그레이디언트 체크포인팅에 대하여 알아본다. 그레이디언트 누적 (Gradient Accumulation) - 큰 batch size를 사용할 수 있도록 보조하는 방법론이다. batch size를 크게 잡을수록 모델 학습이 더 안정적으로 이루어지지만, 이전 글에서 확인했듯이 batch size를 늘릴수록 GPU 자원을 더 많이 소모한다. Gradient Accumulation은 작은 배치를 여러 번 처리한 후, 각 배치에서 계산된 Gradient를 누적하여 하나의 큰 배치처럼 처리한다.그레이디언트 체크포.. [LLM] 3. 좋은 데이터 셋, GPU 지도 미세 조정 LLM이 사용자의 목적에 맞는 적절한 응답을 내놓기 위해서는 지도 미세조정(supervised fine-tuning)이 필요하다. 비록 미세조정 되지 않은 pre-trained LLM 모델도 엄청나게 많은 데이터(Llama-2의 경우 약 10TB의 txt)를 이용하여 사전학습 된 것이기에 대부분의 문제에서 강력한 성능을 보인다. 하지만 LLM이 사용되길 원하는 분야가 아주 마이너하거나 데이터 수집이 어려운 분야라면, 직접 미세조정을 통해 더 우수한 모델을 구축할 수 있을 것이다. 지도 미세조정에 사용하는 데이터셋을 지시 데이터셋(Instruction dataset)이라 부른다. 2023년 공개된 Llama의 추가학습 버전인 Alpaca를 학습하는 데 사용된 알파카 데이터셋을 살펴보도.. [LLM] 2. 허깅페이스 트랜스포머 모델 학습하기 허깅페이스란? 2017년 트랜스포머 아키텍처가 세상에 공개된 이후, BERT와 GPT등 트랜스포머를 기반에 두면서도 구현 방식이 상이한 자연어 처리 모델들이 쏟아져 나왔다. 각 모델들의 활용법 또한 다르기 때문에, 사용자가 각 모델들의 활용법을 숙지하는 데 시간이 제법 소요되는 상황이 발생한 것. 이에 따라 각 모델의 개발/사용이 지연되기도 했다. 이러한 배경 속에서 Hugging face팀은 트랜스포머 라이브러리를 개발했는데, 쉬운 인터페이스로 트랜스포머 기반의 모델을 활용할 수 있도록 하였다. 이를 통해 우리는 트랜스포머 기반 모델을 손쉽게 사용할 수 있고, 심지어는 나만의 데이터로 학습시키는 것 또한 가능하다. (트랜스포머 기반 뿐만 아니라, 시중에 공개되어 있는 매우 다양한 종류의 딥러닝 모델을.. [LLM] 1. 임베딩, 어텐션, 트랜스포머 모델들 컴퓨터는 텍스트를 그대로 계산에 사용할 수 없다.그렇다면 어떻게 해야하는가 .. 텍스트를 적절한 단위로 자르고, 숫자로 변환하는 토큰화(tokenization) 과정이 필요하다. input_text = "나는 최근 파리 여행을 다녀왔다"input_text_list = input_text.split()print("input_text_list: " , input_text_list)str2idx = {word:idx for idx, word in enumerate(input_text_list)}idx2str = {idx:word for idx, word in enumerate(input_text_list)}print("str2idx: ", str2idx)print("idx2str: ", idx2str)inp.. [C++] 객체지향 프로그래밍 - 클래스와 객체 (2) 객체와 멤버변수class Account{public: bool Withdraw(double amount) // 출금 { if (balance - amount 멤버 변수는 하나의 객체에 종속된 것이 아니다. 각 개체마다 독립된 멤버 변수를 사용한다.위 코드에서 kim_account, lee_account는 서로 다른 객체이기 때문에, 서로 독립된 balance를 갖는다.따라서 각각의 balance 값은 100, 200이 될 것이다. 멤버 변수를 클래스 밖에서 정의하기class Account{public: bool Deposit(double amount);private: std::string name; double balance = 0; };bool Account::Deposit(double a.. [C++] 객체지향 프로그래밍 - 클래스와 객체 절차적 프로그래밍이란?데이터와 작업(함수)가 분리되어 있는 개념즉, 데이터는 함수의 매개변수로 입력될 뿐이며 이후 함수의 동작에 의해 작업이 수행되어 output이 출력된다.굉장히 이해가 쉬운 방식이다. 절차적 프로그래밍의 단점어떤 함수에 모든 형식의 데이터가 입력될 수 있는 것이 아니다. 👉 func(int ~) 처럼, 함수에 입력될 수 있는 데이터의 형식이 지정되어 있다.따라서 함수가 데이터의 구조를 정확히 알고 있어야 하며, 데이터가 변하면 함수의 수정 또한 필요하다.이를 데이터와 함수가 Tightly coupled 되었다고 말하는데, 이는 함수의 재사용성을 낮추는 좋지 못한 특성이다. (loosely coupled한 프로그래밍을 작성하는 것이 좋다)이 경우 프로그램의 규모가 작을 때는 큰 문제.. [C++] 참조자 Reference 참조자란?변수가 아니다. 👉 변수는 메모리 공간을 차지한다. 하지만 참조자는 메모리 공간을 차지하지 않는 '변수의 별명' 이다. (엄청난 장점)선언과 동시에 반드시 초기화 되어야 한다. 👉 참조자는 Null 값을 가질 수 없다. 포인터의 경우에는 int* a; 처럼 초기화 하지 않은 선언이 가능했지만, 참조자의 경우에는 int& a=b; 처럼 반드시 변수를 입력해주어야 한다.Const pointer이면서, 사용시 자동으로 역참조를 수행함 👉 포인터의 편리한 버전이라고 생각하면 편하다.함수의 매개변수로 자주 사용 #include using namespace std;int main(){ int a = 10; int& b = a; b = 20; cout Error} 위 코드의 결과는 20포인터에서도 그.. [C++] 포인터를 함수에 input, return 포인터를 함수의 인자로 전달#include using namespace std;void double_data(int* int_ptr){ *int_ptr *= 2;}int main(){ int value = 10; cout 함수 double_data는 input 인자로 int* int_ptr을 받고 있다. 👉 어떤 변수의 주소인 포인터를 입력으로 받아 처리하는 함수를 생성하는 것이 가능하다.해당 함수 내부에서 *int_ptr *= 2; 👉포인터에 저장돼있는 변수에 역참조하여 실제 값을 2배 곱한다. 포인터의 Returnint* largest_int(int* int_ptr1, int* int_ptr2){ if (*int_ptr1 > *int_ptr2) return int_ptr1; else r.. 이전 1 2 3 4 ··· 9 다음