페이지

2024년 12월 9일 월요일

Llama 3.2로 문장 생성 및 챗팅 완성 실습

Llama 3.2로 문장 생성 및 챗팅 완성 실습

Running Meta Llama on Linux 문서의 내용을 참고하여 Llama 3.2 1B 모델로 다음 두 가지 기능을 실습합니다.

  • 문장 완성
  • 챗팅 완성

실습 환경

  • Ubuntu 20.04.6 LTS
  • Python 3.12.7
  • Llama3.2-1B, Llama3.2-1B-Instruct
  • rustc 1.83.0
  • NVIDIA RTX 4090 24GB

프로그램 준비

  1. 실습에서 사용할 wget, md5sum 설치

    sudo apt-get install wget
    sudo apt-get install md5sum
    
  2. NVIDIA GPU 설치 여부 확인

    nvidia-smi
    
  3. 실습 디렉토리 만들기

    mkdir llama3-demo
    cd llama3-demo 
    git clone https://github.com/meta-llama/llama3.git
    
  4. Python 3.10 이상의 버전으로 가상환경 만들고 활성화

    python -m venv llama-venv
    . llama-venv/bin/activate
    
  5. Rust 컴파일러 설치

    How To Install Rust on Ubuntu 20.04 문서를 참고하여 Rust 컴파일러를 설치합니다.

    curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh
    

    위 명령을 실행하면 아래와 같이 세 가지 선택 옵션이 나타나는데 그냥 엔터를 쳐서 1번 옵션으로 진행합니다.

    ...
    1) Proceed with installation (default)
    2) Customize installation
    3) Cancel installation
    

    아래 명령을 실행하여 현재 쉘에 반영하고 설치된 컴파일러 버전을 확인합니다.

    source $HOME/.cargo/env
    rustc --version
    
  6. 의존 라이브러리 설치

    pip install -e .
    

모델 다운로드

  1. Llama 웹 사이트에서 신청

    선택 옵션에 따라 다운로드할 수 있는 모델들과 커스텀 URL이 화면에 표시되고 이메일로도 전송됩니다.

  2. 모델 목록 표시

    llama model list
    

    위 명령을 수행하면 아래와 같은 모델 목록이 표시됩니다.

    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Model Descriptor                        | Hugging Face Repo                                   | Context Length |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-1B                             | meta-llama/Llama-3.2-1B                             | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-3B                             | meta-llama/Llama-3.2-3B                             | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-11B-Vision                     | meta-llama/Llama-3.2-11B-Vision                     | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-90B-Vision                     | meta-llama/Llama-3.2-90B-Vision                     | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-1B-Instruct                    | meta-llama/Llama-3.2-1B-Instruct                    | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-3B-Instruct                    | meta-llama/Llama-3.2-3B-Instruct                    | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-1B-Instruct:int4-qlora-eo8     | meta-llama/Llama-3.2-1B-Instruct-QLORA_INT4_EO8     | 8K             |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-1B-Instruct:int4-spinquant-eo8 | meta-llama/Llama-3.2-1B-Instruct-SpinQuant_INT4_EO8 | 8K             |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-3B-Instruct:int4-qlora-eo8     | meta-llama/Llama-3.2-3B-Instruct-QLORA_INT4_EO8     | 8K             |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-3B-Instruct:int4-spinquant-eo8 | meta-llama/Llama-3.2-3B-Instruct-SpinQuant_INT4_EO8 | 8K             |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-11B-Vision-Instruct            | meta-llama/Llama-3.2-11B-Vision-Instruct            | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    | Llama3.2-90B-Vision-Instruct            | meta-llama/Llama-3.2-90B-Vision-Instruct            | 128K           |
    +-----------------------------------------+-----------------------------------------------------+----------------+
    
  3. 모델 다운로드

    llama download --source meta --model-id Llama3.2-1B
    llama download --source meta --model-id Llama3.2-1B-Instruct
    

    다운로드된 모델들은 아래 디렉토리에 저장됩니다.

    $HOME/.llama/checkpoints
    

예제 실행

  1. 텍스트 생성 예제 실행

    torchrun --nproc_per_node 1 example_text_completion.py --ckpt_dir $HOME/.llama/checkpoints/Llama3.2-1B/ --tokenizer_path $HOME/.llama/checkpoints/Llama3.2-1B/tokenizer.model --max_seq_len 128 --max_batch_size 4
    

    example_text_completion.py 실행시 다음과 같은 에러가 발생합니다.

    TypeError: ModelArgs.__init__() got an unexpected keyword argument 'use_scaled_rope'
    

    이 문제를 해결하기 위하여 $HOME/.llama/checkpoints/Llama3.2-1B/params.json에서 "use_scaled_rope": true, 항목을 제거합니다.

  2. 질의 응답 예제 실행

    torchrun --nproc_per_node 1 example_chat_completion.py --ckpt_dir $HOME/.llama/checkpoints/Llama3.2-1B-Instruct/ --tokenizer_path $HOME/.llama/checkpoints/Llama3.2-1B-Instruct/tokenizer.model --max_seq_len 512 --max_batch_size 6
    

Written with StackEdit.

2024년 11월 16일 토요일

JWT 토큰 생성과 유효성 확인 과정

JWT 토큰 생성과 유효성 확인 과정

API 서비스를 개발하고 이에 대한 접근 권한을 제어하기 위하여 JSON Web Token(JWT)을 활용할 수 있습니다. 이 문서에서는 JWT 토큰의 생성과 유효성 확인 과정을 그림과 Python 코드를 사용하여 설명합니다. 전자서명 알고리즘으로는 HS256을 사용하였습니다.

  • HS256(HMAC-SHA256)
    • 대칭키 암호화 방식
  • HMAC(Hash-based Message Authentication Code)
    • 해시 함수를 기반으로 메시지 인증 코드를 생성하는 알고리즘

다음은 토큰 생성과 유효성 확인 과정에서 사용하게 될 Base64 인코딩/디코딩 함수입니다.

import base64
import hashlib
import hmac

def base64_encode(input_as_bytes):
    b = base64.urlsafe_b64encode(input_as_bytes).decode('utf-8')
    return b.rstrip('=')

def base64_decode(input_as_string):
    padding = 4 - len(input_as_string) % 4
    input_as_string = input_as_string + '=' * padding
    return base64.urlsafe_b64decode(input_as_string.encode('utf-8')).decode('utf-8')

1. 토큰 생성

1.1. 다이어그램

1.2. Python 구현

def create_jwt_token(header_obj_str, payload_obj_str, secret):
    header = base64_encode(header_obj_str.encode('utf-8'))
    payload = base64_encode(payload_obj_str.encode('utf-8'))
    header_plus_payload = f'{header}.{payload}'
    
    m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
    m.update(header_plus_payload.encode('utf-8'))
    d = m.digest()
    signature = base64_encode(d)
    print('** Signature (algorithm: HS256) **')
    print(f'Byte size: {len(d)}')
    print(f'Base64 encoded: {signature}')

    jwt_token = f'{header_plus_payload}.{signature}'
    return jwt_token

header_obj_str = '{\
"typ":"JWT",\
"alg":"HS256"\
}'

payload_obj_str = '{\
"iss":"fun-with-jwts",\
"sub":"AzureDiamond",\
"jti":"f6c1097f-cc48-4949-a627-8b94fc5e37ba",\
"iat":1596185001,\
"exp":1596185061\
}'

secret = 'my-secret'

jwt_token = create_jwt_token(header_obj_str, payload_obj_str, secret)
print('** JWT token (structure: header.payload.signature) **')
print(jwt_token)

실행 결과:

** Signature (algorithm: HS256) **
Byte size: 32
Base64 encoded: UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
** JWT token (structure: header.payload.signature) **
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k

입력

  • header object

    {
        "typ": "JWT",
        "alg": "HS256"
    }
    
  • payload object

    {
        "iss": "fun-with-jwts",
        "sub": "AzureDiamond",
        "jti": "f6c1097f-cc48-4949-a627-8b94fc5e37ba",
        "iat": 1596185001,
        "exp": 1596185061
    }
    
  • secret

    my-secret
    

출력

  • token

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
    

2. 토큰 유효성 확인

2.1. 다이어그램

2.2. Python 구현

def validate_jwt_token(token, secret):
    pos = token.rfind('.')
    header_plus_payload = token[:pos]
    signature = token[pos+1:]
    
    m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
    m.update(header_plus_payload.encode('utf-8'))
    d = m.digest()
    
    signature_derived = base64_encode(d)
    
    return signature_derived == signature

token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k'
secret = 'my-secret'

is_valid = validate_jwt_token(token, secret)
print(f'** is_valid: {is_valid} **')

실행 결과:

** is_valid: True **

입력

  • token

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
    
  • secret

    my-secret
    

출력

  • is_valid

    True
    

Written with StackEdit.

2024년 11월 10일 일요일

Circom SHA256 해시 예제

Circom SHA256 해시 예제

아래 문서의 예제를 약간 변형해서 SHA256 해시 검증을 실습하였습니다.

회로 생성

  1. 프로젝트 디렉토리에서 회로 파일 program.circom 작성

    pragma circom 2.0.0;
    include "./circomlib/circuits/sha256/sha256.circom";
    
    template program() {
        signal input in[8];
        signal output out[256];
    
        component SHA = Sha256(8);
        SHA.in <== in;
        out <== SHA.out;
    }
    
    component main = program();
    
  2. 프로젝트 디렉토리에서 Git 저장소 circomlib 복제

    git clone https://github.com/iden3/circomlib.git
    
  3. 회로 컴파일

    circom program.circom --r1cs --wasm --sym --c
    

신뢰 설정 - Powers of Tau

  1. 프로젝트 디렉토리에서 ‘powers of tau’ ceremony 시작

    snarkjs powersoftau new bn128 15 pot15_0000.ptau -v
    
  2. 첫 번째 기여

    snarkjs powersoftau contribute pot15_0000.ptau pot15_0001.ptau --name="First contribution" -v
    

신뢰 설정 - Phase 2

  1. program_js 디렉토리에서 Phase 2 준비 (시간이 많이 걸림)

    snarkjs powersoftau prepare phase2 ..\pot15_0001.ptau pot15_final.ptau -v
    
  2. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\program.r1cs pot15_final.ptau program_0000.zkey
    
  3. 첫 번째 기여

    snarkjs zkey contribute program_0000.zkey program_0001.zkey --name="1st Contributor Name" -v
    
  4. 검증키 내보내기

    snarkjs zkey export verificationkey program_0001.zkey verification_key.json
    

증명 성공 예시

  1. program_js 디렉토리에 input.json 파일 생성

    정수 1의 big-endian 비트 표현

    {"in":["0","0","0","0","0","0","0","1"]}
    
  2. program_js 디렉토리에서 witness 생성

    node generate_witness.js program.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove program_0001.zkey witness.wtns proof.json public.json
    

    public.json 파일의 내용

    [
     "0", "1", "0", "0", "1", "0", "1", "1",
     "1", "1", "1", "1", "0", "1", "0", "1",
     "0", "0", "0", "1", "0", "0", "1", "0",
     "0", "0", "1", "0", "1", "1", "1", "1",
     "0", "0", "1", "1", "0", "1", "0", "0",
     "0", "1", "0", "0", "0", "1", "0", "1",
     ...
    ]
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

Python 코드로 입출력 검증

스크립트 실행

input.json 파일로부터 big-endian 비트 배열을 읽어서 바이트 배열로 변환하고 SHA256 해시 생성하여 output.txt에 저장

python calc_sha256_python.py --input-filepath input.json --output-dir .

output.txt

Input Bytes:
   1

Output Bits (Little Endian):
1 1 0 1  0 0 1 0      1 0 1 0  1 1 1 1
0 1 0 0  1 0 0 0      1 1 1 1  0 1 0 0
0 0 1 0  1 1 0 0      1 0 1 0  0 0 1 0
0 0 1 0  1 0 1 0      1 0 1 0  0 0 1 1
1 1 0 1  1 1 0 0      0 1 1 1  1 0 1 1
0 1 1 1  0 1 0 0      1 1 0 1  1 1 0 1
0 0 1 1  0 0 0 1      0 1 0 0  1 0 1 1
1 1 1 0  1 1 0 1      1 1 0 0  0 1 1 1
1 0 0 0  1 0 1 1      0 0 0 0  0 1 1 0
0 1 0 1  0 0 0 0      0 1 1 0  1 0 1 1
1 0 0 0  1 1 0 0      1 1 0 0  0 0 1 1
1 0 1 0  0 0 0 1      1 0 1 0  0 1 0 1
1 1 1 0  1 0 1 1      0 0 1 1  0 0 1 1
0 1 0 0  0 1 1 1      0 0 1 1  1 1 0 0
1 1 1 0  1 1 1 0      1 0 1 0  0 0 0 1
1 0 1 0  0 0 1 0      0 1 0 1  1 0 0 1

Output Bits (Big Endian):
0 1 0 0  1 0 1 1      1 1 1 1  0 1 0 1
0 0 0 1  0 0 1 0      0 0 1 0  1 1 1 1
0 0 1 1  0 1 0 0      0 1 0 0  0 1 0 1
0 1 0 1  0 1 0 0      1 1 0 0  0 1 0 1
0 0 1 1  1 0 1 1      1 1 0 1  1 1 1 0
0 0 1 0  1 1 1 0      1 0 1 1  1 0 1 1
1 0 0 0  1 1 0 0      1 1 0 1  0 0 1 0
1 0 1 1  0 1 1 1      1 1 1 0  0 0 1 1
1 1 0 1  0 0 0 1      0 1 1 0  0 0 0 0
0 0 0 0  1 0 1 0      1 1 0 1  0 1 1 0
0 0 1 1  0 0 0 1      1 1 0 0  0 0 1 1
1 0 0 0  0 1 0 1      1 0 1 0  0 1 0 1
1 1 0 1  0 1 1 1      1 1 0 0  1 1 0 0
1 1 1 0  0 0 1 0      0 0 1 1  1 1 0 0
0 1 1 1  0 1 1 1      1 0 0 0  0 1 0 1
0 1 0 0  0 1 0 1      1 0 0 1  1 0 1 0

Output Bytes:
  75  245   18   47   52   69   84  197   59  222   46  187  140  210  183  227
 209   96   10  214   49  195  133  165  215  204  226   60  119  133   69  154

SHA-256 Hash: 4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a

참고 자료

  1. Zero-Knowledge Proof of SHA256 Hash using zkSNARK, Binod, Medium
  2. Circom SHA256, Jonas Pauli, Medium
  3. circom-sha256, jonas089, GitHub

Written with StackEdit.

Circom 예제로 영지식 증명 시작하기 (1)

Circom 예제로 영지식 증명 시작하기 (1)

Circom 2 Getting started 문서를 따라하면서 작성한 문서입니다.

실습 환경:

  • Windows 11
  • Node.js v20.18.0
  • circom compiler 2.1.9
  • snarkjs@0.7.5

1. 소프트웨어 설치

  1. Downloads 페이지에서 circom Windows binary를 클릭하고 파일 circom-windows-amd64.exe 를 원하는 디렉토리에 저장합니다. 파일 크기는 약 10MB입니다. 여기서는 파일 이름을 circom.exe로 바꾸고 아래 경로에 저장합니다.
    C:\DevTools\circom.exe
    
  2. snarkjs를 설치합니다.
    npm install -g snarkjs
    

2. 회로 생성하기

  1. 아래 내용을 multiplier2.circom 에 저장합니다.

    pragma circom 2.0.0;
    
    /*This circuit template checks that c is the multiplication of a and b.*/  
    
    template Multiplier2 () {
       // Declaration of signals.
       signal input a;
       signal input b;
       signal output c;
    
       // Constraints.
       c <== a * b;
    }
    
    component main = Multiplier2();
    

3. 회로 컴파일하기

  1. multiplier2.circom 파일을 컴파일합니다.

    circom multiplier2.circom --r1cs --wasm --sym --c
    

    컴파일 결과 다음과 같은 파일들이 생성됩니다.

    multiplier2.r1cs
    multiplier2.sym
    multiplier2_cpp\
        calcwit.cpp
        calcwit.hpp
        circom.hpp
        fr.asm
        fr.cpp
        fr.hpp
        main.cpp
        Makefile
        multiplier2.cpp
        multiplier2.dat
    multiplier2_js\
        generate_witness.js
        multiplier2.wasm
        witness_calculator.js
    

4. witness 계산하기

입력 값, 중간 신호, 출력 값을 witness라고 합니다.

  1. multiplier2_js 디렉토리로 이동합니다.

    cd multiplier2_js
    
  2. 아래 내용을 input.json 파일에 저장합니다.

    {"a": "3", "b": "11"}
    
  3. witness를 계산하여 witness.wtns 파일에 저장합니다.

    node generate_witness.js multiplier2.wasm input.json witness.wtns
    

5. 회로를 영지식으로 증명하기

증명을 생성하기 위하여 아래 두 파일을 사용합니다.

  • multiplier2.r1cs: 회로를 기술하는 제약사항 포함
  • witness.wtns: 모든 계산된 신호 값 포함

여기서는 Groth16 zk-SNARK 프로토콜을 사용하고자 합니다. 이 프로토콜은 trusted setup을 필요로 하고 이 과정은 두 단계로 구성됩니다.

  1. Powers of tau - 회로에 독립적
  2. Phase 2 - 회로에 의존적
5.1. Powers of Tau
  1. “powers of tau” ceremony 시작

    snarkjs powersoftau new bn128 12 pot12_0000.ptau -v
    
  2. ceremony에 기여

    snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
    
5.2. Phase 2
  1. Phase 생성

    snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v
    
  2. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\multiplier2.r1cs pot12_final.ptau multiplier2_0000.zkey
    
  3. ceremony의 phase 2에 기여

    snarkjs zkey contribute multiplier2_0000.zkey multiplier2_0001.zkey --name="1st Contributor Name" -v
    
  4. 검증키 내보내기

    snarkjs zkey export verificationkey multiplier2_0001.zkey verification_key.json
    
5.3. 증명 생성
  1. 회로 및 witness와 연관된 증명을 생성합니다.

    snarkjs groth16 prove multiplier2_0001.zkey witness.wtns proof.json public.json
    

    위 명령은 다음 두 파일을 생성합니다.

    • proof.json: 증명 포함
      {
       "pi_a": [
        "13983182679953556458842508347137149918023927201985471435159758927740558853016",
        "17126988695844741179284716898691257368385629126542168835554345497343624722940",
        "1"
       ],
       "pi_b": [
        [
         "19140696255248677436910729284929621534969442224058440363361064354121562854264",
         "14257009146984576436317952378148206632799369157719061977972167958840456095938"
        ],
        [
         "7733560110556055181607998374149392520454003067800483949057392794063019344423",
         "2891268127818819654691304244486325795969498402824384674233464052246905803426"
        ],
        [
         "1",
         "0"
        ]
       ],
       "pi_c": [
        "21608704327549608970596366226125688092932784974035385756433099903167703539664",
        "19614360261086173764968380312474156102058426242974580364381559870892304372835",
        "1"
       ],
       "protocol": "groth16",
       "curve": "bn128"
      }
      
    • public.json: 공개 입력 및 출력 값 포함
      [
      	"33"
      ]
      
5.4. 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public.json proof.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

6. 정리

실습을 정상적으로 마쳤을 때 multiplier2_js 디렉토리의 파일 목록은 다음과 같습니다.

generate_witness.js
input.json
multiplier2.wasm
multiplier2_0000.zkey
multiplier2_0001.zkey
pot12_0000.ptau
pot12_0001.ptau
pot12_final.ptau
proof.json
public.json
verification_key.json
witness.wtns
witness_calculator.js

Written with StackEdit.

snarkjs 예제로 영지식 증명 시작하기 (2)

snarkjs 예제로 영지식 증명 시작하기 (2)

snarkjs 예제로 영지식 증명 시작하기 (1)에서 작성한 회로의 제한 조건 개수를 1000에서 1로 변경하여 다음 두 가지 예시를 보여 줍니다.

  • 증명 성공 예시
    • a*a + b의 결과가 20인 두 수를 제공할 수 있음
  • 증명 실패 예시
    • a*a + b의 결과가 21인 두 수를 제공할 수 있음

1. 회로 생성

  1. 제한 조건 개수 변경하여 circuit2.circom 파일로 저장

    pragma circom 2.0.0;
    
    template Multiplier(n) {
        signal input a;
        signal input b;
        signal output c;
    
        signal int[n];
    
        int[0] <== a*a + b;
        for (var i=1; i<n; i++) {
            int[i] <== int[i-1]*int[i-1] + b;
        }
    
        c <== int[n-1];
    }
    
    component main = Multiplier(1);
    
  2. 컴파일

    circom --r1cs --wasm --c --sym --inspect circuit2.circom
    

2. 신뢰 설정 - Phase 2

snarkjs 예제로 영지식 증명 시작하기 (1)의 중간 결과물을 활용하면서 새로 생성하는 파일들이 기존 파일들을 덮어쓰는 것을 피하기 위하여 circuit2_js 디렉토리로 이동하여 다음 작업들을 수행합니다.

  1. Phase 2 준비

    snarkjs powersoftau prepare phase2 ..\pot14_beacon.ptau pot14_final.ptau -v
    
  2. 마지막 ptau 검증

    snarkjs powersoftau verify pot14_final.ptau
    
  3. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\circuit2.r1cs pot14_final.ptau circuit2_0000.zkey
    
  4. ceremony의 phase 2에 기여

    snarkjs zkey contribute circuit2_0000.zkey circuit2_0001.zkey --name="1st Contributor Name" -v
    
  5. 두 번째 기여

    snarkjs zkey contribute circuit2_0001.zkey circuit2_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
    
  6. 세 번째 기여

    snarkjs zkey export bellman circuit2_0002.zkey  challenge_phase2_0003
    snarkjs zkey bellman contribute bn128 challenge_phase2_0003 response_phase2_0003 -e="some random text"
    snarkjs zkey import bellman circuit2_0002.zkey response_phase2_0003 circuit2_0003.zkey -n="Third contribution name"
    
  7. 무작위 비콘 적용

    snarkjs zkey beacon circuit2_0003.zkey circuit2_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"
    
  8. 검증키 내보내기

    snarkjs zkey export verificationkey circuit2_final.zkey verification_key.json
    

5. 증명 생성 및 검증

  1. input.json 작성

    {"a": "3", "b": "11"}
    
  2. witness 계산

    snarkjs wtns calculate circuit2.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove circuit2_final.zkey witness.wtns proof.json public.json
    

    public.json 파일의 내용은 다음과 같습니다.

    [
    	"20"
    ]
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

    실행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

6. 증명 실패 예시

  1. public2.json 파일의 내용

    [
    	"21"
    ]
    
  2. 증명 검증

    snarkjs groth16 verify verification_key.json public2.json proof.json
    

    실행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    

Written with StackEdit.

Circom 예제로 영지식 증명 시작하기 (2)

Circom 예제로 영지식 증명 시작하기 (2)

Circom 예제로 영지식 증명 시작하기 (1)에서 작성한 회로를 사용하여 다음 두 가지 예시를 보여 줍니다.

  • 증명 성공 예시
    • 곱셈의 결과가 34인 두 수를 제공할 수 있음
  • 증명 실패 예시
    • 곱셈의 결과가 33인 두 수를 제공할 수 있음
    • 곱셈의 결과가 34인 두 수를 제공할 수 있음

1. witness 계산하기

입력 값, 중간 신호, 출력 값을 witness라고 합니다.

  1. multiplier2_js 디렉토리로 이동합니다.

    cd multiplier2_js
    
  2. 아래 내용을 input2.json 파일에 저장합니다.

    {"a": "2", "b": "17"}
    
  3. witness를 계산하여 witness2.wtns 파일에 저장합니다.

    node generate_witness.js multiplier2.wasm input2.json witness2.wtns
    

2. 증명 성공 예시

2.1. 증명 생성
  1. 회로 및 witness와 연관된 증명을 생성합니다.

    snarkjs groth16 prove multiplier2_0001.zkey witness2.wtns proof2.json public2.json
    

    위 명령은 다음 두 파일을 생성합니다.

    • proof2.json: 증명 포함
      {
       "pi_a": [
        "14743280952072949668948706550574899717145559551048017963794441189237494636481",
        "14298005267871599183835964858782397954547197261581693679006469198474879205631",
        "1"
       ],
       "pi_b": [
        [
         "3626277144031511427418657496308860145981471611754900712998539558757189996322",
         "19214378261821279575001588540284946453492239896169946671818976034832760915828"
        ],
        [
         "17050251975840390849719173233534275494368423304240394905189026587388563221923",
         "2634421260606614787002565397702133406990838684718588715509117554509241602439"
        ],
        [
         "1",
         "0"
        ]
       ],
       "pi_c": [
        "17316308177915526759196441569174377596954015849854187372616893918873802428359",
        "12807215143857622682136446721264951084285188093999940643258181139940589592908",
        "1"
       ],
       "protocol": "groth16",
       "curve": "bn128"
      }
      
    • public2.json: 공개 입력 및 출력 값 포함
      [
      	"34"
      ]
      
2.2. 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public2.json proof2.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

3. 증명 실패 예시

3.1. input2.json -> public.json 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public.json proof2.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    
3.2. input.json -> public2.json 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public2.json proof.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    

Written with StackEdit.

snarkjs 예제로 영지식 증명 시작하기 (1)

snarkjs 예제로 영지식 증명 시작하기 (1)

snarkjs README.md 문서를 따라하면서 작성한 문서입니다.

실습 환경:

  • Windows 11
  • Node.js v20.18.0
  • circom compiler 2.1.9
  • snarkjs@0.7.5

1. 소프트웨어 설치

  1. Downloads 페이지에서 circom Windows binary를 클릭하고 파일 circom-windows-amd64.exe 를 원하는 디렉토리에 저장합니다. 파일 크기는 약 10MB입니다. 여기서는 파일 이름을 circom.exe로 바꾸고 아래 경로에 저장합니다.
    C:\DevTools\circom.exe
    
  2. snarkjs를 설치합니다.
    npm install -g snarkjs
    

2. 신뢰 설정 - Powers of Tau

  1. “powers of tau” ceremony 시작

    snarkjs powersoftau new bn128 14 pot14_0000.ptau -v
    
  2. 첫 번째 기여

    snarkjs powersoftau contribute pot14_0000.ptau pot14_0001.ptau --name="First contribution" -v
    
  3. 두 번째 기여

    snarkjs powersoftau contribute pot14_0001.ptau pot14_0002.ptau --name="Second contribution" -v -e="some random text"
    
  4. 세 번째 기여

    snarkjs powersoftau export challenge pot14_0002.ptau challenge_0003
    snarkjs powersoftau challenge contribute bn128 challenge_0003 response_0003 -e="some random text"
    snarkjs powersoftau import response pot14_0002.ptau response_0003 pot14_0003.ptau -n="Third contribution name"
    
  5. 프로토콜 검증

    snarkjs powersoftau verify pot14_0003.ptau
    
  6. 무작위 비콘 적용

    snarkjs powersoftau beacon pot14_0003.ptau pot14_beacon.ptau 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon"
    

3. 회로 생성

  1. 회로 파일 작성

    pragma circom 2.0.0;
    
    template Multiplier(n) {
        signal input a;
        signal input b;
        signal output c;
    
        signal int[n];
    
        int[0] <== a*a + b;
        for (var i=1; i<n; i++) {
            int[i] <== int[i-1]*int[i-1] + b;
        }
    
        c <== int[n-1];
    }
    
    component main = Multiplier(1000);
    
  2. 컴파일

    circom --r1cs --wasm --c --sym --inspect circuit.circom
    

4. 신뢰 설정 - Phase 2

  1. Phase 2 준비

    snarkjs powersoftau prepare phase2 pot14_beacon.ptau pot14_final.ptau -v
    
  2. 마지막 ptau 검증

    snarkjs powersoftau verify pot14_final.ptau
    
  3. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup circuit.r1cs pot14_final.ptau circuit_0000.zkey
    
  4. ceremony의 phase 2에 기여

    snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="1st Contributor Name" -v
    
  5. 두 번째 기여

    snarkjs zkey contribute circuit_0001.zkey circuit_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
    
  6. 세 번째 기여

    snarkjs zkey export bellman circuit_0002.zkey  challenge_phase2_0003
    snarkjs zkey bellman contribute bn128 challenge_phase2_0003 response_phase2_0003 -e="some random text"
    snarkjs zkey import bellman circuit_0002.zkey response_phase2_0003 circuit_0003.zkey -n="Third contribution name"
    
  7. 무작위 비콘 적용

    snarkjs zkey beacon circuit_0003.zkey circuit_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"
    
  8. 검증키 내보내기

    snarkjs zkey export verificationkey circuit_final.zkey verification_key.json
    

5. 증명 생성 및 검증

  1. input.json 작성

    {"a": "3", "b": "11"}
    
  2. witness 계산

    snarkjs wtns calculate circuit_js/circuit.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

Written with StackEdit.

2024년 10월 22일 화요일

Python 객체 저장 - pickle, pickletools

Python 객체 저장 - pickle, pickletools

pickle, pickletools 모듈 문서

pickle - Python object serialization

  • Protocol version 0 is the original “human-readable” protocol and is backwards compatible with earlier versions of Python.
  • Protocol version 1 is an old binary format which is also compatible with earlier versions of Python.
  • Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to PEP 307 for information about improvements brought by protocol 2.
  • Protocol version 3 was added in Python 3.0. It has explicit support for bytes objects and cannot be unpickled by Python 2.x. This was the default protocol in Python 3.0–3.7.
  • Protocol version 4 was added in Python 3.4. It adds support for very large objects, pickling more kinds of objects, and some data format optimizations. It is the default protocol starting with Python 3.8. Refer to PEP 3154 for information about improvements brought by protocol 4.
  • Protocol version 5 was added in Python 3.8. It adds support for out-of-band data and speedup for in-band data. Refer to PEP 574 for information about improvements brought by protocol 5.

pickletools — Tools for pickle developers

명령 실행 예시

아래 소스 코드를 실행하여 튜플 (1, 2)를 x.pickle 파일로 저장합니다.

from pickle import dump, load

t = (1, 2) 

with open('x.pickle', 'wb') as f: 
    dump(t, f) 

print(f'Write Done: {t}')

x.pickle 파일에 대한 pickle, pickletools 명령 실행 예시입니다.

$ python -m pickle x.pickle 
(1, 2) 
$ python -m pickletools x.pickle 
    0: \x80 PROTO 3 
    2: K BININT1 1 
    4: K BININT1 2 
    6: \x86 TUPLE2 
    7: q BINPUT 0 
    9: . STOP 
highest protocol among opcodes = 2

위에서 pickle은 x.pickle 파일에 저장되어 있는 객체를 복원하여 출력하고 pickletools는 x.pickle 파일을 파싱하여 출력합니다.

Keras 2와 3에서 Tokenizer 객체 저장 및 읽기 테스트

Tokenizer 객체의 pickle 파일은 Keras 2와 Keras 3 간에 호환되지 않습니다. 테스트를 통해서 그 이유를 파악해 봅니다.

아래 소스 코드는 Tokenizer 객체를 tokenizer.pkl 파일에 저장합니다.

from tensorflow.keras.preprocessing.text import Tokenizer 
from pickle import dump 

sample_texts = [ 
    '산악용 자전거' , 
    '자전거 전조등 후미등' , 
    '온라인 상품권' , 
    '온라인 상품 세트' 
] 

sample_tokenizer = Tokenizer() 
sample_tokenizer.fit_on_texts(sample_texts) 

dump(sample_tokenizer, open('tokenizer.pkl', 'wb'))

위 코드를 Keras 2에서 실행하여 tokenizer.pkl 파일을 생성하고 Keras 3에서 읽기를 시도합니다.

$ python -m pickle tokenizer.pkl 
... 
ModuleNotFoundError: No module named 'keras.src.preprocessing'

Keras 2에서 생성한 tokenizer.pkl 파일을 Keras 3에서 읽는 과정에서 오류가 발생했고 pickletools로 tokenizer.pkl 파일에 대하여 좀 더 자세한 정보를 출력해 봅니다.

$ python -m pickletools tokenizer.pkl 
     0: \x80 PROTO 4 
     2: \x95 FRAME 587 
    11: \x8c SHORT_BINUNICODE 'keras.src.preprocessing.text' 
    41: \x94 MEMOIZE (as 0) 
    42: \x8c SHORT_BINUNICODE 'Tokenizer' 
    53: \x94 MEMOIZE (as 1) 
    ...

이번에는 위 코드를 Keras 3에서 실행하여 tokenizer.pkl 파일을 생성하고 Keras 2에서 읽기를 시도합니다.

$ python -m pickle tokenizer.pkl 
... 
ModuleNotFoundError: No module named 'keras.src.legacy'

Keras 3에서 생성한 tokenizer.pkl 파일을 Keras 2에서 읽는 과정에서 오류가 발생했고 pickletools로 tokenizer.pkl 파일에 대하여 좀 더 자세한 정보를 출력해 봅니다.

python -m pickletools tokenizer.pkl 
     0: \x80 PROTO 4 
     2: \x95 FRAME 594 
    11: \x8c SHORT_BINUNICODE 'keras.src.legacy.preprocessing.text' 
    48: \x94 MEMOIZE (as 0) 
    49: \x8c SHORT_BINUNICODE 'Tokenizer' 
    60: \x94 MEMOIZE (as 1) 
    ...

Keras 2와 비교하여 Keras 3에서 Tokenizer를 저장하고 읽을 때 사용하는 모듈의 이름이 바뀌었고 이름 중에 legacy가 들어가 있습니다.

  • Keras 2: keras.src.preprocessing.text
  • Keras 3: keras.src.legacy.preprocessing.text

이것은 아마도 아래와 같이 Tokenizer 상태를 DEPRECATED로 바꾼 것과 관련이 있어 보입니다.

  • Tokenizer는 DEPRECATED 상태

※ 참고: preprocessing 모듈 전체가 DEPRECATED 상태

정리

  • Tokenizer 객체의 pickle 파일은 Keras 2와 Keras 3 간에 호환되지 않습니다. 호환되지 않는 이유는 Tokenizer 직렬화에 사용하는 Keras 모듈의 이름이 바뀌었기 때문이며 pickle 프로토콜 버전과는 관련이 없습니다.

Written with StackEdit.

2024년 10월 21일 월요일

TensorFlow 버전과 Keras 2 또는 3 버전

TensorFlow 버전과 Keras 2 또는 3 버전

개요

실습 목적

  • Python 버전에 따라 설치할 수 있는 TensorFlow 버전이 어떻게 달라지는지 파악합니다.
  • TensorFlow를 설치하면 Keras도 설치됩니다. 어느 버전의 TensorFlow부터 Keras 3가 설치되는지 파악합니다.
  • Keras 2.15.0에서 발생하는 TextVectorization 객체 직렬화 문제가 Keras 3에서는 발생하지 않는지 파악합니다.

실습 환경

Windows 10 환경에서 실습하고 문서를 작성하였습니다. 가상 환경 도구로는 Python 기본 라이브러리에 포함되어 있는 venv를 사용하였습니다.

SW 버전
Python
  • 3.9.3
  • 3.12.4
  • pip
  • 22.0.4
  • 24.0
  • TensorFlow
  • 2.15.1
  • 2.16.2
  • Keras
  • 2.15.0
  • 3.4.1
  • Python 3.9.13 + TensorFlow

    Python 설치 파일 다운로드 위치

    설치된 Python과 pip 버전 확인

    >python --version
    Python 3.9.13
    >pip --version
    pip 22.0.4 from C:\Users\user1\AppData\Local\Programs\Python\Python39\lib\site-packages\pip (python 3.9)
    

    설치 가능한 TensorFlow 버전 출력

    >pip index versions tensorflow
    WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning.
    tensorflow (2.17.0)
    Available versions: 2.17.0, 2.16.2, 2.16.1, 2.15.1, 2.15.0, 2.14.1, 2.14.0, 2.13.1, 2.13.0, 2.12.1, 2.12.0, 2.11.1, 2.11.0, 2.10.1, 2.10.0, 2.9.3, 2.9.2, 2.9.1, 2.9.0, 2.8.4, 2.8.3, 2.8.2, 2.8.1, 2.8.0, 2.7.4, 2.7.3, 2.7.2, 2.7.1, 2.7.0, 2.6.5, 2.6.4, 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.3, 2.5.2, 2.5.1, 2.5.0
    

    TensorFlow 2.15.1 설치

    1. 가상환경 만들기

      >python -m venv py39_tf215
      >py39_tf215\Scripts\activate.bat
      
    2. TensorFlow 설치

      (py39_tf215) >pip install tensorflow==2.15.1
      
    3. TensorFlow와 Keras 버전 출력

      (py39_tf215) C:\DevEnv>python -c "import tensorflow; print(tensorflow.__version__)"
      2.15.1
      (py39_tf215) C:\DevEnv>python -c "import keras; print(keras.__version__)"
      2.15.0
      
    4. 가상환경 종료

      (py39_tf215) C:\DevEnv>py39_tf215\Scripts\deactivate.bat
      

    TensorFlow 2.16.2 설치

    1. 가상환경 만들기

      >python -m venv py39_tf216
      >py39_tf216\Scripts\activate.bat
      
    2. TensorFlow 설치

      (py39_tf216) >pip install tensorflow==2.16.2
      
    3. TensorFlow와 Keras 버전 출력

      (py39_tf216) C:\DevEnv>python -c "import tensorflow; print(tensorflow.__version__)"
      2.16.2
      (py39_tf216) C:\DevEnv>python -c "import keras; print(keras.__version__)"
      3.4.1
      
    4. 가상환경 종료

      (py39_tf216) C:\DevEnv>py39_tf216\Scripts\deactivate.bat
      

    Python 3.12.4 + TensorFlow

    Python 설치 파일 다운로드 위치

    설치된 Python과 pip 버전 확인

    >python --version
    Python 3.12.4
    >pip --version
    pip 24.0 from C:\Users\user1\AppData\Local\Programs\Python\Python312\Lib\site-packages\pip (python 3.12)
    

    설치 가능한 TensorFlow 버전 출력

    >pip index versions tensorflow
    WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning.
    tensorflow (2.17.0)
    Available versions: 2.17.0, 2.16.2, 2.16.1
    

    TensorFlow 2.16.1 부터 설치 가능하고 이 버전을 설치하면 Keras 3가 함께 설치됩니다.

    그렇다고 Keras 2를 설치할 수 없다는 것은 아닙니다. 아래와 같이 Keras 2, Keras 3에 해당하는 다양한 버전을 설치할 수 있습니다.

    >pip index versions keras
    WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning.
    keras (3.4.1)
    Available versions: 3.4.1, 3.4.0, 3.3.3, 3.3.2, 3.3.1, 3.3.0, 3.2.1, 3.2.0, 3.1.1, 3.1.0, 3.0.5, 3.0.4, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 2.15.0, 2.14.0, 2.13.1, 2.12.0, 2.11.0, 2.10.0, 2.9.0, 2.8.0, 2.7.0, 2.6.0, 2.4.3, 2.4.2, 2.4.1, 2.4.0, 2.3.1, 2.3.0, 2.2.5, 2.2.4, 2.2.3, 2.2.2, 2.2.1, 2.2.0, 2.1.6, 2.1.5, 2.1.4, 2.1.3, 2.1.2, 2.1.1, 2.1.0, 2.0.9, 2.0.8, 2.0.7, 2.0.6, 2.0.5, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 1.2.2, 1.2.1, 1.2.0, 1.1.2, 1.1.1, 1.1.0, 1.0.8, 1.0.7, 1.0.6, 1.0.5, 1.0.4, 1.0.3, 1.0.2, 1.0.1, 1.0.0, 0.3.3, 0.3.2, 0.3.1, 0.3.0, 0.2.0
    

    TextVectorization 객체 직렬화 문제

    Keras 2.15.0에서 오류 발생

    Keras 2.15.0에서 TextVectorization 객체 직렬화 문제가 발생합니다.

    Traceback (most recent call last):
      File "C:\DevWork\trvoid\GitHub\ml-study\python-basics\TextVectorization-basics.py", line 110, in <module>
        main(args)
      File "C:\DevWork\trvoid\GitHub\ml-study\python-basics\TextVectorization-basics.py", line 93, in main
        save_text_vectorization(text_vectorization, output_filepath)
      File "C:\DevWork\trvoid\GitHub\ml-study\python-basics\TextVectorization-basics.py", line 32, in save_text_vectorization
        pickle.dump(text_vectorization, f)
      File "C:\DevEnv\tensorflow215\lib\site-packages\tensorflow\python\framework\ops.py", line 314, in __reduce__
        return convert_to_tensor, (self._numpy(),)
      File "C:\DevEnv\tensorflow215\lib\site-packages\tensorflow\python\framework\ops.py", line 362, in _numpy
        raise core._status_to_exception(e) from None  # pylint: disable=protected-access
    tensorflow.python.framework.errors_impl.InvalidArgumentError: Cannot convert a Tensor of dtype resource to a NumPy array.
    

    해결 방법

    Keras 2.15.0에서의 TextVectorization 객체 직렬화 문제는 아래 문서에서 해결 방법을 찾을 수 있습니다.

    Keras 3.4.1에서는 정상 처리됨

    Keras 3.4.1에서는 TextVectorization 객체 직렬화가 정상적으로 처리됩니다.

    정리

    TensorFlow와 함께 설치되는 Keras 버전

    • TensorFlow 2.15.1 => Keras 2.15.0
    • TensorFlow 2.16.1 => Keras 3.4.1

    참고 사항

    • Python 3.12.4를 설치하면 TensorFlow 2.16.1부터 설치 가능
    • TensorFlow 2.16.1에서 Keras 2.15.0을 설치하는 것도 가능

    Written with StackEdit.

    2024년 7월 27일 토요일

    카이제곱 검정 제대로 이해하기

    카이제곱 검정 제대로 이해하기

    1. 개념 이해

    비교란 무엇인가?

    비교의 대상은 두 개이고 두 비교 대상의 차이를 살펴 보는 것이다.

    • 여기서는 관찰값기댓값의 차이를 사용한다.
      • 관찰값: 관찰을 통해 얻는 값
      • 기댓값: 관찰값에 대한 기댓값으로서 어떤 가정을 바탕으로 함.
    • 두 비교 대상에 대하여 비교할 수 있는 지점은 한 개일 수도 있고 여러 개일 수도 있다.

    비교의 목적은 무엇인가?

    • 관찰값관찰값을 비교 대상으로 삼을 수는 없는가?
      • 비교할 수 있다. 그런데 어떻게 비교할 것인가?
        • 기댓값을 찾고 관찰값들이 기댓값을 중심으로 어떤 분포를 따르는지 이해하는 것이 필요하다.
          • 왜 그런가?
            • 분포를 가정하지 않으면 흔히 일어나는 차이인지 아니면 드물게 일어나는 차이인지 객관적으로 표현하기가 어렵다.
    • 기댓값을 찾으려면 왜 그런 기대를 하게 되었는지와 관련하여 어떤 가정을 세워야 한다.
      • 그 가정 위에서 기댓값을 구하고 차이를 계산했더니 흔히 일어나는 차이에 해당하면 그 가정은 유효하다고 간주하고 드물게 일어나는 차이에 해당하면 그 가정은 유효하지 않다고 간주한다.
      • 결국 관찰값과 기댓값의 차이를 통해 가정이 유효한지 아닌지 판단하는 것이므로 비교의 목적은 어떤 가정을 채택할 것인지 버릴 것인지를 판단하기 위함이라고 말할 수 있다.

    2. 차이의 정도와 의미

    차이의 정도를 수치로 나타낼 수 있는가?

    비교 대상 간의 총체적인 차이는 무엇으로 정의할 것인가?

    • 개별 데이터 지점에서의 차이 값의 제곱의 합이라고 정의하자. 절대값의 합이 아니라 제곱의 합으로 정의한 이유는 수학적으로 다루기가 훨씬 쉽기 때문일 것이다.
    • 아래의 수식은 피어슨 카이제곱 통계량이고 이것으로 총체적인 차이를 계산한다. OiO_iii번째 데이터 지점에서의 관찰값, EiE_iii번째 데이터 지점에서의 기댓값을 나타낸다.

    χ2=i=1m(OiEi)2Ei(1) \chi^2 = \sum_{i=1}^{m} \frac {(O_i-E_i)^2}{E_i} \tag{1}

    특정 값의 총체적인 차이가 발생할 가능성은?

    • 차이의 정도에 대한 가정
      • 개별 데이터 지점에서 관찰값기댓값의 차이의 정도는 확률변수이고 정규분포를 따른다.
        • 오차에 대한 가정을 주로 이렇게 한다는 점을 참고하자.
        • 편차 제곱을 기댓값으로 나눔으로써 표준화를 시도한다.
      • 모든 데이터 지점에서 기댓값은 5 이상이어야 한다.
        • 대표본 가정
    • 그렇다면 총체적인 차이가 특정 값 이상일 가능성은?
      • 총체적인 차이 값은 확률변수이고 자유도를 파라미터로 하는 카이제곱 분포를 따른다.
        • 좀 더 정확하게 표현하자면 이런 경우의 분포를 카이제곱 분포라고 정의한 것이다.
      • 카이제곱 분포표에서 자유도와 유의수준에 해당하는 카이제곱 값을 찾을 수 있다.
        • 총체적인 차이가 카이제곱 분포표에서 찾은 카이제곱 값보다 작으면 흔히 일어날 수 있는 차이로 간주하고 그렇지 않으면 쉽게 일어나기 어려운 차이로 간주한다.

    차이의 정도가 유의미한가?

    1. 유의수준 α\alpha를 설정한다. 여기서는 α=0.05\alpha = 0.05로 하자.
    2. 자유도가 얼마인지 파악한다.
    3. 개별 데이터 지점에 대하여 기댓값을 파악하거나 계산한다.
    4. 피어슨 카이제곱 통계량을 계산한다.
    5. 카이제곱 분포표에서 자유도유의수준에 해당하는 카이제곱 값을 찾는다.
    6. 계산한 카이제곱 값이 분포표에서 찾은 카이제곱 값보다
      • 작으면 차이가 유의미하지 않다고 보고 대립가설을 기각한다.
      • 크면 차이가 유의미하다고 간주하고 대립가설을 채택한다.

    차이가 유의미하다는 것은 무슨 뜻인가?

    검정 목적별로 해석을 달리한다.

    • 적합도 검정 (Goodness-of-fit Test)
      • 주머니속 사탕 색깔의 구성 비율이 특정 비율을 따르는지? ⇒ 구성 비율에 대한 추측이 사실이 아닐 가능성이 높다.
    • 동질성 검정 (Test of Homogeneity)
      • 성별에 따른 메뉴 선호도가 유사한지? ⇒ 성별에 따른 메뉴 선호도가 유사하지 않을 가능성이 높다.
    • 독립성 검정 (Test of Independence)
      • 성별과 메뉴 선호도가 서로 관련이 없는지? ⇒ 성별과 메뉴 선호도가 서로 관련이 있을 가능성이 높다.

    다음 두 가지 설명이 동질성 검정과 독립성 검정의 차이를 이해하는데 도움이 될 것이다.

    • 독립성 검정의 결과
      • 서로 관련이 없다.
        • 동질성 검정 필요 없음
      • 서로 관련이 있다.
        • 동질성 검정의 결과
          • 유사하다.
          • 유사하지 않다.
            • 서로 관련은 있으나 유사하지는 않은 경우
              • 예를 들자면 남자가 좋아하는 메뉴는 여자가 싫어하고 남자가 싫어하는 메뉴는 여자가 좋아함
    • 동질성 검정의 결과
      • 유사하다.
        • 독립성 검정 필요 없음
      • 유사하지 않다.
        • 독립성 검정의 결과
          • 서로 관련이 없다.
          • 서로 관련이 있다.
            • 유사하지는 않으나 서로 관련은 있는 경우
              • 예를 들자면 남자가 좋아하는 메뉴는 여자가 싫어하고 남자가 싫어하는 메뉴는 여자가 좋아함

    카이제곱 검정 예를 좀 더 구체적으로 살펴 본다면?

    • 적합도 검정
      • 관찰값의 분포를 통해 모집단의 분포를 확인하는 검정
        • 예시: 주머니 속 사탕을 복원추출하여 파악한 색깔 구성 비율을 토대로 주머니 속 사탕 색깔이 골고루 섞여 있다고 볼 수 있는지?
          • 첫 번째 행은 관찰도수, 두 번째 행은 기대도수
          • 관찰도수와 기대도수의 차이를 사용하여 χ2\chi^2 구하기
    • 동질성 검정
      • 각기 다른 모집단으로부터 표본을 추출하여 특성 값에 따라 분류하고 두 모집단의 특성 값 비율이 유사한지 검정
        • 예시: 성별에 따른 메뉴 선호도가 유사한지?
          • 행은 집단, 열은 특성 값
          • 행의 주변도수 크기 고정
          • 열의 주변도수(marginal frequency)를 구하고 이들의 분포를 활용하여 각 행의 특성 값들에 대하여 기대도수 구하기
          • 관찰도수와 기대도수의 차이를 사용하여 χ2\chi^2 구하기
    • 독립성 검정
      • 두 종류 이상의 범주형 변수를 사용하여 자료를 분류하였을 때 변수들이 서로 독립적인지 검정
        • 예시: 성별과 메뉴 선호도가 서로 관련이 없는지?
          • 표본 크기 고정
          • 두 변수가 서로 독립적이다라는 전제로 기댓값 구하기
          • 관찰도수와 기대도수의 차이를 사용하여 χ2\chi^2 구하기

    카이제곱 검정의 세 종류는 서로 다른 목적을 가지고 있지만 공통점은 다음과 같다.

    • 관찰값기댓값의 차이를 계산한다. 관찰값과 관찰값의 차이를 계산하는 것이 아님에 주목하자.

    더 많은 예시

    • 적합도 검정
      • 멘델의 유전법칙에 의하면 4종류의 식물이 9:3:3:1의 비율로 나오게 되어 있다고 한다. 240그루의 식물을 관찰하였더니 120:40:55:25로 나타났다. 유의수준 5%로 적합도 검정을 하시오
      • 어느 공정의 부적합품률은 15%로 알려져있다. 시료를 80개 추출하여 검사한 결과 불량이 16개이다. 유의수준 5%로 적합도 검정을 하시오.
      • 두 정당에 대한 지지율이 한 달 전에는 54:46이었다.
    • 동질성 검정
      • 남,녀 각각 500명을 임의로 추출하였고, 성별에 따른 선호도가 관련성이 있는지, 유의수준 0.05에서 검정하시오.
      • 기존약과 신약의 효과 비교
      • 성별에 따른 흡연 여부의 분포
    • 독립성 검정
      • 영화 장르와 간식류 구매는 서로 연관이 있는지 검정하시오.
      • 보호구 착용과 부상 정도
      • 성별과 흡연 여부의 관련성

    3. 카이제곱 분포와 검정

    카이제곱 분포

    양의 정수 kk에 대하여 kk 개의 독립적이고 표준정규분포를 따르는 확률변수 X1X_1, …, XkX_k를 정의하면 자유도 kk의 카이제곱 분포는 확률변수

    Q=i=1kXi2(2) Q = \sum_{i=1}^{k} X_i^2 \tag{2}

    가 따르는 분포입니다.


    이미지 출처: 카이제곱 분포와 검정, 공돌이의 수학정리노트

    피어슨 카이제곱 통계량

    χ2=i=1m(OiEi)2Ei(3) \chi^2 = \sum_{i=1}^{m} \frac {(O_i-E_i)^2}{E_i} \tag{3}

    1. 기댓값을 파악한다.
    2. 관찰값과 기댓값의 차이를 구하여 제곱하고 기댓값으로 나눔으로써 정규화를 한다.
    3. 각각의 관찰 속성에 대하여 위와 같이 구한 값을 더한다.

    모든 관찰값이 5 이상이면 카이제곱 분포 식 (1)에 근사한다고 증명되어 있다.

    • 관찰값이 5보다 작은 경우라면 카이제곱이 아니라 피셔의 정확 검증 시도

    카이제곱 검정

    예를 들어 자유도 kk인 카이제곱 분포에 대해 아래와 같이 검정을 수행한다.

    1. 유의수준 α\alpha를 정한다.
      • 예: α=0.05\alpha = 0.05
    2. 자유도 kk인 확률변수의 관찰값들에 대하여 카이제곱 값 QQ를 구한다.
      • 예: k=2k = 2 => Q=6.1Q = 6.1
    3. 카이제곱 분포표에서 자유도 kk인 경우 유의수준 α\alpha에 해당하는 카이제곱 값 χ2\chi^2을 찾는다.
      • 예: k=2,α=0.05k = 2, \alpha = 0.05 => χ2=5.99\chi^2 = 5.99
    4. 계산한 카이제곱 값이 카이제곱 분포표에서 찾은 값보다 크면 귀무가설을 기각하고 대립가설을 채택한다.
      • 예: Q>χ2Q > \chi^2 => 차이가 유의하므로 귀무가설 기각, 대립가설 채택

    참고 자료

    Written with StackEdit.

    Llama 3.2로 문장 생성 및 챗팅 완성 실습

    Llama 3.2로 문장 생성 및 챗팅 완성 실습 Running Meta Llama on Linux 문서의 내용을 참고하여 Llama 3.2 1B 모델로 다음 두 가지 기능을 실습합니다. 문장 완성 챗팅 ...