배경
내가 클라우드를 좋아 하고, 인공지능을 하지 않고 별로 좋아하지 않는 이유는 1) 수학이 싫어서 2) GPU 설정하기 싫어서. 두 가지로 나뉜다. 하지만, N 교수님이 당장 인공지능을 LLM을 돌려보라는 말을 하셔서 해야한다. 정확히는 스토리가 길지만, 언제나 그렇듯 원래 다른 사람의 일이였으나 어쩔 수 없이 울며 겨지먹기로 인공지능을 해야한다.
제약사항: PCI Passthrough
언제나 그렇듯, 우리의 환경은 클라우드 환경이다. 누군가는
아니 그냥 설치하고 cuda 툴킷 설치하면 되는거 아니냐? 그거 못 설치하면서 리눅스 한다고 하냐?
이래서 인프라 하는 놈들은 안된다.
이라는 말을 할지 모른다. 하지만, 우리에게는 언제나 그렇듯, 제약사항이 존재한다
우리의 머신은 RTX 4090 두대가 들어간 머신에다가 ESXi를 돌리고 있다. 그리고 각 VM은 vSphere를 통해서 PCI Passthrough 한다. 즉, 일반 호스트에서 돌리는게 아니다. 그래서 드라이버 잡는것 부터 삽질의 시작이다. 이건 교수님이 해주셨다.
혹사리도 삽질을 해야하면, 이걸 참고하면 "드라이버는 깔린다". 그리고 525.89.02 버전의 드라이버가 돌아간다. 하지만...
삽질 시작 + 문제점
$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02 Driver Version: 525.89.02 CUDA Version: 12.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA GeForce ... Off | 00000000:03:00.0 Off | Off |
| 30% 29C P0 52W / 450W | 0MiB / 24564MiB | 7% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
자, nvidia-smi 하면 이제 드라이버는 잘 잡힌다. 하지만...
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Wed_Nov_22_10:17:15_PST_2023
Cuda compilation tools, release 12.3, V12.3.107
Build cuda_12.3.r12.3/compiler.33567101_0
nvcc --version을 하면 버전이 다르다. 즉:
- nvidia-smi의 cuda: 12.0
- nvcc의 cuda: 12.3
두개의 런타임 버전이 다르다. 사실 Pytorch는 돈다.
$ python run_localGPT.py
2024-01-08 15:56:56,996 - INFO - run_localGPT.py:241 - Running on: cuda
2024-01-08 15:56:56,996 - INFO - run_localGPT.py:242 - Display Source Documents set to: False
2024-01-08 15:56:56,996 - INFO - run_localGPT.py:243 - Use history set to: False
2024-01-08 15:56:57,240 - INFO - SentenceTransformer.py:66 - Load pretrained SentenceTransformer: hkunlp/instructor-large
load INSTRUCTOR_Transformer
max_seq_length 512
2024-01-08 15:56:59,241 - INFO - run_localGPT.py:59 - Loading Model: TheBloke/Llama-2-7b-Chat-GGUF, on: cuda
2024-01-08 15:56:59,241 - INFO - run_localGPT.py:60 - This action can take a few minutes!
2024-01-08 15:56:59,241 - INFO - load_models.py:38 - Using Llamacpp for GGUF/GGML quantized models
llama-2-7b-chat.Q4_K_M.gguf: 100%|███████████████████████████████████████████████████████████| 4.08G/4.08G [01:29<00:00, 45.8MB/s]
ggml_init_cublas: found 1 CUDA devices:
Device 0: NVIDIA GeForce RTX 4090, compute capability 8.9
...
llm_load_tensors: ggml ctx size = 0.09 MB
llm_load_tensors: using CUDA for GPU acceleration
llm_load_tensors: mem required = 70.41 MB (+ 2048.00 MB per state)
llm_load_tensors: offloading 32 repeating layers to GPU
llm_load_tensors: offloading non-repeating layers to GPU
llm_load_tensors: offloading v cache to GPU
llm_load_tensors: offloading k cache to GPU
llm_load_tensors: offloaded 35/35 layers to GPU
llm_load_tensors: VRAM used: 5869 MB
정확히는 이러고 나서, GPU에 offloading이 끝나고 동작은 한다. 하지만... 뭔가 작업을 하게 되면
CUDA error 222 at /tmp/pip-install-idqgfwvo/llama-cpp-python_9eda948acf65402a866d95918cccbb80/vendor/llama.cpp/ggml-cuda.cu:6046: the provided PTX was compiled with an unsupported toolchain.
컴파일 툴체인 달라서 안된다. 저러고는 프로그램이 죽는다!
해결책: nvidia-docker
Nvidia에서 GPU를 사용하는 도커 이미지를 배포한다. 무슨 일이지만 이런걸 해준다. 일단 우리 상황에서, VM 내부의 nvidia 관련 드라이버를 건들면 안될 것같아 보인다. 그렇다면 컨테이너로 컨테이너를 쓰면 될 것이다...
즉, nvidia-docker 컨테이너에다가 nvcc 버전을 12.0 으로 수동으로 깔아주고, 그다음에 컴파일을 하면, 런타임이랑 호스트의 CUDA 런타임이랑 12.0으로 같을테니, 동작하지 않을까? 하는 추정이다.
일단 nvidia-docker를 설치해준다. 물론 도커는 사전에 설치되어야 한다.
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
이제 컨테이너를 돌린다:
docker run --gpus=all --env NVIDIA_DISABLE_REQUIRE=1 -d nvidia/cuda:12.0.0-runtime-ubuntu22.04
이후, 컨테이너 내부에서 수동으로 nvcc 컴파일러를 깔아준다 https://developer.nvidia.com/cuda-12-0-0-download-archive
경고: 여기 .deb, network 설치 다 있는데 이거 사실 12.0 설치 안되고 12.3 이 설치 된다. 이거 쓰면 안된다. runfile 로 다운받아야 한다.
runfile 명령어를 실행해주기 전에, 컨테이너에 아무것도 패키지가 없을테니 설치해주자:
apt-get update && apt-get install sudo wget dpkg -y
sudo apt-get install libxml2 build-essential kmod -y
컨테이너라서 kmod, modprobe 안되는거 안다, 하지만 저 runfile에서 modprobe 명령어를 입력하는 파트가 있는것 같아보인다. 없으면 안된다고 설치 안된다.
이후, runfile을 실행해주자
wget https://developer.download.nvidia.com/compute/cuda/12.0.0/local_installers/cuda_12.0.0_525.60.13_linux.run
sudo sh cuda_12.0.0_525.60.13_linux.run
이를 실행하면, UI가 하나 뜰 것이고, 이거로 설치 과정 중 옵션을 선택하라고 할것이다.
이런식으로 뜬다. 하지만, 우리는 드라이버 + Demo + 문서에 관심 없고 CUDA Toolkit 12.0에만 관심이 있으니, 이거만 설치하면 된다. 저거 설치가 끝나면 WARNING이 뜰 것이다, 드라이버 설치 안했다고:
To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-12.0/bin
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 525.00 is required for CUDA 12.0 functionality to work.
To install the driver using this installer, run the following command, replacing <CudaInstaller> with the name of this run file:
sudo <CudaInstaller>.run --silent --driver
하지만, 드라이버 설치하는 순간 호스트의 드라이버랑 달라져서 동작을 안한다. 따라서, 이는 무시해도 된다. 그리고 우리가 원하는 것은 그냥 nvcc만 설치하는 것이므로 오히려 우리의 의도와 맞는다. 이제, nvcc 버전을 확인하면
root@264deceaa0ad:/# nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2022 NVIDIA Corporation
Built on Mon_Oct_24_19:12:58_PDT_2022
Cuda compilation tools, release 12.0, V12.0.76
Build cuda_12.0.r12.0/compiler.31968024_0
CUDA 12.0 으로 잡힌다. 이제 인프라가 설치되었다.
머신 러닝
이제는 사람 사는 단계까지 왔다. 컨테이너에다가 추가적으로 몇개의 패키지를 설치해준다.
apt-get install python3 python3-pip git
이후 https://github.com/PromtEngineer/localGPT 에서 요구하는 설치과정을 해주면 된다. 우리는 컨테이너 내부니까 conda를 굳이 안해줘도 될것 같아서 난 무시할거다.
git clone https://github.com/PromtEngineer/localGPT.git
pip install -r requirements.txt
CMAKE_ARGS="-DLLAMA_CUBLAS=on" FORCE_CMAKE=1 pip install llama-cpp-python==0.1.83 --no-cache-dir
이거로 llama를 설치해준다. 이게 뭔지는 모르겠으나, CUDA nvcc 가 필요한건 확실해 보인다. 추가적으로 ingest.py 를 돌리려면 몇 개(?)의 패키지가 더 필요하다.
apt-get install libgl1 libglib2.0-0 poppler-utils libleptonica-dev tesseract-ocr libtesseract-dev python3-pil tesseract-ocr-en
g tesseract-ocr-script-latn -y
이제 ingest.py 를 통해서 SOURCE_DOCUMENTS 디렉토리의 파일들을 훈련(?) 시키면 된다.
$ python3 ingest.py
...
2024-01-08 17:58:37,319 - INFO - ingest.py:153 - Loaded 8 documents from /app/localGPT/SOURCE_DOCUMENTS
2024-01-08 17:58:37,319 - INFO - ingest.py:154 - Split into 13995 chunks of text
...
load INSTRUCTOR_Transformer
max_seq_length 512
root@264deceaa0ad:/app/localGPT#
root@264deceaa0ad:/app/localGPT#
뭐 로드가 잘 된것 같고, 이후에 모델도 다운로드 받아온다. 그냥 잠시 기다리면서 딴짓 좀 하다가 있으면 될 것이다. 사실 딴 짓 하면서 블로그 글을 쓰고 있는 것이다. 저게 완료 되면 이제 실행하면 된다!
python3 run_localGPT.py
초기 실행이니 모델을 받아올 것이다. 아무튼 또 기다린다. 이제 모델이 로딩 되면, GPU에 오프로딩을 한다.
Mon Jan 8 18:05:24 2024
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02 Driver Version: 525.89.02 CUDA Version: 12.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA GeForce ... Off | 00000000:03:00.0 Off | Off |
| 0% 33C P2 169W / 450W | 9776MiB / 24564MiB | 2% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 103848 C python3 9770MiB |
+-----------------------------------------------------------------------------+
보는 것과 같이, 프로세스를 잡아먹는다! 무려 9GB의 램을 잡아먹고 GPU의 169W를 잡아먹는다. 기껏 해야 CPU를 돌리던 나에게는 놀라운 수치다... 이래서 학교에 전기세가 많이 나온다는 썰이 있는거구나... 아무튼
이런식으로 이제 답도 해준다! 아주 고마운 친구다. 성공 했다 결과적으로는...
결론
그냥 과정이 분노와 삽질의 연속이다. 요약하면:
- nvidia-docker 컨테이너 설치
- 여기다가 nvcc 12.0만 설치
- 이후 머신 러닝 모델 설치
- 돌리기
이 순서로 진행하면 된다. 언제나 그렇듯, 인공지능 머신 러닝은 GPU 셋업 하는데 하루가 지나는 것 같다. 이게 싫다 정말로. 게다가 nvidia와 VMWare는 좀 PCI Passthrough 지원좀 깔끔하게 해줬으면 좋겠다. 이 글이 머신러닝 관련 마지막 글이면 참 좋겠다.
'Knowledge > Linux' 카테고리의 다른 글
[Network] 간단한 가상 라우터 만들기 (OVS, NAT) (0) | 2024.05.29 |
---|---|
[DNS] Public DNS 서버 구축 (0) | 2023.06.09 |
[CentOS] 인터페이스 이름 변경 (0) | 2023.06.05 |
[Bind9] Private DNS 서버 + OpenVPN (0) | 2023.06.02 |