|
<!--Copyright 2020 The HuggingFace Team. All rights reserved. |
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
|
the License. You may obtain a copy of the License at |
|
|
|
http: |
|
|
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
|
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
|
specific language governing permissions and limitations under the License. |
|
--> |
|
|
|
# Exportar modelos 🤗 Transformers |
|
|
|
Si necesitas implementar modelos 🤗 Transformers en entornos de producción, te |
|
recomendamos exportarlos a un formato serializado que se pueda cargar y ejecutar |
|
en tiempos de ejecución y hardware especializados. En esta guía, te mostraremos cómo |
|
exportar modelos 🤗 Transformers en dos formatos ampliamente utilizados: ONNX y TorchScript. |
|
|
|
Una vez exportado, un modelo puede optimizarse para la inferencia a través de técnicas |
|
como la cuantización y _pruning_. Si estás interesado en optimizar tus modelos para |
|
que funcionen con la máxima eficiencia, consulta la |
|
[biblioteca de 🤗 Optimum](https: |
|
|
|
## ONNX |
|
|
|
El proyecto [ONNX (Open Neural Network eXchange)](http: |
|
estándar abierto que define un conjunto común de operadores y un formato |
|
de archivo común para representar modelos de aprendizaje profundo en una |
|
amplia variedad de _frameworks_, incluidos PyTorch y TensorFlow. Cuando un modelo |
|
se exporta al formato ONNX, estos operadores se usan para construir un |
|
grafo computacional (a menudo llamado _representación intermedia_) que |
|
representa el flujo de datos a través de la red neuronal. |
|
|
|
Al exponer un grafo con operadores y tipos de datos estandarizados, ONNX facilita |
|
el cambio entre frameworks. Por ejemplo, un modelo entrenado en PyTorch se puede |
|
exportar a formato ONNX y luego importar en TensorFlow (y viceversa). |
|
|
|
🤗 Transformers proporciona un paquete llamado `transformers.onnx`, el cual permite convertir |
|
los checkpoints de un modelo en un grafo ONNX aprovechando los objetos de configuración. |
|
Estos objetos de configuración están hechos a la medida de diferentes arquitecturas de modelos |
|
y están diseñados para ser fácilmente extensibles a otras arquitecturas. |
|
|
|
Las configuraciones a la medida incluyen las siguientes arquitecturas: |
|
|
|
<!--This table is automatically generated by `make fix-copies`, do not fill manually!--> |
|
|
|
- ALBERT |
|
- BART |
|
- BEiT |
|
- BERT |
|
- BigBird |
|
- BigBird-Pegasus |
|
- Blenderbot |
|
- BlenderbotSmall |
|
- BLOOM |
|
- CamemBERT |
|
- CLIP |
|
- CodeGen |
|
- ConvBERT |
|
- ConvNeXT |
|
- ConvNeXTV2 |
|
- Data2VecText |
|
- Data2VecVision |
|
- DeBERTa |
|
- DeBERTa-v2 |
|
- DeiT |
|
- DETR |
|
- DistilBERT |
|
- ELECTRA |
|
- FlauBERT |
|
- GPT Neo |
|
- GPT-J |
|
- I-BERT |
|
- LayoutLM |
|
- LayoutLMv3 |
|
- LeViT |
|
- LongT5 |
|
- M2M100 |
|
- Marian |
|
- mBART |
|
- MobileBERT |
|
- MobileViT |
|
- MT5 |
|
- OpenAI GPT-2 |
|
- Perceiver |
|
- PLBart |
|
- ResNet |
|
- RoBERTa |
|
- RoFormer |
|
- SqueezeBERT |
|
- T5 |
|
- ViT |
|
- XLM |
|
- XLM-RoBERTa |
|
- XLM-RoBERTa-XL |
|
- YOLOS |
|
|
|
En las próximas dos secciones, te mostraremos cómo: |
|
|
|
|
|
|
|
|
|
### Exportar un model a ONNX |
|
|
|
Para exportar un modelo 🤗 Transformers a ONNX, tienes que instalar primero algunas |
|
dependencias extra: |
|
|
|
```bash |
|
pip install transformers[onnx] |
|
``` |
|
|
|
El paquete `transformers.onnx` puede ser usado luego como un módulo de Python: |
|
|
|
```bash |
|
python -m transformers.onnx --help |
|
|
|
usage: Hugging Face Transformers ONNX exporter [-h] -m MODEL [--feature {causal-lm, ...}] [--opset OPSET] [--atol ATOL] output |
|
|
|
positional arguments: |
|
output Path indicating where to store generated ONNX model. |
|
|
|
optional arguments: |
|
-h, --help show this help message and exit |
|
-m MODEL, --model MODEL |
|
Model ID on huggingface.co or path on disk to load model from. |
|
--feature {causal-lm, ...} |
|
The type of features to export the model with. |
|
--opset OPSET ONNX opset version to export the model with. |
|
--atol ATOL Absolute difference tolerence when validating the model. |
|
``` |
|
|
|
Exportar un checkpoint usando una configuración a la medida se puede hacer de la siguiente manera: |
|
|
|
```bash |
|
python -m transformers.onnx --model=distilbert-base-uncased onnx/ |
|
``` |
|
|
|
que debería mostrar los siguientes registros: |
|
|
|
```bash |
|
Validating ONNX model... |
|
-[✓] ONNX model output names match reference model ({'last_hidden_state'}) |
|
- Validating ONNX Model output "last_hidden_state": |
|
-[✓] (2, 8, 768) matches (2, 8, 768) |
|
-[✓] all values close (atol: 1e-05) |
|
All good, model saved at: onnx/model.onnx |
|
``` |
|
|
|
Esto exporta un grafo ONNX del checkpoint definido por el argumento `--model`. |
|
En este ejemplo, es un modelo `distilbert-base-uncased`, pero puede ser cualquier |
|
checkpoint en Hugging Face Hub o que esté almacenado localmente. |
|
|
|
El archivo `model.onnx` resultante se puede ejecutar en uno de los |
|
[muchos aceleradores](https: |
|
que admiten el estándar ONNX. Por ejemplo, podemos cargar y ejecutar el |
|
modelo con [ONNX Runtime](https: |
|
|
|
```python |
|
>>> from transformers import AutoTokenizer |
|
>>> from onnxruntime import InferenceSession |
|
|
|
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") |
|
>>> session = InferenceSession("onnx/model.onnx") |
|
>>> # ONNX Runtime expects NumPy arrays as input |
|
>>> inputs = tokenizer("Using DistilBERT with ONNX Runtime!", return_tensors="np") |
|
>>> outputs = session.run(output_names=["last_hidden_state"], input_feed=dict(inputs)) |
|
``` |
|
|
|
Los nombres necesarios de salida (es decir, `["last_hidden_state"]`) se pueden obtener |
|
echando un vistazo a la configuración ONNX de cada modelo. Por ejemplo, para DistilBERT tenemos: |
|
|
|
```python |
|
>>> from transformers.models.distilbert import DistilBertConfig, DistilBertOnnxConfig |
|
|
|
>>> config = DistilBertConfig() |
|
>>> onnx_config = DistilBertOnnxConfig(config) |
|
>>> print(list(onnx_config.outputs.keys())) |
|
["last_hidden_state"]s |
|
``` |
|
|
|
El proceso es idéntico para los checkpoints de TensorFlow en Hub. |
|
Por ejemplo, podemos exportar un checkpoint puro de TensorFlow desde |
|
[Keras](https: |
|
|
|
```bash |
|
python -m transformers.onnx --model=keras-io/transformers-qa onnx/ |
|
``` |
|
|
|
Para exportar un modelo que está almacenado localmente, deberás tener los pesos |
|
y tokenizadores del modelo almacenados en un directorio. Por ejemplo, podemos cargar |
|
y guardar un checkpoint de la siguiente manera: |
|
|
|
<frameworkcontent> |
|
<pt> |
|
```python |
|
>>> from transformers import AutoTokenizer, AutoModelForSequenceClassification |
|
|
|
>>> # Load tokenizer and PyTorch weights form the Hub |
|
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") |
|
>>> pt_model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased") |
|
>>> # Save to disk |
|
>>> tokenizer.save_pretrained("local-pt-checkpoint") |
|
>>> pt_model.save_pretrained("local-pt-checkpoint") |
|
``` |
|
|
|
Una vez que se guarda el checkpoint, podemos exportarlo a ONNX usando el argumento `--model` |
|
del paquete `transformers.onnx` al directorio deseado: |
|
|
|
```bash |
|
python -m transformers.onnx --model=local-pt-checkpoint onnx/ |
|
``` |
|
</pt> |
|
<tf> |
|
```python |
|
>>> from transformers import AutoTokenizer, TFAutoModelForSequenceClassification |
|
|
|
>>> # Load tokenizer and TensorFlow weights from the Hub |
|
>>> tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") |
|
>>> tf_model = TFAutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased") |
|
>>> # Save to disk |
|
>>> tokenizer.save_pretrained("local-tf-checkpoint") |
|
>>> tf_model.save_pretrained("local-tf-checkpoint") |
|
``` |
|
|
|
Una vez que se guarda el checkpoint, podemos exportarlo a ONNX usando el argumento `--model` |
|
del paquete `transformers.onnx` al directorio deseado: |
|
|
|
```bash |
|
python -m transformers.onnx --model=local-tf-checkpoint onnx/ |
|
``` |
|
</tf> |
|
</frameworkcontent> |
|
|
|
### Seleccionar características para diferentes topologías de un modelo |
|
|
|
Cada configuración a la medida viene con un conjunto de _características_ que te permiten exportar |
|
modelos para diferentes tipos de topologías o tareas. Como se muestra en la siguiente tabla, cada |
|
función está asociada con una auto-clase de automóvil diferente: |
|
|
|
| Feature | Auto Class | |
|
| ------------------------------------ | ------------------------------------ | |
|
| `causal-lm`, `causal-lm-with-past` | `AutoModelForCausalLM` | |
|
| `default`, `default-with-past` | `AutoModel` | |
|
| `masked-lm` | `AutoModelForMaskedLM` | |
|
| `question-answering` | `AutoModelForQuestionAnswering` | |
|
| `seq2seq-lm`, `seq2seq-lm-with-past` | `AutoModelForSeq2SeqLM` | |
|
| `sequence-classification` | `AutoModelForSequenceClassification` | |
|
| `token-classification` | `AutoModelForTokenClassification` | |
|
|
|
Para cada configuración, puedes encontrar la lista de funciones admitidas a través de `FeaturesManager`. |
|
Por ejemplo, para DistilBERT tenemos: |
|
|
|
```python |
|
>>> from transformers.onnx.features import FeaturesManager |
|
|
|
>>> distilbert_features = list(FeaturesManager.get_supported_features_for_model_type("distilbert").keys()) |
|
>>> print(distilbert_features) |
|
["default", "masked-lm", "causal-lm", "sequence-classification", "token-classification", "question-answering"] |
|
``` |
|
|
|
Le puedes pasar una de estas características al argumento `--feature` en el paquete `transformers.onnx`. |
|
Por ejemplo, para exportar un modelo de clasificación de texto, podemos elegir un modelo ya ajustado del Hub y ejecutar: |
|
|
|
```bash |
|
python -m transformers.onnx --model=distilbert-base-uncased-finetuned-sst-2-english \ |
|
--feature=sequence-classification onnx/ |
|
``` |
|
|
|
que mostrará los siguientes registros: |
|
|
|
```bash |
|
Validating ONNX model... |
|
-[✓] ONNX model output names match reference model ({'logits'}) |
|
- Validating ONNX Model output "logits": |
|
-[✓] (2, 2) matches (2, 2) |
|
-[✓] all values close (atol: 1e-05) |
|
All good, model saved at: onnx/model.onnx |
|
``` |
|
|
|
Ten en cuenta que, en este caso, los nombres de salida del modelo ajustado son `logits` en lugar de `last_hidden_state` |
|
que vimos anteriormente con el checkpoint `distilbert-base-uncased`. Esto es de esperarse ya que el modelo ajustado |
|
tiene un cabezal de clasificación secuencial. |
|
|
|
<Tip> |
|
|
|
Las características que tienen un sufijo 'with-past' (por ejemplo, 'causal-lm-with-past') corresponden a topologías |
|
de modelo con estados ocultos precalculados (clave y valores en los bloques de atención) que se pueden usar para una |
|
decodificación autorregresiva más rápida. |
|
|
|
</Tip> |
|
|
|
|
|
### Exportar un modelo para una arquitectura no compatible |
|
|
|
Si deseas exportar un modelo cuya arquitectura no es compatible de forma nativa |
|
con la biblioteca, debes seguir tres pasos principales: |
|
|
|
1. Implementa una configuración personalizada en ONNX. |
|
2. Exporta el modelo a ONNX. |
|
3. Valide los resultados de PyTorch y los modelos exportados. |
|
|
|
En esta sección, veremos cómo se implementó la serialización de DistilBERT |
|
para mostrar lo que implica cada paso. |
|
|
|
#### Implementar una configuración personalizada en ONNX |
|
|
|
Comencemos con el objeto de configuración de ONNX. Proporcionamos tres clases abstractas |
|
de las que debe heredar, según el tipo de arquitectura del modelo que quieras exportar: |
|
|
|
|
|
|
|
|
|
|
|
<Tip> |
|
|
|
Una buena manera de implementar una configuración personalizada en ONNX es observar la implementación |
|
existente en el archivo `configuration_<model_name>.py` de una arquitectura similar. |
|
|
|
</Tip> |
|
|
|
Dado que DistilBERT es un modelo de tipo _encoder_, su configuración se hereda de `OnnxConfig`: |
|
|
|
```python |
|
>>> from typing import Mapping, OrderedDict |
|
>>> from transformers.onnx import OnnxConfig |
|
|
|
|
|
>>> class DistilBertOnnxConfig(OnnxConfig): |
|
... @property |
|
... def inputs(self) -> Mapping[str, Mapping[int, str]]: |
|
... return OrderedDict( |
|
... [ |
|
... ("input_ids", {0: "batch", 1: "sequence"}), |
|
... ("attention_mask", {0: "batch", 1: "sequence"}), |
|
... ] |
|
... ) |
|
``` |
|
|
|
Cada objeto de configuración debe implementar la propiedad `inputs` y devolver un mapeo, |
|
donde cada llave corresponde a una entrada esperada y cada valor indica el eje de esa entrada. |
|
Para DistilBERT, podemos ver que se requieren dos entradas: `input_ids` y `attention_mask`. |
|
Estas entradas tienen la misma forma de `(batch_size, sequence_length)`, es por lo que vemos |
|
los mismos ejes utilizados en la configuración. |
|
|
|
<Tip> |
|
|
|
Observa que la propiedad `inputs` para `DistilBertOnnxConfig` devuelve un `OrderedDict`. |
|
Esto nos asegura que las entradas coincidan con su posición relativa dentro del método |
|
`PreTrainedModel.forward()` al rastrear el grafo. Recomendamos usar un `OrderedDict` |
|
para las propiedades `inputs` y `outputs` al implementar configuraciones ONNX personalizadas. |
|
|
|
</Tip> |
|
|
|
Una vez que hayas implementado una configuración ONNX, puedes crear una |
|
instancia proporcionando la configuración del modelo base de la siguiente manera: |
|
|
|
```python |
|
>>> from transformers import AutoConfig |
|
|
|
>>> config = AutoConfig.from_pretrained("distilbert-base-uncased") |
|
>>> onnx_config = DistilBertOnnxConfig(config) |
|
``` |
|
|
|
El objeto resultante tiene varias propiedades útiles. Por ejemplo, puedes ver el conjunto de operadores ONNX que se |
|
utilizará durante la exportación: |
|
|
|
```python |
|
>>> print(onnx_config.default_onnx_opset) |
|
11 |
|
``` |
|
|
|
También puedes ver los resultados asociados con el modelo de la siguiente manera: |
|
|
|
```python |
|
>>> print(onnx_config.outputs) |
|
OrderedDict([("last_hidden_state", {0: "batch", 1: "sequence"})]) |
|
``` |
|
|
|
Observa que la propiedad de salidas sigue la misma estructura que las entradas; |
|
devuelve un objecto `OrderedDict` de salidas nombradas y sus formas. La estructura |
|
de salida está vinculada a la elección de la función con la que se inicializa la configuración. |
|
Por defecto, la configuración de ONNX se inicializa con la función `default` que |
|
corresponde a exportar un modelo cargado con la clase `AutoModel`. Si quieres exportar |
|
una topología de modelo diferente, simplemente proporciona una característica diferente |
|
al argumento `task` cuando inicialices la configuración de ONNX. Por ejemplo, si quisiéramos |
|
exportar DistilBERT con un cabezal de clasificación de secuencias, podríamos usar: |
|
|
|
```python |
|
>>> from transformers import AutoConfig |
|
|
|
>>> config = AutoConfig.from_pretrained("distilbert-base-uncased") |
|
>>> onnx_config_for_seq_clf = DistilBertOnnxConfig(config, task="sequence-classification") |
|
>>> print(onnx_config_for_seq_clf.outputs) |
|
OrderedDict([('logits', {0: 'batch'})]) |
|
``` |
|
|
|
<Tip> |
|
|
|
Todas las propiedades base y métodos asociados con [`~onnx.config.OnnxConfig`] y las |
|
otras clases de configuración se pueden sobreescribir si es necesario. |
|
Consulte [`BartOnnxConfig`] para ver un ejemplo avanzado. |
|
|
|
</Tip> |
|
|
|
#### Exportar el modelo |
|
|
|
Una vez que hayas implementado la configuración de ONNX, el siguiente paso es exportar el modelo. |
|
Aquí podemos usar la función `export()` proporcionada por el paquete `transformers.onnx`. |
|
Esta función espera la configuración de ONNX, junto con el modelo base y el tokenizador, |
|
y la ruta para guardar el archivo exportado: |
|
|
|
```python |
|
>>> from pathlib import Path |
|
>>> from transformers.onnx import export |
|
>>> from transformers import AutoTokenizer, AutoModel |
|
|
|
>>> onnx_path = Path("model.onnx") |
|
>>> model_ckpt = "distilbert-base-uncased" |
|
>>> base_model = AutoModel.from_pretrained(model_ckpt) |
|
>>> tokenizer = AutoTokenizer.from_pretrained(model_ckpt) |
|
|
|
>>> onnx_inputs, onnx_outputs = export(tokenizer, base_model, onnx_config, onnx_config.default_onnx_opset, onnx_path) |
|
``` |
|
|
|
Los objetos `onnx_inputs` y `onnx_outputs` devueltos por la función `export()` |
|
son listas de llaves definidas en las propiedades `inputs` y `outputs` de la configuración. |
|
Una vez exportado el modelo, puedes probar que el modelo está bien formado de la siguiente manera: |
|
|
|
```python |
|
>>> import onnx |
|
|
|
>>> onnx_model = onnx.load("model.onnx") |
|
>>> onnx.checker.check_model(onnx_model) |
|
``` |
|
|
|
<Tip> |
|
|
|
Si tu modelo tiene más de 2GB, verás que se crean muchos archivos adicionales durante la exportación. |
|
Esto es _esperado_ porque ONNX usa [Búferes de protocolo](https: |
|
para almacenar el modelo y éstos tienen un límite de tamaño de 2 GB. Consulta la |
|
[documentación de ONNX](https: |
|
instrucciones sobre cómo cargar modelos con datos externos. |
|
|
|
</Tip> |
|
|
|
#### Validar los resultados del modelo |
|
|
|
El paso final es validar que los resultados del modelo base y exportado coincidan dentro |
|
de cierta tolerancia absoluta. Aquí podemos usar la función `validate_model_outputs()` |
|
proporcionada por el paquete `transformers.onnx` de la siguiente manera: |
|
|
|
```python |
|
>>> from transformers.onnx import validate_model_outputs |
|
|
|
>>> validate_model_outputs( |
|
... onnx_config, tokenizer, base_model, onnx_path, onnx_outputs, onnx_config.atol_for_validation |
|
... ) |
|
``` |
|
|
|
Esta función usa el método `OnnxConfig.generate_dummy_inputs()` para generar entradas para el modelo base |
|
y exportado, y la tolerancia absoluta se puede definir en la configuración. En general, encontramos una |
|
concordancia numérica en el rango de 1e-6 a 1e-4, aunque es probable que cualquier valor menor que 1e-3 esté bien. |
|
|
|
### Contribuir con una nueva configuración a 🤗 Transformers |
|
|
|
¡Estamos buscando expandir el conjunto de configuraciones a la medida para usar y agradecemos las contribuciones de la comunidad! |
|
Si deseas contribuir con su colaboración a la biblioteca, deberás: |
|
|
|
|
|
|
|
|
|
|
|
Revisa cómo fue la contribución para la [configuración de IBERT](https: |
|
y así tener una idea de lo que necesito. |
|
|
|
## TorchScript |
|
|
|
<Tip> |
|
|
|
Este es el comienzo de nuestros experimentos con TorchScript y todavía estamos explorando sus capacidades con modelos de |
|
tamaño de entrada variable. Es un tema de interés y profundizaremos nuestro análisis en las próximas |
|
versiones, con más ejemplos de código, una implementación más flexible y puntos de referencia que comparen códigos |
|
basados en Python con TorchScript compilado. |
|
|
|
</Tip> |
|
|
|
Según la documentación de PyTorch: "TorchScript es una forma de crear modelos serializables y optimizables a partir del |
|
código de PyTorch". Los dos módulos de Pytorch [JIT y TRACE](https: |
|
desarrollador exportar su modelo para reutilizarlo en otros programas, como los programas C++ orientados a la eficiencia. |
|
|
|
Hemos proporcionado una interfaz que permite exportar modelos de 🤗 Transformers a TorchScript para que puedan reutilizarse |
|
en un entorno diferente al de un programa Python basado en PyTorch. Aquí explicamos cómo exportar y usar nuestros modelos |
|
usando TorchScript. |
|
|
|
Exportar un modelo requiere de dos cosas: |
|
|
|
- un pase hacia adelante con entradas ficticias. |
|
- instanciación del modelo con la indicador `torchscript`. |
|
|
|
Estas necesidades implican varias cosas con las que los desarrolladores deben tener cuidado. Éstas se detallan a continuación. |
|
|
|
### Indicador de TorchScript y pesos atados |
|
|
|
Este indicador es necesario porque la mayoría de los modelos de lenguaje en este repositorio tienen pesos vinculados entre su capa |
|
de `Embedding` y su capa de `Decoding`. TorchScript no permite la exportación de modelos que tengan pesos atados, por lo que es |
|
necesario desvincular y clonar los pesos previamente. |
|
|
|
Esto implica que los modelos instanciados con el indicador `torchscript` tienen su capa `Embedding` y `Decoding` separadas, |
|
lo que significa que no deben entrenarse más adelante. El entrenamiento desincronizaría las dos capas, lo que generaría |
|
resultados inesperados. |
|
|
|
Este no es el caso de los modelos que no tienen un cabezal de modelo de lenguaje, ya que no tienen pesos atados. |
|
Estos modelos se pueden exportar de forma segura sin el indicador `torchscript`. |
|
|
|
### Entradas ficticias y longitudes estándar |
|
|
|
Las entradas ficticias se utilizan para crear un modelo de pase hacia adelante. Mientras los valores de las entradas se |
|
propagan a través de las capas, PyTorch realiza un seguimiento de las diferentes operaciones ejecutadas en cada tensor. |
|
Estas operaciones registradas se utilizan luego para crear el "rastro" del modelo. |
|
|
|
El rastro se crea en relación con las dimensiones de las entradas. Por lo tanto, está limitado por las dimensiones de la |
|
entrada ficticia y no funcionará para ninguna otra longitud de secuencia o tamaño de lote. Al intentar con un tamaño diferente, |
|
un error como: |
|
|
|
`The expanded size of the tensor (3) must match the existing size (7) at non-singleton dimension 2` |
|
|
|
aparecerá. Por lo tanto, se recomienda rastrear el modelo con un tamaño de entrada ficticia al menos tan grande como la |
|
entrada más grande que se alimentará al modelo durante la inferencia. El _padding_ se puede realizar para completar los |
|
valores que faltan. Sin embargo, como el modelo se habrá rastreado con un tamaño de entrada grande, las dimensiones de |
|
las diferentes matrices también serán grandes, lo que dará como resultado más cálculos. |
|
|
|
Se recomienda tener cuidado con el número total de operaciones realizadas en cada entrada y seguir de cerca el rendimiento |
|
al exportar modelos de longitud de secuencia variable. |
|
|
|
### Usar TorchScript en Python |
|
|
|
A continuación se muestra un ejemplo que muestra cómo guardar, cargar modelos y cómo usar el rastreo para la inferencia. |
|
|
|
#### Guardando un modelo |
|
|
|
Este fragmento muestra cómo usar TorchScript para exportar un `BertModel`. Aquí, el `BertModel` se instancia de acuerdo |
|
con la clase `BertConfig` y luego se guarda en el disco con el nombre de archivo `traced_bert.pt` |
|
|
|
```python |
|
from transformers import BertModel, BertTokenizer, BertConfig |
|
import torch |
|
|
|
enc = BertTokenizer.from_pretrained("bert-base-uncased") |
|
|
|
# Tokenizing input text |
|
text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]" |
|
tokenized_text = enc.tokenize(text) |
|
|
|
# Masking one of the input tokens |
|
masked_index = 8 |
|
tokenized_text[masked_index] = "[MASK]" |
|
indexed_tokens = enc.convert_tokens_to_ids(tokenized_text) |
|
segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] |
|
|
|
# Creating a dummy input |
|
tokens_tensor = torch.tensor([indexed_tokens]) |
|
segments_tensors = torch.tensor([segments_ids]) |
|
dummy_input = [tokens_tensor, segments_tensors] |
|
|
|
# Initializing the model with the torchscript flag |
|
# Flag set to True even though it is not necessary as this model does not have an LM Head. |
|
config = BertConfig( |
|
vocab_size_or_config_json_file=32000, |
|
hidden_size=768, |
|
num_hidden_layers=12, |
|
num_attention_heads=12, |
|
intermediate_size=3072, |
|
torchscript=True, |
|
) |
|
|
|
# Instantiating the model |
|
model = BertModel(config) |
|
|
|
# The model needs to be in evaluation mode |
|
model.eval() |
|
|
|
# If you are instantiating the model with *from_pretrained* you can also easily set the TorchScript flag |
|
model = BertModel.from_pretrained("bert-base-uncased", torchscript=True) |
|
|
|
# Creating the trace |
|
traced_model = torch.jit.trace(model, [tokens_tensor, segments_tensors]) |
|
torch.jit.save(traced_model, "traced_bert.pt") |
|
``` |
|
|
|
#### Cargar un modelo |
|
|
|
Este fragmento muestra cómo cargar el `BertModel` que se guardó previamente en el disco con el nombre `traced_bert.pt`. |
|
Estamos reutilizando el `dummy_input` previamente inicializado. |
|
|
|
```python |
|
loaded_model = torch.jit.load("traced_bert.pt") |
|
loaded_model.eval() |
|
|
|
all_encoder_layers, pooled_output = loaded_model(*dummy_input) |
|
``` |
|
|
|
#### Usar un modelo rastreado para la inferencia |
|
|
|
Usar el modelo rastreado para la inferencia es tan simple como usar su método `__call__`: |
|
|
|
```python |
|
traced_model(tokens_tensor, segments_tensors) |
|
``` |
|
|
|
### Implementar los modelos HuggingFace TorchScript en AWS mediante Neuron SDK |
|
|
|
AWS presentó la familia de instancias [Amazon EC2 Inf1](https: |
|
de aprendizaje automático de bajo costo y alto rendimiento en la nube. Las instancias Inf1 funcionan con el chip AWS |
|
Inferentia, un acelerador de hardware personalizado, que se especializa en cargas de trabajo de inferencia de aprendizaje |
|
profundo. [AWS Neuron](https: |
|
que admite el rastreo y la optimización de modelos de transformers para su implementación en Inf1. El SDK de Neuron proporciona: |
|
|
|
|
|
1. API fácil de usar con una línea de cambio de código para rastrear y optimizar un modelo de TorchScript para la inferencia en la nube. |
|
2. Optimizaciones de rendimiento listas para usar con un [costo-rendimiento mejorado](https: |
|
3. Soporte para modelos HuggingFace Transformers construidos con [PyTorch](https: |
|
o [TensorFlow](https: |
|
|
|
#### Implicaciones |
|
|
|
Los modelos Transformers basados en la arquitectura |
|
[BERT (Representaciones de _Enconder_ bidireccional de Transformers)](https: |
|
o sus variantes, como [distilBERT](https: |
|
[roBERTa](https: |
|
generativas, como la respuesta extractiva de preguntas, la clasificación de secuencias y la clasificación de tokens. |
|
Como alternativa, las tareas de generación de texto se pueden adaptar para ejecutarse en Inf1, según este |
|
[tutorial de AWS Neuron MarianMT](https: |
|
Puedes encontrar más información sobre los modelos que están listos para usarse en Inferentia en la |
|
[sección _Model Architecture Fit_ de la documentación de Neuron](https: |
|
|
|
#### Dependencias |
|
|
|
Usar AWS Neuron para convertir modelos requiere las siguientes dependencias y entornos: |
|
|
|
|
|
que viene preconfigurado en [AWS Deep Learning AMI](https: |
|
|
|
#### Convertir un modelo a AWS Neuron |
|
|
|
Con el mismo script usado en [Uso de TorchScript en Python](https: |
|
para rastrear un "BertModel", puedes importar la extensión del _framework_ `torch.neuron` para acceder a los componentes |
|
del SDK de Neuron a través de una API de Python. |
|
|
|
```python |
|
from transformers import BertModel, BertTokenizer, BertConfig |
|
import torch |
|
import torch.neuron |
|
``` |
|
Y modificando la línea de código de rastreo de: |
|
|
|
```python |
|
torch.jit.trace(model, [tokens_tensor, segments_tensors]) |
|
``` |
|
|
|
con lo siguiente: |
|
|
|
```python |
|
torch.neuron.trace(model, [token_tensor, segments_tensors]) |
|
``` |
|
|
|
Este cambio permite a Neuron SDK rastrear el modelo y optimizarlo para ejecutarse en instancias Inf1. |
|
|
|
Para obtener más información sobre las funciones, las herramientas, los tutoriales de ejemplo y las últimas actualizaciones |
|
de AWS Neuron SDK, consulte la [documentación de AWS NeuronSDK](https: |
|
|