import warningswarnings.filterwarnings("ignore", message="CUDA is not available")# Imports & setupimport spacyimport numpy as npfrom tabulate import tabulatefrom pprint import pprintnlp = spacy.load('la_core_web_trf')# Workaround: _similarity in trf_vectors calls obj.vector, which is 0 for trf docs.# The correct approach is to mean-pool trf_token_vecs directly.from spacy.language import Languagedef _trf_cosine(v1, v2): n1, n2 = np.linalg.norm(v1), np.linalg.norm(v2)returnfloat(np.dot(v1, v2) / (n1 * n2)) if n1 and n2 else0.0def _trf_doc_similarity(obj, other): v1 = obj._.trf_token_vecs.mean(axis=0) v2 = other._.trf_token_vecs.mean(axis=0)return _trf_cosine(v1, v2)def _trf_token_similarity(obj, other):return _trf_cosine(obj.vector, other.vector)try:@Language.component('trf_similarity_fix')def _trf_similarity_fix(doc): doc.user_hooks['similarity'] = _trf_doc_similarity doc.user_span_hooks['similarity'] = _trf_doc_similarity doc.user_token_hooks['similarity'] = _trf_token_similarityreturn docexceptValueError:pass# already registeredif'trf_similarity_fix'notin nlp.pipe_names: nlp.add_pipe('trf_similarity_fix', after='trf_vectors')text ="Haec narrantur a poetis de Perseo. Perseus filius erat Iovis, maximi deorum; avus eius Acrisius appellabatur. Acrisius volebat Perseum nepotem suum necare; nam propter oraculum puerum timebat."doc = nlp(text)print(doc)
Haec narrantur a poetis de Perseo. Perseus filius erat Iouis, maximi deorum; auus eius Acrisius appellabatur. Acrisius uolebat Perseum nepotem suum necare; nam propter oraculum puerum timebat.
As noted in the previous notebook, the trf vectors work slightly differently than vectors in the other pipelines. This notebook covers the specifics of working with the trf contextual vectors.
Here is the vector for the first token ‘Haec’ in the text given above…
tokens = [token for token in doc]for token in tokens:print(token.text)print(token.vector[:10], "etc.")break
Haec
[ 1.0053577 -0.6338967 0.28178048 0.3656186 1.6352 -0.96579456
1.3706194 0.7118512 1.210259 -0.2383545 ] etc.
The LatinCy trf model uses MultilingualBERT as the basis of its ‘transformer’ component. The trf model has a custom Doc attribute that can give access to the per-token contextual vectors which is in turn mapped back to the vector attribute of the Token object via a user hook. Accordingly, you can just access the vector as you do with the other pipelines, but the output will be contextually informed.
# Here is an example using Acrisius, a word which appears twice in the given text...print("Token.text values for two tokens...")print(doc[17])print(doc[20])# Note that we have a Doc custom attribute `trf_token_vecs` which is a list of the vectors for each token in the document. We can access the vector for a specific token by using the index of the token in the document.print("\nSlices correspondiong to Acrisius from the trf_token_vecs Doc custom attribute...")print(doc._.trf_token_vecs[17][:5])print(doc._.trf_token_vecs[20][:5])# But we can access these contextual vectors directly via the `vector` Token attribute.print("\nToken attribute for the Acrisius slices...")print(doc[17].vector[:5])print(doc[20].vector[:5])print("\nVectors are the same?")print(np.mean(doc[17].vector) == np.mean(doc._.trf_token_vecs[17]))
Token.text values for two tokens...
Acrisius
Acrisius
Slices correspondiong to Acrisius from the trf_token_vecs Doc custom attribute...
[ 0.15758377 -0.7168379 2.458179 -1.4819897 2.422638 ]
[ 0.14679147 -0.7611529 1.8628647 -0.72165 2.1575801 ]
Token attribute for the Acrisius slices...
[ 0.15758377 -0.7168379 2.458179 -1.4819897 2.422638 ]
[ 0.14679147 -0.7611529 1.8628647 -0.72165 2.1575801 ]
Vectors are the same?
True
Reminder that the shape of the (MultilingualBERT-derived) vectors is 768…
print(doc[0].vector.shape)
(768,)
For the trf pipelines, the similarity method is available via a user hook registered by the trf_vectors component. This means you can compare tokens, spans, or docs using .similarity() just as you would with the other pipelines — the comparison uses cosine similarity over the contextual vectors.
text_1 ="Omnia vincit amor."text_2 ="Omnia vincit amicitia."doc_1 = nlp(text_1)doc_2 = nlp(text_2)print("Similarity between the two sentences...")print(doc_1.similarity(doc_2))
Similarity between the two sentences...
0.9511939883232117
References
SLP Chapter 5, “Embeddings” link SLP Ch. 10 “Masked Language Models” link