Eine Wortstufe -Transformatorschicht basierend auf Pytorch und? Transformatoren.
Installieren Sie die Bibliothek von PYPI:
pip install transformers-embedderoder von Conda:
conda install -c riccorl transformers-embedderEs bietet eine Pytorch -Schicht und einen Tokenizer, der fast jedes vorbereitete Modell aus der Suggingface -Transformers -Bibliothek unterstützt. Hier ist ein kurzes Beispiel:
import transformers_embedder as tre
tokenizer = tre . Tokenizer ( "bert-base-cased" )
model = tre . TransformersEmbedder (
"bert-base-cased" , subword_pooling_strategy = "sparse" , layer_pooling_strategy = "mean"
)
example = "This is a sample sentence"
inputs = tokenizer ( example , return_tensors = True ) {
'input_ids': tensor([[ 101, 1188, 1110, 170, 6876, 5650, 102]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0]])
'scatter_offsets': tensor([[0, 1, 2, 3, 4, 5, 6]]),
'sparse_offsets': {
'sparse_indices': tensor(
[
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6]
]
),
'sparse_values': tensor([1., 1., 1., 1., 1., 1., 1.]),
'sparse_size': torch.Size([1, 7, 7])
},
'sentence_length': 7 # with special tokens included
}
outputs = model ( ** inputs ) # outputs.word_embeddings.shape[1:-1] # remove [CLS] and [SEP]
torch.Size([1, 5, 768])
# len(example)
5
Eines der Ärger der Verwendung von Transformator-basierten Modellen ist, dass es nicht trivial ist, Wort-Einbettungen aus den von ihnen ausgegebenen Unterketten zu berechnen. Mit dieser API ist es so einfach wie die Verwendung von Transformatoren, Einbettungen auf Wortebene von theoretisch jedem von ihr unterstützten Transformatormodell zu erhalten.
Die TransformersEmbedder -Klasse bietet 3 Möglichkeiten, um die Einbettungen zu erhalten:
subword_pooling_strategy="sparse" : Berechnet den Mittelwert der Einbettungen der Untertoken jedes Wortes (dh die Einbettungen der Untertoken werden zusammen mit einer spärlichen Matrixmultiplikation zusammengefasst. Diese Strategie ist die Standardeinstellung.subword_pooling_strategy="scatter" Es ist nicht deterministisch, aber es funktioniert mit Onnx -Export.subword_pooling_strategy="none" : Gibt die RAW-Ausgabe des Transformatormodells ohne Pooling zurück.Hier eine kleine Feature -Tabelle:
| Pooling | Deterministisch | Onnx | |
|---|---|---|---|
| Spärlich | ✅ | ✅ | |
| Streuen | ✅ | ✅ | |
| Keiner | ✅ | ✅ |
Es gibt auch mehrere Ausgabetypen layer_pooling_strategy die Sie verwenden können.
layer_pooling_strategy="last" : Gibt den letzten versteckten Zustand des Transformatormodells zurücklayer_pooling_strategy="concat" : Gibt die Verkettung der ausgewählten output_layers zurücklayer_pooling_strategy="sum" : Gibt die Summe der ausgewählten output_layers des Transformatormodells zurücklayer_pooling_strategy="mean" : Gibt den Durchschnitt der ausgewählten output_layers des Transformatormodells zurücklayer_pooling_strategy="scalar_mix" : Gibt die Ausgabe einer parametrisierten Skalarmischungsschicht der ausgewählten output_layers des Transformatormodells zurück Wenn Sie auch alle Ausgänge aus dem Huggingface -Modell möchten, können Sie return_all=True festlegen, um sie zu erhalten.
class TransformersEmbedder ( torch . nn . Module ):
def __init__ (
self ,
model : Union [ str , tr . PreTrainedModel ],
subword_pooling_strategy : str = "sparse" ,
layer_pooling_strategy : str = "last" ,
output_layers : Tuple [ int ] = ( - 4 , - 3 , - 2 , - 1 ),
fine_tune : bool = True ,
return_all : bool = True ,
) Die Tokenizer -Klasse bietet die tokenize -Methode zur Vorverarbeitung der Eingabe für die TransformersEmbedder -Schicht. Sie können rohe Sätze, vorgefängerte Sätze und Sätze in Batch übergeben. Es wird sie vorbereiten und ein Wörterbuch mit den Eingaben für das Modell zurückgeben. Durch das Bestehen return_tensors=True wird die Eingänge als torch.Tensor zurückgegeben.
Wenn Sie Text (oder Stapel) als Zeichenfolgen bestehen, verwendet es standardmäßig mit dem Tokenizer von Suggingface, um sie zu tokenisieren.
text = "This is a sample sentence"
tokenizer ( text )
text = [ "This is a sample sentence" , "This is another sample sentence" ]
tokenizer ( text ) Sie können einen vorgefängerten Satz (oder eine Stapel von Sätzen) übergeben, indem Sie is_split_into_words=True festlegen
text = [ "This" , "is" , "a" , "sample" , "sentence" ]
tokenizer ( text , is_split_into_words = True )
text = [
[ "This" , "is" , "a" , "sample" , "sentence" , "1" ],
[ "This" , "is" , "sample" , "sentence" , "2" ],
]
tokenizer ( text , is_split_into_words = True )Initialisieren Sie zunächst den Tokenizer
import transformers_embedder as tre
tokenizer = tre . Tokenizer ( "bert-base-cased" ) text = "This is a sample sentence"
tokenizer ( text ) {
{
'input_ids': [[101, 1188, 1110, 170, 6876, 5650, 102]],
'token_type_ids': [[0, 0, 0, 0, 0, 0, 0]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1]],
'scatter_offsets': [[0, 1, 2, 3, 4, 5, 6]],
'sparse_offsets': {
'sparse_indices': tensor(
[
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 2, 3, 4, 5, 6],
[0, 1, 2, 3, 4, 5, 6]
]
),
'sparse_values': tensor([1., 1., 1., 1., 1., 1., 1.]),
'sparse_size': torch.Size([1, 7, 7])
},
'sentence_lengths': [7],
}
text = "This is a sample sentence A"
text_pair = "This is a sample sentence B"
tokenizer ( text , text_pair ) {
'input_ids': [[101, 1188, 1110, 170, 6876, 5650, 138, 102, 1188, 1110, 170, 6876, 5650, 139, 102]],
'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]],
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]],
'scatter_offsets': [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]],
'sparse_offsets': {
'sparse_indices': tensor(
[
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
]
),
'sparse_values': tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]),
'sparse_size': torch.Size([1, 15, 15])
},
'sentence_lengths': [15],
}
padding=True und return_tensors=True gibt der Tokenizer den Text zurück, der für das Modell bereit ist batch = [
[ "This" , "is" , "a" , "sample" , "sentence" , "1" ],
[ "This" , "is" , "sample" , "sentence" , "2" ],
[ "This" , "is" , "a" , "sample" , "sentence" , "3" ],
# ...
[ "This" , "is" , "a" , "sample" , "sentence" , "n" , "for" , "batch" ],
]
tokenizer ( batch , padding = True , return_tensors = True )
batch_pair = [
[ "This" , "is" , "a" , "sample" , "sentence" , "pair" , "1" ],
[ "This" , "is" , "sample" , "sentence" , "pair" , "2" ],
[ "This" , "is" , "a" , "sample" , "sentence" , "pair" , "3" ],
# ...
[ "This" , "is" , "a" , "sample" , "sentence" , "pair" , "n" , "for" , "batch" ],
]
tokenizer ( batch , batch_pair , padding = True , return_tensors = True ) Es ist möglich, der Modelleingabe benutzerdefinierte Felder hinzuzufügen und dem tokenizer mitzuteilen, wie er mit add_padding_ops gepadelt wird. Beginnen Sie zunächst initialisieren des Tokenizers mit dem Modellnamen:
import transformers_embedder as tre
tokenizer = tre . Tokenizer ( "bert-base-cased" )Fügen Sie dann die benutzerdefinierten Felder hinzu:
custom_fields = {
"custom_filed_1" : [
[ 0 , 0 , 0 , 0 , 1 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 ]
]
} Jetzt können wir die Polsterlogik für unser benutzerdefiniertes Feld custom_filed_1 hinzufügen. add_padding_ops Methode nimmt die Eingabe ein
key : Name des Feldes im Tokenizer -Eingangvalue : Wert für die Polsterung zu verwendenlength : Länge zu Pad. Es kann ein int oder zwei Zeichenfolgenwert sein, subword , in dem das Element so gepolstert wird, dass sie mit der Länge der Unterwörter übereinstimmen, und word , bei dem das Element relativ zur Länge der Stapel nach dem Zusammenführen der Unterwörter gepolstert ist. tokenizer . add_padding_ops ( "custom_filed_1" , 0 , "word" )Schließlich können wir die Eingabe mit dem benutzerdefinierten Feld tokenisieren:
text = [
"This is a sample sentence" ,
"This is another example sentence just make it longer, with a comma too!"
]
tokenizer ( text , padding = True , return_tensors = True , additional_inputs = custom_fields )Die Eingänge sind für das Modell bereit, einschließlich der benutzerdefinierten eingereichten.
>>> inputs
{
'input_ids': tensor(
[
[ 101, 1188, 1110, 170, 6876, 5650, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 101, 1188, 1110, 1330, 1859, 5650, 1198, 1294, 1122, 2039, 117, 1114, 170, 3254, 1918, 1315, 106, 102]
]
),
'token_type_ids': tensor(
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
),
'attention_mask': tensor(
[
[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
),
'scatter_offsets': tensor(
[
[ 0, 1, 2, 3, 4, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16]
]
),
'sparse_offsets': {
'sparse_indices': tensor(
[
[ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16],
[ 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
]
),
'sparse_values': tensor(
[1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000,
1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000,
1.0000, 1.0000, 0.5000, 0.5000, 1.0000, 1.0000, 1.0000]
),
'sparse_size': torch.Size([2, 17, 18])
}
'sentence_lengths': [7, 17],
}
Einige Code in der TransformersEmbedder -Klasse stammen aus der Pytorch -Streubibliothek. Die vorbereiteten Modelle und der Kern des Tokenizers stammen aus? Transformatoren.