일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- leetcode 561
- Hortonworks Sandbox
- 블로그 이전했어요
- 머신러닝
- leetcode 234
- leetcode 5
- 컴퓨터구조
- 문자열 조작
- Python
- leetcode
- leetcode125
- leetcode 937
- ctf-d
- webcrawler
- 데이터레이크와 데이터웨어하우스
- leetcode 121
- MapReduce 실습
- airflow docker
- leetcode 819
- leetcode 344
- leetcode 15
- 스파크 완벽 가이드
- leetcode 49
- wargame.kr
- docker로 airflow 설치하기
- Hadoop
- 올바른 변수명 짓기
- 배열
- leetcode 238
- 빅데이터를 지탱하는 기술
- Today
- Total
HyeM
6부_4장 MLP 텍스트 분류하기 본문
지난주에는 베이스정리로 텍스트를 분류해보았다.
이번주는 MLP를 이용하여 텍스트를 분류해보자.
01. MLP란 무엇인가?
MLP(다충 퍼셉트론):
입력층과 출력층 상에 각각 전체 결합하는 은닉층을 넣은 뉴럴 네트워크
가장 기본적이 인공신경망 구조이고, 하나의 입력층과 출력층, 그리고 하나 이상의 은닉층으로 구성된다.
input layer(입력층), hidden layer(은닉층), output layer(출력층) 있고, 각 층의 뉴런의 개수에는 제약이 없다. (다음 그림에서 뉴런은 원으로 표현됨)
MLP는 이 글의 아래의 <실습2> 에서 자세히 다루어 보겠다.
머신러닝 프레임워크는 글을 그대로 입력할 수 없기 때문에, 텍스트 데이터를 숫자로 변환해야 한다. 근데 텍스트 데이터는 길이가 다르므로 고정된 길이의 벡터로 변환하는 작업이 필요하다. 이를 MLP를 이용해 실습해 보려한다. 우선 개념부터 정리하고 가보자.
02. 텍스트 데이터를 고정길이의 벡터로 변환하는 방법
텍스트 데이터를 벡터로 변환하는 방법은 여러가지 있는데,
가장 기본적인 방법은 단어 하나하나에 ID를 부여하고, ID의 출현빈도와 정렬 순서를 기반으로 벡터를 만든다.
이번 실습에서는 단어의 정렬 순서는 무시하고, 출현 빈도만 사용할 것이다.
글에 어떠한 단어가 있는지 수치로 나타내는 방법 Bow(Bag-of-words)로
"몇 번을 쓰러지더라도 몇 번을 무너지더라도 다시 일어나라" 라는 문장을 나타내보자.
▣ 과정 1. 형태소 분석
몇;번;을;쓰러지다;몇;번;을;무너지다;다시;일어나다 |
형태소분석시에는 원형으로 바꾸어 표기한다.
▣ 과정 2. 단어에 ID 부여
형태소 |
몇 |
번 |
을 |
쓰러지다 |
몇 |
번 |
을 |
무너지다 |
다시 |
일어나다 |
ID |
1 |
2 |
3 |
4 |
1 |
2 |
3 |
5 |
6 |
7 |
okt.pos("몇 번을 쓰러지더라도 몇 번을 무너지더라도 다시 일어나라", stem=True, norm=True)를 실행했을 때 결과
▣ 과정 3. 단어의 출현횟수 세기
형태소 |
몇 |
번 |
을 |
쓰러지다 |
무너지다 |
다시 |
일어나다 |
ID |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
출현횟수 |
2 |
2 |
2 |
1 |
1 |
1 |
1 |
단어의 출현 횟수를 기반으로 문장을 나타낼 수 있음. => 어떤 문장이든 고정길이의 데이터로 나타낼 수 있음.
03. 텍스트 분류하기
텍스트 분류하는 과정
-
텍스트에서 불필요한 품사를 제거
-
사전을 기반으로 단어를 숫자로 변환
-
파일 내부의 단어 출현 비율을 계산
-
데이터를 학습
-
테스트 데이터를 넣어 성공률 확인
04. 단어를 ID로 변환하고 출현 횟수 구하기 _(실습1)
* 실습 준비 : 책에서 제공하는 파일을 가지고 실습을 한다. 이 파일은 텍스트에서 불필요한 품사를 제거한 파일로,
이 파일을 소스코드에 위치한 곳에서 newstext파일 안에 word-dic.json이라는 이름으로 저장한다.
* 실습 내용 : 형태소로 구분한 텍스트를 단어 ID로 변환하고, 텍스트 내부에서의 출현 빈도를 구하는 프로그램
* 실습 결과 : data-mini.json, data.json 파일 두개 생성 ; 6개의 카테고리에서 각각 20개씩만 추출해서 120개의 파일로만 처리한 파일임
* 실습코드 :
import os, glob, json
os.chdir("C:/Users/xxx/Desktop/python 코드/machineLearning/chatbot6")
print(os.getcwd())
#파일(경로) 지정
root_dir ="./newstext" #폴더 지정
dic_file = root_dir + "/word-dic.json" # 파일이름
data_file = root_dir + "/data.json"
data_file_min = root_dir + "/data-mini.json"
#어구를 자르고 ID로 변환하기-- (#1)
word_dic={"_MAX" :0} #MAX는 단어들에 부여되는 ID로, 분석하는 순서대로 id가 부여됨 (ex. 0,1,2)
def text_to_ids(text):
text=text.strip() #strip함수 : 문자열 맨 앞과 맨 뒤의 공백 제거
words=text.split(" ") #split() : 공백을 기준으로 나눔
result=[]
for n in words:
n=n.strip()
if n =="" : continue
if not n in word_dic : #word_dic에 없는 새 단어라면
wid=word_dic[n]=word_dic["_MAX"] #ID를 부여
word_dic["_MAX"]+=1 #ID인 MAX에 +1함
print(wid,n)
else:
wid=word_dic[n] #새 단어가 아닌경우는, id부여할 필요없음
result.append(wid) #단어를 결과배열result에 추가하여 return함
return result
#파일을 읽고 고정길이의 배열 리턴하기 --(#2)
def file_to_ids(fname):
with open(fname, "r",encoding='UTF8') as f: #읽기 모드로 열고,
text=f.read() # 파일 내용을 읽음
return text_to_ids(text) #그런다음, 위의 text_to_ids 함수를 호출하여, 어구를 자른다.
#딕셔너리에 단어 모두 등록하기 --(#3)
def register_dic():
files=glob.glob(root_dir+"/*/*.txt.wakati", recursive=True) #어떠 폴더든 상관없이 들어가, 확장자가 gubun으로 끝나는 파일을 고른다.
#glob: 파일들의 리스트를 뽑을때 사용하는데, 파일의 경로를 이용할 수 있다.
for i in files:
file_to_ids(i) #파일하나당 함수 호출
#파일내부의 단어 세기-- (#4)
def count_file_freq(fname):
cnt=[0 for n in range(word_dic["_MAX"])] #cnt배열을 word_dic의 길이 만큼의 개수(MAX)로 0을 채운다.
with open(fname,"r",encoding='UTF8') as f:
text=f.read().strip()
ids= text_to_ids(text) #text의 어구를 자르고 ID부여
for wid in ids: #한 단어씩 접근하여
cnt[wid] +=1 #개수를 센다. ;인덱스는 단어, 값은 단어 횟수
return cnt #단어와 출현횟수가 저장된 cnt 배열을 return
#카테고리마다 파일 읽어들이기 --(#5)
def count_freq(limit=0):
X=[]
Y=[]
max_words=word_dic["_MAX"] #max_words배열을 word_dic의 길이 만큼의 개수(MAX)로 0을 채운다
cat_names=[]
for cat in os.listdir(root_dir): #os.listdir : 해당 디렉터리에 있는 파일들의 리스트를 구함
cat_dir=root_dir+"/"+cat #하위 파일 경로 설정
if not os.path.isdir(cat_dir) :continue #하위 파일이 없으면 continue
cat_idx=len(cat_names)
cat_names.append(cat) #cat_names 배열에 파일명을 append
files=glob.glob(cat_dir+"/*.txt.wakati") #하위파일 경로 밑에 .gubun으로 끝나는 파일 찾음
i=0
for path in files: #하위파일/*.gubun으로 끝나는 파일 하나씩 다룸
print(path) #경로 출력
cnt=count_file_freq(path) #함수호출_파일 내부 단어 세기
X.append(cnt)
Y.append(cat_idx)
if limit >0: #?
if i > limit: break
i+=1
return X,Y
#단어 딕셔너리 만들기 --(#5)
if os.path.exists(dic_file): #os.path.exists : 파일이나 폴더가 존재하는지 확인
word_dic=json.load(open(dic_file)) #dic_file을 읽어 json으로 읽어와, word_dic에 저장
else: #파일이 없다면
register_dic() #함수호출 _ *.gubun 파일 가져옴
json.dump(word_dic, open(dic_file,"w",encoding='UTF8'))
#벡터를 파일로 출력하기 --(#5)
#테스트 목적의 소규모 데이터 만들기
X,Y =count_freq(20)
json.dump({"X": X, "Y" :Y}, open(data_file_min,"w")) #json.dump : python객체를 json 데이터로 쓰기, 직렬화, 인코딩 ; 벡터로 나타내는듯
#전체 데이터를 기반으로 데이터 만들기
X, Y = count_freq() #함수호출_ 카테고리마다 파일 읽어오기
json.dump({"x": X, "Y": Y}, open(data_file,"w"))
print("ok")
코드 설명은 주석으로 표기함
※변경사항 : 형태소 파일을 추가함 + 파일 열때 encoding을 utf-8로 설정 + 파일 확장자 명을 gubun에서 txt.wakati로 변경
05. MLP로 텍스트 분류하기 _(실습2)
▣ 케라스 모델
Keras 모델을 만드는 방법은 Sequential과 functional 방법이 있다.
-
sequential 방법 : layer-by-layer 대로 층층히 쌓아 올리는 방법이다. 이 방법은 layer을 공유하는 구조나, 다중입출력을 사용하지 못한다. 또한, layer을 재사용하지 못한다.
-
functional 방법 : layer가 앞,뒤로만 연결된 구조가 아닌, 자유롭게 구조가 정의 될 수 있다. 이는 siamese네트워크와 residual 네트워크 같은 복잡한 구조의 네트워크를 만들 수 있다.
이번 실습에선 sequential 모델을 사용하려고 한다.
▣ 과정 1. 모델 만들기
model = Sequential() #케라스의 Sequential 모델 이용
▣ 과정 2. 레이어 추가하기 _ 아래 설명과 주석에 설명있음
model.add(Dense(512, input_shape=(max_words,))) #dense(512)는 입력층
model.add(Activation('relu')) #은닉층1; 각 층 사이에 활성화 함수 activation을 넣어 이전층의 계산을 단순화 하여, 성능을 높인다.
model.add(Dropout(0.5)) #dropout 또한 신경망을 최적화 해준다.
model.add(Dense(nb_classes)) #dene(nb_classe)가 출력층
model.add(Activation('softmax')) #은닉층2
add함수로 레이어를 추가한다.
위의 소스코드에서 input_shape은 입력데이터의 차원을 정의한다. (첫번째 층의 차원과 같은 의미)
Dropout(드롭아웃) : 은닉층의 뉴런을 무작위로 삭제하고 학습하여 범용 성능을 높이는 방법이다. (신경망모델이 복잡해지면 가중치 감소만으로 억제가 어려우니, dropout을 사용함) ; Dropout(0.5)은 50%를 적용한 것을 의미한다. (dropout 참고 : http://blog.daum.net/geoscience/1162 )
dense 레이어 : 입력과 출력을 연결해준다. 각 연결선에는 가중치(weight)를 포함하고 있는데, 연결강도를 의미한다.
ex)
Dense(512, input_dim=4, init='normal', activation='relu')
* 512 (첫번째 인자) : 출력 뉴런의 수는 512이다.
* input_dim : 입력뉴런의 수를 설정
* init : 가중치 초기화 방법 설정
uniform(균일분포)와 normal(가우시안 분포)가 있음
* activation : 활성화 함수 설정
linear : (default) 입력 뉴런과 가중치가 계산된 결과값이 그대로 출력
relu : rectifier 함수로, 은닉층에 주로 사용된다.
sigmoid : 이진 분류 문제에서 출력층에서 주로 사용한다.
softmax : 다중 클래스 분류 문제에서 출력층에서 사용한다.
활성화 함수에 대한 자세한 설명은 https://tykimos.github.io/2017/01/27/MLP_Layer_Talk/ 를 참고.
▣ 과정 3. 모델 컴파일
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
compile 함수로 모델을 컴파일한다.
-
손실함수 (loss function) : 가중치 세트를 평가하는데 사용한 손실함수, categorical_cressentropy 이용
-
최적화 방법(optimizer) : 최적의 가중치를 검색하는데 사용되는 최적화 알고리즘으로 효율적인 경사 하강법 알고리즘 중 하나인 adam을 이용
-
평가척도 (metrics) : 분류 문제에서는 일반적으로 accuracy로 지정한다.
출처 : https://tykimos.github.io/2017/03/08/CNN_Getting_Started/
▣ 과정 4. 학습할 데이터 셋 가져오기
X_train, X_test, Y_train, Y_test = train_test_split(X, Y) # X가 텍스트를 나타내는 데이터, Y가 카테고리를 나타내는 데이터이다.
Y_train = np_utils.to_categorical(Y_train, nb_classes)
* train_test_split() : 학습 데이터셋과 테스트 셋을 분리해줌.
* np_utils.to_categorical() : 원핫인코딩(one-hot인코딩) 처리
※ 원핫인코딩 ?
자연어처리에서 문자를 숫자로 바꾸는 여러 가지 기법들중 하나로, 단어를 표혀하는 가장 기본적인 표현 방법이다.
원핫 인코딩을 위해서는 텍스트의 모든 단어를 중복 없이 모아 놓은 '단어집합'을 제일 먼저 해줘야한다.
원핫 인코딩은 단어 집합의 크기를 벡터 차원으로 하고, 표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 다른 인덱스에는 0을 부여하는 단어의 벡터 표현 방식이다.
원핫 인코딩 과정은 1)각 단어에 고유한 인덱스를 부여하고, 2) 표현하고 싶은 단어의 인덱스 위치에 1을 부여하고, 다른 단어의 인덱스의 위치에는 0을 부여하는 것이다.
참고 : https://wikidocs.net/22647
▣ 과정 5. 모델 학습
model = KerasClassifier(
build_fn=build_model,
nb_epoch=nb_epoch,
batch_size=batch_size)
model.fit(X_train, Y_train)
fit함수에선 학습데이터와 기타 파라미터를 가지고 모델 학습을 진행한다.
-
build_fn : 호출 가능한 함수 혹은 클래스 인스턴스
-
nb_epoch : 모델 학습 횟수
-
batch_size : 몇 개의 샘플로 가중치를 생신할 것인지 지정
참고 : https://keras.io/ko/scikit-learn-api/ ,
https://buomsoo-kim.github.io/keras/2018/04/21/Easy-deep-learning-with-Keras-1.md/
▣ 과정 6. 모델 사용하기
y = model.predict(X_test)
ac_score = metrics.accuracy_score(Y_test, y)
cl_report = metrics.classification_report(Y_test, y)
print("정답률 =", ac_score)
print("리포트 =\n", cl_report)
predict 함수를 이용하여 모델을 사용한다.
* metrics.accuracy_score : scikit-learn의 선형분류의 결과 평가함수로, Y_test와 y를 비교하여 정확도를 계산해준다.
* metrics.classification_report : 정밀도, 재현율, F1 점수를 구하는 함수이다.
▣ . 전체 소스 코드 (코드 설명은 위에서 부분적으로 설명함)
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils import np_utils
from sklearn.model_selection import train_test_split
from sklearn import model_selection, metrics
import json
max_words = 56681 # 입력 단어 수: word-dic.json 파일 참고
nb_classes = 6 # 6개의 카테고리
batch_size = 64
nb_epoch = 20
# MLP 모델 생성하기 --- (#1)
def build_model():
model = Sequential() #케라스의 Sequential 모델 이용
model.add(Dense(512, input_shape=(max_words,)))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
return model
# 데이터 읽어 들이기--- (#2)
data = json.load(open("./newstext/data-mini.json")) #좀 더 작은 데이터
#data = json.load(open("./newstext/data.json"))
X = data["X"] # 텍스트를 나타내는 데이터
Y = data["Y"] # 카테고리 데이터
# 학습하기 --- (#3)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y)
Y_train = np_utils.to_categorical(Y_train, nb_classes)
print(len(X_train),len(Y_train))
model = KerasClassifier(
build_fn=build_model,
nb_epoch=nb_epoch,
batch_size=batch_size)
model.fit(X_train, Y_train)
# 예측하기 --- (#4)
y = model.predict(X_test)
ac_score = metrics.accuracy_score(Y_test, y)
cl_report = metrics.classification_report(Y_test, y)
print("정답률 =", ac_score)
print("리포트 =\n", cl_report)
위 글은 [(파이썬을 이용한)머신러닝, 딥러닝 실전 개발 입문] 을 읽고 정리한 글입니다.
keras의 MLP 내용 참고 : https://buomsoo-kim.github.io/keras/2018/04/21/Easy-deep-learning-with-Keras-1.md/
'Study > AI&DeepLearning' 카테고리의 다른 글
6부_6장 마르코프 체인과 LSTM으로 문장 생성하기 (0) | 2020.08.14 |
---|---|
6부_5장 N-gram으로 문장유사도 분석하기 (0) | 2020.08.04 |
6부_3장 베이스정리로 텍스트 분류하기 (0) | 2020.07.25 |
6부_2장 Word2Vec로 문장을 백터로 변환하기 (0) | 2020.07.17 |
6부_1장 한국어 분석(형태소 분석) (1) | 2020.07.17 |