본문 바로가기
프로그램/SKT FLY AI

SKT FLY AI : 24일차

by hsloth 2023. 7. 27.

성능 최적화

데이터를 사용한 성능 최적화


  • 최대한 많은 데이터 수집하기
  • 데이터 생성하기 (어그멘테이션 말하는듯)
  • 데이터 범위 조정하기 : 활성화 함수로 시그보이드를 사용한다면 데이터셋 범위를 01로 갖도록 하고, tanh를 사용한다면 데이터셋 범위를 -11의 값을 갖도록 조정한다. (정규화, 규제화, 표준화도 성능 향상에 도움이 된다)

알고리즘을 이용한 성능 최적화


  • 용도마다 성능이 가장 좋은 모델을 선택하여 사용한다.

알고리즘 튜닝을 위한 성능 최적화


  • 모델을 하나 선택해서 훈련시키려면 다양한 하이퍼파라미터를 변경하면서 훈련시키고 최적의 성능을 도출해야 한다. 이때 선택할 수 있는 하이퍼파라미터로는 다음 항목들이 있다.
  • 진단 : 성능 향상이 어느 순간 멈췄다면 원인을 분석할 필요가 있다.
    • 훈련 성능이 검증보다 눈에 띄게 좋다면 과적함 의심. 이것을 해결하기 위헤 규제화 진행.
    • 현련과 검증 결과가 모두 성능이 좋지 않다면, 과소적합의심. 네트워크 구조를 변경하거나 훈련을 늘리기 위해 에포크 수 조정
    • 훈련 성능이 검증을 넘어서는 변곡점이 있다면 조기 종료 고려
  • 가중치 : 가중치 초기값은 작은 난수 사용.
  • 학습률 : 학습률은 모델의 네트워크 구성에 따라 다르기 때문에 초기에 매우 크거나 작은 임의의 난수를 선택하여 학습 결과를 보고 조금씩 변경해야 한다. 네트워크 계층이 많다면 학습률은 높아야하고, 적으면 학습률은 작게 설정해야 한다.
  • 활성화 함수 : 활성화 함수의 변경은 신중해야 한다. 손실함수도 함께 변경해야 하는 경우가 많기 때문.
  • 배치와 에포크 : 일반적으로 큰 에포크와 작은 배치를 사용하는 것이 트렌드이긴 하지만, 다양한 테스트를 진행하는게 좋다.
  • 옵티마이저 및 손실 함수 : 옵티마이저는 확률적 경사 하강법을 많이 사용한다. 하지만 이것 역시 다양한 테스트를 진행하는게 좋다.
  • 네트워크 구성 : 네트워크 토폴로지라고도 한다.

앙상블을 이용한 성능 최적화


  • 두 개 이상의 간단한 모델을 사용하는 것
  • 데이터가 너무너무 충분히 많으면 굳이 앙상블을 쓰지 않아도 된다. (성능에 큰 차이가 없다) - 강사님의 생각이신것 같다.

하드웨어를 이용한 성능 최적화

CPU와 GPU 사용의 차이


  • 역전파처럼 복잡한 미적분은 병렬 연산을 해야 속도가 빨라지는데, CPU는 순차적 연산일 경우 적합하고, 이럴 때는 GPU를 사용해야 한다.

GPU를 이용한 성능 최적화


  • CUDA를 사용해야 GPU 사용가능
  • 본인 컴퓨터에 맞는 CUDA 툴킷 설치
  • cuDNN 설치
  • GPU 설치 확인 : nvidia-smi

하이퍼파라미터를 이용한 성능 최적화


  • 하이퍼파라미터를 이용한 성능 최적화의 추가적인 방법으로 배치 정규화, 드롭아웃, 조기종료가 있다.

배치 정규화를 이용한 성능 최적화

정규화

  • 데이터 범위를 사용자가 원하는 범위로 제한
  • 데이터의 범위가 각각 너무 차이가 날 경우 정규화를 해주면 좋다.

규제화

  • 모델의 복잡도를 줄이기 위해 제약을 두는 방법
  • 네트워크에 들어가기 전에 필터를 적용한 것이라고 생각하자.
  • 모든 데이터가 아닌 필터로 걸러진 데이터만 네트워크에 투입되어 빠르고 정확한 결과를 얻을 수 있다.
  • 드롭아웃, 조기종료가 있다.

표쥰화

  • 기존 데이터를 평균 0, 표준편차 1인 형태의 데이터로 만드는 방법

배치 정규화

  • 데이터 분포가 안정되어 학습 속도를 높일 수 있다.
  • 기울기 소멸이나 기울기 폭발 같은 문제를 해결하기 위한 방법
  • 네트워크의 각 층마다 활성화 함수가 적용되면서 입력 값들의 분포가 계속 바뀌는 현상을 공변량 변화라고 하는데, 이러한 분산된 분포를 정규분포로 만들기 위해 표준화와 유사한 방식을 미니 배치에 적용하여 평균은 0으로 표준편차는 1로 유지하도록 한다.
    1. 미니 배치 평균을 구한다.
    2. 미니 배치의 분산과 표준편차를 구한다.
    3. 정규화를 수행한다.
    4. 스케일을 조정한다.

드롭아웃을 이용한 성능 최적화


  • 과적합 방지
  • 과적합도, 엄청나게 많은 데이터가 있으면 일어나지 않는다고 한다.
  • 훈련 데이터셋에 대한 오류는 줄어들지만 테스트 데이터셋에 대한 오류는 증가하는 현상이다.
  • 드롭아웃 : 훈련할 때 일정 비율의 뉴런만 사용하고 나머지 뉴런에 해당하는 가중치는 업데이트하지 않는 방법

import torch
import matplotlib.pyplot as plt
import numpy as np
import torchvision
import torchvision.transforms as transforms

import torch.nn as nn
import torch.optim as optim

# 데이터셋 내려 받기
trainset = torchvision.datasets.FashionMNIST(
    root='./data/', train=True, download=True, transform=transforms.ToTensor()
)

# 데이터셋을 메모리로 가져오기
batch_size = 4
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)

# 데이터셋 분리
dataiter = iter(trainloader)
images, labels = next(dataiter)

print(images.shape)
print(images[0].shape)
print(labels[0].item())

# 이미지 데이터를 출력하기 위한 전처리
def imshow(img, title):
  plt.figure(figsize=(batch_size * 4, 4)) # 출력할 개별 이미지의 크기 지정
  plt.axis('off')
  plt.imshow(np.transpose(img, (1, 2, 0)))
  plt.title(title)
  plt.show()

# 이미지 데이터 출력 함수
def show_batch_images(dataloader):
  images, labels = next(iter(dataloader)) # 이미지의 크기는 (4, 28, 28, 1(배치 크기, 높이, 너비, 채널))이 된다.

  img = torchvision.utils.make_grid(images) # 좌표에 이미지 픽셀을 대응시켜 그리드 형태로 출력

  imshow(img, title=[str(x.item()) for x in labels]) # imshow 함수를 사용함으로써 데이터의 형태는 (채널, 높이, 너비)에서 (높이, 너비, 채널)로 변경됩니다.

  return images, labels

# 이미지 출력
images, labels = show_batch_images(trainloader)

# 배치 정규화가 적용되지 않은 네트워크
class NormalNet(nn.Module):
  def __init__(self):
    super(NormalNet, self).__init__()
    self.classifier = nn.Sequential(
        nn.Linear(784, 48),
        nn.ReLU(),
        nn.Linear(48, 24),
        nn.ReLU(),
        nn.Linear(24, 10) # FashionMNIST의 클래스는 총 열 개
    )

  def forward(self, x):
    x = x.view(x.size(0), -1)
    x = self.classifier(x) # nn.Sequential에서 정의한 계층 호출
    return x

# 배치정규화가 포함된 네트워크
class BNNet(nn.Module):
  def __init__(self):
    super(BNNet, self).__init__()
    self.classifier = nn.Sequential(
        nn.Linear(784, 48),
        nn.BatchNorm1d(48),
        nn.ReLU(),
        nn.Linear(48, 24),
        nn.BatchNorm1d(24),
        nn.ReLU(),
        nn.Linear(24, 10)
    )

  def forward(self, x):
    x = x.view(x.size(0), -1)
    x = self.classifier(x)
    return x

# 배치 정규화가 적용되지 않은 모델 선언
model = NormalNet()
print(model)

# 배치 정규화가 적용된 모델 선언
model_bn = BNNet()
print(model_bn)

# 데이터셋 메모리로 볼러오기
batch_size = 512
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)

# 옵티마이저, 손실 함수 지정
loss_fn = nn.CrossEntropyLoss()
opt = optim.SGD(model.parameters(), lr=0.01)
opt_bn = optim.SGD(model_bn.parameters(), lr=0.01)

# 모델 학습
loss_arr = []
loss_bn_arr = []
max_epochs = 2

for epoch in range(max_epochs):
  for i, data in enumerate(trainloader, 0):
    inputs, labels = data
    opt.zero_grad() # 배치 정규화가 적용되지 않은 모델의 학습
    outputs = model(inputs)
    loss = loss_fn(outputs, labels)
    loss.backward()
    opt.step()

    opt_bn.zero_grad() # 배치 정규화가 적용된 모델의 학습
    outputs_bn = model_bn(inputs)
    loss_bn = loss_fn(outputs_bn, labels)
    loss_bn.backward()
    opt_bn.step()

    loss_arr.append(loss.item())
    loss_bn_arr.append(loss_bn.item())

  plt.plot(loss_arr, 'yellow', label='Normal')
  plt.plot(loss_bn_arr, 'blue', label='BatchNorm')
  plt.legend()
  plt.show()

# 데이터셋의 분포를 출력하기 위한 전처리
N = 50
noise = 0.3

x_train = torch.unsqueeze(torch.linspace(-1, 1, N), -1)
y_train = x_train + noise * torch.normal(torch.zeros(N, 1), torch.ones(N, 1))

x_test = torch.unsqueeze(torch.linspace(-1, 1, N), -1)
y_test = x_test + noise * torch.normal(torch.zeros(N, 1), torch.ones(N, 1))

# 데이터 분포를 그래프로 출력
plt.scatter(x_train.data.numpy(), y_train.data.numpy(), c='purple', alpha=0.5, label='train')
plt.scatter(x_test.data.numpy(), y_test.data.numpy(), c='yellow', alpha=0.5, label='test')
plt.legend()
plt.show()

# 드롭아웃을 이용한 모델 생성
N_h = 100
model = torch.nn.Sequential(
    torch.nn.Linear(1, N_h),
    torch.nn.ReLU(),
    torch.nn.Linear(N_h, N_h),
    torch.nn.ReLU(),
    torch.nn.Linear(N_h, 1)
) # 드롭아웃이 적용되지 않은 모델

model_dropout = torch.nn.Sequential(
    torch.nn.Linear(1, N_h),
    torch.nn.Dropout(0.2), # 드롭아웃 적용
    torch.nn.ReLU(),
    torch.nn.Linear(N_h, N_h),
    torch.nn.Dropout(0.2),
    torch.nn.ReLU(),
    torch.nn.Linear(N_h, 1)
) # 드롭아웃이 적용된 모델

# 옵티마이저와 손실함수 지정
opt = torch.optim.Adam(model.parameters(), lr=0.01)
opt_dropout = torch.optim.Adam(model_dropout.parameters(), lr=0.01)
loss_fn = torch.nn.MSELoss()

# 모델 학습
max_epochs = 1000
for epoch in range(max_epochs):
  pred = model(x_train) # 드롭아웃이 적용되지 않은 모델 학습
  loss = loss_fn(pred, y_train)
  opt.zero_grad()
  loss.backward()
  opt.step()

  pred_dropout = model_dropout(x_train)
  loss_dropout = loss_fn(pred_dropout, y_train)
  opt_dropout.zero_grad()
  loss_dropout.backward()
  opt_dropout.step()

  if epoch % 50 == 0: # epoch를 50으로 나눈 나머지가 0이면 다음 진행
    model.eval()
    model_dropout.eval()

    test_pred = model(x_test)
    test_loss = loss_fn(test_pred, y_test)

    test_pred_dropout = model_dropout(x_test)
    test_loss_dropout = loss_fn(test_pred_dropout, y_test)

    plt.scatter(x_train.data.numpy(), y_train.data.numpy(), c='purple', alpha=0.5, label='train')
    plt.scatter(x_test.data.numpy(), y_test.data.numpy(), c='yellow', alpha=0.5, label='test')
    plt.plot(x_test.data.numpy(), test_pred.data.numpy(), 'b-', lw=3, label='normal')
    plt.plot(x_test.data.numpy(), test_pred.data.numpy(), 'g--', lw=3, label='dropout')
    plt.title('Epoch %d, Loss=%0.4f, Loss with dropout=%0.4f' % (epoch, test_loss, test_loss_dropout)) # 에포크, 드롭아웃이 적용되지 않은 모델의 오차, 드롭아웃이 적용된 모델의 오차를 타이틀로 출력

    plt.legend()
    model.train()
    model_dropout.train()
    plt.pause(0.05)

조기 종료를 이용한 성능 최적화


  • 뉴럴 네트워크가 과적합을 회피하는 규제 기법
  • 매 에포크마다 검증 데이터에 대한 오차를 측정하여 모델의 종료 시점 제어
  • 검증 데이터셋에 대한 오차가 증가하는 시점에서 학습을 멈추도록 조정

자연어 처리란

  • 우리가 일상생활에서 사용하는 언어의 의미를 분석하여 컴퓨터가 처리할 수 있도록 하는 과정
  • 인간 언어에 대한 이해가 필요하기 때문에 접근하기 어려운 분야이다.

자연어 처리 용어 및 과정


자연어 처리 관련 용어

  • 말뭉치(corpus) : 자연어 처리에서 모델을 학습시키기 위한 데이터. 자연어 연구를 위해 특정한 목적에서 표본을 추출한 집합
  • 토큰 : 자연어 처리를 위한 문서는 작은 단위로 나누어야 하는데, 이때 문서를 나누는 단위가 토큰이다. 문자열을 토큰으로 나누는 작업을 토큰 생성이라고 하며, 문자열을 토큰으로 분리하는 함수를 토큰 생성 함수라고 한다.
  • 토큰화 : 텍스트를 문장이나 단어로 분리하는 것을 의미한다. 토큰화 단계를 마치면 텍스트가 단어 단위로 분리된다.
  • 불용어(stop words) : 문장 내에서 많이 등장하는 단어. 분석과 관계없으며, 자주 등장하는 빈도 때문에 성능에 영향을 미치므로 사전에 제거해 주어야 한다.
    • ex) 'he', 'she', 'the', 'a'
  • 어간 추출(stemming) : 단어를 기본 형태로 만드는 작업.
    • ex) 'consign', 'consigned', 'consigning', 'consignment'가 있을 때, 기본 단어인 'consign'으로 통일하는 것
  • 품사 태깅(part of speech tagging) : 주어진 문장에서 품사를 식별하기 위해 붙여 주는 태그를 의미한다.
    • Det : 한정사
    • Noun : 명사
    • Verb : 동사
    • Prep : 전치사
    • 품사 태깅은 NLTK를 이용할 수 있다.
    • pip install nltk

자연어 처리를 위한 라이브러리


NLTK

  • Natural Language ToolKit는 교육용으로 개발된 자연어 처리 및 문서 분석용 파이썬 라이브러리.
  • 말뭉치
  • 토큰 생성
  • 형태소 분석
  • 품사 태깅

KoNLPy

  • 코엔엘파이.
  • 한국어 처리를 위한 파이썬 라이브러리
  • 꼬꼬마(Kkma), 코모란(Komoran), 한나눔(Hannanum), 트위터(Twitter), 메카브(Mecab) 분석기를 한 번에 설치하고 동일한 방법으로 사용할 수 있게 해준다.

우분투에서 KoNLPy 설치 방법


sudo apt-get install g++ openjdk-11-jdk
sudo apt-get install python3-dev; pip3 install konlpy

Gensim

  • 파이썬에서 제공하는 Word to Vector 라이브러리
  • 딥러닝 라이브러리는 아니지만 효율적이고 확장 가능
  • 주요 기능
    • 임베딩 : 워드투벡터
    • 토픽 모델링
    • LDA : Latent Dirichlet Allocation
      pip install -U gensim

사이킷런

  • CountVectorizer : 텍스트에서 단어의 등장 횟수를 기준으로 특성을 추출
  • Tfidfvectorizer : TF-IDF 값을 사용해서 텍스트에서 특성 추출
  • HashingVectorizer : CountVectorizer와 방법이 동일하지만 텍스트를 처리할 때 해시 함수를 사용하기 때문에 실행 시간이 필요하다.

자연어 처리 전처리

  • 전처리 과정
    • 문장 -> 결측치 확인, 토큰화 -> 단어 색인 -> 불용어 제거 -> 축소된 단어 색인 -> 어간 추출

결측치 확인


  • 결측치 : 주어진 데이터셋에서 데이터가 없는(NaN)것

결측치 확인, 처리


# 결측치 개수 확인
df.isnull().sum()

# 결측치 비율
df.isnull().sum() / len(df)

# 결측치 삭제 처리
df = df.dropna(how='all') # 모든 행이 NaN일 때만 삭제

df1 = df.dropna() # 데이터에 하나라도 NaN값이 있으면 행을 삭제

df2 = df.fillna(0) # 결측치를 0으로 채우기

df['x'].fillna(df['x'].mean(), inplace=True) # 결측치를 평균으로 채우기

토큰화


  • 주어진 텍스트를 단어/문자 단위로 자르는 것을 의미

문장 토큰화

  • 주어진 문장을 마침표, 느낌표, 물음표 등 문장의 마지막을 뜻하는 기호에 따라 분리

from nltk import sent_tokenize
text_sample = '문장'

tokenized_sentences = sent_tokenize(text_sample)
print(tokenized_sentences)

단어 토큰화

  • 띄어쓰기를 기준으로 문장을 구분

from nltk import word_tokenize
sentence = '문장'
words = word_tokenize(sentece)
print(words)

# 아포스트로피가 포함된 문장에서 단어 토큰화
from nltk.tokenize import WordPunctTokenizer
sentence = '문장'
words = WordPunctTokenizer().tokenize(sentence)
print(words)

한글 토큰화 예제

import csv
from konlpy.tag import Okt
from gensim.models import word2vec

f = open(r'./data/ratings_train.txt', 'r', encoding='utf-8')
rdr = csv.reader(f, delimiter='\t')
rdw = list(rdr)
f.close()

# 오픈 소스 한글 형태소 분석기 호출
twitter = Okt()
result = []

for line in rdw: # 텍스트를 한 줄씩 처리
  malist = twitter.pos(line[1], norm=True, stem=True) # 형태소 분석
  r = []
  for word in malist:
    if not word[1] in ["Josa", "Eomi", "Punctuation"]: # 조사, 어미, 문장 부호는 제외하고 처리
      r.append(word[0])

  rl = (" ".join(r)).strip() # 형태소 사이에 " "(공백)을 넣고, 양쪽 공백은 삭제
  result.append(rl)
  print(rl)

  # 형태소 저장
with open("NaverMovie.nlp", "w", encoding='utf-8') as fp:
  fp.write("\n".join(result))

# Word2Vec 모델 생성
mData = word2vec.LineSentence("NaverMovie.nlp")
mModel = word2vec.Word2Vec(mData, vector_size=200, window=10, hs=1, min_count=2, sg=1)
mModel.save("NaverMovie.model") # 모델 저장

불용어 제거

어간 추출

  • 어간 추출과 표제어 추출은 단어의 원형을 찾아 주는 것
  • writing, writes, wrote에서 write를 찾는 것
  • 어간 추출은 사전에 없는 단어도 추출할 수 있고, 표제어 추출은 사전에 있는 단어만 추출할 수 있다.

표제어 추출

  • 일반적으로 어간 추출보다 표제어 추출이 성능이 더 좋다.
  • 품사같은 문법뿐만 아니라 문장내에서 단어 의미도 고려하기 때문에 성능이 더 좋다.
  • 하지만 어간 추출보다 시간이 더 오래걸린다.
  • 주로 WordNetLemmatizer를 사용한다.

임베딩

  • 좌표 공간에 놨다는 뜻
  • 사람이 사용하는 언어를 컴퓨터가 이해할 수 있는 언어(숫자) 형태인 벡터로 변환한 결과 혹은 일련이 과정을 의미한다.

희소 표현 기반 임베딩


  • 희소 표현(sparse representation)은 대부분의 값이 0으로 채워져 있는 경우

원-핫 인코딩

  • 주어진 텍스트를 숫자(벡터)로 변환해 주는 것
  • 단어 N개를 각각 N차원의 벡터로 표현하는 방식으로 단어가 포함되어 있는 위치에 1을 넣고 나머지는 0값을 채운다.
  • 하나만 핫하다 해서 원-핫 인코딩
    • ex) [clam, fast, cat] 에서 fast를 표현하는 벡터는 [0, 1, 0] 이다.
  • 단점
    • 단어끼리 관계성(유의어, 반의어) 없이 서로 독립적인 관계가 된다.
    • 차원의 저주 발생 : 하나의 단어를 표현하는 데 말뭉치에 있는 수만큼 차원이 존재하기 때문에 복잡해진다.

횟수 기반 임베딩

  • 단어가 출현한 빈도를 고려하여 임베딩하는 방법
  • 대표적으로 카운터 벡터와 TF-IDF가 있다.
  • 벡터 두 개의 유사도를 분석하는 방법
    • 유클리드 거리
    • 코사인 유사도

카운터 벡터

  • 문서의 집합에서 단어를 토큰으로 생성하고 각 단어의 출현 빈도수를 이용하여 인코딩해서 벡터를 만드는 방법
  • 토크나이징과 벡터화가 동시에 가능한 방법
  • 사이킷런의 CountVectorizer를 사용하여 구현
    1. 문서를 토큰 리스트로 변환
    2. 각 문서에서 토큰의 출현 빈도를 센다.
    3. 각 문서를 인코딩하고 벡터로 변환한다.

TF-IDF

  • 정보 검색론에서 가중치를 구할 때 사용되는 알고리즘
  • TF(Term Frequency, 단어빈도)는 문서 내에서 특정 단어가 출현한 빈도를 의미
    • ex) '신문기사'에서 '딥러닝'이라는 단어가 많이 등장했는지. 특정 문서 d에서 특정 단어 t의 등장 횟수를 의미한다.
  • DF(Document Frequency, 문서 빈도) : 한 단어가 전체 문서에서 얼마나 공통적으로 많이 등장하는지 나타내는 값. 즉, 특정 단어가 나타난 문서의 개수
    • 특정 단어 t가 모든 문서에 등장하는 일반적인 단어라면, TF-IDF 가중치를 낮추어 줄 필요가 있다.
    • 따라서, DF 값이 클수록 TF-IDF 가중치 값이 낮추기 위해 DF 값에 역수를 취한다.
    • 역수를 취하면 전체 문서 개수가 많아질수록 IDF 값도 커지므로 IDF는 로그를 취해야한다.
  • IDF(Inverse Document Frequency, 역문서 빈도) : DF 값에 역수를 취한 값
    • idf = log(전체 문서 개수 / 특정 단어 t가 포함된 문서 개수)
  • TF-IDF는 다음 상황에서 주로 사용된다.
    • 키워드 검색을 기반으로 하는 검색 엔진
    • 중요 키워드 분석
    • 검색 엔진에서 검색 결과의 순위를 결정

예측 기반 임베딩

  • 특정 문맥에서 어떤 단어가 나올지 예측하면서 단어를 벡터로 만드는 방식
  • 가중치를 임베딩

워드투벡터

  • 워드 투 벡터는 신경망 알고리즘으로, 주어진 텍스트에서 텍스트의 각 단어마다 하나씩 일련의 벡터를 출력한다.

CBOW

  • Continuous Bag Of Words
  • 단어를 여러 개 나열한 후 이와 관련된 단어를 추정하는 방식
  • 문장에서 등장하는 n개의 단어 열에서 다음에 등장할 단어를 찾는다.
    • ex) clam cat slept on the sofa 라는 문장이 있을 때, calm cat on the sofa라는 문맥이 주어지면, slept를 예측한다.

패스트텍스트

  • 워드투벡터의 단점을 보완하고자 페이스북에서 개발한 임베딩 알고리즘
  • 기존 워드투벡터의 워드 임베딩 방식은 분산 표현을 이용하여 단어의 분산 분포가 유사한 단어들에 비슷한 벡터 값을 할당하여 표현해서, 사전에 없는 단어에 대해서는 벡터 값을 얻을 수 없다.
  • 또한, 워드투벡터는 자주 사용되지 않는단어에 대해서는 학습이 불안정하다.
  • 패스트텍스트는 개발된 단어 표현(word representation) 방법을 사용
  • 패스트텍스트는 노이즈에 강하며, 새로운 단어에 대해서는 형태적 유사성을 고려한 벡터 값을 얻기 때문에 자연어 처리에서 많이 사용된다.

사전에 없는 단어에 벡터 값을 부여하는 방법

  • 패스트텍스트는 주어진 문서의 각 단어를 n-그램으로 표현
  • 이때 n설정에 따라 단어의 분리 수준이 결정된다.
    • ex) n을 3으로 설정(트라이그램)하면 "This is Deep Learning Book"은 This is Deep, is Deep Learning, Deep Learning Book으로 분리한 후 임베딩한다. (단어 수만큼 연속적으로 묶어서 분리)

자주 사용되지 않는 단어에 학습 안정성을 확보하는 방법

  • 워드투벡터는 단어의 출현 빈도가 적으면 임베딩의 정확도가 낮았다.
  • 패스트텍스트는 등장 빈도수가 적더라도, n-그램으로 임베딩하기 때문에 참고할 수 있는 경우의 수가 많아서, 자주 사용되지 않는 단어도 정확도가 높다.

횟수/예측 기반 임베딩

글로브

  • 횟수 기반의 LSA(Latent Semantic Analysis)와 예측 기반의 워드투벡터의 단점을 보완하기 위한 모델
  • 단어에 대한 글로벌 동시 발생 확률 정보를 포함하는 단어를 임베딩
  • 단어에 대한 통계 정보와 skip-gram을 합친 방식 (skip-gram 방법을 사용하되, 통계적 기법이 추가된 것)
    • 단어 간의 관련성을 통계적 방법으로 표현해준다.

트랜스포머 어텐션

  • 어텐션은 주로 언어 번역에서 사용되기 때문에 인코더와 디코더 네트워크를 사용한다.
  • 인코더 : 입력에 대한 벡터 변환 (예를 들자면, 자연어를 벡터로 변환하는 것)
  • 디코더 : 벡터를 인간이 이해할 수 있는 형태로 바꿔주는 것
  • 인코더-디코더 구조는 번역할 때 참 좋다.
  • Autoregressive : 이전 단계의 output이 다음 단계의 input으로 사용
  • Attention : 모든 벡터들 중에서 꼭 살펴보아야할 벡터들에 집중하겠다는 의미
    • 디코더는 은닉 상태에 중점적으로 집중해서 보아야 할 벡터를 소프트맥스 함수로 점수를 매긴 후 각각 은닉 상태의 벡터들과 곱한다. 그리고 이 은닉 상태를 모두 더해서 하나의 값으로 만든다.
  • 하나의 인코더는 셀프 어텐션과 전방향 신경망으로 구성되어 있다.
    • 셀프 어텐션은 문장 안에서 각 단어끼리 얼마나 관계가 있는지 계산해서 반영한다.
      • 셀프 어텐션으로 단어 간 관계 파악 가능
  • 디코더는 층을 총 3개 가지고 있다.
    • 인코더에서 넘어온 벡터가 처음으로 만나는 층이 셀프 어텐션 층이다. (인코더와 동일)
    • 그 후, 인코더-디코더 어텐션 층에서 인코더가 처리한 저오를 받아 어텐션 메커니즘을 수행하고, 마지막으로 전방향 신경망으로 데이터가 전달된다.
      • 어텐션 메커니즘을 이용하려면 어텐션 스코어를 구해야한다.
    • 어텐션 스코어가 계산되었다면 이 값을 소프트맥스 함수에 적용하여 확률로 변형한다.
    • 이렇게 계산된 0~1 사이의 값들이 특정 시점에 대한 가중치, 즉 시간의 가중치가 된다.
    • 시간의 가중치와 은닉 상태의 가중합을 계산하면 하나의 벡터가 계산되는데, 이것을 컨벡스트 벡터라고 한다.
    • 마지막으로 컨텍스트 벡터와 디코더 이전 시점의 은닉 상태와 출력을 이용해서 디코더의 은닉상태를 구한다.
  • 어텐션 스코어 : 현재 디코더의 시점 i에서 단어를 예측하기 위해, 인코더의 모든 은닉 상태 값이 디코더의 현 시점의 은닉 상태와 얼마나 관련이 있는지 판단하는 값
    • 인코더의 모든 은닉 상태의 값(h)와 디코더에서의 이전 시점의 은닉 상태값을 이용하여 구할 수 있다.

인코더 입력 - input Embedding

  • inputs에 입력된 데이터를 컴퓨터가 이해할 수 있도록 행렬 값으로 바꾸어 준다.
  • Transformer는 한번에 병렬로 문장 전체가 들어가기 때문에, 문장의 순서 정보가 없다. 그래서 Positional Encoding을 해서 포지션을 넣어준다. (LSTM은 순차적으로 하나씩 들어감)