본문 바로가기
프로그램 활용/인공지능(AI)

AI | 문장을 384차원으로 변환

by 3604 2026. 8. 18.
728x90

문장을 384차원으로 변환해 주는 임베딩 모델(예: HuggingFace의 all-MiniLM-L6-v2 등)을 거쳐 생성된 384개의 숫자 배열을 생성하는 방법을 단계별로 친절하게 설명해줘. 소스 생성이 필요하면 소스 내용도 알려줘

 
 
 

문장을 384개의 숫자로 이루어진 배열(벡터)로 변환하는 과정은 AI가 텍스트의 의미를 이해하고 비교할 수 있게 만드는 RAG(검색 증강 생성) 파이프라인의 가장 핵심적인 첫 단계입니다.

가장 널리 쓰이고 간편한 Python의 sentence-transformers 라이브러리를 사용하여 all-MiniLM-L6-v2 모델을 구동하는 방법을 단계별로 안내해 드리겠습니다.

1
필수 라이브러리 설치하기
터미널 또는 명령 프롬프트 환경

HuggingFace의 모델들을 쉽게 다운로드하고 사용할 수 있게 해주는 패키지를 설치해야 합니다. 터미널(또는 주피터 노트북 셀)에 아래 명령어를 입력하여 설치를 진행합니다.

Bash
 
pip install sentence-transformers
2
임베딩 모델 불러오기

Python 스크립트에서 라이브러리를 불러온 뒤, 사용할 모델의 이름을 지정해 줍니다. 코드를 처음 실행할 때 HuggingFace 서버에서 모델 파일을 자동으로 다운로드하므로 약간의 시간이 소요될 수 있습니다.

Python
 
from sentence_transformers import SentenceTransformer

# 384차원 출력을 지원하는 경량화 모델 로드
model = SentenceTransformer('all-MiniLM-L6-v2')
3
문장을 임베딩(숫자 배열)으로 변환하기

변환하고 싶은 문장을 정의한 후, 모델의 encode() 함수를 사용하면 즉시 숫자 배열로 변환됩니다.

Python
 
text = "인공지능은 텍스트를 숫자로 변환하여 의미를 이해합니다."

# 문장을 임베딩 벡터로 변환
embedding = model.encode(text)
4
결과 확인하기

생성된 데이터의 형태와 실제 숫자 배열의 일부를 출력하여 384차원의 배열이 맞는지 검증합니다.

Python
 
print(f"배열의 형태: {embedding.shape}") # (384,) 라고 출력되어야 합니다.
print(f"변환된 숫자 배열의 일부: {embedding[:5]}") # 처음 5개의 숫자만 확인

전체 통합 소스 코드

위의 과정을 한 번에 실행해 볼 수 있는 완성된 소스 코드입니다. 복사해서 바로 테스트해 보실 수 있습니다.

Python
 
from sentence_transformers import SentenceTransformer

def generate_embedding(sentence):
    # 1. 모델 로드 (최초 실행 시 자동 다운로드 됨)
    print("모델을 불러오는 중...")
    model = SentenceTransformer('all-MiniLM-L6-v2')
    
    # 2. 문장 인코딩
    print("문장을 변환하는 중...")
    embedding = model.encode(sentence)
    
    # 3. 결과 출력
    print("\n[변환 완료]")
    print(f"입력한 문장: '{sentence}'")
    print(f"데이터 타입: {type(embedding)}")
    print(f"배열의 차원 크기: {len(embedding)}")
    print(f"배열 데이터 (앞 5개 숫자): {embedding[:5]}")
    
    return embedding

# 실행 테스트
if __name__ == "__main__":
    sample_sentence = "데이터베이스 아키텍처와 통합 시스템 구축은 중요한 작업입니다."
    vector_result = generate_embedding(sample_sentence)

이 코드를 실행하면 문장의 의미가 압축된 384개의 실수(float) 배열이 NumPy Array 형태로 생성됩니다.

생성된 384차원 벡터를 PyMilvus 데이터베이스에 저장하는 방법도 알아볼까요?
 

파이썬 소스를 RUST로 작성하여 동일하게 수행할 수 있나?

 
 
 

네, 완벽하게 동일한 작업을 Rust로 수행할 수 있습니다.

Rust 생태계에서는 자연어 처리(NLP)를 위해 rust-bert라는 강력한 크레이트(Crate)를 제공하며, 이 라이브러리는 Python의 sentence-transformers와 거의 1:1로 매칭되는 사용 경험을 제공합니다.

Rust로 384차원 임베딩 벡터를 생성하는 파이프라인을 구축하는 방법을 단계별로 안내해 드리겠습니다.

1
Rust 프로젝트 생성
터미널 환경

먼저 Cargo를 사용하여 새로운 Rust 프로젝트를 생성합니다.

Bash
 
cargo new embedding_test
cd embedding_test
2
의존성(Dependencies) 추가
Cargo.toml

Cargo.toml 파일에 모델 구동을 위한 rust-bert와 에러 처리를 위한 anyhow 크레이트를 추가합니다.

Ini, TOML
 
[dependencies]
rust-bert = "0.22" # 최신 버전에 따라 달라질 수 있습니다.
anyhow = "1.0"
3
Rust 소스 코드 작성
src/main.rs

Python 코드와 동일한 흐름(모델 로드 -> 인코딩 -> 결과 출력)으로 동작하는 코드를 작성합니다. AllMiniLmL6V2 모델 타입이 라이브러리에 기본 내장되어 있어 호출이 매우 간단합니다.

Rust
 
use rust_bert::pipelines::sentence_embeddings::{
    SentenceEmbeddingsBuilder, SentenceEmbeddingsModelType,
};
use anyhow::Result;

fn main() -> Result<()> {
    let sentence = "데이터베이스 아키텍처와 통합 시스템 구축은 중요한 작업입니다.";

    // 1. 모델 로드 (최초 실행 시 HuggingFace에서 자동 다운로드)
    println!("모델을 불러오는 중...");
    let model = SentenceEmbeddingsBuilder::remote(SentenceEmbeddingsModelType::AllMiniLmL6V2)
        .create_model()?;

    // 2. 문장 인코딩 (배열 형태로 입력받음)
    println!("문장을 변환하는 중...");
    let sentences = [sentence];
    let embeddings = model.encode(&sentences)?;

    // 3. 결과 출력
    let vector = &embeddings[0]; // 첫 번째 문장의 결과 추출
    
    println!("\n[변환 완료]");
    println!("입력한 문장: '{}'", sentence);
    println!("데이터 타입: Vec");
    println!("배열의 차원 크기: {}", vector.len());
    println!("배열 데이터 (앞 5개 숫자): {:?}", &vector[..5]);

    Ok(())
}
4
빌드 및 실행
cargo run

터미널에서 아래 명령어를 통해 코드를 컴파일하고 실행합니다. 첫 실행 시 모델 가중치를 다운로드하느라 시간이 조금 걸릴 수 있습니다.

Bash
 
cargo run

💡 인프라 환경 구축 시 참고 사항 (Python vs Rust)

Python은 pip install만으로 런타임 환경이 대부분 해결되지만, Rust의 rust-bert는 백엔드에서 C++ 기반의 PyTorch 라이브러리(libtorch)를 사용합니다.

따라서 Rocky Linux 같은 엔터프라이즈 서버나 외부 인터넷이 차단된 폐쇄망(Air-gapped) 환경에서 이 시스템을 통합 구축하시려면 다음 두 가지를 사전에 아키텍처 구성에 반영하셔야 합니다.

  1. libtorch 바이너리 수동 배치: 빌드 환경과 운영 환경 모두에 OS 아키텍처에 맞는 libtorch를 다운로드하여 적절한 경로(예: /usr/local/lib)에 배치하고 LD_LIBRARY_PATH 환경 변수를 설정해야 컴파일이 성공합니다.
  2. 오프라인 모델 로드: 인터넷이 안 되는 환경이라면, 로컬 모델 파일(config.json, rust_model.ot, vocab.txt 등)을 내부망으로 반입한 뒤, Builder::remote() 대신 Builder::local() 메서드를 사용하여 시스템 내부 경로를 직접 지정하도록 소스를 수정해야 합니다.
 

그럼 C++로도 위 코드와 같이 생성할 수 있나? 가능하면 소스도 알려줘

 
 

네, C++로도 완벽하게 구현할 수 있습니다.

다만, Python이나 Rust처럼 텍스트를 넣으면 자동으로 다운로드부터 변환까지 한 번에 처리해 주는 통합 라이브러리는 C++에 존재하지 않습니다. 엔터프라이즈 환경에서 C++로 임베딩 파이프라인을 구축할 때는 일반적으로 ONNX Runtime이라는 고성능 추론 엔진을 사용하는 아키텍처를 채택합니다.

이 방식은 의존성이 매우 적은 독립된 바이너리로 컴파일되므로, 패키지 관리가 까다로운 폐쇄망(Air-gapped) 환경이나 Rocky Linux 같은 엔터프라이즈 서버에 배포하여 벡터 데이터베이스와 연동할 때 매우 안정적이고 유리합니다.

C++로 구현하기 위한 전체 과정을 단계별로 안내해 드립니다.

1
모델을 ONNX 포맷으로 변환 (Python)
사전 준비

C++ 환경에서는 HuggingFace 서버에서 모델을 실시간으로 다운로드하기 어렵습니다. 따라서 인터넷이 연결된 환경에서 Python을 이용해 all-MiniLM-L6-v2 모델을 C++이 읽을 수 있는 단일 파일(model.onnx)로 미리 변환하여 반입해야 합니다.

2
C++ 프로젝트 빌드 설정
CMakeLists.txt

ONNX Runtime C++ API를 사용하기 위해 CMake 설정 파일을 작성합니다.

CMake
 
cmake_minimum_required(VERSION 3.14)
project(EmbeddingTest CXX)

set(CMAKE_CXX_STANDARD 17)

# ONNX Runtime 라이브러리 경로 설정
find_package(OnnxRuntime REQUIRED)

add_executable(embedding_test main.cpp)
target_link_libraries(embedding_test PRIVATE OnnxRuntime::OnnxRuntime)
3
C++ 추론 소스 코드 작성
main.cpp

ONNX Runtime을 초기화하고, 텐서(Tensor)를 생성하여 384차원 배열을 뽑아내는 핵심 C++ 코드입니다.

(참고: C++에서는 텍스트를 숫자 ID로 바꾸는 '토큰화' 작업에 tokenizers-cpp 같은 별도 라이브러리가 필요하지만, 핵심 로직인 모델 추론에 집중하기 위해 아래 코드는 토큰화가 완료된 숫자 배열이 들어왔다고 가정합니다.)

C++
 
#include 
#include 
#include 
#include 

int main() {
    // 1. ONNX Runtime 환경 및 세션 초기화
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "EmbeddingModel");
    Ort::SessionOptions session_options;
    session_options.SetIntraOpNumThreads(1); // CPU 스레드 최적화

    // 내부망 등에 적재된 로컬 ONNX 모델 경로 지정
    const char* model_path = "model.onnx"; 
    Ort::Session session(env, model_path, session_options);

    // 2. 입력 데이터 준비 (예: "통합 시스템 구축..."이 토큰화된 ID 배열)
    std::vector input_ids = {101, 7592, 10606, 102}; 
    std::vector attention_mask = {1, 1, 1, 1};
    std::vector input_shape = {1, 4}; // batch_size = 1, sequence_length = 4

    Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);

    // 입력 텐서 생성
    Ort::Value input_tensor = Ort::Value::CreateTensor(
        memory_info, input_ids.data(), input_ids.size(), input_shape.data(), input_shape.size());
    Ort::Value mask_tensor = Ort::Value::CreateTensor(
        memory_info, attention_mask.data(), attention_mask.size(), input_shape.data(), input_shape.size());

    std::vector input_tensors;
    input_tensors.push_back(std::move(input_tensor));
    input_tensors.push_back(std::move(mask_tensor));

    // 3. 모델 추론 실행
    std::vector input_names = {"input_ids", "attention_mask"};
    std::vector output_names = {"last_hidden_state"}; // 모델 출력층 이름

    auto output_tensors = session.Run(Ort::RunOptions{nullptr}, 
                                      input_names.data(), 
                                      input_tensors.data(), 
                                      2, 
                                      output_names.data(), 
                                      1);

    // 4. 추론 결과 추출 (384차원 배열 접근)
    // 실제로는 여기서 Mean Pooling(평균값 계산)을 수행하여 최종 384차원으로 압축합니다.
    float* floatarr = output_tensors.front().GetTensorMutableData();
    
    std::cout << "\n[C++ 추론 완료]\n";
    std::cout << "데이터 타입: float 배열\n";
    std::cout << "배열 데이터 (앞 5개 숫자): ";
    for(int i = 0; i < 5; i++) {
        std::cout << floatarr[i] << " ";
    }
    std::cout << "\n";

    return 0;
}

위의 C++ 코드로 생성된 float 배열은 Milvus C++ SDK 등을 통해 시스템 아키텍처 내 벡터 데이터베이스로 곧바로 적재할 수 있는 규격을 갖추게 됩니다.

728x90