aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sentence_emb_matching.py153
-rw-r--r--sentence_emb_retrieval.py151
-rw-r--r--sentence_embedding.py179
3 files changed, 179 insertions, 304 deletions
diff --git a/sentence_emb_matching.py b/sentence_emb_matching.py
deleted file mode 100644
index 38812d7..0000000
--- a/sentence_emb_matching.py
+++ /dev/null
@@ -1,153 +0,0 @@
1import argparse
2
3parser = argparse.ArgumentParser(description='run matching using sentence embeddings and cosine similarity')
4parser.add_argument('source_lang', help='source language short name')
5parser.add_argument('target_lang', help='target language short name')
6parser.add_argument('source_vector', help='path of the source vector')
7parser.add_argument('target_vector', help='path of the target vector')
8parser.add_argument('source_defs', help='path of the source definitions')
9parser.add_argument('target_defs', help='path of the target definitions')
10parser.add_argument('-n', '--instances', help='number of instances in each language to retrieve', default=2000, type=int)
11
12args = parser.parse_args()
13
14source_lang = args.source_lang
15target_lang = args.target_lang
16
17def load_embeddings(path, dimension = 300):
18 """
19 Loads the embeddings from a word2vec formatted file.
20 The first line may or may not include the word count and dimension
21 """
22 vectors = {}
23 with open(path, mode='r', encoding='utf8') as fp:
24 first_line = fp.readline().rstrip('\n')
25 if first_line.count(' ') == 1: # includes the "word_count dimension" information
26 (word_count, dimension) = map(int, first_line.split())
27 else: # assume the file only contains vectors
28 fp.seek(0)
29 for line in fp:
30 elems = line.split()
31 vectors[" ".join(elems[:-dimension])] = " ".join(elems[-dimension:])
32 return vectors
33
34source_vectors_filename = args.source_vector
35target_vectors_filename = args.target_vector
36vectors_source = load_embeddings(source_vectors_filename)
37vectors_target = load_embeddings(target_vectors_filename)
38
39source_defs_filename = args.source_defs
40target_defs_filename = args.target_defs
41defs_source = [line.rstrip('\n') for line in open(source_defs_filename, encoding='utf8')]
42defs_target = [line.rstrip('\n') for line in open(target_defs_filename, encoding='utf8')]
43
44import numpy as np
45from mosestokenizer import *
46
47def clean_corpus_using_embeddings_vocabulary(
48 embeddings_dictionary,
49 corpus,
50 vectors,
51 language,
52 ):
53 '''
54 Cleans corpus using the dictionary of embeddings.
55 Any word without an associated embedding in the dictionary is ignored.
56 '''
57 clean_corpus, clean_vectors, keys = [], {}, []
58 words_we_want = set(embeddings_dictionary)
59 tokenize = MosesTokenizer(language)
60 for key, doc in enumerate(corpus):
61 clean_doc = []
62 words = tokenize(doc)
63 for word in words:
64 if word in words_we_want:
65 clean_doc.append(word)
66 clean_vectors[word] = np.array(vectors[word].split()).astype(np.float)
67 if len(clean_doc) > 3 and len(clean_doc) < 25:
68 keys.append(key)
69 clean_corpus.append(' '.join(clean_doc))
70 tokenize.close()
71 return np.array(clean_corpus), clean_vectors, keys
72
73clean_src_corpus, clean_src_vectors, src_keys = clean_corpus_using_embeddings_vocabulary(
74 set(vectors_source.keys()),
75 defs_source,
76 vectors_source,
77 source_lang,
78 )
79
80clean_target_corpus, clean_target_vectors, target_keys = clean_corpus_using_embeddings_vocabulary(
81 set(vectors_target.keys()),
82 defs_target,
83 vectors_target,
84 target_lang,
85 )
86
87import random
88take = args.instances
89
90common_keys = set(src_keys).intersection(set(target_keys))
91take = min(len(common_keys), take) # you can't sample more than length
92experiment_keys = random.sample(common_keys, take)
93
94instances = len(experiment_keys)
95
96clean_src_corpus = list(clean_src_corpus[experiment_keys])
97clean_target_corpus = list(clean_target_corpus[experiment_keys])
98
99print(f'{source_lang} - {target_lang} : document sizes: {len(clean_src_corpus)}, {len(clean_target_corpus)}')
100
101del vectors_source, vectors_target, defs_source, defs_target
102
103from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
104
105vocab_counter = CountVectorizer().fit(clean_src_corpus + clean_target_corpus)
106common = [w for w in vocab_counter.get_feature_names() if w in clean_src_vectors or w in clean_target_vectors]
107W_common = []
108
109for w in common:
110 if w in clean_src_vectors:
111 W_common.append(np.array(clean_src_vectors[w]))
112 else:
113 W_common.append(np.array(clean_target_vectors[w]))
114
115print(f'{source_lang} - {target_lang}: the vocabulary size is {len(W_common)}')
116
117from sklearn.preprocessing import normalize
118W_common = np.array(W_common)
119W_common = normalize(W_common) # default is l2
120
121vect_tfidf = TfidfVectorizer(vocabulary=common, dtype=np.double, norm='l2')
122vect_tfidf.fit(clean_src_corpus + clean_target_corpus)
123X_idf_source = vect_tfidf.transform(clean_src_corpus)
124X_idf_target = vect_tfidf.transform(clean_target_corpus)
125
126print(f'Matrices are {X_idf_source.shape} and {W_common.shape}')
127print(f'The dimensions are {X_idf_source.ndim} and {W_common.ndim}')
128
129X_idf_source_array = X_idf_source.toarray()
130X_idf_target_array = X_idf_target.toarray()
131S_emb_source = np.matmul(X_idf_source_array, W_common)
132S_emb_target = np.matmul(X_idf_target_array, W_common)
133
134S_emb_target_transpose = np.transpose(S_emb_target)
135
136cost_matrix = np.matmul(S_emb_source, S_emb_target_transpose)
137
138from lapjv import lapjv
139cost_matrix = cost_matrix * -1000
140row_ind, col_ind, a = lapjv(cost_matrix, verbose=False)
141
142result = zip(row_ind, col_ind)
143hit_one = len([x for x,y in result if x == y])
144print(f'{hit_one} definitions have been mapped correctly, shape of cost matrix: {str(cost_matrix.shape)}')
145
146import csv
147percentage = hit_one / instances * 100
148fields = [f'{source_lang}', f'{target_lang}', f'{instances}', f'{hit_one}', f'{percentage}']
149
150with open('semb_matcing.csv', 'a') as f:
151 writer = csv.writer(f)
152 writer.writerow(fields)
153
diff --git a/sentence_emb_retrieval.py b/sentence_emb_retrieval.py
deleted file mode 100644
index 63ebcdc..0000000
--- a/sentence_emb_retrieval.py
+++ /dev/null
@@ -1,151 +0,0 @@
1import argparse
2
3parser = argparse.ArgumentParser(description='Run Retrieval using Sentence Embedding + Cosine')
4parser.add_argument('source_lang', help='source language short name')
5parser.add_argument('target_lang', help='target language short name')
6parser.add_argument('source_vector', help='path of the source vector')
7parser.add_argument('target_vector', help='path of the target vector')
8parser.add_argument('source_defs', help='path of the source definitions')
9parser.add_argument('target_defs', help='path of the target definitions')
10parser.add_argument('-n', '--instances', help='number of instances in each language to retrieve', default=1000, type=int)
11args = parser.parse_args()
12
13source_lang = args.source_lang
14target_lang = args.target_lang
15
16def load_embeddings(path, dimension = 300):
17 """
18 Loads the embeddings from a word2vec formatted file.
19 The first line may or may not include the word count and dimension
20 """
21 vectors = {}
22 with open(path, mode='r', encoding='utf8') as fp:
23 first_line = fp.readline().rstrip('\n')
24 if first_line.count(' ') == 1: # includes the "word_count dimension" information
25 (word_count, dimension) = map(int, first_line.split())
26 else: # assume the file only contains vectors
27 fp.seek(0)
28 for line in fp:
29 elems = line.split()
30 vectors[" ".join(elems[:-dimension])] = " ".join(elems[-dimension:])
31 return vectors
32
33lang_source = args.source_lang
34lang_target = args.target_lang
35
36vectors_filename_source = args.source_vector
37vectors_filename_target = args.target_vector
38
39vectors_source = load_embeddings(vectors_filename_source)
40vectors_target = load_embeddings(vectors_filename_target)
41
42defs_filename_source = args.source_defs
43defs_filename_target = args.target_defs
44defs_source = [line.rstrip('\n') for line in open(defs_filename_source, encoding='utf8')]
45defs_target = [line.rstrip('\n') for line in open(defs_filename_target, encoding='utf8')]
46
47print('Read {} {} documents and {} {} documents'.format(len(defs_source), lang_source, len(defs_target), lang_target))
48
49import numpy as np
50from mosestokenizer import *
51
52def clean_corpus_using_embeddings_vocabulary(
53 embeddings_dictionary,
54 corpus,
55 vectors,
56 language,
57 ):
58 '''
59 Cleans corpus using the dictionary of embeddings.
60 Any word without an associated embedding in the dictionary is ignored.
61 Adds '__target-language' and '__source-language' at the end of the words according to their language.
62 '''
63 clean_corpus, clean_vectors, keys = [], {}, []
64 words_we_want = set(embeddings_dictionary)
65 tokenize = MosesTokenizer(language)
66 for key, doc in enumerate(corpus):
67 clean_doc = []
68 words = tokenize(doc)
69 for word in words:
70 if word in words_we_want:
71 clean_doc.append(word + '__%s' % language)
72 clean_vectors[word + '__%s' % language] = np.array(vectors[word].split()).astype(np.float)
73 if len(clean_doc) > 3 and len(clean_doc) < 25:
74 keys.append(key)
75 clean_corpus.append(' '.join(clean_doc))
76 tokenize.close()
77 return np.array(clean_corpus), clean_vectors, keys
78
79clean_corpus_source, clean_vectors_source, keys_source = clean_corpus_using_embeddings_vocabulary(
80 set(vectors_source.keys()),
81 defs_source,
82 vectors_source,
83 lang_source,
84 )
85
86clean_corpus_target, clean_vectors_target, keys_target = clean_corpus_using_embeddings_vocabulary(
87 set(vectors_target.keys()),
88 defs_target,
89 vectors_target,
90 lang_target,
91 )
92
93import random
94take = args.instances
95
96common_keys = set(keys_source).intersection(set(keys_target)) # definitions that fit the above requirements
97take = min(len(common_keys), take) # you can't sample more than length
98experiment_keys = random.sample(common_keys, take)
99
100instances = len(experiment_keys)
101
102clean_corpus_source = list(clean_corpus_source[experiment_keys])
103clean_corpus_target = list(clean_corpus_target[experiment_keys])
104print(f'{source_lang} - {target_lang} : document sizes: {len(clean_corpus_source)}, {len(clean_corpus_target)}')
105
106del vectors_source, vectors_target, defs_source, defs_target
107
108from sklearn.feature_extraction.text import CountVectorizer
109from sklearn.feature_extraction.text import TfidfVectorizer
110
111vocab_counter = CountVectorizer().fit(clean_corpus_source + clean_corpus_target)
112common = [w for w in vocab_counter.get_feature_names() if w in clean_vectors_source or w in clean_vectors_target]
113
114W_common = []
115for w in common:
116 if w in clean_vectors_source:
117 W_common.append(np.array(clean_vectors_source[w]))
118 else:
119 W_common.append(np.array(clean_vectors_target[w]))
120
121print('The vocabulary size is %d' % (len(W_common)))
122
123from sklearn.preprocessing import normalize
124W_common = np.array(W_common)
125W_common = normalize(W_common) # default is l2
126
127vect_tfidf = TfidfVectorizer(vocabulary=common, dtype=np.double, norm='l2')
128vect_tfidf.fit(clean_corpus_source + clean_corpus_target)
129X_idf_source = vect_tfidf.transform(clean_corpus_source)
130X_idf_target = vect_tfidf.transform(clean_corpus_target)
131
132print(f'Matrices are {X_idf_source.shape} and {W_common.shape}')
133print(f'The dimensions are {X_idf_source.ndim} and {W_common.ndim}')
134
135X_idf_source_array = X_idf_source.toarray()
136X_idf_target_array = X_idf_target.toarray()
137S_emb_source = np.matmul(X_idf_source_array, W_common)
138S_emb_target = np.matmul(X_idf_target_array, W_common)
139
140S_emb_target_transpose = np.transpose(S_emb_target)
141
142cost_matrix = np.matmul(S_emb_source, S_emb_target_transpose)
143
144hit_at_one = len([x for x,y in enumerate(cost_matrix.argmax(axis=1)) if x == y])
145
146import csv
147percentage = hit_at_one / instances * 100
148fields = [f'{source_lang}', f'{target_lang}', f'{instances}', f'{hit_at_one}', f'{percentage}']
149with open('/home/syigit/multilang_results/sentence_emb_retrieval_axis_1.csv', 'a') as f:
150 writer = csv.writer(f)
151 writer.writerow(fields)
diff --git a/sentence_embedding.py b/sentence_embedding.py
new file mode 100644
index 0000000..0cd5361
--- /dev/null
+++ b/sentence_embedding.py
@@ -0,0 +1,179 @@
1import argparse
2import csv
3import random
4
5import numpy as np
6from lapjv import lapjv
7from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
8from sklearn.preprocessing import normalize
9
10from Wasserstein_Distance import load_embeddings, process_corpus
11
12
13def main(args):
14
15 run_method = list()
16
17 if input_paradigm == "all":
18 run_paradigm.extend("matching", "retrieval")
19 else:
20 run_paradigm.append(input_paradigm)
21
22 source_lang = args.source_lang
23 target_lang = args.target_lang
24 batch = args.batch
25
26 source_vectors_filename = args.source_vector
27 target_vectors_filename = args.target_vector
28
29 vectors_source = load_embeddings(source_vectors_filename)
30 vectors_target = load_embeddings(target_vectors_filename)
31
32 source_defs_filename = args.source_defs
33 target_defs_filename = args.target_defs
34 defs_source = [
35 line.rstrip("\n") for line in open(source_defs_filename, encoding="utf8")
36 ]
37 defs_target = [
38 line.rstrip("\n") for line in open(target_defs_filename, encoding="utf8")
39 ]
40
41 clean_source_corpus, clean_source_vectors, source_keys = process_corpus(
42 set(vectors_source.keys()), defs_source, vectors_source, source_lang
43 )
44
45 clean_target_corpus, clean_target_vectors, target_keys = process_corpus(
46 set(vectors_target.keys()), defs_target, vectors_target, target_lang
47 )
48
49 take = args.instances
50 common_keys = set(source_keys).intersection(set(target_keys))
51 take = min(len(common_keys), take) # you can't sample more than length
52 experiment_keys = random.sample(common_keys, take)
53
54 instances = len(experiment_keys)
55
56 clean_source_corpus = list(clean_source_corpus[experiment_keys])
57 clean_target_corpus = list(clean_target_corpus[experiment_keys])
58
59 if not batch:
60 print(
61 f"{source_lang} - {target_lang} "
62 + f" document sizes: {len(clean_source_corpus)}, {len(clean_target_corpus)}"
63 )
64
65 del vectors_source, vectors_target, defs_source, defs_target
66
67 vocab_counter = CountVectorizer().fit(clean_source_corpus + clean_target_corpus)
68 common = [
69 w
70 for w in vocab_counter.get_feature_names()
71 if w in clean_source_vectors or w in clean_target_vectors
72 ]
73 W_common = []
74
75 for w in common:
76 if w in clean_source_vectors:
77 W_common.append(np.array(clean_source_vectors[w]))
78 else:
79 W_common.append(np.array(clean_target_vectors[w]))
80
81 W_common = np.array(W_common)
82 W_common = normalize(W_common) # default is l2
83
84 vect_tfidf = TfidfVectorizer(vocabulary=common, dtype=np.double, norm="l2")
85 vect_tfidf.fit(clean_source_corpus + clean_target_corpus)
86 X_idf_source = vect_tfidf.transform(clean_source_corpus)
87 X_idf_target = vect_tfidf.transform(clean_target_corpus)
88
89 X_idf_source_array = X_idf_source.toarray()
90 X_idf_target_array = X_idf_target.toarray()
91 S_emb_source = np.matmul(X_idf_source_array, W_common)
92 S_emb_target = np.matmul(X_idf_target_array, W_common)
93
94 S_emb_target_transpose = np.transpose(S_emb_target)
95
96 cost_matrix = np.matmul(S_emb_source, S_emb_target_transpose)
97
98 for paradigm in run_paradigm:
99 if paradigm == 'matching':
100
101 cost_matrix = cost_matrix * -1000
102 row_ind, col_ind, a = lapjv(cost_matrix, verbose=False)
103
104 result = zip(row_ind, col_ind)
105 hit_at_one = len([x for x, y in result if x == y])
106 percentage = hit_at_one / instances * 100
107
108 if not batch:
109 print(f"{hit_at_one} definitions have been matched correctly")
110
111 if batch:
112 fields = [
113 f"{source_lang}",
114 f"{target_lang}",
115 f"{instances}",
116 f"{hit_at_one}",
117 f"{percentage}",
118 ]
119
120 with open("semb_matcing_results.csv", "a") as f:
121 writer = csv.writer(f)
122 writer.writerow(fields)
123
124 if paradigm == 'retrieval':
125
126 hit_at_one = len([x for x, y in enumerate(cost_matrix.argmax(axis=1)) if x == y])
127 percentage = hit_at_one / instances * 100
128
129 if not batch:
130 print(f"{hit_at_one} definitions have retrieved correctly")
131
132 if batch:
133 fields = [
134 f"{source_lang}",
135 f"{target_lang}",
136 f"{instances}",
137 f"{hit_at_one}",
138 f"{percentage}",
139 ]
140
141 with open("semb_retrieval_results.csv", "a") as f:
142 writer = csv.writer(f)
143 writer.writerow(fields)
144
145
146if __name__ == "__main__":
147
148 parser = argparse.ArgumentParser(
149 description="align dictionaries using sentence embedding representation"
150 )
151 parser.add_argument("source_lang", help="source language short name")
152 parser.add_argument("target_lang", help="target language short name")
153 parser.add_argument("source_vector", help="path of the source vector")
154 parser.add_argument("target_vector", help="path of the target vector")
155 parser.add_argument("source_defs", help="path of the source definitions")
156 parser.add_argument("target_defs", help="path of the target definitions")
157 parser.add_argument(
158 "-n",
159 "--instances",
160 help="number of instances in each language to retrieve",
161 default=1000,
162 type=int,
163 )
164 parser.add_argument(
165 "-b",
166 "--batch",
167 action="store_true",
168 help="running in batch (store results in csv) or"
169 + "running a single instance (output the results)",
170 )
171 parser.add_argument(
172 "paradigm",
173 choices=["all", "retrieval", "matching"],
174 default="all",
175 help="which paradigms to align with",
176 )
177
178 args = parser.parse_args()
179 main(args)