Una capa de transformador de nivel de palabra basada en Pytorch y? Transformadores.
Instale la biblioteca desde PYPI:
pip install transformers-embeddero de Conda:
conda install -c riccorl transformers-embedderOfrece una capa de pytorch y un tokenizador que admite casi todos los modelos de petróleo de Huggingface? Biblioteca de transformadores. Aquí hay un ejemplo rápido:
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
Una de las molestias del uso de modelos basados en transformadores es que no es trivial calcular los incrustaciones de palabras de los incrustaciones sub-setken que salen. Con esta API es tan fácil como usar los transformadores para obtener incrustaciones de nivel de palabra de teóricamente cada modelo de transformador que admite.
La clase TransformersEmbedder ofrece 3 formas de obtener los incrustaciones:
subword_pooling_strategy="sparse" : calcula la media de los incrustaciones de los sub-tokens de cada palabra (es decir, las incrustaciones de los sub-tokens se agrupan) utilizando una multiplicación de matriz dispersa. Esta estrategia es la predeterminada.subword_pooling_strategy="scatter" : calcula la media de las incrustaciones de los sub-tokens de cada palabra utilizando una operación de dispersión-recipiente. No es determinista, pero funciona con la exportación ONNX.subword_pooling_strategy="none" : Devuelve la salida sin procesar del modelo de transformador sin agrupación sub-bata.Aquí una pequeña mesa de características:
| Agrupación | Determinista | ONNX | |
|---|---|---|---|
| Escaso | ✅ | ✅ | |
| Dispersión | ✅ | ✅ | |
| Ninguno | ✅ | ✅ |
También hay múltiples tipos de salidas que puede obtener utilizando el parámetro layer_pooling_strategy :
layer_pooling_strategy="last" : Devuelve el último estado oculto del modelo Transformerlayer_pooling_strategy="concat" : Devuelve la concatenación de la output_layers seleccionada de lalayer_pooling_strategy="sum" : Devuelve la suma de las output_layers seleccionadas del modelo Transformerlayer_pooling_strategy="mean" : Devuelve el promedio de los output_layers seleccionados del modelo Transformerlayer_pooling_strategy="scalar_mix" : Devuelve la salida de una capa de mezcla escalar parametrizada de la output_layers seleccionada del modelo Transformer Si también desea todas las salidas del modelo Huggingface, puede establecer return_all=True para obtenerlas.
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 ,
) La clase Tokenizer proporciona el método tokenize para preprocesar la entrada para la capa TransformersEmbedder . Puede aprobar oraciones crudas, oraciones y oraciones pre-tocadas en lotes. Los preprocesará devolviendo un diccionario con las entradas para el modelo. Al pasar return_tensors=True devolverá las entradas como torch.Tensor .
De manera predeterminada, si pasa texto (o por lotes) como cadenas, utiliza el tokenizer Huggingface para tokenizarlos.
text = "This is a sample sentence"
tokenizer ( text )
text = [ "This is a sample sentence" , "This is another sample sentence" ]
tokenizer ( text ) Puede pasar una oración pre-realizada (o lote de oraciones) configurando is_split_into_words=True
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 )Primero, inicializa el tokenizador
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 y return_tensors=True , el tokenizer devuelve el texto listo para el modelo 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 posible agregar campos personalizados a la entrada del modelo y decirle al tokenizer cómo rellenarlos usando add_padding_ops . Comience inicializando el tokenizador con el nombre del modelo:
import transformers_embedder as tre
tokenizer = tre . Tokenizer ( "bert-base-cased" )Luego agregue los campos personalizados:
custom_fields = {
"custom_filed_1" : [
[ 0 , 0 , 0 , 0 , 1 , 0 , 0 ],
[ 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 ]
]
} Ahora podemos agregar la lógica de relleno para nuestro campo personalizado custom_filed_1 . El método add_padding_ops toma entrada
key : Nombre del campo en la entrada de tokenizadorvalue : valor para usar para rellenolength : longitud a la almohadilla. Puede ser un valor int , o dos de cadena, subword en la que el elemento está acolchado para que coincida con la longitud de las subvenciones, y word donde el elemento está acolchado en relación con la longitud de la lote después de la fusión de las subvenciones. tokenizer . add_padding_ops ( "custom_filed_1" , 0 , "word" )Finalmente, podemos tokenizar la entrada con el campo personalizado:
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 )Las entradas están listas para el modelo, incluido el personalizado archivado.
>>> 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],
}
Algún código en la clase TransformersEmbedder se toma de la biblioteca de dispersión de Pytorch. ¿Los modelos previos al estado previo y el núcleo del tokenizador son? Transformadores.