딥러닝: 머신러닝의 한 종류로, 데이터 처리 유닛의 층을 여러 개 쌓아 구조적이지 않은 데이터에서 고수준 표현을 학습!

 

2.1 데이터

일반적으로 머신러닝에서 사용되는 정형 데이터이다.

정형 데이터: 양적 데이터, 사전에 정의됨(유연하지 않음). 분석이 상대적으로 쉬움

비정형 데이터: 질적 데이터, 특정 스키마(DB를 구성하는 요소들의 관계)가 포함되어 있지 않다. 유연함, 분석 어려움

 

구체적으로, 비정형 데이터는 이미지/오디오/텍스트와 같이 태생적으로 특성의 열로 구성할 수 없는 것들을 말한다.

픽셀/진동 수/문자 하나하나에는 정보가 거의 없다. 예를 들어 이미지의 234번 째의 픽셀이 황토색이라는 정보는 의미는 도움이 되지 않는다는 뜻이다.

 

물론 딥러닝에서 정형데이터를 사용하면 안되는 것은 아니지만, 딥러닝의 강력함은 비정형 데이터를 다루는 것에서 나온다는 것이다.

 

2.2 심층 신경망

딥러닝 여러 개의 은닉층을 쌓은 인공 신경망(ANN(Artificial Neural Network)이다.

따라서 심층 신경망(DNN(Deep Neural Network)와 동의어로 쓰이곤 한다.

 

2.2.1 신경망이란?

심층 신경망은 층을 연속하여 쌓아 만든다. 각 층은 유닛을 가지며, 이전 층의 유닛과는 가중치로 연결된다.

"층"은 종류가 많으며, 보통 모든 유닛 이전 층의 모든 유닛과 연결되는 완전 연결층이 있다.(밀집 층이라고함)

 

다층 퍼셉트론 (MLP(multilayer perception)

-인접한 모든 층이 완전하게 연결된 신경망

 

2.2.2 고수준 특성 학습

신경망의 최대 장점은 사람의 개입 없이도 데이터를 스스로 학습하는 능력이라고 할 수 있다.

즉, 특성 공학(feature engineering)을 수행할 필요가 없다는 것.

(예측 오차를 줄이기 위해 가중치를 어떻게 조정할 지를 모델이 결정)

 

아래 텍스트 그림을 살펴보자.

 

2.3.1 예제 학습

keras에서 제공하는 CIFAR-10 데이터 셋을 이용하여 학습을 진행해보자.

 

 

여기서 만약 x_train 데이터에서 54번째 사진에서, 픽셀 12,13에 위치해 있는 RGB 값을 보고 싶다면?

슬라이싱!

 

이제 텐서 라이브러리를 이용해서 다층 퍼셉트론을 만들어보자.

 

방법1)

방법2)

 

방법1과 방법2 중 어떤것이 나을까? 

지금 예제 실습에서는 상관없지만, 보통 2번의 방식을 선호한다고 한다.

방법1은 층 별로 직접 변수를 설정했지만, 나중에 수 백 수 천개의 층을 만들기에는 적합하지 않을 수 있다.

따라서 함수 API를 불러오는 방법2의 방식을 사용하도록 하자!

 

참고로 방법 1,2 모두 아래 그림을 프로그래밍한것과 같다.

위 코드 & 그림을 보면 알 수 있듯이 층의 종류는 총 세 가지 임을 확인할 수 있다.

Input, Flatten, Dense층이다. 세 가지 모두 자세히 알아보도록 하자.

Input 층

- 네트워크의 시작점이라고 할 수 있다. 여기서 입력 데이터의 배치 크기는 필요하지 않기 때문에 배치 크기는 지정하지 않는다. 여기서 배치 크기는 50,000.

그 다음 Flatten 층은 이름처럼 하나의 벡터로 펼친다. 이렇게 되면 (32x32x3 = 3,072가 되겠다.)

Flatten을 하는 이유는 뒤에 따르는 Dense 층에서 받는 배열이 1차원이기 때문이다. 

(다른 종류의 층은 Flat한 층이 아닌 다차원 배열을 입력으로 받는다는 점 주의)

 

 Dense 층

-기본적인 신경망 구성요소.

1. Dense층의 각 유닛은 이전 층의 모든 유닛들과 완전 연결된다. +모든 연결마다 가중치가 동반

2. 유닛의 출력은 이전 층에서 넘겨받은 입력과 가중치의 곱들을 모두 더하여 구함.

3. 그 다음 비선형 활성화 함수에 전달

 

 활성화 함수

- 퍼셉트론의 출력값을 결정하는 비선형 함수

- 대표적으로 렐루, 시그모이드, 소프트맥스 함수가 있음

렐루: 음수면 0, 양수면 그 값 그대

리키렐루: 양수일 경우는 렐루와 같지만, 음수일 경우 0이 아닌 값에 비례한 작은 음수값을 반환함

                기존렐루의 경우 모두 0이면 그라디언트 값이 0이되어 학습진행에 차질이 있을 수 있기 때문

시그모이드: 출력값이 0~1. (이진 분류 / 다중 레이블 분류시 사용가능)

소프트맥스: 층의 전체 출력값들의 합이 1 (다중 분류 시 용이)

                   

 

모델 검사하기

-model.summary()를 사용해 각 층을 조사할 수 있다.

Input층의 크기는 x_train의 크기와 같아야 하고, Dense층의 크기는 y_train의 크기와 같아야 한다.(???)

 

Input 층에서, None이 나오는데, 이는 위에서 언급했듯이, 배치 크기는 필요없기 때문.

텐서플로우의 연산 방식은 선형 대수학을 이용, 입력된 샘플(n개)상관없이 동시에 수행하기 때문이다.

(GPU가 중요한 이유, GPU는 텐서 곱셈에 최적)

 

파라미터 개수

Dense#1층 = 32x32x3 + 200(Dense층의 bias(상수)) = 614,600개

Dense#2층 = (200x150) + 150 = 30,150개

Dense#3층 = (150x10) + 10 = 1,510개

2.3.2 모델 컴파일

- 모델 컴파일은 손실 함수 & 옵티마이저를 이용

 

손실 함수

손실 함수의 결과값은 모델의 예측값과 정답값의 차이를 통해 구한다. (결과가 크면 bad)

대표적으로 MSE, 범주형 크로스 엔트로피(categorical), 이진 크로스 엔트로피(binary)가 있다.

회귀 -> MSE / MAPE / SMAPE 등

다중 분류 -> 범주형 크로스 엔트로피 (categorical cross-entropy)

이진 분류 -> 이진 크로스 엔트로피 (binary cross-entropy)

옵티마이저

손실 함수 그레디언트를 기반으로 신경망의 가중치를 갱신할 때 사용함.

Adam / Adagrid / RMSprop / Momentum / SGD 등등 (일반적으로는 Adam 사용)

 

 

2.4 모델 훈련 & 평가

 

 

 

2.5 합성곱 신경망

위의 결과값을 보면 알겠지만 정확도가 아주 처참하다.!

이 이유는 입력 이미지의 공간 구조를 잘 다루지 못했기 때문이다. (무지성 Flatten으로 갈겼기 때문)

 

2.5.1 합성곱 층

위 설명을 참조하게 되면, 이미지 영역이 필터와 비슷할 수록 큰 양수, 반대일 수록 큰 음수가 출력되는 것이다.

 

직접 코드를 짜보자.

스트라이드: 도장(필터)의 이동 간격!

패딩: 제로패딩 등 특정 값으로 채워넣는것, 크기를 맞춰주기 위한 용도라고 보면 된다.

         정확히는  입력 배열의 주위를 가상의 원소로 채우는 작업이라고 할 수 있다.

풀링: 맥스풀링 등 아래 그림을 통해 이해! (축소시킨다는 개념)

직접 합성곱의 층을 쌓아보자

그림으로 이해해보면 아래와 같다.

 

'딥 러닝 > 생성형 AI' 카테고리의 다른 글

05. 확산 모델 (Diffusion model)  (0) 2024.05.31
04. 적대적 생성 신경망(GAN)  (0) 2024.04.06
03. 변이형 오토인코더  (2) 2024.03.22
01. 생성 모델  (1) 2024.03.11

생성 모델링 (generative modeling)이란 주어진 데이터셋과 유사한 데이터셋을 생성하도록 모델을 훈련하는 머신러닝의 한 분야,

훈련 데이터의 말에 대해서, 말을 잘 정의할 수 있는 픽셀값들의 관계를 학습하여, 새로운 말을 만들어낼 수 있는 것이다.

훈련 데이터 중에서 하나의 데이터를 샘플이라 부르고, 각 샘플은 많은 특성(feature)들로 이루어져 있다. 

이미지 생성의 경우, 특성이라 함은  픽셀값이라고 할 수 있다.

텍스트 생성의 경우, 특성이라 함은 단어 혹은 문자의 그룹일 수 있다.

 

이미지 생성의 경우, 원본 이미지와 같은 새로운 이미지를 만들어내는 것은 매우 어렵다고 함.

픽셀 값이 가질 수 있는 경우의 수가 너무 많은데, 이 중에서 아주 작은 수의 조합 생성하려는 개체에 대한 이미지를 구성하기 때문이다.

 

생성 모델은 또한 결정적(deterministic)이 아닌 확률적(probablistic)이여야 한다.

-> 매 번 동일한 결과값이 아닌, 다양한 결과를 뱉어내야 하기 때문 (생성 모델은 랜덤한 요소를 모두 포함해야하기 때문)

1.1 생성 모델링과 판별 모델링

어떠한 개념을 잘 이해하는 방법 중에는 그 개념과 반대되는 개념을 이해하는 것도 도움이 된다.

생성 모델링(generative modeling)과 판별 모델링(discriminative modeling)이 그 예이다.

 

판별 모델링은 보통 머신러닝의 개념과 익숙하다고 할 수 있다.

또한 판별 모델링이란 생성 모델링과 다르게 각 샘플에 레이블(label)이 있어야 한다.

먼저 반 고흐의 많은 작품들을 훈련 데이터로 학습을 시켜서 어떠한 그림이 들어오면 반 고흐가 그렸는지(아닌지) 판별하는 훈련을 가정해보자.

이진 분류로 가정한다면 반 고흐 그림이면 1, 아니면 0인 레이블이 있는 것이다.

 

결론적으로는 아래 그림과 같다.

 

1.3 생성 모델링과 AI

왜 생성형 AI가 GOAT인가?

-> 1. 순전 이론적인 관점에서 단순 데이터 분류하는 판별 모델링에 그쳐서는 안된다!

        (레이블을 넘어 데이터분포를 완전 이해해야 하는 개념으로 확장시켜야 한다는 점에서)

 

-> 2. 생성형 AI는 강화 학습같은 다른 AI 분야를 선도하기 때문이다.

        (예시로 로봇의 기동 훈련에서, 어떻게 기동할 것인지에 대한 반복적인 훈련이 아닌,

         독립적으로{자율적으로} 수행할 수 있어 매우 효율적으로 바뀔 수 있다.)

 

-> 3. 강 인공지능과 같이, 인간과 견줄 수 있는 AI가 만들어진다면, 반드시 생성형 AI기반일 수 밖에 없다는 점이다.

         창의적인 생각, 창작물과 같은 분야는 인간 고유의 영역이기 때문.

 

 

2. 간단한 생성형 모델

좌표평면위에 어떠한 데이터 포인터를 분포 시키고 실습해보자.

좌표평면 위의 집합 X를 생성, 같은 규칙으로 생성된 것 같은 이 공간의 다른 점들을 선택하는 것이 목표

 

그렇다면 어디를 선택하겠는가? 우선 범위로 따진다면, 주황색 박스 안에서만 데이터 포인터가 있을 것이라 예측할 것이다. ( 기존 데이터 포인터와 같은 원리인 것을 가정한다면)

그러면 당신은 첫 생성 모델링을 성공한 것이다!

 

2.1 생성 모델링 프레임워크

이제 맨 처음 데이터 포인터들의 근거를 알아보자. 

 

1. 세계지도의 대륙 위에서 위치할 것.

2. 바다는 포인터가 찍히지 않을것.

3. 주황색 박스 안에서 찍혀야 할 것

위 그림의 A,B,C 모델을 통해서 해석해보자면,

A는 바다에 찍혀있기 때문에 원본 데이터셋이 아니고, 생성 모델이 찍은 포인터이다.(실패)

B는 대륙위에 찍혀 있지만 주황색 박스 밖에 위치해 있기 때문에 A와 마찬가지로 생성 모델이 찍은 실패 포인터

C는 성공한 모델.

 

이 예제는 쉽고 단순해 보이지만 생성 모델링의 아주 중요한 기본 개념이다. 

 

2.2 표현학습

표현(representation)의 의미에 대해서는 심도 있게 생각해볼 필요가 있다.

이 책 뿐 아니라, 인공지능 학습 전반에 걸쳐 "고차원 데이터"를 "표현"한다는 의미는 매우 중요하기 때문이다.

 

먼저 표현학습의 핵심 아이디어를 알아보자.

당근마켓에서 나는 판매자A와 신도림역에서 거래를 하기로했다. 나와 A는 서로를 알지 못한다.

수많은 인파속에서, 나는 A를 만나기위해 나의 생김새를 설명해야한다. 여기서 나는 (1,1,16),(1,2,15) 이렇게 픽셀값으로 전달하지 않고, 안경을끼고 있고, 검은색 코트를 입고 있다 등과 같이 설명할 것이다. 이런 설명들이 많아진다면 A는 머릿속에 내 이미지를 상상할 수 있을것이다.

이것이 표현학습의 핵심 아이디어이다.

 

고차원의 표본 공간을 직접 모델링 하는 방식이 아닌, 저차원의 잠재 공간을 이용, 훈련 세트의 각 샘플을 표현하고 이를 원본 공간의 포인트에 매핑한다. -> 따라서 잠재 공간의 각 포인트는 고차원 이미지에 대한 표현이라고 할 수 있다.

  

이 깡통은 높이와 너비라는 두 가지 feature로 정의할 수 있다. 이 말인 즉슨, 고차원 이미지(3차원)가 저차원(2차원)상의

x(높이), y(너비) 두 가지로 표현할 수 있다는 것이다. 이를 통해서 모델을 훈련하게 되면, 큰 장점이 하나 있다.

 

"잠재 공간에서 표현 벡터 값을 수정하여 이미지의 고수준 속성에 영향을 주는 연산을 (쉽게)할 수 있다는 점"이다.

-> 고차원에서 이미지가 input 되었을 때, 높이를 키우려면 개별 픽셀을 어떻게 조정할 지 복잡하다.

    (높이 키우고 RGB값 조정 등) 하지만, 잠재공간에서 이는 단순 높이라는 feature만 조정하면 되기 때문!!

 

위 개념에 대해서 더 자세히 들어가보자.

훈련 데이터 셋을 잠재공간으로 들이기 위해서는 "인코딩(encoding)" 작업이 필요하다.

인코딩 이후 잠재공간에서 샘플링을 한 후 디코딩(decoding)하여 원래 도메인으로 되돌아가는 개념으로 확장할 수 있다.

 

위 작업을 "인코더-디코더"라고 하고, 이는 데이터가 놓여있는 고차원 비선형 매니폴드를 샘플링 가능한 잠재공간으로 변환한다. 아래 그림을 통해 이해해보자.

 

다른 종 강아지 세 마리와 사과, 자동차 이미지가 있다고 해보자.

당연하게도 강아지 세 마리는 모두 매우 유사한 거리를 가질 것이고, 사과와 자동차와 개는 상대적으로 거리가 멀다.

 

- 매니폴드 : "데이터가 존재하는 공간"

- 매니폴드에 대한 가정: "고차원일지라 하더라도, 집합을 포함하는 저차원의 매니폴드는 존재한다."

- 흥미로운 진실 : 고차원 상에서는 가까운 데이터 -> 실제로는 가깝지 않다.

                            저차원 상에서는 가까운 데이터 -> 가깝다!

 

따라서 아래 그림-> 고차원 매니폴드를 저차원으로 변환 -> 강아지들끼리의 유사도를 매핑할 수 있다는 것 같다.

 

참고:<매니폴드에 대한 이해>

https://blog.naver.com/coniecual/221417921857

 

매니폴드(manifold)란 뭘까?

논문을 읽을 때, manifold라는 단어가 많이 나와서 한 번 찾아봤었는데,  그래도 막 명확히 와닿지 않...

blog.naver.com

 

 

1.3 핵심 확률 이론

생성 모델링이 확률분포의 통계적 모델링과 밀접하게 연관이 되있음을 살펴보았다.

이 파트에서는 딥러닝, 생성형 AI와 관련된 핵심 확률/통계 개념에 대해서 알아보도록 하자.

 

1. 표본공간

- 샘플 x가 가질 수 있는 모든 값의 집합

 

2. 확률 밀도 함수 (=밀도 함수)

- 포인트 x를 0과 1의 숫자로 매핑하는 함수 p(x).

- 표본 공간에 있는 모든 포인트에 대해 밀도 함수를 적분했을 때 1이 되는 함수.

 

3. 모수 모델링

- 안정적인 P ^ model(x)을 찾는데 사용하는 기법.

- 모수 모델은 유한한 개수의 파라미터(θ)를 사용해 기술할 수 있는 밀도 함수 p(x)의 한 종류.

 

4. 가능도(likelyhood)

- 파라미터 집합 θ의  가능도{L(θ|x)} = 관측된 포인트 x가 주어졌을 때 θ의 타당성을 측정하는 함수.

- 입력으로 주어진 확률분포(=파라미터(세타))가 얼마나 데이터를 잘 설명하는 나타내는 점수

-> 데이터를 잘 설명한다 -> 해당 확률 분포에서 높은 확률 값을 가지는 것을 말함

이게 뭔소리노?

쉽게 이해해보자. 확률과 우도를 같은 선상에서 이해하면 와닿을 수 있다.

 

일반적으로 확률을 떠올리면 이산형 확률 변수를 생각하기 쉽다. ex) 동전-> 앞면 나올 확률 등

하지만 연속형 확률 변수라면? ex) 지하철 화장실 변기를 열었을 때 똥이 있을 확률 등

 

여기서는 고양이 몸무게의 확률 변수에 대해서 가정해보자. ex) 고양이 몸무게가 4kg~5kg 사이일 확률은?

확률: 입력 데이터는 변하지만 분포는 고정되어 있는 상황!

 

 

이에 반해 우도는 입력 데이터는 고정되어 있고, 분포가 변한다.(데이터가 주어졌을 때, 분포가 데이터를 잘 설명하는가)

좌측과 우측을 보면 알겠지만 서로 다른 분포를 가진다. (데이터는 고정)

여기서, 고양이 몸무게가 5kg 일 때의 likelihood는 오른쪽이 0.7979로 훨씬 더 높다.(더 잘 설명하는 것(값 높기 때)

"좌측의 분포보다, 우측의 분포가 주어진 데이터들 더 잘 설명한다, 발생가능성이 더 높다" 라 설명할 수 있음 

데이터가 주어졌을때 분포가 데이터를 얼마나 잘 설명하는가  --> 이게 사실 머신러닝의 주 목적이라 할 수 있다.

 

참조: https://huidea.tistory.com/276 

 

[Machine learning] 우도(likelihood) 총정리 (MLE, log-likelihood, cross-entropy)

머신러닝을 수식 기반으로 뜯어보면 우도 개념이 빈번히 등장하는데, 우도 개념을 확실히 잡고 가보려한다. 우도는 분류 문제의 loss function 으로 Maximum log-likelihood (MLE)로 등장한다. 우도를 이해

huidea.tistory.com

따라서, 우리는 이 likelihood(우도)를 최대화 하는 방향으로 모델을 학습시켜야 겠지??

이를 MLE(Maximum Liklihood Estimation) 최대 우도법이라 하는 것이다.

 

 

L(θ|x) = p(x)라 정의됨.

-> 포인트 x가 주어졌을 때 θ의 가능도는 포인트x에서 θ를 파라미터로 가진 밀도 함수의 값으로 정의.

독립된 샘플로 구성된 전체 데이터 셋 X가 있다면 다음과 같이 쓸 수 있다.

L(θ|x) = ∏ p(x)

0과 1사이의 숫자를 곱하는 일은 계산 비용이 많이 들기 때문에 로그 가능도를 ℓ 대신 사용하는 경우가 많다고 한다.

L(θ|x) = ∑ log p(x)

 

 

일반적으로 모델링 할 때 손실함수를 최소화하는 방향으로 진행한다.

따라서, 음의 로그 가능도를 최소화하는 파라미터 집합을 찾는 것 과 같다고 할 수 있다.

 

참조:

https://89douner.tistory.com/339

 

1. Representation Learning 이란?

안녕하세요. 이번글에서는 representation learning이라는 개념에 대해서 설명하려고 합니다. 개인적으로 2021년 동안 논문을 살펴보면서 가장 눈에 많이 띄었던 용어가 representation learning 이었습니다.

89douner.tistory.com

 

'딥 러닝 > 생성형 AI' 카테고리의 다른 글

05. 확산 모델 (Diffusion model)  (0) 2024.05.31
04. 적대적 생성 신경망(GAN)  (0) 2024.04.06
03. 변이형 오토인코더  (2) 2024.03.22
02. 딥러닝  (1) 2024.03.17

컴퓨터는 텍스트보다는 숫자를 더 잘 처리한다.

이를 위해 자연어 처리에서는 텍스트를 숫자로 바꾸는 여러가지 기법들이 있다. 그리고 그러한 기법들을 본격적으로 적용시키기 위한 첫 단계로 각 단어를 고유한 정수에 맵핑(mapping)시키는 전처리 작업이 필요함.

 

예를 들어 갖고 있는 텍스트에 단어가 5,000개가 있다면, 5,000개의 단어들 각각에 1번부터 5,000번까지 단어와 맵핑되는 고유한 정수. 다른 표현으로는 인덱스를 부여합니다. 가령, book은 150번, dog는 171번, love는 192번, books는 212번과 같이 숫자가 부여됩니다.

인덱스를 부여하는 방법은 여러 가지가 있을 수 있는데 랜덤으로 부여하기도 하지만, 보통은 단어 등장 빈도수를 기준으로 정렬한 뒤에 부여합니다. ("빈도수 기준" -> 허프만 알고리즘 같다.)

 

정수인코딩 = 단어를 정수와 매핑 = 빈도수 기준 ! 

 

1. 정수 인코딩(Integer Encoding)

단어에 정수를 부여하는 방법 중 하나로 단어를 빈도수 순으로 정렬한 단어 집합(vocabulary)을 만들고, 빈도수가 높은 순서대로 차례로 낮은 숫자부터 정수를 부여하는 방법이 있다.

이해를 돕기위해 단어의 빈도수가 적당하게 분포되도록 의도적으로 만든 텍스트 데이터를 가지고 실습해보겠습니다.

예제)

위 코드 -> 문장 단위로 토큰화 수행.

 

이제 앞으로는 정제 작업과 정규화 작업을 병행하며, 단어 토큰화를 수행.

여기서는 단어들을 소문자화하여 단어의 개수를 통일시키고, 불용어와 단어 길이가 2이하인 경우에 대해서 단어를 일부 제외.

텍스트를 수치화하는 단계라는 것은 본격적으로 자연어 처리 작업에 들어간다는 의미이므로, 단어가 텍스트일 때만 할 수 있는 최대한의 전처리를 끝내놓아야 한다는 점이 뽀인뜨

 

이에 따른 단어 토큰화 진행

 

현재 vocab에는 각 단어에 대한 빈도수가 기록되어 있다. 출력해보자.

 

파이썬의 딕셔너리 구조로 단어를 키(key)로, 단어에 대한 빈도수가 값(value)으로 저장되어 있음.

vocab에 단어를 입력하면 빈도수를 리턴.

 

이제 빈도수가 높은 순서대로 정렬해보자.

 

 

높은 빈도수를 가진 단어일수록 낮은 정수를 부여한다! 정수는 1부터 부여

따라서 1의 인덱스를 가지는 단어가 가장 빈도수가 높다는 뜻이다.

스트에서 등장 빈도가 매우 낮은 단어의 경우는 의미가 없을 가능성이 농후하기 때문에, 제외하는 것이 국룰이다.

(등장 빈도가 낮다는 것 = 인덱스 num이 높다는 것!)

 

글 참조 : https://wikidocs.net/31766

 

텍스트 전처리에서 정규 표현식은 아주 유용한 도구입니다. 이번에는 정규 표현식 모듈 re의 사용 방법 & NLTK를 통한 정규 표현식을 이용한 토큰화에 대해서 알아보자.

 

기본적으로 re 모듈에 대한 복습시간이 될 것 같다.

 

1) 정규 표현식 문법

정규 표현을 위해 사용되는 문법 중 특수 문자들은 아래와 같다.

또한, 정규 표현식 문법에는 백슬래쉬를 ( \ ) 이용해서 쓰이는 문자 규칙 또한 존재한다.

2) 정규표현식 모듈 함수

정규표현식 모듈에서 지원하는 함수는 아래와 같다.

 

실습

 

#1 " . "

실습#1

 .(점) 은 한 개의 임의의 문자를 나타다. 예를 들어서 정규 표현식이 a.c라고 합시다. a와 c 사이에는 어떤 1개의 문자라도 올 수 있습니다. akc, azc, avc, a5c, a!c와 같은 형태는 모두 a.c의 정규 표현식과 매치된다고 할 수 있다.

 

#2 " ?  " 기호

?는 ?앞의 문자가 있을 수도, 없을 수도 있는 경우를 말한다. ex) ab?c -> 물음표(?) 앞의 "b"는 슈뢰딩거의 고양이마냥 있을수도, 없을 수 도 있는 것이다. 따라서 abc, ac 모두 가능하다.

 

#3 " * " 기호

 

*은 바로 앞의 문자가 0개 이상일 경우를 나타낸다. 앞의 문자는 존재하지 않을 수도 있으며, 또는 여러 개일 수도 있는 것이다. 만약 정규 표현식이 ab*c라면 ac, abc, abbc, abbbc 등과 매치할 수 있으며 b의 개수는 무수히 많을 수 있다.

?기호에서 존재하는 개수의 제한이 없다는 점이 추가되었다고 볼 수 있다.!

 

#4  " + " 기호

" + " 기호는 " * " 기호와 유사하다고도 볼 수 있다.

다른 점은 앞의 문자가 최소 1개 이상이어야 한다는 점. 정규 표현식이 ab+c라고 한다면 ac는 해당 X.

하지만 abc, abbc, abbbc 등과 매치할 수 있으며 b의 개수는 무수히 많을 수 있습니다.

 

#4  " ^ " 기호

^는 시작되는 문자열을 지정한다.

정규표현식이 ^ab라면 문자열 ab로 시작되는 경우 매치.

 

기타) 자주쓰이는 함수 실습

1) re.split()

파이썬 내장함수인 split메소드와 매우 유사하다.

예제1)

위 방법 말고도, 줄바꿈이나 다른 정규표현을 기준으로 텍스트를 분리할 수 도 있다.

예제2)

 

2) re.findall()

findall() 메소드는  정규 표현식과 매치되는 모든 문자열들을 리스트로 리턴한다.

단, 매치되는 문자열이 없다면 빈 리스트를 리턴.

임의의 텍스트에 정규 표현식으로 숫자를 의미하는 규칙으로, 전체 텍스트로부터 숫자만 찾아내서 리스트로 리턴.

 

 

3) re.sub()

sub() 함수는 정규 표현식 패턴과 일치하는 문자열을 찾아 다른 문자열로 대체할 수 있습니다. 아래와 같은 정제 작업에 많이 사용되는데, 영어 문장에 각주 등과 같은 이유로 특수 문자가 섞여있는 경우에 특수 문자를 제거하고 싶다면 알파벳 외의 문자는 공백으로 처리하는 등의 용도로 쓸 수 있습니다.

 

 

2. 정규 표현식을 이용한 토큰화

RegexpTokenizer()에서 괄호 안에 하나의 토큰으로 규정하기를 원하는 정규 표현식을 넣어서 토큰화를 수행한다. tokenizer1에 사용한 \w+는 문자 또는 숫자가 1개 이상인 경우를 의미.

tokenizer2에서는 공백을 기준으로 토큰화하도록 진행. gaps=true는 해당 정규 표현식을 토큰으로 나누기 위한 기준으로 사용한다는 의미. 만약 gaps=True라는 부분을 기재하지 않는다면, 토큰화의 결과는 공백들만 나오게 된다. tokenizer2의 결과는 위의 tokenizer1의 결과와는 달리 아포스트로피나 온점을 제외하지 않고 토큰화가 수행된 것을 확인할 수 있다.

 

글 참조 :https://wikidocs.net/21703

 

02-05 정규 표현식(Regular Expression)

텍스트 전처리에서 정규 표현식은 아주 유용한 도구입니다. 이번에는 파이썬에서 지원하고 있는 정규 표현식 모듈 re의 사용 방법과 NLTK를 통한 정규 표현식을 이용한 토큰화에 대…

wikidocs.net

 

텍스트 전처리에서 정규 표현식은 아주 유용한 도구입니다. 이번에는 정규 표현식 모듈 re의 사용 방법 & NLTK를 통한 정규 표현식을 이용한 토큰화에 대해서 알아보자.

 

기본적으로 re 모듈에 대한 복습시간이 될 것 같다.

 

1) 정규 표현식 문법

정규 표현을 위해 사용되는 문법 중 특수 문자들은 아래와 같다.

또한, 정규 표현식 문법에는 백슬래쉬를 ( \ ) 이용해서 쓰이는 문자 규칙 또한 존재한다.

2) 정규표현식 모듈 함수

정규표현식 모듈에서 지원하는 함수는 아래와 같다.

 

실습

 

#1 " . "

실습#1

 .(점) 은 한 개의 임의의 문자를 나타다. 예를 들어서 정규 표현식이 a.c라고 합시다. a와 c 사이에는 어떤 1개의 문자라도 올 수 있습니다. akc, azc, avc, a5c, a!c와 같은 형태는 모두 a.c의 정규 표현식과 매치된다고 할 수 있다.

 

#2 " ?  " 기호

?는 ?앞의 문자가 있을 수도, 없을 수도 있는 경우를 말한다. ex) ab?c -> 물음표(?) 앞의 "b"는 슈뢰딩거의 고양이마냥 있을수도, 없을 수 도 있는 것이다. 따라서 abc, ac 모두 가능하다.

 

#3 " * " 기호

 

*은 바로 앞의 문자가 0개 이상일 경우를 나타낸다. 앞의 문자는 존재하지 않을 수도 있으며, 또는 여러 개일 수도 있는 것이다. 만약 정규 표현식이 ab*c라면 ac, abc, abbc, abbbc 등과 매치할 수 있으며 b의 개수는 무수히 많을 수 있다.

?기호에서 존재하는 개수의 제한이 없다는 점이 추가되었다고 볼 수 있다.!

 

#4  " + " 기호

" + " 기호는 " * " 기호와 유사하다고도 볼 수 있다.

다른 점은 앞의 문자가 최소 1개 이상이어야 한다는 점. 정규 표현식이 ab+c라고 한다면 ac는 해당 X.

하지만 abc, abbc, abbbc 등과 매치할 수 있으며 b의 개수는 무수히 많을 수 있습니다.

 

#4  " ^ " 기호

^는 시작되는 문자열을 지정한다.

정규표현식이 ^ab라면 문자열 ab로 시작되는 경우 매치.

 

기타) 자주쓰이는 함수 실습

1) re.split()

파이썬 내장함수인 split메소드와 매우 유사하다.

예제1)

위 방법 말고도, 줄바꿈이나 다른 정규표현을 기준으로 텍스트를 분리할 수 도 있다.

예제2)

 

2) re.findall()

findall() 메소드는  정규 표현식과 매치되는 모든 문자열들을 리스트로 리턴한다.

단, 매치되는 문자열이 없다면 빈 리스트를 리턴.

임의의 텍스트에 정규 표현식으로 숫자를 의미하는 규칙으로, 전체 텍스트로부터 숫자만 찾아내서 리스트로 리턴.

 

 

3) re.sub()

sub() 함수는 정규 표현식 패턴과 일치하는 문자열을 찾아 다른 문자열로 대체할 수 있습니다. 아래와 같은 정제 작업에 많이 사용되는데, 영어 문장에 각주 등과 같은 이유로 특수 문자가 섞여있는 경우에 특수 문자를 제거하고 싶다면 알파벳 외의 문자는 공백으로 처리하는 등의 용도로 쓸 수 있습니다.

 

 

2. 정규 표현식을 이용한 토큰화

RegexpTokenizer()에서 괄호 안에 하나의 토큰으로 규정하기를 원하는 정규 표현식을 넣어서 토큰화를 수행한다. tokenizer1에 사용한 \w+는 문자 또는 숫자가 1개 이상인 경우를 의미.

tokenizer2에서는 공백을 기준으로 토큰화하도록 진행. gaps=true는 해당 정규 표현식을 토큰으로 나누기 위한 기준으로 사용한다는 의미. 만약 gaps=True라는 부분을 기재하지 않는다면, 토큰화의 결과는 공백들만 나오게 된다. tokenizer2의 결과는 위의 tokenizer1의 결과와는 달리 아포스트로피나 온점을 제외하지 않고 토큰화가 수행된 것을 확인할 수 있다.

 

자주 등장하지만, 문장 분석에 있어서 큰 도움이 안되는 단어들은 불용어 처리를 통해서 제거할 수 있다.

 

ex) I, my, me....조사, 접미사 등

NLTK에서는 약 100개 정도의 영단어들을 불용어로 사전에 정의했다고 한다.

 

먼저 NLTK를 호출하고 불용어를 확인해보자.

위에서 말했다시피 100개가 넘기 때문에 10개만 확인.

 

 

2. NLTK 이용해서 불용어 제거

위 코드는 "Family is not an important thing. It's everything."라는 임의의 문장에서, NLTK의 word_tokenize를 통해서 단어 토큰화를 수행한 것이다.

그리고 단어 토큰화 결과로부터 NLTK가 정의하고 있는 불용어를 제외한 결과를 출력하고 있다.

결과적으로 'is', 'not', 'an'가 문장에서 제거된 것 확인가능.

 

3. 한국어에서의 불용어 제거

 

한국어에서 불용어를 제거하는 방법으로는 간단하게는 토큰화 후에 조사, 접속사 등을 제거하는 방법이 있다.

하지만 불용어를 제거하려고 하다보면 조사나 접속사와 같은 단어들뿐만 아니라 명사, 형용사와 같은 단어들 중에서 불용어로서 제거하고 싶은 단어들이 생기기도 한다.

 

결국에는 사용자가 직접 불용어 사전을 만들게 되는 경우가 많다.

이번에는 직접 불용어를 정의해보고, 주어진 문장으로부터 사용자가 정의한 불용어 사전으로부터 불용어를 제거해보겠습니다.

아래의 불용어는 임의 선정한 것으로 실제 의미있는 선정 기준이 아니다.

 

이번 장에서는 정규화 기법퍼스에 있는 단어의 개수를 줄일 수 있는 기법표제어 추출(lemmatization)

어간 추출(stemming)의 개념에 대해서 알아보자. 또한 이 둘의 결과가 어떻게 다른지도 확인해보자!.

 

1. 표제어 추출(Lemmatization)

표제어: Lemma라고 부르며, "기본 단어"라는 뜻을 갖고 있다. 따라서 표제어 추출이란, 단어들로부터 표제어를 찾아가는                것이라고 할 수 있다.

핵심은 단어들이 다른 형태를 갖더라도, 뿌리 단어와 비교했을 때 단어의 개수를 줄일 수 있을지 판단한다. 

예를 들어 am, are, is는 서로 다른 스펠링 이지만, be V라는 점에서는 모두 동일하다.

따라서 am, are, is에 대한 표제어 추출결과는 be인 것이다.

 

표제어 추출을 위한 방법으로는 단어를 형태학적으로 파싱(parsing)하는 것이다.

따라서 모든 단어들을 형태소로 만들어야 한다. 

 

그리고 형태소는 크게 두 가지로 이루어져 있다.

1. 어간 (stem) : 단어의 의미를 담고있는 단어의 핵심 부분

2. 접사 (affix)  : 단어에 추가적인 의미를 주는 부분

 

결론적으로, 표제어 추출은 위 두 가지를 분리하는 작업이라고 할 수 있다.

"cats"에 대한 추출값은 cat(어간) + s(접사)

 

코드를 통해서 실습을 진행해보자.

결과를 보면 알겠지만, 표제어 추출은 어간 추출과는 달리 단어의 형태가 적절히 보존되는 양상을 보이는 특징을 가진다.

 

하지만 그럼에도 위의 결과에서는 dy나 ha와 같이 의미를 알 수 없는 적절하지 못한 단어를 출력하고 있다.

이는 표제어 추출기(lemmatizer)가 본래 단어의 품사 정보를 알아야만 정확한 결과를 얻을 수 있기 때문이다.

 

WordNetLemmatizer는 입력으로 단어가 동사 품사라는 사실을 알려줄 수 있습니다.

즉, dies와 watched, has가 문장에서 동사로 쓰였다는 것을 알려준다면 표제어 추출기는 품사의 정보를 보존하면서 정확한 Lemma를 출력할 수 있다.

 

2. 어간 추출 (Stemming)

어간 추출은 형태학적 분석을 단순화한 버전이라고 볼 수도 있고, 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이라고 볼 수도 있다. 따라서 추출 값이 사전에 존재하지 않는 단어일 수도 있다! 

" This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes." 라는 문장을 어간 추출을 돌려보자.

추출 값을 보면 thi, wa, copi 등 사전에 없는 단어가 추출된 것을 확인할 수 있다.

stemmer = PorterStemmer()를 사용한것을 확인할 수 가 있는데,

포터 알고리즘의 규칙 중 대표적으로 아래의 규칙들을 가진다.

 

ALIZE → AL    (realize -> real)
ANCE → 제거 (allowance -> allow)
ICAL → IC       (electricical -> electic)

 

보통 어간 추출은 표제어 추출보다 더 빠르게 작동한다.

또한 어간 추출기 중 포터 어간 추출기 (PorterStemmer())이 가장 준수한 성능을 자랑한다고 한다.

 

 

2. 한국어 어간 추출 (Stemming)

한국어의 어간을 먼저 살펴보면, 5언 9품사의 구조를 갖고 있다.

이 중에서, 용언(동사 및 형용사)은 어간+어미로 구성되어 있다.

 

 

1) 활용(conjugation)

활용이란 용언의 어간(stem)어미(ending)를 가지는 일을 말한다.

활용(conjugation)은 한국을 포함한 인도유럽어(indo-european language)에서도 주로 볼 수 있는 언어적 특징 중 하나를 말하는 통칭적인 개념이다. 

 

어간(stem) : 용언(동사, 형용사)을 활용할 때, 원칙적으로 모양이 변하지 않는 부분.

활용에서 어미에 선행하는 부분. 때론 어간의 모양도 바뀔 수 있음(예: 긋다, 긋고, 그어서, 그어라).

 

어미(ending): 용언의 어간 뒤에 붙어서 활용하면서 변하는 부분이며, 여러 문법적 기능을 수행

어간이 어미를 취할 때, 어간의 모습이 일정하다면 규칙 활용, 어간이나 어미의 모습이 변하는 불규칙 활용으로 나뉨.

 

(2) 규칙 활용

규칙 활용은 어간이 어미를 취할 때, 어간의 모습이 일정합니다. 아래의 예제는 어간과 어미가 합쳐질 때, 어간의 형태가 바뀌지 않음을 보여줍니다.

잡/어간 + 다/어미

이 경우에는 어간이 어미가 붙기전의 모습과 어미가 붙은 후의 모습이 같으므로, 규칙 기반으로 어미를 단순히 분리해주면 어간 추출이 됩니다.

(3) 불규칙 활용

불규칙 활용은 어간이 어미를 취할 때 어간의 모습이 바뀌거나 취하는 어미가 특수한 어미일 경우를 말한다.

예를 들어 ‘듣-, 돕-, 곱-, 잇-, 오르-, 노랗-’ 등이 ‘듣/들-, 돕/도우-, 곱/고우-, 잇/이-, 올/올-, 노랗/노라-’와 같이 어간의 형식이 달라지는 일이 있거나 ‘오르+ 아/어→올라, 하+아/어→하여, 이르+아/어→이르러, 푸르+아/어→푸르러’와 같이 일반적인 어미가 아닌 특수한 어미를 취하는 경우 불규칙활용을 하는 예에 속한다.

 

이 경우에는 어간이 어미가 붙는 과정에서 어간의 모습이 바뀌었으므로 단순한 분리만으로 어간 추출이 되지 않고 좀 더 복잡한 규칙을 필요로 합니다. 아래의 링크는 다양한 불규칙 활용의 예를 보여준다.

 

출처:https://wikidocs.net/21707

엔엘티케이라는 자연어 처리 라이브러리를 불러와보자.!

nltk의 버전을 확인하고 실습에 필요한 Data를 대비하여 모두 다운로드 받아보자.

 

KoNLPy 설치

 

코엔엘파이(KoNLPy)는 한국어 자연어 처리를 위한 형태소 분석기 패키지이다.

 

pip install은 설치가 되지만, import 하였을 때 불러오지 못한다.

이는 JDK오류 혹은 JPype 오류 때문이다. (koNLPy가 JAVA로 구성되어 있기 때문에 그렇다고한다.)

 

이를 해결하기 위해 먼저 JDK (버전 1.7이상)를 설치 하고, 경로를 윈도우 환경변수에 추가해야 한다.

(설치 주소 : https://www.oracle.com/technetwork/java/javase/downloads/index.html)

 

Download the Latest Java LTS Free

Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.

www.oracle.com

 

이후, JAVA와 Python을 연결해주는 역할을 하는 JPype를 설치해야 한다.

설치 주소 : https://github.com/jpype-project/jpype/releases

 

Releases · jpype-project/jpype

JPype is cross language bridge to allow Python programs full access to Java class libraries. - jpype-project/jpype

github.com

 

 

앞서 배운 단어 데이터(코퍼스)에서 용도에 맞게 토큰으로 분류하는 토큰화(tokenization)에 대해서 배웠다.

이번에는 토큰화의 작업 전,후에서 사용하는 정제(cleaning) & 정규화(normalization)에 대해서 배워보자.

 

먼저 정제와 정규화의 목적은 아래와 같다.

정제(cleaning) : 갖고 있는 코퍼스로부터 노이즈를 제거

정규화(normalization) : 표현 방법이 다른 단어를 통합시켜서 같은 단어로 만들어줆

1. 규칙에 기반한 표기가 다른 단어들의 통합

필요에 따라 같은 의미를 갖고 있음에도, 표기가 다를 수 있다. 이를 하나의 단어로 정규화 할 수 있다.

ex) USA와 US

위 두개는 같은 의미를 가지므로 같게 정규화 해보자.

 

먼저, 대/소문자 통합이다.

통상 영어의 첫 글자는 대문자로 표기한다. He is ~~~ 에서 He 는 he와 같다.

따라서 He/he의 정규화는 대/소문자 통합으로 해결할 수 있다.

 

주의할 점은 대문자와 소문자가 다른의미를 가지는 경우이다.

위 예시에서 미국인 US와 우리를 뜻하는 us가 다른 것처럼!

 

또한 고유명사로써 회사 이름, 사람 이름의 경우 또한 마찬가지이다.

 

그 밖에도, 아래와 같은 방식 등으로 텍스트 전처리를 수행할 수 있다.

2. 불용어 제거 

3. 등장 빈도가 적은 단어

4. 길이가 짧은 단어

 

위 방법들에 대해서는 다음 포스트에서 자세히 다뤄 보도록 하자.

 

어간 추출(Stemming)과 표제어 추출(Lemmatization)

어간추출과 표제어추출 모두 단어의 개수를 줄이는 방식이다.

먼저 어간 추출이란  형태학적 분석을 단순화한 버전이라고 볼 수도 있고, 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이라고 볼 수도 있다고 한다.

This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes.

위의 예시 문장에 대해서 어간추출을 진행해보도록 하자.

 

규칙 기반의 접근을 하고 있으므로 어간 추출 후의 결과에는 사전에 없는 단어들도 포함되어 있다.

가령, 포터 알고리즘의 어간 추출은 이러한 규칙들을 가진다.

ALIZE → AL
ANCE → 제거
ICAL → IC

 

위의 규칙에 따르면 좌측의 단어는 우측의 단어와 같은 결과를 얻게된다.

 

formalize → formal
allowance → allow
electricical → electric

 

실제 코드를 통해 확인해보자.

words = ['formalize', 'allowance', 'electricical']

print('어간 추출 전 :',words)
print('어간 추출 후 :',[stemmer.stem(word) for word in words])
어간 추출 전 : ['formalize', 'allowance', 'electricical']
어간 추출 후 : ['formal', 'allow', 'electric']

어간 추출 속도는 표제어 추출보다 일반적으로 빠른데, 포터 어간 추출기는 정밀하게 설계되어 정확도가 높으므로 영어 자연어 처리에서 어간 추출을 하고자 한다면 가장 준수한 선택이다. NLTK에서는 포터 알고리즘 외에도 랭커스터 스태머(Lancaster Stemmer) 알고리즘을 지원한다. 이번에는 포터 알고리즘과 랭커스터 스태머 알고리즘으로 각각 어간 추출을 진행했을 때, 이 둘의 결과를 비교해보자.

from nltk.stem import PorterStemmer
from nltk.stem import LancasterStemmer

porter_stemmer = PorterStemmer()
lancaster_stemmer = LancasterStemmer()

words = ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print('어간 추출 전 :', words)
print('포터 스테머의 어간 추출 후:',[porter_stemmer.stem(w) for w in words])
print('랭커스터 스테머의 어간 추출 후:',[lancaster_stemmer.stem(w) for w in words])
어간 추출 전 : ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
포터 스테머의 어간 추출 후: ['polici', 'do', 'organ', 'have', 'go', 'love', 'live', 'fli', 'die', 'watch', 'ha', 'start']
랭커스터 스테머의 어간 추출 후: ['policy', 'doing', 'org', 'hav', 'going', 'lov', 'liv', 'fly', 'die', 'watch', 'has', 'start']

동일한 단어들의 나열에 대해서 두 스태머는 전혀 다른 결과를 보여준다. 두 스태머 알고리즘은 서로 다른 알고리즘을 사용하기 때문이다. 그렇기 때문에 이미 알려진 알고리즘을 사용할 때는, 사용하고자 하는 코퍼스에 스태머를 적용해보고 어떤 스태머가 해당 코퍼스에 적합한지를 판단한 후에 사용하여야 한다.

이런 규칙에 기반한 알고리즘은 종종 제대로 된 일반화를 수행하지 못 할 수 있다. 어간 추출을 하고나서 일반화가 지나치게 되거나, 또는 덜 되거나 하는 경우다. 예를 들어 포터 알고리즘에서 organization을 어간 추출했을 때의 결과를 보자.

organization → organ

organization과 organ은 완전히 다른 단어 임에도 organization에 대해서 어간 추출을 했더니 organ이라는 단어가 나왔다. organ에 대해서 어간 추출을 한다고 하더라도 결과는 역시 organ이 되기 때문에, 두 단어에 대해서 어간 추출을 한다면 동일한 어간을 갖게 될 수 있다. 이는 의미가 동일한 경우에만 같은 단어를 얻기를 원하는 정규화의 목적에는 맞지 않다.

마지막으로 동일한 단어에 대해서 표제어 추출과 어간 추출을 각각 수행했을 때, 결과에서 어떤 차이가 있는지 간단한 예를 통해서 알아 보도록 하자.

 

Stemming

am → am
the going → the go
having → hav

 

Lemmatization
am → be
the going → the going
having → have

 

 

출처: 위키독스

         (https://wikidocs.net/21707)

+ Recent posts