ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2장 토큰화와 Emdeding Python code 예
    LLM/LLM을 활용한 실전 AI 애플리케이션 개발 2025. 1. 18. 22:02

    목차

      github code & 사전준비

      github : 

      https://github.com/onlybooks/llm/blob/main/02%E1%84%8C%E1%85%A1%E1%86%BC/chapter_2_transformer_with_code.ipynb

       

      llm/02장/chapter_2_transformer_with_code.ipynb at main · onlybooks/llm

      LLM을 활용한 실전 AI 애플리케이션 개발. Contribute to onlybooks/llm development by creating an account on GitHub.

      github.com

       

      사전 준비

      01. python 설치 : mac 은 기 설치되어 있음

      python --version
      python3 --version
      # Python 3.12.8

       

      02. pycharm 설치 https://www.jetbrains.com/pycharm

       

      03. pytorch 설치  https://pytorch.org/

      pip3 install torch torchvision torchaudio
      import torch
      print(torch.__version__)

       

      04. numpy 설치 

      pip3 install numpy
      pip3 show numpy
      # 2.2.2

       

      예제 2.1 토큰화 코드

      # 띄어쓰기 단위로 분리
      input_text = "나는 최근 파리로 여행을 다녀왔다"
      input_text_list = input_text.split()
      print("input_text_list: ", input_text_list)
      
      # 토큰 -> 아이디 딕셔너리와 아이디 -> 토큰 딕셔너리 만들기
      str2idx = {word:idx for idx, word in enumerate(input_text_list)}
      idx2str = {idx:word for idx, word in enumerate(input_text_list)}
      print("str2idx: ", str2idx)
      print("idx2str: ", idx2str)
      
      # 토큰을 토큰 아이디로 변환
      input_ids = [str2idx[word] for word in input_text_list]
      print("input_ids: ", input_ids)

       

      result

      input_text_list:  ['나는', '최근', '알프스와', '파리로', '여행을', '다녀왔다']
      str2idx:  {'나는': 0, '최근': 1, '알프스와': 2, '파리로': 3, '여행을': 4, '다녀왔다': 5}
      idx2str:  {0: '나는', 1: '최근', 2: '알프스와', 3: '파리로', 4: '여행을', 5: '다녀왔다'}
      input_ids:  [0, 1, 2, 3, 4, 5]

       

      딕셔너리 컴프리헨션 (Dictionary Comprehension)

      이 코드는 파이썬의 강력한 기능 중 하나인 딕셔너리 컴프리헨션을 활용하여 딕셔너리를 생성하는 부분입니다. 딕셔너리 컴프리헨션은 간결한 문법으로 딕셔너리를 만들 수 있게 해주는 기능입니다.

      {word:idx for idx, word in enumerate(input_text_list)}

       

      코드 분석1

      {word:idx for idx, word in enumerate(input_text_list)}

      1-1) {key:value for item in iterable} 형태

      key : word :  나는 최근 파리로 ...

      value: idx 0,1,2,3,4

       

      1-2) enumerate(input_text_list)는 리스트의 각 요소에 인덱스를 부여합니다:

      # enumerate() 결과
      # (0, "나는")
      # (1, "최근")
      # (2, "파리로")
      # (3, "여행을")
      # (4, "다녀왔다")
       
       
      1-3) for idx, word in enumerate(input_text_list)에서:
      • idx는 각 단어의 인덱스 (0, 1, 2, ...)
      • word는 각 단어 ("나는", "최근", ...)
      • enumerate로 반환된 각 (인덱스, 요소) 쌍을 idx와 word 변수로 각각 저장합니다.
      • 즉, 반복 과정에서 첫 번째 값이 인덱스 idx로, 두 번째 값이 요소 word로 할당됩니다.

      1-4) 최종적으로 생성되는 딕셔너리는:

      str2idx = {
          "나는": 0,
          "최근": 1,
          "파리로": 2,
          "여행을": 3,
          "다녀왔다": 4
      }

       

       

      코드분석2

      input_ids = [str2idx[word] for word in input_text_list]

      결과

      input_ids:  [0, 1, 2, 3, 4]

       

      설명

      input_text_list:  ['나는', '최근', '알프스와', '파리로', '여행을', '다녀왔다']  

      str2idx:  {'나는': 0, '최근': 1, '알프스와': 2, '파리로': 3, '여행을': 4, '다녀왔다': 5}

      input_text_list 에서 for 문을 돌며 글자를 가져와서, str2idx dictionary 의 value 인 index(0,1,2...) 를 가져온다

       

       

      Embedding이란?

      Embedding은 이산적인(discrete) 데이터를 연속적인(continuous) 벡터 공간으로 매핑하는 것입니다.

      주로 자연어 처리에서 단어를 벡터로 변환할 때 사용됩니다.

       

      torch.nn.Embedding의 기본 구조
      pythonCopytorch.nn.Embedding(num_embeddings: int, embedding_dim: int)
      주요 매개변수:
      num_embeddings: 임베딩할 단어의 총 개수 (vocabulary size)
      embedding_dim: 각 단어를 표현할 벡터의 차원

      embedding 예제코드1

      import torch
      import torch.nn as nn
      
      # Embedding 레이어 생성 (단어 개수: 10, 임베딩 차원: 3)
      embedding = nn.Embedding(10, 3)
      
      # 입력 텐서 (단어 인덱스)
      input_ids = torch.LongTensor([1, 4, 3])
      
      # 임베딩 실행
      output = embedding(input_ids)
      output.shape
      # 결과 torch.Size([3, 3])

       

      임베딩 레이어는 (10 × 3) 크기의 가중치 행렬을 생성
      각 단어 인덱스는 이 행렬에서 해당하는 행의 벡터값으로 변환
      output의 shape는 [3, 3]이 됨 (입력 길이 × 임베딩 차원)

       

      embedding 예제코드2

      # 간단한 문장 처리 예시
      vocab_size = 5000  # 단어 사전 크기
      embedding_dim = 100  # 임베딩 차원
      
      embedding_layer = nn.Embedding(vocab_size, embedding_dim)
      
      # 문장을 인덱스로 변환한 텐서
      sentence = torch.LongTensor([[1, 2, 3], [4, 5, 6]])
      
      # 임베딩 적용
      embedded_sentence = embedding_layer(sentence)
      embedded_sentence.shape
      # 결과 torch.Size([2, 3, 100])  (배치 크기, 문장 길이, 임베딩 차원)

       

       

       

      예제 2.2 토큰 아이디에서 벡터로 변환

      import torch
      import torch.nn as nn
      
      input_text = "나는 최근 파리로 여행을 다녀왔다"
      input_text_list = input_text.split()
      str2idx = {word:idx for idx, word in enumerate(input_text_list)}
      input_ids = [str2idx[word] for word in input_text_list] # {0,1,2,3,4}
      
      embedding_dim = 16
      embed_layer = nn.Embedding(len(str2idx), embedding_dim)
      
      input_embeddings = embed_layer(torch.tensor(input_ids)) # (5, 16)
      input_embeddings = input_embeddings.unsqueeze(0) # (1, 5, 16)
      input_embeddings.shape

      result

      torch.Size([1, 5, 16])

       

       

      input_ids:  [0, 1, 2, 3, 4] 이므로 len(str2idx) = 5  입니다.

      embed_layer = nn.Embedding(len(str2idx), embedding_dim) 에서 (5,16) 의 임베딩 벡터 차원이 생성됩니다 

       

      input_embeddings = input_embeddings.unsqueeze(0) # (1, 5, 16) 에서 

      unsqueeze(0) 을 통해 첫번째에 1인 차원을 생성했으므로

      (5,16) -> (1,5,16) 으로 임베딩 벡터 차원이 변경됩니다

       

      Squeeze 함수

      squeeze함수는 차원이 1인 차원을 제거해준다.

      따로 차원을 설정하지 않으면 1인 차원을 모두 제거한다. 그리고 차원을 설정해주면 그 차원만 제거한다.

      import torch
      
      x = torch.rand(3, 1, 20, 128)
      x = x.squeeze() #[3, 1, 20, 128] -> [3, 20, 128]

       

      import torch
      
      x = torch.rand(1, 1, 20, 128)
      x = x.squeeze() # [1, 1, 20, 128] -> [20, 128]
      
      x2 = torch.rand(1, 1, 20, 128)
      x2 = x2.squeeze(dim=1) # [1, 1, 20, 128] -> [1, 20, 128]

       

      unsqueeze함수

      unsqueeze함수는 squeeze함수의 반대로 1인 차원을 생성하는 함수이다.

      그래서 어느 차원에 1인 차원을 생성할 지 꼭 지정해주어야한다.

      import torch
      
      x = torch.rand(3, 20, 128)
      x = x.unsqueeze(dim=1) #[3, 20, 128] -> [3, 1, 20, 128]

       

      출처 : [PyTorch] squeeze, unsqueeze함수: 차원 삭제와 차원 삽입

      https://sanghyu.tistory.com/86

       

      [PyTorch] squeeze, unsqueeze함수: 차원 삭제와 차원 삽입

      squeeze함수 squeeze함수는 차원이 1인 차원을 제거해준다. 따로 차원을 설정하지 않으면 1인 차원을 모두 제거한다. 그리고 차원을 설정해주면 그 차원만 제거한다. Python 코드 import torch x = torch.rand(3

      sanghyu.tistory.com

       

       

      torch.arrange 함수

      torch.arange는 PyTorch에서 사용되는 함수로, 주어진 범위의 값을 포함하는 1차원 텐서를 생성합니다. 

      이 함수는 주로 데이터 생성 및 초기화에 유용합니다.

      PyTorch 라이브러리의 함수로, 일정 간격을 가지고 숫자의 배열을 생성하는 데 사용됩니다. 
      이 함수는 NumPy의 arange 함수와 유사합니다. 주요 사용법은 다음과 같습니다:

      torch.arange(start=0, end, step=1, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)


      각 매개변수는 다음과 같은 의미를 가집니다:
      start: 배열의 시작 값 (포함).
      end: 배열의 끝 값 (포함되지 않음).
      step: 숫자 간의 간격 (기본값은 1).
      dtype: 생성할 배열의 데이터 타입 (선택 사항).
      device: 배열이 할당될 장치 (선택 사항).

       


      import torch
      tensor1 = torch.arange(5)  # tensor([0, 1, 2, 3, 4])

      tensor2 = torch.arange(1, 4)  # tensor([1, 2, 3])

      tensor3 = torch.arange(0, 10, 2)  # tensor([0, 2, 4, 6, 8])

       

       

      예제 2.3 절대적 위치 인코딩

      import torch
      import torch.nn as nn
      
      embedding_dim = 16
      max_position = 12
      # 토큰 임베딩 층 생성
      embed_layer = nn.Embedding(len(str2idx), embedding_dim)
      
      # 위치 인코딩 층 생성
      position_embed_layer = nn.Embedding(max_position, embedding_dim)
      
      position_ids = torch.arange(len(input_ids), dtype=torch.long).unsqueeze(0)
      position_encodings = position_embed_layer(position_ids)
      
      token_embeddings = embed_layer(torch.tensor(input_ids)) # (5, 16)
      token_embeddings = token_embeddings.unsqueeze(0) # (1, 5, 16)
      
      # 토큰 임베딩과 위치 인코딩을 더해 최종 입력 임베딩 생성
      input_embeddings = token_embeddings + position_encodings
      input_embeddings.shape
      
      print("position_ids:", position_ids)
      print("input_embeddings.shape",input_embeddings.shape)
      
      # result 
      # position_ids: tensor([[0, 1, 2, 3, 4]])
      # input_embeddings.shape torch.Size([1, 5, 16])

       

      str2idx:  {'나는': 0, '최근': 1, '파리로': 2, '여행을': 3, '다녀왔다': 4}

      input_ids:  [0, 1, 2, 3, 4]

      를 이용하여, 

      token_embeddings 과 

      position_enbedding 을 하는 코드 입니다

       

      둘다 차원은 5,16 -> 1,5,16 입니다.

       

      position_embed_layer = nn.Embedding(max_position, embedding_dim)
      print("position_embed_layer:", position_embed_layer)
      # position_embed_layer: Embedding(12, 16)

      위 코드로 위치 인코딩 층을 12,16 으로 생성합니다

       

      position_ids = torch.arange(len(input_ids), dtype=torch.long).unsqueeze(0)
      print("position_ids:", position_ids)
      # position_ids: tensor([[0, 1, 2, 3, 4]])

      위 코드에서  torch.arrange 를 사용하여 position_ids 를 만듭니다.

       

      position_encodings = position_embed_layer(position_ids)
      print("position_encodings:", position_encodings)
      # position_encodings: 
      # tensor([[[ 1.2249,  0.6867,  1.7294,  0.3493,  0.0687,  1.5959,  1.9263,
      #            2.1862, -0.0935, -0.1626,  0.9718,  1.3019,  2.8211, -0.6323,
      #           -1.2881,  0.1205],
      #          [ 0.4762,  0.6097, -0.2412,  0.0338, -2.1402, -0.4766,  2.0567,
      #           -1.1137,  0.8133, -0.2408, -0.7346,  0.1239, -1.3321, -0.3675,
      #           -1.9920,  2.4420],
      #          [ 0.2850, -1.9323, -1.4105,  0.8441,  1.2749,  0.5842, -0.0642,
      #            0.6701,  0.5678,  1.1704, -0.8503,  1.6145,  0.2567,  0.9667,
      #            1.2605, -0.4639],
      #          [ 2.4829,  0.0128,  1.4214,  1.2140,  1.3723, -0.4188, -0.5099,
      #           -0.9746,  1.2901, -0.1404,  0.9404,  1.9529, -0.0886,  1.9274,
      #           -0.0831,  1.8268],
      #          [-0.2267,  0.0037, -0.4448,  0.9218, -1.5701,  0.3842, -0.5214,
      #            1.6281,  0.5830,  2.2555,  0.1615,  0.2579, -0.6377,  0.3406,
      #           -0.1599, -1.7529]]], grad_fn=<EmbeddingBackward0>)

      positions_ids 를  생성해둔 poistion_embed_layer 층에 넣어서, position encoding 을 합니다.

       

       

      token_embeddings = embed_layer(torch.tensor(input_ids)) # (5, 16)
      token_embeddings = token_embeddings.unsqueeze(0) # (1, 5, 16)
      print("token_embeddings", token_embeddings)
      #token_embeddings 
      # tensor([[[ 1.2940,  0.5634, -0.9380,  2.0672, -0.7711, -0.5628,  1.5723,
      #           -0.0757,  0.0325,  0.3588,  0.1069,  1.1663, -0.0736,  0.4490,
      #           -0.5269, -0.3489],
      #          [-0.7662,  0.0792, -0.2584, -1.4920,  1.6173,  1.3689, -1.0596,
      #           -0.9092,  0.3055, -0.9085,  0.2122,  0.3238,  0.3050, -0.8115,
      #            0.5968, -1.5606],
      #          [-1.0736,  2.1904,  0.4247,  1.1781, -1.3371, -1.0677, -0.6786,
      #            0.1351, -0.8071, -0.0088,  0.4296,  1.9977, -0.8690,  1.0972,
      #            0.1069,  0.3029],
      #          [ 0.2464,  0.2058,  0.3025,  0.2863, -0.3435, -2.3024, -1.5169,
      #            0.9519,  1.2383,  0.3907,  0.9274, -0.7000, -2.3389, -1.5153,
      #           -1.5764, -0.7036],
      #          [ 0.7313,  0.0512,  0.6351, -0.4502, -0.3187, -0.3763, -1.0381,
      #           -1.8719,  1.3853, -1.1969,  0.9985,  0.2518,  0.6452,  0.7640,
      #            0.5743,  0.5138]]], grad_fn=<UnsqueezeBackward0>)

      token 도 유사한 방법으로 embeding 합니다

       

      댓글

    Designed by Tistory.