본문 바로가기

Develop/Machine Learning

GGUF 파일 정보 출력하기

Recap

이전글에서 GGUF 파일 포맷 구조를 간단히 살펴보았다. 

2024.01.31 - [Develop] - GGUF (Georgi Gerganov Unified Format)

 

GGUF (Georgi Gerganov Unified Format)

GGUF GGUF 는 Georgi Gerganov(@ggerganov)란 개발자가 만든 딥러닝 모델을 저장 용도의 단일 파일 포맷이다. GGML 라이브러리 기반의 런타임에서 주로 사용이 되고 있다. 현재는 주로 LLM 추론에 많이 활용이

bitwise-life.tistory.com

 

이번 글에서는 GGUF의 구조를 C++ 코드 레벨로 살펴보고, 이 구조를 참고해서 GGUF 파일을 읽어서 내부 정보를 출력하는 스크립트를 만들어 볼 것이다.

 

Header

GGUF - Header

 

Header 구조체 

struct gguf_header_t {
    uint32_t magic;
    uint32_t version;
    uint64_t tensor_count;
    uint64_t metadata_kv_count;
    // The metadata key-value pairs.
    gguf_metadata_kv_t metadata_kv[metadata_kv_count];
};

Header에는 매직넘버와 구조체의 버전 명이 있다.
GGUF는 사실 처음 나온 포맷이 아니며, 앞서 GGML, GGJT란 포맷이 존재했다.
하지만 GGUF가 가장 최신의 버전이고 현재는 이 포맷을 주로 쓰고 있다. 

 

매직넘버는  `0x47` `0x47` `0x55` `0x46` 의 4바이트의 정수이다. 파일을 읽을 때 처음 이 매직넘버를 보고 이 파일이 GGUF인지 아닌지 검사한다.

 

메타데이터 구조체

struct gguf_metadata_kv_t {
    gguf_string_t key;
    gguf_metadata_value_type value_type;
    gguf_metadata_value_t value;
};

내가 관심이 있는 구조체는 메타데이터 파트이다.

Key-Value 쌍의 메타데이터를 담고 있다. Key는 문자열 타입이고, 문자열 저장을 위한 구조체가 선언되어있다. (gguf_string_t)

Value를 저장하기 위해 데이터 타입과 값을 저장하고 있다.
값은 아마도 이진형태의 데이터이니 사실상 중요한건 value_type의 구조체일 것이다. 

 

문자열 타입과 메타데이터 값 구조체

struct gguf_string_t {
    // The length of the string, in bytes.
    uint64_t len;
    // The string as a UTF-8 non-null-terminated string.
    char string[len];
}

enum gguf_metadata_value_type: uint32_t {
    GGUF_METADATA_VALUE_TYPE_UINT8 = 0,
    GGUF_METADATA_VALUE_TYPE_INT8 = 1,
    GGUF_METADATA_VALUE_TYPE_UINT16 = 2,
    GGUF_METADATA_VALUE_TYPE_INT16 = 3,
    GGUF_METADATA_VALUE_TYPE_UINT32 = 4,
    GGUF_METADATA_VALUE_TYPE_INT32 = 5,
    GGUF_METADATA_VALUE_TYPE_FLOAT32 = 6,
    GGUF_METADATA_VALUE_TYPE_BOOL = 7,
    GGUF_METADATA_VALUE_TYPE_STRING = 8,
    GGUF_METADATA_VALUE_TYPE_ARRAY = 9,
    GGUF_METADATA_VALUE_TYPE_UINT64 = 10,
    GGUF_METADATA_VALUE_TYPE_INT64 = 11,
    GGUF_METADATA_VALUE_TYPE_FLOAT64 = 12,
}

union gguf_metadata_value_t {
    uint8_t uint8;
    int8_t int8;
    uint16_t uint16;
    int16_t int16;
    uint32_t uint32;
    int32_t int32;
    float float32;
    uint64_t uint64;
    int64_t int64;
    double float64;
    bool bool_;
    gguf_string_t string;
    struct {
        gguf_metadata_value_type type;
        uint64_t len;
        gguf_metadata_value_t array[len];
    } array;
};

문자열은 16 바이트와 1바이트의 배열로 이뤄져있다. 단순히 len 값을 보고 이 값만큼의 바이트를 읽으면 되겠다.

 

gguf_metadata_value_type 으로 값의 타입을 기록한다. 

대부분 특별하진 않지만 다만 유의해야할 점이 있다.  GGUF_METADATA_VALUE_TYPE_BOOL은 boolean 타입인데 C++에서 boolean 타입의 값은 1바이트를 차지하기 때문에 유의해야한다. 그래서 1 바이트를 읽어줘야한다.

 

gguf_metadata_value_t는 유니온 구조체로 값을 표현하고 있고, array만 len만큼 값을 반복적으로 읽어오도록 구현하는 것 외에 특별한 것은 없다. 

 

 

Tensor Info

GGUF - Tensor Info (Tensor Data는 이진수이기에 생략하였다)

 

Tensor Info는 아주 단순하다.

Header에서 읽어온 tensor_count만큼 아래 gguf_tensor_info_t 구조체를 읽어준다.

 

Tensor Info 구조체

struct gguf_tensor_info_t {
    gguf_string_t name;
    uint32_t n_dimensions;
    uint64_t dimensions[n_dimensions];
    ggml_type type;
    uint64_t offset;
};

 

 

이름, 차원 수 그리고 Tensor의 데이터 타입 그리고 위치 정보를 읽는다.

ggml_type은 아래처럼 4바이트 정수이다. 

 

텐서 타입 구조체

enum ggml_type: uint32_t {
    GGML_TYPE_F32  = 0,
    GGML_TYPE_F16  = 1,
    GGML_TYPE_Q4_0 = 2,
    GGML_TYPE_Q4_1 = 3,
    // GGML_TYPE_Q4_2 = 4, support has been removed
    // GGML_TYPE_Q4_3 (5) support has been removed
    GGML_TYPE_Q5_0 = 6,
    GGML_TYPE_Q5_1 = 7,
    GGML_TYPE_Q8_0 = 8,
    GGML_TYPE_Q8_1 = 9,
    // k-quantizations
    GGML_TYPE_Q2_K = 10,
    GGML_TYPE_Q3_K = 11,
    GGML_TYPE_Q4_K = 12,
    GGML_TYPE_Q5_K = 13,
    GGML_TYPE_Q6_K = 14,
    GGML_TYPE_Q8_K = 15,
    GGML_TYPE_I8,
    GGML_TYPE_I16,
    GGML_TYPE_I32,
    GGML_TYPE_COUNT,
};

 

이번에는 GGUF 의 메타데이터를 출력해보자.

위의 구조를 토대로 GGUF 포맷의  Key Value형식의 메타데이터와 Weight Tensor 정보를 출력하는 툴을 만들어았다. 

 

만들다보니.. 생각보다 길어져서 github 에 올렸다.

https://github.com/mozzilemon/print_gguf

 

GitHub - mozzilemon/print_gguf

Contribute to mozzilemon/print_gguf development by creating an account on GitHub.

github.com

 

 

사용 방법은 간단하다. 

python print_gguf.py {gguf_file}

 

 

출력 예시)

Array 타입의 경우 굉장히 길이가 길어져서 글 줄임표를 추가했다. 

magic                                   =  0x46554747
version                                 =  3
tensor_count                            =  291
metadata_kv_count                       =  16
general.architecture                    =  llama
general.name                            =  LLaMA
llama.context_length                    =  2048
llama.embedding_length                  =  4096
llama.block_count                       =  32
llama.feed_forward_length               =  11008
llama.rope.dimension_count              =  128
llama.attention.head_count              =  32
llama.attention.head_count_kv           =  32
llama.attention.layer_norm_rms_epsilon  =  9.999999974752427e-07
general.file_type                       =  10
tokenizer.ggml.model                    =  llama
tokenizer.ggml.tokens                   =  ['<unk>', '<s>', '</s>', '<0x00>', '<0x01>', '<...
tokenizer.ggml.scores                   =  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0...
tokenizer.ggml.token_type               =  [2, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6...
general.quantization_version            =  2
name          =  token_embd.weight
n_dimensions  =  2
shape         =  [4096, 32000]
ggml_type     =  GGML_TYPE_Q2_K
offset        =  0
==================================================
name          =  output_norm.weight
n_dimensions  =  1
shape         =  [4096]
ggml_type     =  GGML_TYPE_FP32
offset        =  43008000
==================================================
name          =  output.weight
n_dimensions  =  2
shape         =  [4096, 32000]
ggml_type     =  GGML_TYPE_Q6_K
offset        =  43024384
==================================================
name          =  blk.0.attn_q.weight
n_dimensions  =  2
shape         =  [4096, 4096]
ggml_type     =  GGML_TYPE_Q2_K
offset        =  150544384
==================================================

 

결과는 꽤나 만족스럽게 나온 것 같다. 내가 사용한 gguf 파일은

https://huggingface.co/ikawrakow/llama-v1-2bit-gguf/blob/main/llama-v1-7b-q2k.gguf 이곳에서 확인할 수 있다.

'Develop > Machine Learning' 카테고리의 다른 글

GGUF (Georgi Gerganov Unified Format)  (1) 2024.01.31