Showing
1 changed file
with
240 additions
and
1 deletions
1 | -test | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +# Ko-Sentence-BERT | ||
2 | +https://github.com/BM-K/KoSentenceBERT <br> | ||
3 | +Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks (EMNLP 2019) 논문에서 공개한 코드, kakaobrain 팀이 공개한 KorNLUDatasets 과 ETRI KorBERT를 통해 Korea Sentence BERT를 학습하였습니다. | ||
4 | + | ||
5 | +## Installation | ||
6 | +ETRI KorBERT는 transformers 2.4.1 ~ 2.8.0에서만 동작하고 Sentence-BERT는 3.1.0 버전 이상에서 동작하여 라이브러리를 수정하였습니다. <br> | ||
7 | +**huggingface transformer, sentence transformers, tokenizers** 라이브러리 코드를 직접 수정하므로 가상환경 사용을 권장합니다. <br> | ||
8 | +사용한 Docker image는 Docker Hub에 첨부합니다. https://hub.docker.com/r/klbm126/kosbert_image/tags <br> | ||
9 | +ETRI KoBERT를 사용하여 학습하였고 본 레파지토리에선 ETRI KoBERT를 제공하지 않습니다. | ||
10 | +``` | ||
11 | +git clone https://github.com/BM-K/KoSentenceBERT.git | ||
12 | +python -m venv .KoSBERT | ||
13 | +. .KoSBERT/bin/activate | ||
14 | +pip install -r requirements.txt | ||
15 | +``` | ||
16 | +transformer, tokenizers, sentence_transformers 디렉토리를 .KoSBERT/lib/python3.7/site-packages/ 로 이동합니다. <br> | ||
17 | +ETRI_KoBERT 모델과 tokenizer가 KoSentenceBERT 디렉토리 안에 존재하여야 합니다.<br> | ||
18 | +ETRI 모델과 tokenizer는 다음 예시와 같이 불러옵니다 : | ||
19 | + | ||
20 | +```python | ||
21 | +from ETRI_tok.tokenization_etri_eojeol import BertTokenizer | ||
22 | +self.auto_model = BertModel.from_pretrained('./ETRI_KoBERT/003_bert_eojeol_pytorch') | ||
23 | +self.tokenizer = BertTokenizer.from_pretrained('./ETRI_KoBERT/003_bert_eojeol_pytorch/vocab.txt', do_lower_case=False) | ||
24 | +``` | ||
25 | + | ||
26 | +## Train Models | ||
27 | +모델 학습을 원하시면 KoSentenceBERT 디렉토리 안에 KorNLUDatasets이 존재하여야 합니다. <br> | ||
28 | +저는 STS를 학습할 때에 모델 구조에 맞게 STS데이터를 수정하여 사용하였고 데이터와 학습 방법은 아래와 같습니다 : <br><br> | ||
29 | +KoSentenceBERT/KorNLUDatates/KorSTS/tune_test.tsv <br> | ||
30 | +<img src="https://user-images.githubusercontent.com/55969260/93304207-97afec00-f837-11ea-88a2-7256f2f1664e.png"></img> | ||
31 | +*STS test 데이터셋의 일부* <br> | ||
32 | +``` | ||
33 | +python training_nli.py # NLI 데이터로만 학습 | ||
34 | +python training_sts.py # STS 데이터로만 학습 | ||
35 | +python con_training_sts.py # NLI 데이터로 학습 후 STS 데이터로 Fine-Tuning | ||
36 | +``` | ||
37 | + | ||
38 | +## Pre-Trained Models | ||
39 | +**pooling mode**는 **MEAN-strategy**를 사용하였으며, 학습시 모델은 output 디렉토리에 저장 됩니다. <br> | ||
40 | +<img src='https://user-images.githubusercontent.com/55969260/99897241-43176a00-2cdb-11eb-8359-957667e4ac42.png'> | ||
41 | + | ||
42 | +## Performance | ||
43 | +Seed 고정, Dev set | ||
44 | +<img src='https://user-images.githubusercontent.com/55969260/99897252-5aeeee00-2cdb-11eb-9b14-bc412ae0fb8b.png'> | ||
45 | + | ||
46 | +향상된 모델 성능은 다음 레파지토리에 있습니다. <br> https://github.com/BM-K/KoSentenceBERT_V2 | ||
47 | + | ||
48 | +## Application Examples | ||
49 | +생성 된 문장 임베딩을 다운 스트림 애플리케이션에 사용할 수 있는 방법에 대한 몇 가지 예를 제시합니다. | ||
50 | +<br> 제일 높은 성능을 내는 STS + NLI pretrained 모델을 통해 진행합니다. | ||
51 | + | ||
52 | +### Semantic Search | ||
53 | +SemanticSearch.py는 주어진 문장과 유사한 문장을 찾는 작업입니다.<br> | ||
54 | +먼저 Corpus의 모든 문장에 대한 임베딩을 생성합니다. | ||
55 | +```python | ||
56 | +from sentence_transformers import SentenceTransformer, util | ||
57 | +import numpy as np | ||
58 | + | ||
59 | +model_path = './output/training_nli_sts_ETRI_KoBERT-003_bert_eojeol' | ||
60 | + | ||
61 | +embedder = SentenceTransformer(model_path) | ||
62 | + | ||
63 | +# Corpus with example sentences | ||
64 | +corpus = ['한 남자가 음식을 먹는다.', | ||
65 | + '한 남자가 빵 한 조각을 먹는다.', | ||
66 | + '그 여자가 아이를 돌본다.', | ||
67 | + '한 남자가 말을 탄다.', | ||
68 | + '한 여자가 바이올린을 연주한다.', | ||
69 | + '두 남자가 수레를 숲 속으로 밀었다.', | ||
70 | + '한 남자가 담으로 싸인 땅에서 백마를 타고 있다.', | ||
71 | + '원숭이 한 마리가 드럼을 연주한다.', | ||
72 | + '치타 한 마리가 먹이 뒤에서 달리고 있다.'] | ||
73 | + | ||
74 | +corpus_embeddings = embedder.encode(corpus, convert_to_tensor=True) | ||
75 | + | ||
76 | +# Query sentences: | ||
77 | +queries = ['한 남자가 파스타를 먹는다.', | ||
78 | + '고릴라 의상을 입은 누군가가 드럼을 연주하고 있다.', | ||
79 | + '치타가 들판을 가로 질러 먹이를 쫓는다.'] | ||
80 | + | ||
81 | +# Find the closest 5 sentences of the corpus for each query sentence based on cosine similarity | ||
82 | +top_k = 5 | ||
83 | +for query in queries: | ||
84 | + query_embedding = embedder.encode(query, convert_to_tensor=True) | ||
85 | + cos_scores = util.pytorch_cos_sim(query_embedding, corpus_embeddings)[0] | ||
86 | + cos_scores = cos_scores.cpu() | ||
87 | + | ||
88 | + #We use np.argpartition, to only partially sort the top_k results | ||
89 | + top_results = np.argpartition(-cos_scores, range(top_k))[0:top_k] | ||
90 | + | ||
91 | + print("\n\n======================\n\n") | ||
92 | + print("Query:", query) | ||
93 | + print("\nTop 5 most similar sentences in corpus:") | ||
94 | + | ||
95 | + for idx in top_results[0:top_k]: | ||
96 | + print(corpus[idx].strip(), "(Score: %.4f)" % (cos_scores[idx])) | ||
97 | + | ||
98 | +``` | ||
99 | +<br> 결과는 다음과 같습니다 : | ||
100 | +``` | ||
101 | +======================== | ||
102 | + | ||
103 | + | ||
104 | +Query: 한 남자가 파스타를 먹는다. | ||
105 | + | ||
106 | +Top 5 most similar sentences in corpus: | ||
107 | +한 남자가 음식을 먹는다. (Score: 0.7557) | ||
108 | +한 남자가 빵 한 조각을 먹는다. (Score: 0.6464) | ||
109 | +한 남자가 담으로 싸인 땅에서 백마를 타고 있다. (Score: 0.2565) | ||
110 | +한 남자가 말을 탄다. (Score: 0.2333) | ||
111 | +두 남자가 수레를 숲 속으로 밀었다. (Score: 0.1792) | ||
112 | + | ||
113 | + | ||
114 | +======================== | ||
115 | + | ||
116 | + | ||
117 | +Query: 고릴라 의상을 입은 누군가가 드럼을 연주하고 있다. | ||
118 | + | ||
119 | +Top 5 most similar sentences in corpus: | ||
120 | +원숭이 한 마리가 드럼을 연주한다. (Score: 0.6732) | ||
121 | +치타 한 마리가 먹이 뒤에서 달리고 있다. (Score: 0.3401) | ||
122 | +두 남자가 수레를 숲 속으로 밀었다. (Score: 0.1037) | ||
123 | +한 남자가 음식을 먹는다. (Score: 0.0617) | ||
124 | +그 여자가 아이를 돌본다. (Score: 0.0466) | ||
125 | + | ||
126 | + | ||
127 | +======================= | ||
128 | + | ||
129 | + | ||
130 | +Query: 치타가 들판을 가로 질러 먹이를 쫓는다. | ||
131 | + | ||
132 | +Top 5 most similar sentences in corpus: | ||
133 | +치타 한 마리가 먹이 뒤에서 달리고 있다. (Score: 0.7164) | ||
134 | +두 남자가 수레를 숲 속으로 밀었다. (Score: 0.3216) | ||
135 | +원숭이 한 마리가 드럼을 연주한다. (Score: 0.2071) | ||
136 | +한 남자가 빵 한 조각을 먹는다. (Score: 0.1089) | ||
137 | +한 남자가 음식을 먹는다. (Score: 0.0724) | ||
138 | +``` | ||
139 | +### Clustering | ||
140 | +Clustering.py는 문장 임베딩 유사성을 기반으로 유사한 문장을 클러스터링하는 예를 보여줍니다. <br> | ||
141 | +이전과 마찬가지로 먼저 각 문장에 대한 임베딩을 계산합니다. <br> | ||
142 | +```python | ||
143 | +from sentence_transformers import SentenceTransformer, util | ||
144 | +import numpy as np | ||
145 | + | ||
146 | +model_path = './output/training_nli_sts_ETRI_KoBERT-003_bert_eojeol' | ||
147 | + | ||
148 | +embedder = SentenceTransformer(model_path) | ||
149 | + | ||
150 | +# Corpus with example sentences | ||
151 | +corpus = ['한 남자가 음식을 먹는다.', | ||
152 | + '한 남자가 빵 한 조각을 먹는다.', | ||
153 | + '그 여자가 아이를 돌본다.', | ||
154 | + '한 남자가 말을 탄다.', | ||
155 | + '한 여자가 바이올린을 연주한다.', | ||
156 | + '두 남자가 수레를 숲 속으로 밀었다.', | ||
157 | + '한 남자가 담으로 싸인 땅에서 백마를 타고 있다.', | ||
158 | + '원숭이 한 마리가 드럼을 연주한다.', | ||
159 | + '치타 한 마리가 먹이 뒤에서 달리고 있다.', | ||
160 | + '한 남자가 파스타를 먹는다.', | ||
161 | + '고릴라 의상을 입은 누군가가 드럼을 연주하고 있다.', | ||
162 | + '치타가 들판을 가로 질러 먹이를 쫓는다.'] | ||
163 | + | ||
164 | +corpus_embeddings = embedder.encode(corpus) | ||
165 | + | ||
166 | +# Then, we perform k-means clustering using sklearn: | ||
167 | +from sklearn.cluster import KMeans | ||
168 | + | ||
169 | +num_clusters = 5 | ||
170 | +clustering_model = KMeans(n_clusters=num_clusters) | ||
171 | +clustering_model.fit(corpus_embeddings) | ||
172 | +cluster_assignment = clustering_model.labels_ | ||
173 | + | ||
174 | +clustered_sentences = [[] for i in range(num_clusters)] | ||
175 | +for sentence_id, cluster_id in enumerate(cluster_assignment): | ||
176 | + clustered_sentences[cluster_id].append(corpus[sentence_id]) | ||
177 | + | ||
178 | +for i, cluster in enumerate(clustered_sentences): | ||
179 | + print("Cluster ", i+1) | ||
180 | + print(cluster) | ||
181 | + print("") | ||
182 | + | ||
183 | +``` | ||
184 | +결과는 다음과 같습니다 : | ||
185 | + ``` | ||
186 | + Cluster 1 | ||
187 | +['두 남자가 수레를 숲 속으로 밀었다.', '치타 한 마리가 먹이 뒤에서 달리고 있다.', '치타가 들판을 가로 질러 먹이를 쫓는다.'] | ||
188 | + | ||
189 | +Cluster 2 | ||
190 | +['한 남자가 말을 탄다.', '한 남자가 담으로 싸인 땅에서 백마를 타고 있다.'] | ||
191 | + | ||
192 | +Cluster 3 | ||
193 | +['한 남자가 음식을 먹는다.', '한 남자가 빵 한 조각을 먹는다.', '한 남자가 파스타를 먹는다.'] | ||
194 | + | ||
195 | +Cluster 4 | ||
196 | +['그 여자가 아이를 돌본다.', '한 여자가 바이올린을 연주한다.'] | ||
197 | + | ||
198 | +Cluster 5 | ||
199 | +['원숭이 한 마리가 드럼을 연주한다.', '고릴라 의상을 입은 누군가가 드럼을 연주하고 있다.'] | ||
200 | +``` | ||
201 | +<img src = "https://user-images.githubusercontent.com/55969260/96250228-78001500-0fe9-11eb-9ee5-914705182a55.png"> | ||
202 | + | ||
203 | +## Downstream Tasks Demo | ||
204 | +<img src = "https://user-images.githubusercontent.com/55969260/99897723-73610780-2cdf-11eb-9b71-3d31a309a53a.gif"> <br> | ||
205 | +<img src = "https://user-images.githubusercontent.com/55969260/99897743-94295d00-2cdf-11eb-9b16-d6fec66e43d0.gif"> <br> | ||
206 | +<img src = "https://user-images.githubusercontent.com/55969260/99897764-a73c2d00-2cdf-11eb-8bcf-0235d1fda0f7.gif"> <br> | ||
207 | +데모 영상으로 제작된 버전은 다음 레파지토리에 있습니다. <br> https://github.com/BM-K/KoSentenceBERT_V2 | ||
208 | + | ||
209 | +## Citing | ||
210 | +### KorNLU Datasets | ||
211 | +```bibtex | ||
212 | +@article{ham2020kornli, | ||
213 | + title={KorNLI and KorSTS: New Benchmark Datasets for Korean Natural Language Understanding}, | ||
214 | + author={Ham, Jiyeon and Choe, Yo Joong and Park, Kyubyong and Choi, Ilji and Soh, Hyungjoon}, | ||
215 | + journal={arXiv preprint arXiv:2004.03289}, | ||
216 | + year={2020} | ||
217 | +} | ||
218 | +``` | ||
219 | +### Sentence Transformers: Multilingual Sentence Embeddings using BERT / RoBERTa / XLM-RoBERTa & Co. with PyTorch | ||
220 | +```bibtex | ||
221 | +@inproceedings{reimers-2019-sentence-bert, | ||
222 | + title = "Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks", | ||
223 | + author = "Reimers, Nils and Gurevych, Iryna", | ||
224 | + booktitle = "Proceedings of the 2019 Conference on Empirical Methods in Natural Language Processing", | ||
225 | + month = "11", | ||
226 | + year = "2019", | ||
227 | + publisher = "Association for Computational Linguistics", | ||
228 | + url = "http://arxiv.org/abs/1908.10084", | ||
229 | +} | ||
230 | + | ||
231 | +@article{reimers-2020-multilingual-sentence-bert, | ||
232 | + title = "Making Monolingual Sentence Embeddings Multilingual using Knowledge Distillation", | ||
233 | + author = "Reimers, Nils and Gurevych, Iryna", | ||
234 | + journal= "arXiv preprint arXiv:2004.09813", | ||
235 | + month = "04", | ||
236 | + year = "2020", | ||
237 | + url = "http://arxiv.org/abs/2004.09813", | ||
238 | +} | ||
239 | +``` | ||
240 | + | ... | ... |
-
Please register or login to post a comment