본문 바로가기
기계학습/자연어 처리 머신러닝

개체명 인식기 - N:N 양방향 LSTM 모델

by tryotto 2020. 2. 17.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from google.colab import drive
drive.mount('/content/drive')
 
 
file = open('/content/drive/My Drive/train.txt''r')
 
 
 
 
 
# trainning 데이터 전처리 하기 - BIO 개체명 태깅화
import re
 
tagged_sentence = []
tmp_sentence = []
 
for line in file:
  if line.startswith("-DOCSTART-"or line[0]=="\n" or len(line)==0:
    if len(tmp_sentence)>0:  
      tagged_sentence.append(tmp_sentence)
      tmp_sentence = []
    continue
 
  # 공백 기준으로 토큰화 하기
  token = line.split(' ')
 
  # 이름 추출하기
  lower_words = token[0].lower()
 
  # '\n' 문자 제거하기
  token[-1= re.sub('\n','',token[-1])
 
  # tmp_sentence 에 set 으로 저장하기
  tmp_sentence.append([lower_words, token[-1]])
 
 
 
 
 
 
# 문장 따로, 개체명 따로 저장하기 - zip 이용
list_sentence = []
list_bio = []
 
for sentence in tagged_sentence:
  word, bio = zip(*sentence)
 
  list_sentence.append(list(word))
  list_bio.append(list(bio))
 
 
 
 
 
 
# 정수로 인코딩하기
from tensorflow.keras.preprocessing.text import Tokenizer
 
# 1. 각 단어별로 정수 인덱싱 부여 
max_vocab_size_sentence = 4000  # max_vocab_size 의 빈도를 넘어서는 단어는 'OOV' 로 대체한다
tokenizer_sentence = Tokenizer(num_words=max_vocab_size_sentence, oov_token='OOV')
tokenizer_sentence.fit_on_texts(list_sentence)
 
tokenizer_bio = Tokenizer()
tokenizer_bio.fit_on_texts(list_bio)
 
# 2. 텍스트를 정수 인덱스로 변환
seq_sentence = tokenizer_sentence.texts_to_sequences(list_sentence)
seq_bio = tokenizer_bio.texts_to_sequences(list_bio)
 
 
 
 
 
 
# 패딩 과정 수행
from tensorflow.keras.preprocessing.sequence import pad_sequences
 
# 적당한 길이까지만 padding 을 수행해준다
max_len = 70
pad_sentence = pad_sequences(seq_sentence, maxlen = max_len)
pad_bio = pad_sequences(seq_bio, maxlen = max_len)
 
 
 
 
 
 
# 출력값에 대해 원핫 인코딩을 수행해준다
from tensorflow.keras.utils import to_categorical
 
onehot_bio = to_categorical(pad_bio)
 
 
 
 
 
 
# 학습 시작 - 레이어 설정
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Embedding, Bidirectional, TimeDistributed
 
model = Sequential()
model.add(Embedding(input_dim=max_vocab_size_sentence, output_dim=64, mask_zero=True))
model.add(Bidirectional(LSTM(64, return_sequences=True)))
model.add(TimeDistributed(Dense(10, activation='softmax')))
 
 
 
 
# 모델 학습하기
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
model.fit(pad_sentence, onehot_bio, batch_size=100, epochs=10)
 
cs



출력층이 3차원 텐서라는 곳에서 개념의 혼란이 왔다.

입력층은 2차원 텐서로 시작되나,
임베딩 과정을 거치면서 3차원 텐서로 변환된다

결국, 출력층과 정답 라벨은 모두 3차원 텐서이며, 
이 상황에서 loss 값을 구해서 최적 해를 구할 수 있게 된다