일、대규모 모델 업무의 전체 과정
-
AI 클러스터 구축:컴퓨팅、통신、스토리지 구축
-
대규모 모델 데이터:대규모 모델 데이터셋、데이터 처리、벡터 데이터베이스
-
대규모 모델 알고리즘:전통적인 NLP에서 사전 학습 LLM까지
-
대규모 모델 학습:일반적인 알고리즘 기법과 안정성 분석
-
분산 병렬 처리:모델 병렬 처리、데이터 병렬 처리、옵티마이저 병렬 처리 등
-
대규모 모델 미세 조정:전체 매개변수 미세 조정, 소수 매개변수 미세 조정, 지시 미세 조정 알고리즘
-
대규모 모델 추론:양자화 압축, 긴 시퀀스 확장 추론, 캐시 기법
-
대규모 모델 평가: NLP 다운스트림 작업, CV 다운스트림 작업, 평가 방안
-
대형 언어 모델 에이전트:RLHF 절차、에이전트、평생 학습
이、벡터
개에 익숙한 사람은 품종을 빠르게 구별할 수 있다. 이렇게 할 수 있는 이유는 몸집의 크기처럼 여러 관점에서 개들의 특징을 관찰하기 때문이다.
하나의 좌표축으로 크기라는 특징을 나타내면, 이 개들은 서로 다른 좌표에 놓인다. 하지만 체격이라는 특징 하나만으로는 충분하지 않다. 체격이 매우 비슷한 개들도 있기 때문이다.
털의 길이처럼 다른 특징도 살펴보고 좌표축을 하나 더 만들면, 크기가 같은 개들 중 일부를 구분할 수 있습니다
하지만 여전히 일부가 겹치므로, 코의 길이처럼 더 다양한 관점에서 계속 관찰해야 한다.
눈의 크기처럼 더 많은 차원을 추가할 수도 있습니다. 4차원 공간에 그림을 그릴 수는 없지만, 좌표점의 수치로는 구현하기가 매우 쉽습니다. 뒤에 계속 덧붙이면 됩니다.
우리는 더 많은 관점, 다시 말해 차원에서 개 한 마리의 특징을 관찰할 수도 있습니다. 예를 들어 다리의 굵기, 털의 곱슬거림, 나아가 복종성이나 도구성 같은 추상적인 관점도 있습니다. 사용하는 차원이 많을수록 개를 구별하는 능력이 높아집니다. 동시에 좌표점이 놓인 공간의 차원도 높아집니다.
개뿐만 아니라 실제로 거의 모든 사물을 이런 방식으로 표현할 수 있다. 구체적인 대상일 수도 있고,
추상적인 희로애락이나 슬픔과 기쁨, 이별과 만남일 수도 있다. 서로 다른 사물은 각 특성 차원에서 서로 다른 양상, 다시 말해 서로 다른 수치를 보이므로, 결국 고차원 특성 공간의 한 좌표점에 대응하게 된다. 다만 범위가 이렇게 넓어지면 사물을 제대로 구분하기 위해 더 높은 특성 차원이 필요할 수 있다. 수백 또는 수천 차원일 수도 있고, 수만 차원일 수도 있다.
하지만 3차원을 넘는 그래프는 그릴 수 없으므로, 2차원 좌표로 설명하겠습니다.
개념적으로 더 가까운 점들은 공간에서 더 밀집하고, 개념적으로 크게 다른 점들은 거리가 매우 멀어진다는 것을 알 수 있다. 여기서 한 걸음 더 나아가 좌표 원점을 시작점으로, 이 좌표점들을 끝점으로 삼으면, 이것이 바로 방향과 크기를 가진 벡터다.
이미지를 벡터화하면 유사한 벡터를 검색하여 이미지로 이미지를 찾는 기능을 구현할 수 있다
동영상을 벡터화하면, 유사한 벡터를 검색하여 비슷한 동영상을 추천할 수 있다
상품을 벡터화하면, 유사한 벡터를 검색하여 사용자가 현재 보고 있는 상품과 관련된 추천을 제공할 수 있다
텍스트를 벡터화하면 지능형 질의응답 시스템에서 사용자의 현재 질문에 따라 이미 해결된 유사한 질문을 찾아 참고할 수 있습니다
삼、벡터 데이터베이스
AI의 도래와 함께 벡터는 중요한 데이터 형태가 될 것이다. 기존 데이터베이스는 벡터 데이터의 저장과 검색에 적합하지 않으므로 이러한 문제를 처리하도록 특별히 설계된 데이터베이스가 필요하며, 이는 미래의 데이터 인프라가 될 수도 있다. 데이터를 테이블에 저장하고 쿼리문으로 정확하게 검색하는 기존 데이터베이스와 달리, 벡터 데이터베이스는 벡터 데이터를 저장한다. 검색 과정에서는 데이터베이스에서 쿼리 벡터와 가장 유사한 벡터들을 찾으므로 어느 정도 모호성을 띤다.

1、벡터 검색
벡터 데이터의 주요 활용 사례 중 하나는 다음과 같다:쿼리 벡터가 주어졌을 때, 수많은 벡터 중에서 가장 유사한 벡터들을 찾는 것이다. 이것이 이른바 최근접 이웃 문제이며, 이를 구현하는 알고리즘을 최근접 이웃 알고리즘이라고 한다. 가장 쉽게 떠올릴 수 있는 방법은 아마도 완전 탐색일 것이다. 모든 벡터와 쿼리 벡터의 유사도를 차례로 비교하여 유사도가 가장 높은 몇 개를 고르는 방식이다. 두 벡터의 유사도를 비교하는 구체적인 방법은 여러 가지가 있는데,유클리드 거리와 코사인 유사도.
-
유클리드 거리는 두 벡터 사이의 직선거리를 계산하는 것을 말합니다. 2차원 좌표계에 벡터 p와 q가 있다고 가정하면, 유클리드 거리는 p와 q를 잇는 직선의 길이를 계산한 것입니다. 3차원 좌표계에서는 각 벡터가 x、y、z라는 세 좌표를 포함하며, 공식에 따라 임의의 두 점 사이의 거리를 계산합니다. n차원 좌표계에는 100개의 좌표가 있으며, 공식에 따라 임의의 두 점 사이의 거리를 계산합니다. 거리가 짧을수록 두 벡터가 일부 차원에서 더 높은 유사성을 가진다는 뜻입니다

-
또 다른 방법은 코사인 유사도다. 거리 외에도 벡터 사이의 각도로 두 벡터의 관계를 설명할 수 있다. 2차원 좌표계에서는 각도가 작을수록 두 벡터의 연관성이 높다는 뜻이다. 공식을 사용하면 임의의 두 벡터 사이의 코사인 유사도를 계산할 수 있다. 3차원 좌표계에서도 같은 원리로 임의의 두 벡터 사이의 각도와 코사인 유사도를 계산할 수 있다.

벡터 데이터가 너무 많으면 이런 단순한 무차별 대입 방식은 검색에 매우 오랜 시간이 걸린다. 하지만 모든 벡터를 실제로 비교하므로 검색 품질 자체는 완벽하다. 따라서 데이터베이스의 데이터 규모가 비교적 작고 모든 벡터를 순회하는 데 걸리는 시간이 감당할 만하다면, 이 역시 좋은 방법이다. 그러나 실제 응용에서는 데이터 규모가 작은 경우가 드물기 때문에 최적화할 방법을 찾아야 한다.
2、벡터 인덱스
앞서 벡터 데이터베이스의 검색 원리를 설명했지만, 실제로 벡터 데이터베이스에서 유사도를 비교할 때는 공식을 그대로 적용하여 계산할 수만은 없습니다. 벡터 데이터베이스는 보통 데이터양이 많고 차원도 높기 때문입니다. 공식으로 두 1000차원 벡터 사이의 유사도를 계산하면 계산량이 상당하고, CPU에 많은 연산을 요구합니다. 벡터가 1억 개 있어 각각 한 번씩 계산해야 한다면 시간과 계산 비용은 더욱 커집니다. 그래서 여기서 벡터 인덱스라는 개념을 도입합니다.
벡터 인덱스는 관계형 데이터베이스의 인덱스와 비슷하지만 한 가지 차이가 있다. 벡터 데이터베이스에서 벡터 인덱스로 찾아내는 것은 근사 결과이며, 100% 정확한 결과가 아니다.벡터 인덱스는 유사도의 높고 낮음을 나타낸다。따라서 이를 근사 최근접 이웃 검색(ANS)이라고 부른다。 벡터 인덱스가 없다면 벡터의 유사도를 찾는 작업은 관계형 데이터베이스의 전체 테이블 검색과 비슷합니다. 하지만 전체 테이블 검색에 연산이 한 단계 더 추가되므로, 관계형 데이터베이스의 전체 테이블 검색보다 비용이 훨씬 높습니다.
구현 방식에 따라 ANNS 벡터 인덱스는 크게 네 가지로 나눌 수 있다:
-
트리 기반 인덱스
-
그래프 기반 인덱스
-
해시 기반 인덱스
-
양자화 기반 인덱스
1、트리 기반 방법
트리 기반 방법의 핵심은 이진 탐색 트리처럼 데이터를 분할해 검색 공간을 줄임으로써 빠르게 검색하는 것입니다. 하지만 이 방법은 고차원 공간에는 적합하지 않습니다. 대표적인 트리 기반 방법으로는 KDTree(K-Dimensional Tree)와 Annoy(Approximate
Nearest Neighbors Oh Yeah)가 있습니다.
1.1
KDTree
KDTree의 구성 역시 재귀적 분할이라는 개념을 기반으로 한다. 먼저 분산이 가장 큰 차원을 선택하고, 해당 차원의 모든 데이터의 중앙값을 분할점으로 삼아 초직사각형 영역을 두 하위 영역으로 나눈다. 중앙값보다 작은 것은 왼쪽에, 중앙값보다 작은 것은 오른쪽에 배치하고, 모든 데이터가 분할될 때까지 왼쪽과 오른쪽 서브트리를 재귀적으로 구성한다.
KDTree 기반 검색 절차:
1、조회 데이터 p와 현재 노드의 분할 차원 d에 대해,데이터 p의 차원 d 좌표값과 노드값의 크기를 비교합니다. 더 크면 왼쪽 자식 노드로,더 작으면 오른쪽 자식 노드로 이동합니다;
2、리프 노드에 도달할 때까지 순회한 뒤, 방문한 것으로 표시하고 리프 노드까지의 거리를 최단 거리로 계산한다;
3、리프 노드에서 역추적하며, 되돌아갈 때마다 p와 부모 노드의 아직 방문하지 않은 분기 사이의 거리를 판단합니다.
a)해당 분기 노드와 p 사이의 거리가 현재 최근접 거리보다 크면, 루트 노드에 이를 때까지 계속 위로 역추적한다;
b)해당 분기 노드와 p 사이의 거리가 현재 최단 거리보다 작으면,해당 분기를 사용해 리프 노드에 도달할 때까지 단계 1과 단계 2를 수행하고,리프 노드와 Q 사이의 최단 거리를 갱신한다。
1.2Annoy
Annoy는 초평면으로 공간을 분할한다。초평면은 KMeans(k=2)를 이용해 두 군집 중심을 찾고,그 중심들을 잇는 선분에 수직인 평면을 분할 초평면으로 삼아 구한다。각 부분 공간의 데이터 개수가 지정된 임곗값보다 작아질 때까지 반복한다。


이 공간의 어느 점이든 검색하려면 루트부터 이진 트리를 탐색하면 된다. 각 중간 노드(위 트리의 작은 사각형)는 하나의 초평면을 정의하므로, 초평면을 기준으로 다음에 왼쪽 자식 노드로 갈지 오른쪽 자식 노드로 갈지 판단할 수 있다. 한 점의 검색은 로그 시간 안에 완료할 수 있으며, 이는 트리의 높이에 해당한다.
장점:저차원 데이터의 정확도가 비교적 높음 단점:데이터의 복잡성을 충분히 포착하지 못하며,고차원 데이터의 정확도가 비교적 낮음
2、그래프 기반 방법
그래프 기반 방법은 주로 그래프라는 자료구조를 사용하며, 이웃 노드 사이의 연결성을 이용해 고속도로를 구축합니다. 문제를 그래프 순회로 바꾸어 검색 범위를 빠르게 좁히고 검색 속도를 높일 수 있습니다. 하지만 그래프 자료구조는 비교적 복잡하므로, 극한의 검색 속도를 얻기 위해 일반적으로 그래프 전체를 메모리에 올립니다. 이 때문에 메모리 사용량이 매우 높지만, 검색이 빠르고 재현율이 높습니다.
현재 널리 사용되는 그래프 검색 알고리즘은 주로 HNSW(Hierarchical Navigating Small World)이며, NSW(Navigating Small World)는 그에 앞선 알고리즘이므로 함께 알아둘 필요가 있다.
2.1 NSW
NSW는 단순한 그래프 구성 방식을 바탕으로 다음 규칙을 추가했다:모든 노드에는 이웃 노드가 있어야 한다;이웃 노드끼리는 간선으로 연결되어야 한다;인접 이웃의 수는 사용자가 지정하는 하이퍼파라미터다. 주로 단순한 그래프 구성 방식의 몇 가지 한계를 해결하는 데 쓰인다.
NSW 그래프 구성 과정:
새 노드를 삽입할 때 먼저 새 노드에서 가장 가까운 m개의 노드를 찾고, 새 노드를 이 m개의 노드와 연결한다.
NSW 검색 과정:
질의 데이터 q에 대해, 그래프에서 무작위로 entry
point 노드와 그 이웃 노드를 찾고, entry point 및 이웃 노드와 p 사이의 거리를 계산합니다. p와의 거리가 p와 entry
point 사이의 거리보다 짧은 이웃이 있으면 최소 거리 지점을 설정하며, 마지막으로 모든 이웃과 query 사이의 거리가 해당 point와 query 사이의 거리보다 큰 point를 찾을 때까지 반복합니다.
위 그림처럼, 구축된 근접 이웃 그래프에서 녹색 노드 query와 가장 가까운 노드를 검색하려면 무작위로 고른 entry
points에서 시작합니다. 먼저 빨간색 long-link를 통해 query 근처의 노드로 빠르게 이동한 뒤, 검은색 short-link를 통해 조건을 만족하는 점을 찾습니다.
NSW 역시 근사 계산 방식이므로 실제 최근접 이웃임을 보장할 수 없다. 먼저 삽입된 점에는 중복 간선이 많아 고속도로를 형성할 가능성이 더 높으며, 나중에 삽입된 점일수록 고속도로를 가질 가능성이 낮다.
2.1 HNSW
HNSW는 NSW를 개선한 방식으로, 주로 스킵 리스트의 아이디어를 활용하여 계층 구조로 구현합니다. 각 계층이 하나의 NSW이므로 계층형 NSW 방식이라고도 할 수 있습니다. 상위 계층일수록 노드가 적고 노드 사이의 거리가 멀며, 하위 계층으로 내려갈수록 노드와 연결이 많아지고 평균 거리가 짧아집니다.
장점:고차원 데이터에서 유사한 이웃을 찾아 검색 성능을 높일 수 있습니다. 단점:그래프 구성 방식이 복잡해 메모리 효율에 영향을 줍니다.
3、해시 기반 방법
해시 기반 방법은 주로 해시 함수의 특성, 즉 유사도가 높은 데이터는 해시값도 비슷하다는 점을 이용한다. 해시 함수는 고차원 데이터를 저차원 데이터로 변환하여 구축 효율을 크게 높일 수 있다. 하지만 해시 함수에도 또 다른 한계가 있다. 해시값이 비슷한 데이터가 반드시 서로 유사한 것은 아니므로 이 방법의 재현율은 그리 높지 않다. 해시 기반 방법의 대표적인 예는 LSH(Locality-Sensitive
Hashing, 지역 민감 해싱)다. 두 벡터가 유사하면 해시값도 유사하다고 가정한다. 해시 함수를 이용해 유사한 벡터를 같은 버킷에 매핑한다. 검색할 때는 먼저 검색 벡터와 가장 유사한 버킷을 찾고, 이어 버킷 안의 데이터를 검색하고 계산해 가장 유사한 topk를 구한다.
LSH(위치 민감 해시)도 공간 분할에 기반한 방식이다. 구현 방법은 다음 그림과 같다. 직선을 무작위로 하나 생성하고, 이 선을 기준으로 양의 쪽과 음의 쪽을 구분한다. 벡터가 이 선의 양의 쪽에 있으면 1, 음의 쪽에 있으면 0로 정한다. 그런 다음 직선을 무작위로 하나 더 생성해 마찬가지로 양의 쪽은 1, 음의 쪽은 0으로 정한다; 이렇게 여러 직선을 생성하면,
각 벡터에 대해 4개의 0 또는 1을 계산하여 각각 4비트의 이진 코드를 얻는다. 이제 이 4개 이진 코드의 유사도를 살펴보자.





장점:대규모 데이터로 확장했을 때 데이터 처리 속도가 매우 빠르다, 단점:정확성은 보통 수준이다
5、양자화(Quantized)기반 인덱스
5.1、군집화
질의 벡터를 검색할 때 대략적인 범위를 정한 뒤 그 안에서 검색할 수 있다면, 검색 속도를 크게 높일 수 있다. 먼저 나눌 분류의 수를 정한다. 예를 들어 아래 그림처럼 4개의 분류를 정하고, 4개의 중심점을 무작위로 생성한 다음, 각 벡터를 가장 가까운 중심점에 배정한다. 이어서 현재 같은 분류에 배정된 벡터들의 평균 벡터점을 계산하고, 중심점 위치를 그 평균 벡터점으로 옮긴 뒤, 각 벡터점에서 가장 가까운 중심점을 다시 판단하여 재분류한다. 이런 반복 과정을 훈련이라고 하며, 최종적으로 중심점들은 안정된 상태에 가까워지는데, 이를 수렴이라고도 한다. 검색할 때는 질의 벡터와 가장 가까운 군집 중심을 찾아, 그 군집 중심에 속하는 벡터만 검색하면 된다. 이로써 검색 범위를 좁히려는 목적을 달성할 수 있다
5.2、양자화(Quantization)
하지만 방대한 벡터 데이터에서는 검색 속도뿐 아니라 메모리 사용량도 큰 과제입니다. 실제 응용 환경에서는 수천 개의 벡터 차원과 수억 개의 벡터 데이터도 드물지 않으므로, 메모리 사용 부담이 매우 커집니다.
앞선 군집화에서 중심점을 알아보았는데, 사실 이를 무게중심이라고 부른다. 그렇다면 무게중심으로 군집 안의 점들을 대표할 수 있지 않을까. 가능할 것이다. 사실 이러한 방법은 전형적인손실 압축 ,이미지로 예를 들면 다음과 같습니다:

이렇게 하면 벡터 값의 일부가 손실되지만, 군집 중심과 해당 군집에 속한 벡터 사이의 연관성을 고려하면 원래 정보의 일부가 상당 부분 보존됩니다. 이러한 손실 압축으로 세부 정보 일부가 사라지는 것에 비해 얻는 이점은 매우 큽니다. 아래 그림처럼 저장할 수 있습니다. 그러면 특정 벡터를 사용할 때 그 코드 값으로 코드북에서 대응하는 중심점을 찾고, 다시 그 중심점에 해당하는 구체적인 값을 복원합니다. 벡터를 중심점 코드로 표현하는 것, 이것이 이른바 벡터 양자화(Quantization)입니다
5.3、곱 양자화 PQ(Product Quantization)
벡터를 양자화하면 코드북이 하나 추가된다. 벡터 자체의 메모리 사용량은 확실히 줄어들지만, 이 코드북으로 인해 새로운 메모리 사용량이 발생하며 그 양도 상당하다。저차원에서는 크게 드러나지 않지만, 실제 환경에서 벡터 차원이 수백에서 수천에 이르면 이 코드북의 크기는 엄청나게 커진다。개수가 일정한 상황에서 양자화 품질을 보장하려면, 벡터 분포가 희소할수록 더 많은 클러스터 벡터가 필요하다。




실제 응용에서는 벡터 차원이 수백에서 수천에 이르므로 데이터가 매우 희소해진다. 따라서 고차원 공간에서 양자화 품질을 보장하려면 매우 많은 클러스터가 필요할 수 있다. 전형적인 사례는 아래 그림과 같다:128차원 벡터 하나에 2의 64제곱 개에 달하는 클러스터 중심이 필요할 수 있으며, 이 때문에 중심점의 코드를 기록하는 코드북이 매우 거대해진다. 이 코드북을 저장하는 데 드는 메모리는 양자화 자체로 절약하는 메모리를 이미 훨씬 넘어선다
이 문제를 해결하는 방법은 먼저 고차원 벡터를 여러 개의 저차원 부분 벡터로 나눈 뒤, 이 저차원 부분 벡터들에 대해 독립적으로 양자화를 수행하는 것이다. 예를 들어 128차원의 고차원 벡터를 8개의 16차원 부분 벡터로 나눈 뒤, 8개의 16차원 부분 벡터 각각에서 독립적으로 군집화 학습을 수행한다.
따라서 각 벡터는 8개 부분 공간의 학습 결과를 사용해 자신에 대응하는 8개 부분 벡터를 양자화할 수 있습니다. 각 부분 벡터의 차원은 16로 그리 높지 않으므로, 각 16차원 부분 공간에서는 클러스터 수가 256개만 되어도 꽤 괜찮은 양자화 효과를 얻을 수 있습니다. 따라서 각 부분 벡터의 코드 값은 0-255 범위에 속하며, 8개 부분 벡터의 양자화 코드를 합치면 원본 벡터의 최종 양자화 코드 값을 얻습니다. 즉, 이제 벡터 하나가 8개의 코드 값으로 양자화됩니다. 각 부분 공간도 자체 부분 코드북을 구축하며, 사용할 때는 8개의 코드 값으로 각 부분 코드북에서 8개의 16차원 부분 벡터를 찾아 합쳐서 하나의 128차원 벡터를 복원합니다.


