A. 텍스트 전처리 전체 흐름 요약
텍스트(문장) → 토큰화 → 정수 인코딩 → 패딩 → 텐서 변환
import json
file_path = '/content/일상생활및구어체_한영_valid_set.json'
with open(file_path, 'r', encoding='utf-8') as f:
raw_json = json.load(f)
data = raw_json['data']
print(f"전체 문장 쌍 개수: {len(data)}")
# 샘플 하나 확인
print("예시 샘플:")
print(f"한국어: {data[0]['ko']}")
print(f"영어: {data[0]['mt']}")
전체 문장 쌍 개수: 150000
예시 샘플:
한국어: >아, 진짜요?
영어: Oh, really?
1. 텍스트 정제 : 특수 기호 제거, 소문자 통일, 불용어 제거..
예: "I'm a student!" → "i am a student"
+ 기계번역에선 불용어 제거를 하지 않는 것이 일반적이기에 코드 X
2. 토큰화 : 문장을 단어 혹은 형태소로 쪼개는 과정도구 : nltk(영어), Okt(한국어), KoNLPy(한국어)
예: I am a student → ["I", "am", "a", "student"]
import nltk
nltk.download('punkt') # 영어 토큰화용 룰 데이터
nltk.download('punkt_tab')
from nltk.tokenize import word_tokenize
def tokenize_ko(sentence):
return sentence.strip().replace(">", "").split() # 간단하게 띄어쓰기 기준
# 후에 Okt 로 토큰화 더 자연스럽게 진행할 수 있음
def tokenize_en(sentence):
return word_tokenize(sentence.strip().replace(">", ""))
tokenized_pairs = [] # 문자 토큰들..
for item in data:
ko = item['ko']
en = item['mt']
tokenized_ko = tokenize_ko(ko)
tokenized_en = tokenize_en(en)
tokenized_pairs.append((tokenized_ko, tokenized_en)) # 토큰화된 한글/영어 문장 쌍을 하나의 튜플로 묶어서 리스트에 추가
print("샘플 토큰화 결과:")
print("한국어:", tokenized_pairs[0][0]) # 0번째 문장 한국어 토큰 리스트
print("영어:", tokenized_pairs[0][1]) # 0번째 문장 영어 토큰 리스트
샘플 토큰화 결과:
한국어: ['아,', '진짜요?']
영어: ['Oh', ',', 'really', '?']
+ 토큰 길이 측정
ko_lengths = [len(pair[0]) for pair in tokenized_pairs]
en_lengths = [len(pair[1]) for pair in tokenized_pairs]
print(f"한국어 평균 길이: {sum(ko_lengths)/len(ko_lengths):.2f}, 최대 길이: {max(ko_lengths)}")
print(f"영어 평균 길이: {sum(en_lengths)/len(en_lengths):.2f}, 최대 길이: {max(en_lengths)}")
한국어 평균 길이: 6.53, 최대 길이: 78
영어 평균 길이: 11.52, 최대 길이: 69
+ MAX_LENGTH = 80으로 설정 .. (최대길이 78 + a)
3. 어휘 사전 구축 & 정수 인코딩 : 각 단어를 고유한 숫자 인덱스로 바꿔줌→ "나는 학생" → [4, 5]
word2index = { "<pad>": 0, "<sos>": 1, "<eos>": 2, "<unk>": 3, "나는": 4, "학생": 5, ... }
4. 특수 토큰 추가토큰 용도 인덱스 (보통 ..)
| <sos> | 문장 시작 표시 | 1 |
| <eos> | 문장 끝 표시 | 2 |
| <pad> | 고정 길이로 맞추기 위한 패딩 | 0 |
| <unk> | 사전에 없는 단어 처리용 | 3 |
→ "나는 학생" → [1, 4, 5, 2] (sos, eos 포함)
PAD_token = 0 # 패딩용
SOS_token = 1 # 문장 시작
EOS_token = 2 # 문장 끝
UNK_token = 3 # 사전에 없는 단어
5. 패딩 : 모든 문장을 동일한 길이로 맞추기 위한 과정
MAX_LENGTH = 10 → [1, 4, 5, 2] → [1, 4, 5, 2, 0, 0, 0, 0, 0, 0] # PAD = 0
- PAD_token을 뒤에 붙여 고정 길이로 맞춤
- PyTorch 모델 입력 시 필수
6. 텐서 변환 : 파이토치 모델에 넣기 위해 torch.tensor()로 바꿈
tensor = torch.tensor([1, 4, 5, 2, 0, 0, 0, 0, 0, 0], dtype=torch.long)
+ 코드에는 어휘 사전 구축 + 텐서 변환 + 패딩 한 번에 진행
class Lang:
def __init__(self, name):
self.name = name
self.word2index = {} # 단어 -> 인덱스
self.index2word = {} # 인덱스 -> 단어
self.word2count = {} # 단어 등장 횟수
self.n_words = 4 # 전체 개순데 특수 토큰 4개 먼저 등록된 상태로 시작
# 특수 토큰 미리 등록
self.addWord("<pad>")
self.addWord("<sos>")
self.addWord("<eos>")
self.addWord("<unk>")
def addSentence(self, sentence, tokenizer):
for word in tokenizer(sentence):
self.addWord(word)
def addWord(self, word):
if word not in self.word2index:
self.word2index[word] = self.n_words # 딕셔너리로 저장
self.index2word[self.n_words] = word
self.word2count[word] = 1
self.n_words += 1
else:
self.word2count[word] += 1
# addSentence로 문장 받아서 addWord로 보내서 어휘 사전에 Word 추가
input_lang = Lang("ko") # input_lang : 한국어 문장을 위한 어휘 사전 인스턴스
output_lang = Lang("en") # output_lang : 영어 문장을 위한 어휘 사전 인스턴스
for ko, en in tokenized_pairs:
input_lang.addSentence(" ".join(ko), tokenize_ko)
output_lang.addSentence(" ".join(en), tokenize_en)
########################################################
# tokenized_pairs 리스트
#[
# (['안녕하세요', '.'], ['Hello', '.']),
# (['저는', '학생입니다'], ['I', 'am', 'a', 'student']),
# ...
#]
########################################################
print(f"한국어 어휘 수: {input_lang.n_words}")
print(f"영어 어휘 수: {output_lang.n_words}")
한국어 어휘 수: 170947
영어 어휘 수: 35294
문장(토큰들)을 숫자 인덱스 시퀀스로 변환하고 텐서로 바꾸는 작업
토큰 리스트 -> 숫자 인덱스 리스트 -> 패딩 처리 -> PyTorch 텐서로 변환 해야 함
문장 하나를 인덱스 텐서로 바꾸는 함수
import torch
def tensorFromSentence(lang, sentence, tokenizer, max_length):
indexes = [SOS_token] # 시작 토큰 추가
for word in tokenizer(sentence):
index = lang.word2index.get(word, UNK_token) # 단어를 인덱스로 변환
indexes.append(index)
indexes.append(EOS_token) # 끝 토큰 추가
# 패딩
while len(indexes) < MAX_LENGTH:
indexes.append(PAD_token)
return torch.tensor(indexes[:max_length], dtype = torch.long)
# 파이토치 형태로 싹 바꾸기
input_tensors = [tensorFromSentence(input_lang, " ".join(pair[0]), tokenize_ko, MAX_LENGTH) for pair in tokenized_pairs]
output_tensors = [tensorFromSentence(output_lang, " ".join(pair[1]), tokenize_en, MAX_LENGTH) for pair in tokenized_pairs]
근데 왜 리스트를 문자열로 만들었다가 다시 토크나이징 하는 걸까?
이미 tokenized_pairs의 각 문장은 토큰화된 리스트 형태로 저장돼 있는데?
-> Lang 클래스의 addSentence나 tensorFromSentence가 문자열을 받는 설계이기 때문!
+_+ 이후 데이터 로더 구성 ~~
정리
단계 예시 입력 예시 출력
| 정제 | I'm a student! | i am a student |
| 토큰화 | i am a student | ["i", "am", "a", "student"] |
| 인덱싱 | ["i", "am", ...] | [4, 7, 2, 10] |
| 특수토큰 추가 | [4, 7, 2, 10] | [1, 4, 7, 2, 10, 2] |
| 패딩 | [1, 4, 7, 2, 10, 2] | [1, 4, 7, 2, 10, 2, 0, 0, 0, 0] |
| 텐서 변환 | [1, 4, 7, 2, ...] | torch.tensor([...]) |
'Weekly Question' 카테고리의 다른 글
| Q. Word2Vec와 FastText의 차이점 (0) | 2025.04.16 |
|---|