Multilingual Universal Sentence Encoder를 사용한 교차 언어 유사성 및 의미론적 검색 엔진

TensorFlow.org에서 보기 Google Colab에서 실행 GitHub에서 보기 노트북 다운로드 TF Hub 모델 보기

이 노트북은 Multilingual Universal Sentence Encoder 모듈에 액세스하고 이 모듈을 다국어 문장 유사성에 사용하는 방법을 보여줍니다. 이 모듈은 원래 Universal Encoder 모듈의 확장입니다.

이 노트북의 내용은 다음과 같이 구성됩니다.

  • 첫 번째 섹션에서는 언어 쌍 사이의 문장 시각화를 보여줍니다. 다소 학문적인 내용입니다.
  • 두 번째 섹션에서는 여러 언어로 된 Wikipedia Corpus 샘플에서 의미론적 검색 엔진을 빌드하는 방법을 보여줍니다.

인용

이 colab에서 탐구한 모델을 사용하는 연구 논문에는 다음 인용구를 넣어야 합니다.

###

의미론적 검색을 위한 다국어 범용 문장 인코더

Yinfei Yang, Daniel Cer, Amin Ahmad, Mandy Guo, Jax Law, Noah Constant, Gustavo Hernandez Abrego, Steve Yuan, Chris Tar, Yun-Hsuan Sung, Brian Strope, and Ray Kurzweil. 2019. arXiv preprint arXiv:1907.04307

설정

이 섹션에서는 Multilingual Universal Sentence Encoder 모듈에 액세스할 수 있는 환경을 설정하고 일련의 영어 문장과 해당 번역을 준비합니다. 다음 섹션에서는 다국어 모듈을 사용하여 교차 언어 유사성을 계산합니다.

Setup Environment

Setup common imports and functions

다음은 이 노트북 전체에서 텍스트를 인코딩하는 데 사용할 사전 훈련된 ML 모델을 가져오는 추가 상용구 코드입니다.

# The 16-language multilingual module is the default but feel free
# to pick others from the list and compare the results.
module_url = 'https://tfhub.dev/google/universal-sentence-encoder-multilingual/3'

model = hub.load(module_url)

def embed_text(input):
  return model(input)

언어 간 텍스트 유사성 시각화하기

이제 문장 임베딩이 준비되었으므로 다양한 언어 사이에서 의미론적 유사성을 시각화할 수 있습니다.

텍스트 임베딩 계산하기

먼저 다양한 언어로 번역된 일련의 문장을 병렬로 정의합니다. 그런 다음 모든 문장에 대한 임베딩을 미리 계산합니다.

# Some texts of different lengths in different languages.
arabic_sentences = ['كلب', 'الجراء لطيفة.', 'أستمتع بالمشي لمسافات طويلة على طول الشاطئ مع كلبي.']
chinese_sentences = ['狗', '小狗很好。', '我喜欢和我的狗一起沿着海滩散步。']
english_sentences = ['dog', 'Puppies are nice.', 'I enjoy taking long walks along the beach with my dog.']
french_sentences = ['chien', 'Les chiots sont gentils.', 'J\'aime faire de longues promenades sur la plage avec mon chien.']
german_sentences = ['Hund', 'Welpen sind nett.', 'Ich genieße lange Spaziergänge am Strand entlang mit meinem Hund.']
italian_sentences = ['cane', 'I cuccioli sono carini.', 'Mi piace fare lunghe passeggiate lungo la spiaggia con il mio cane.']
japanese_sentences = ['犬', '子犬はいいです', '私は犬と一緒にビーチを散歩するのが好きです']
korean_sentences = ['개', '강아지가 좋다.', '나는 나의 개와 해변을 따라 길게 산책하는 것을 즐긴다.']
russian_sentences = ['собака', 'Милые щенки.', 'Мне нравится подолгу гулять по пляжу со своей собакой.']
spanish_sentences = ['perro', 'Los cachorros son agradables.', 'Disfruto de dar largos paseos por la playa con mi perro.']

# Multilingual example
multilingual_example = ["Willkommen zu einfachen, aber", "verrassend krachtige", "multilingüe", "compréhension du langage naturel", "модели.", "大家是什么意思" , "보다 중요한", ".اللغة التي يتحدثونها"]
multilingual_example_in_en =  ["Welcome to simple yet", "surprisingly powerful", "multilingual", "natural language understanding", "models.", "What people mean", "matters more than", "the language they speak."]
# Compute embeddings.
ar_result = embed_text(arabic_sentences)
en_result = embed_text(english_sentences)
es_result = embed_text(spanish_sentences)
de_result = embed_text(german_sentences)
fr_result = embed_text(french_sentences)
it_result = embed_text(italian_sentences)
ja_result = embed_text(japanese_sentences)
ko_result = embed_text(korean_sentences)
ru_result = embed_text(russian_sentences)
zh_result = embed_text(chinese_sentences)

multilingual_result = embed_text(multilingual_example)
multilingual_in_en_result = embed_text(multilingual_example_in_en)

유사성 시각화하기

텍스트 임베딩이 준비되었으므로 내적을 사용하여 언어 간에 문장이 얼마나 유사한지 시각화할 수 있습니다. 어두운 색은 임베딩이 의미상 유사함을 나타냅니다.

다국어 유사성

visualize_similarity(multilingual_in_en_result, multilingual_result,
                     multilingual_example_in_en, multilingual_example,  "Multilingual Universal Sentence Encoder for Semantic Retrieval (Yang et al., 2019)")

영어-아랍어 유사성

visualize_similarity(en_result, ar_result, english_sentences, arabic_sentences, 'English-Arabic Similarity')

영어-러시아어 유사성

visualize_similarity(en_result, ru_result, english_sentences, russian_sentences, 'English-Russian Similarity')

영어-스페인어 유사성

visualize_similarity(en_result, es_result, english_sentences, spanish_sentences, 'English-Spanish Similarity')

영어-이탈리아어 유사성

visualize_similarity(en_result, it_result, english_sentences, italian_sentences, 'English-Italian Similarity')

이탈리아어-스페인어 유사성

visualize_similarity(it_result, es_result, italian_sentences, spanish_sentences, 'Italian-Spanish Similarity')

영어-중국어 유사성

visualize_similarity(en_result, zh_result, english_sentences, chinese_sentences, 'English-Chinese Similarity')

영어-한국어 유사성

visualize_similarity(en_result, ko_result, english_sentences, korean_sentences, 'English-Korean Similarity')

중국어-한국어 유사성

visualize_similarity(zh_result, ko_result, chinese_sentences, korean_sentences, 'Chinese-Korean Similarity')

기타 언어

위의 예는 영어, 아랍어, 중국어, 네덜란드어, 프랑스어, 독일어, 이탈리아어, 일본어, 한국어, 폴란드어, 포르투갈어, 러시아어, 스페인어, 태국어 및 터키어의 모든 언어 쌍으로 확장할 수 있습니다. 즐거운 코딩되세요!

다국어 의미론적 유사성 검색 엔진 만들기

이전 예제에서는 몇 개의 문장을 시각화했지만 이 섹션에서는 Wikipedia Corpus에서 약 200,000개의 문장에 대한 의미론적 검색 인덱스를 빌드합니다. Universal Sentence Encoder의 다국어 기능을 보여주기 위해 약 절반은 영어로, 나머지 절반은 스페인어로 제공됩니다.

인덱스로 데이터 다운로드하기

먼저 News Commentary Corpus [1]에서 여러 언어로 된 뉴스 문장을 다운로드합니다. 이 접근 방식은 일반성을 잃지 않고, 지원되는 나머지 언어의 인덱싱에도 효과적으로 적용됩니다.

데모의 속도를 높이기 위해 언어당 문장을 1000개로 제한합니다.

corpus_metadata = [
    ('ar', 'ar-en.txt.zip', 'News-Commentary.ar-en.ar', 'Arabic'),
    ('zh', 'en-zh.txt.zip', 'News-Commentary.en-zh.zh', 'Chinese'),
    ('en', 'en-es.txt.zip', 'News-Commentary.en-es.en', 'English'),
    ('ru', 'en-ru.txt.zip', 'News-Commentary.en-ru.ru', 'Russian'),
    ('es', 'en-es.txt.zip', 'News-Commentary.en-es.es', 'Spanish'),
]

language_to_sentences = {}
language_to_news_path = {}
for language_code, zip_file, news_file, language_name in corpus_metadata:
  zip_path = tf.keras.utils.get_file(
      fname=zip_file,
      origin='http://opus.nlpl.eu/download.php?f=News-Commentary/v11/moses/' + zip_file,
      extract=True)
  news_path = os.path.join(os.path.dirname(zip_path), news_file)
  language_to_sentences[language_code] = pd.read_csv(news_path, sep='\t', header=None)[0][:1000]
  language_to_news_path[language_code] = news_path

  print('{:,} {} sentences'.format(len(language_to_sentences[language_code]), language_name))
Downloading data from http://opus.nlpl.eu/download.php?f=News-Commentary/v11/moses/ar-en.txt.zip
24715264/24714354 [==============================] - 2s 0us/step
1,000 Arabic sentences
Downloading data from http://opus.nlpl.eu/download.php?f=News-Commentary/v11/moses/en-zh.txt.zip
18104320/18101984 [==============================] - 2s 0us/step
1,000 Chinese sentences
Downloading data from http://opus.nlpl.eu/download.php?f=News-Commentary/v11/moses/en-es.txt.zip
28106752/28106064 [==============================] - 2s 0us/step
1,000 English sentences
Downloading data from http://opus.nlpl.eu/download.php?f=News-Commentary/v11/moses/en-ru.txt.zip
24854528/24849511 [==============================] - 2s 0us/step
1,000 Russian sentences
1,000 Spanish sentences

사전 훈련된 모델을 사용하여 문장을 벡터로 변환하기

GPU의 RAM에 맞도록 여러 배치로 임베딩을 계산합니다.

# Takes about 3 minutes

batch_size = 2048
language_to_embeddings = {}
for language_code, zip_file, news_file, language_name in corpus_metadata:
  print('\nComputing {} embeddings'.format(language_name))
  with tqdm(total=len(language_to_sentences[language_code])) as pbar:
    for batch in pd.read_csv(language_to_news_path[language_code], sep='\t',header=None, chunksize=batch_size):
      language_to_embeddings.setdefault(language_code, []).extend(embed_text(batch[0]))
      pbar.update(len(batch))
0%|          | 0/1000 [00:00<?, ?it/s]
Computing Arabic embeddings
83178it [00:30, 2768.60it/s]
  0%|          | 0/1000 [00:00<?, ?it/s]
Computing Chinese embeddings
69206it [00:18, 3664.60it/s]
  0%|          | 0/1000 [00:00<?, ?it/s]
Computing English embeddings
238853it [00:37, 6319.00it/s]
  0%|          | 0/1000 [00:00<?, ?it/s]
Computing Russian embeddings
190092it [00:34, 5589.16it/s]
  0%|          | 0/1000 [00:00<?, ?it/s]
Computing Spanish embeddings
238819it [00:41, 5754.02it/s]

의미론적 벡터 인덱스 빌드하기

Annoy 라이브러리의 래퍼인 SimpleNeighbors 라이브러리를 사용하여 Corpus에서 결과를 효율적으로 조회합니다.

%%time

# Takes about 8 minutes

num_index_trees = 40
language_name_to_index = {}
embedding_dimensions = len(list(language_to_embeddings.values())[0][0])
for language_code, zip_file, news_file, language_name in corpus_metadata:
  print('\nAdding {} embeddings to index'.format(language_name))
  index = SimpleNeighbors(embedding_dimensions, metric='dot')

  for i in trange(len(language_to_sentences[language_code])):
    index.add_one(language_to_sentences[language_code][i], language_to_embeddings[language_code][i])

  print('Building {} index with {} trees...'.format(language_name, num_index_trees))
  index.build(n=num_index_trees)
  language_name_to_index[language_name] = index
0%|          | 1/1000 [00:00<02:21,  7.04it/s]
Adding Arabic embeddings to index
100%|██████████| 1000/1000 [02:06<00:00,  7.90it/s]
  0%|          | 1/1000 [00:00<01:53,  8.84it/s]
Building Arabic index with 40 trees...

Adding Chinese embeddings to index
100%|██████████| 1000/1000 [02:05<00:00,  7.99it/s]
  0%|          | 1/1000 [00:00<01:59,  8.39it/s]
Building Chinese index with 40 trees...

Adding English embeddings to index
100%|██████████| 1000/1000 [02:07<00:00,  7.86it/s]
  0%|          | 1/1000 [00:00<02:17,  7.26it/s]
Building English index with 40 trees...

Adding Russian embeddings to index
100%|██████████| 1000/1000 [02:06<00:00,  7.91it/s]
  0%|          | 1/1000 [00:00<02:03,  8.06it/s]
Building Russian index with 40 trees...

Adding Spanish embeddings to index
100%|██████████| 1000/1000 [02:07<00:00,  7.84it/s]
Building Spanish index with 40 trees...
CPU times: user 11min 21s, sys: 2min 14s, total: 13min 35s
Wall time: 10min 33s

%%time

# Takes about 13 minutes

num_index_trees = 60
print('Computing mixed-language index')
combined_index = SimpleNeighbors(embedding_dimensions, metric='dot')
for language_code, zip_file, news_file, language_name in corpus_metadata:
  print('Adding {} embeddings to mixed-language index'.format(language_name))
  for i in trange(len(language_to_sentences[language_code])):
    annotated_sentence = '({}) {}'.format(language_name, language_to_sentences[language_code][i])
    combined_index.add_one(annotated_sentence, language_to_embeddings[language_code][i])

print('Building mixed-language index with {} trees...'.format(num_index_trees))
combined_index.build(n=num_index_trees)
0%|          | 1/1000 [00:00<02:00,  8.29it/s]
Computing mixed-language index
Adding Arabic embeddings to mixed-language index
100%|██████████| 1000/1000 [02:06<00:00,  7.92it/s]
  0%|          | 1/1000 [00:00<02:24,  6.89it/s]
Adding Chinese embeddings to mixed-language index
100%|██████████| 1000/1000 [02:05<00:00,  7.95it/s]
  0%|          | 1/1000 [00:00<02:05,  7.98it/s]
Adding English embeddings to mixed-language index
100%|██████████| 1000/1000 [02:06<00:00,  7.88it/s]
  0%|          | 1/1000 [00:00<02:18,  7.20it/s]
Adding Russian embeddings to mixed-language index
100%|██████████| 1000/1000 [02:04<00:00,  8.03it/s]
  0%|          | 1/1000 [00:00<02:17,  7.28it/s]
Adding Spanish embeddings to mixed-language index
100%|██████████| 1000/1000 [02:06<00:00,  7.90it/s]
Building mixed-language index with 60 trees...
CPU times: user 11min 18s, sys: 2min 13s, total: 13min 32s
Wall time: 10min 30s

의미론적 유사성 검색 엔진이 동작하는지 확인하기

이 섹션에서는 다음을 시연합니다.

  1. 의미론적 검색 기능: Corpus에서 주어진 쿼리와 의미적으로 유사한 문장을 검색합니다.
  2. 다국어 기능: 쿼리 언어와 인덱스 언어가 일치하면 여러 언어에서도 작업을 수행합니다.
  3. 교차 언어 기능: 인덱싱된 Corpus와 다른 언어로 쿼리를 실행합니다.
  4. 혼합 언어 Corpus: 모든 언어의 항목을 포함하는 단일 인덱스에 대해 위의 모든 항목을 수행합니다.

의미론적 검색 교차 언어 기능

이 섹션에서는 샘플 영어 문장 세트와 관련된 문장을 검색하는 방법을 보여줍니다. 다음을 시도합니다.

  • 몇 가지 다른 샘플 문장을 시도합니다.
  • 반환된 결과의 수를 변경해 봅니다(유사성 순서로 반환됨).
  • 여러 언어로 결과를 반환하여 다국어 기능을 사용해 봅니다(일부 결과에 구글 번역을 사용하여 모국어의 온전성을 확인할 수 있음).

English sentences similar to: "The stock market fell four points."
['Nobel laureate Amartya Sen attributed the European crisis to four failures – political, economic, social, and intellectual.',
 'Just last December, fellow economists Martin Feldstein and Nouriel Roubini each penned op-eds bravely questioning bullish market sentiment, sensibly pointing out gold’s risks.',
 'His ratings have dipped below 50% for the first time.',
 'As a result, markets were deregulated, making it easier to trade assets that were perceived to be safe, but were in fact not.',
 'Consider the advanced economies.',
 'But the agreement has three major flaws.',
 'This “predetermined equilibrium” thinking – reflected in the view that markets always self-correct – led to policy paralysis until the Great Depression, when John Maynard Keynes’s argument for government intervention to address unemployment and output gaps gained traction.',
 'Officials underestimated tail risks.',
 'Consider a couple of notorious examples.',
 'Stalin was content to settle for an empire in Eastern Europe.']

혼합 코퍼스 기능

이제 영어로 쿼리를 제출하지만 결과는 인덱싱된 언어 중 하나에서 나옵니다.

English sentences similar to: "The stock market fell four points."
['Nobel laureate Amartya Sen attributed the European crisis to four failures – political, economic, social, and intellectual.',
 'It was part of the 1945 consensus.',
 'The end of the East-West ideological divide and the end of absolute faith in markets are historical turning points.',
 'Just last December, fellow economists Martin Feldstein and Nouriel Roubini each penned op-eds bravely questioning bullish market sentiment, sensibly pointing out gold’s risks.',
 'His ratings have dipped below 50% for the first time.',
 'As a result, markets were deregulated, making it easier to trade assets that were perceived to be safe, but were in fact not.',
 'Consider the advanced economies.',
 'Since their articles appeared, the price of gold has moved up still further.',
 'But the agreement has three major flaws.',
 'Gold prices even hit a record-high $1,300 recently.',
 'This “predetermined equilibrium” thinking – reflected in the view that markets always self-correct – led to policy paralysis until the Great Depression, when John Maynard Keynes’s argument for government intervention to address unemployment and output gaps gained traction.',
 'What Failed in 2008?',
 'Officials underestimated tail risks.',
 'Consider a couple of notorious examples.',
 'One of these species, orange roughy, has been caught commercially for only around a quarter-century, but already is being fished to the point of collapse.',
 'Meanwhile, policymakers were lulled into complacency by the widespread acceptance of economic theories such as the “efficient-market hypothesis,” which assumes that investors act rationally and use all available information when making their decisions.',
 'Stalin was content to settle for an empire in Eastern Europe.',
 'Intelligence assets have been redirected.',
 'A new wave of what the economist Joseph Schumpeter famously called “creative destruction” is under way: even as central banks struggle to maintain stability by flooding markets with liquidity, credit to business and households is shrinking.',
 'It all came about in a number of ways.',
 'The UN, like the dream of European unity, was also part of the 1945 consensus.',
 'The End of 1945',
 'The Global Economy’s New Path',
 'But this scenario failed to materialize.',
 'Gold prices are extremely sensitive to global interest-rate movements.',
 'Fukushima has presented the world with a far-reaching, fundamental choice.',
 'It was Japan, the high-tech country par excellence (not the latter-day Soviet Union) that proved unable to take adequate precautions to avert disaster in four reactor blocks.',
 'Some European academics tried to argue that there was no need for US-like fiscal transfers, because any desired degree of risk sharing can, in theory, be achieved through financial markets.',
 '$10,000 Gold?',
 'One answer, of course, is a complete collapse of the US dollar.',
 '1929 or 1989?',
 'The goods we made were what economists call “rival" and “excludible" commodities.',
 'This dream quickly faded when the Cold War divided the world into two hostile blocs. But in some ways the 1945 consensus, in the West, was strengthened by Cold War politics.',
 'The first flaw is that the spending reductions are badly timed: coming as they do when the US economy is weak, they risk triggering another recession.',
 'One successful gold investor recently explained to me that stock prices languished for a more than a decade before the Dow Jones index crossed the 1,000 mark in the early 1980’s.',
 'Eichengreen traces our tepid response to the crisis to the triumph of monetarist economists, the disciples of Milton Friedman, over their Keynesian and Minskyite peers – at least when it comes to interpretations of the causes and consequences of the Great Depression.',
 "However, America's unilateral options are limited.",
 'Once it was dark, a screen was set up and Mark showed home videos from space.',
 'These aspirations were often voiced in the United Nations, founded in 1945.',
 'Then I got distracted for about 40 years.']

자신의 쿼리를 시도합니다.

English sentences similar to: "The stock market fell four points."
['(Chinese) 新兴市场的号角',
 '(English) It was part of the 1945 consensus.',
 '(Russian) Брюссель. Цунами, пронёсшееся по финансовым рынкам, является глобальной катастрофой.',
 '(Arabic) هناك أربعة شروط مسبقة لتحقيق النجاح الأوروبي في أفغانستان:',
 '(Spanish) Su índice de popularidad ha caído por primera vez por debajo del 50 por ciento.',
 '(English) His ratings have dipped below 50% for the first time.',
 '(Russian) Впервые его рейтинг опустился ниже 50%.',
 '(English) As a result, markets were deregulated, making it easier to trade assets that were perceived to be safe, but were in fact not.',
 '(Arabic) وكانت التطورات التي شهدتها سوق العمل أكثر تشجيعا، فهي على النقيض من أسواق الأصول تعكس النتائج وليس التوقعات. وهنا أيضاً كانت الأخبار طيبة. فقد أصبحت سوق العمل أكثر إحكاما، حيث ظلت البطالة عند مستوى 3.5% وكانت نسبة الوظائف إلى الطلبات المقدمة فوق مستوى التعادل.',
 '(Russian) Это было частью консенсуса 1945 года.',
 '(English) Consider the advanced economies.',
 '(English) Since their articles appeared, the price of gold has moved up still further.',
 '(Russian) Тогда они не только смогут накормить свои семьи, но и начать получать рыночную прибыль и откладывать деньги на будущее.',
 '(English) Gold prices even hit a record-high $1,300 recently.',
 '(Chinese) 另一种金融危机',
 '(Russian) Европейская мечта находится в кризисе.',
 '(English) What Failed in 2008?',
 '(Spanish) Pero el acuerdo alcanzado tiene tres grandes defectos.',
 '(English) Officials underestimated tail risks.',
 '(English) Consider a couple of notorious examples.',
 '(Spanish) Los mercados financieros pueden ser frágiles y ofrecen muy poca capacidad de compartir los riesgos relacionados con el ingreso de los trabajadores, que constituye la mayor parte de la renta de cualquier economía avanzada.',
 '(Chinese) 2008年败在何处?',
 '(Spanish) Consideremos las economías avanzadas.',
 '(Spanish) Los bienes producidos se caracterizaron por ser, como señalaron algunos economistas, mercancías “rivales” y “excluyentes”.',
 '(Arabic) إغلاق الفجوة الاستراتيجية في أوروبا',
 '(English) Stalin was content to settle for an empire in Eastern Europe.',
 '(English) Intelligence assets have been redirected.',
 '(Spanish) Hoy, envalentonados por la apreciación continua, algunos están sugiriendo que el oro podría llegar incluso a superar esa cifra.',
 '(Russian) Цены на золото чрезвычайно чувствительны к мировым движениям процентных ставок.',
 '(Russian) Однако у достигнутой договоренности есть три основных недостатка.']

추가 주제

다국어

마지막으로, 지원되는 언어(영어, 아랍어, 중국어, 네덜란드어, 프랑스어, 독일어, 이탈리아어, 일본어, 한국어, 폴란드어, 포르투갈어, 러시아어, 스페인어, 태국어 및 터키어로 쿼리를 시도해 볼 것을 권장합니다.

또한 여기서는 일부 언어로만 인덱싱했지만 지원되는 모든 언어로 콘텐츠를 인덱싱할 수도 있습니다.

모델 변형

메모리, 대기 시간 및/또는 품질과 같은 다양한 요소에 최적화된 다양한 Universal Encoder 모델이 제공됩니다. 자유롭게 시도해 보고 적절한 모델을 찾으세요.

NN(Nearest neighbor) 라이브러리

Annoy를 사용하여 NN을 효율적으로 검색했습니다. 트리 수(메모리 종속) 및 검색할 항목 수(대기 시간 종속)에 대해서는 상충 관계 섹션을 참조하세요. SimpleNeighbors에서는 트리 수만 제어할 수 있지만 Annoy를 직접 사용하도록 코드를 간단하게 리팩토링할 수 있습니다. 일반적인 사용자를 위해 이 코드를 최대한 간단하게 유지하려고 했습니다.

해당 애플리케이션에 맞게 Annoy의 크기를 조정할 수 없으면 FAISS도 확인해 보세요.

멋진 다국어 의미론 애플리케이션을 빌드해 보세요!

[1] J. Tiedemann, 2012, Parallel Data, Tools and Interfaces in OPUS. In Proceedings of the 8th International Conference on Language Resources and Evaluation (LREC 2012)