llama.cpp
Enlaces simples de Python para la biblioteca llama.cpp
de @ggerganov . Este paquete proporciona:
ctypes
.La documentación está disponible en https://llama-cpp-python.readthedocs.io/en/latest.
Requisitos:
Para instalar el paquete, ejecute:
pip install llama-cpp-python
Esto también compilará llama.cpp
desde el código fuente y lo instalará junto con este paquete de Python.
Si esto falla, agregue --verbose
a la pip install
consulte el registro completo de compilación de cmake.
Rueda prefabricada (nueva)
También es posible instalar una rueda prediseñada con soporte básico de CPU.
pip install llama-cpp-python
--extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu
llama.cpp
admite varios backends de aceleración de hardware para acelerar la inferencia, así como opciones específicas del backend. Consulte el archivo LÉAME de llama.cpp para obtener una lista completa.
Todas las opciones de compilación llama.cpp
cmake se pueden configurar mediante la variable de entorno CMAKE_ARGS
o mediante el indicador --config-settings / -C
cli durante la instalación.
# Linux and Mac
CMAKE_ARGS= " -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS "
pip install llama-cpp-python
# Windows
$ env: CMAKE_ARGS = " -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS "
pip install llama - cpp - python
También se pueden configurar mediante el comando pip install -C / --config-settings
y guardar en un archivo requirements.txt
:
pip install --upgrade pip # ensure pip is up to date
pip install llama-cpp-python
-C cmake.args= " -DGGML_BLAS=ON;-DGGML_BLAS_VENDOR=OpenBLAS "
# requirements.txt
llama-cpp-python -C cmake.args="-DGGML_BLAS=ON;-DGGML_BLAS_VENDOR=OpenBLAS"
A continuación se muestran algunos backends comunes, sus comandos de compilación y cualquier variable de entorno adicional requerida.
Para instalar con OpenBLAS, configure las variables de entorno GGML_BLAS
y GGML_BLAS_VENDOR
antes de instalar:
CMAKE_ARGS= " -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS " pip install llama-cpp-python
Para instalar con soporte CUDA, configure la variable de entorno GGML_CUDA=on
antes de instalar:
CMAKE_ARGS= " -DGGML_CUDA=on " pip install llama-cpp-python
Rueda prefabricada (nueva)
También es posible instalar una rueda prefabricada con soporte CUDA. Siempre que su sistema cumpla con algunos requisitos:
pip install llama-cpp-python
--extra-index-url https://abetlen.github.io/llama-cpp-python/whl/ < cuda-version >
Donde <cuda-version>
es uno de los siguientes:
cu121
: CUDA 12.1cu122
: CUDA 12.2cu123
: CUDA 12.3cu124
: CUDA 12.4cu125
: CUDA 12.5Por ejemplo, para instalar la rueda CUDA 12.1:
pip install llama-cpp-python
--extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu121
Para instalar con Metal (MPS), configure la variable de entorno GGML_METAL=on
antes de instalar:
CMAKE_ARGS= " -DGGML_METAL=on " pip install llama-cpp-python
Rueda prefabricada (nueva)
También es posible instalar una rueda prefabricada con soporte metálico. Siempre que su sistema cumpla con algunos requisitos:
pip install llama-cpp-python
--extra-index-url https://abetlen.github.io/llama-cpp-python/whl/metal
Para instalar con soporte hipBLAS/ROCm para tarjetas AMD, configure la variable de entorno GGML_HIPBLAS=on
antes de instalar:
CMAKE_ARGS= " -DGGML_HIPBLAS=on " pip install llama-cpp-python
Para instalar con soporte Vulkan, configure la variable de entorno GGML_VULKAN=on
antes de instalar:
CMAKE_ARGS= " -DGGML_VULKAN=on " pip install llama-cpp-python
Para instalar con soporte SYCL, configure la variable de entorno GGML_SYCL=on
antes de instalar:
source /opt/intel/oneapi/setvars.sh
CMAKE_ARGS= " -DGGML_SYCL=on -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx " pip install llama-cpp-python
Para instalar con soporte RPC, configure la variable de entorno GGML_RPC=on
antes de instalar:
source /opt/intel/oneapi/setvars.sh
CMAKE_ARGS= " -DGGML_RPC=on " pip install llama-cpp-python
Si tiene problemas en los que se queja de que no puede encontrar 'nmake'
'?'
o CMAKE_C_COMPILER, puede extraer w64devkit como se menciona en el repositorio llama.cpp y agregarlos manualmente a CMAKE_ARGS antes de ejecutar pip
install:
$env:CMAKE_GENERATOR = "MinGW Makefiles"
$env:CMAKE_ARGS = "-DGGML_OPENBLAS=on -DCMAKE_C_COMPILER=C: /w64devkit/bin/gcc.exe -DCMAKE_CXX_COMPILER=C: /w64devkit/bin/g++.exe"
Consulte las instrucciones anteriores y configure CMAKE_ARGS
en el backend BLAS que desea utilizar.
La documentación detallada sobre la instalación de MacOS Metal GPU está disponible en docs/install/macos.md
Nota: Si está utilizando Apple Silicon (M1) Mac, asegúrese de haber instalado una versión de Python que admita la arquitectura arm64. Por ejemplo:
wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh
bash Miniforge3-MacOSX-arm64.sh
De lo contrario, durante la instalación se creará la versión llama.cpp x86, que será 10 veces más lenta en Apple Silicon (M1) Mac.
Intente instalar con
CMAKE_ARGS= " -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_APPLE_SILICON_PROCESSOR=arm64 -DGGML_METAL=on " pip install --upgrade --verbose --force-reinstall --no-cache-dir llama-cpp-python
Para actualizar y reconstruir llama-cpp-python
agregue los indicadores --upgrade --force-reinstall --no-cache-dir
al comando pip install
para garantizar que el paquete se reconstruya desde el código fuente.
Referencia de API
La API de alto nivel proporciona una interfaz administrada sencilla a través de la clase Llama
.
A continuación se muestra un breve ejemplo que demuestra cómo utilizar la API de alto nivel para completar texto básico:
from llama_cpp import Llama
llm = Llama (
model_path = "./models/7B/llama-model.gguf" ,
# n_gpu_layers=-1, # Uncomment to use GPU acceleration
# seed=1337, # Uncomment to set a specific seed
# n_ctx=2048, # Uncomment to increase the context window
)
output = llm (
"Q: Name the planets in the solar system? A: " , # Prompt
max_tokens = 32 , # Generate up to 32 tokens, set to None to generate up to the end of the context window
stop = [ "Q:" , " n " ], # Stop generating just before the model would generate a new question
echo = True # Echo the prompt back in the output
) # Generate a completion, can also call create_completion
print ( output )
De forma predeterminada, llama-cpp-python
genera completaciones en un formato compatible con OpenAI:
{
"id" : "cmpl-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ,
"object" : "text_completion" ,
"created" : 1679561337 ,
"model" : "./models/7B/llama-model.gguf" ,
"choices" : [
{
"text" : "Q: Name the planets in the solar system? A: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune and Pluto." ,
"index" : 0 ,
"logprobs" : None ,
"finish_reason" : "stop"
}
],
"usage" : {
"prompt_tokens" : 14 ,
"completion_tokens" : 28 ,
"total_tokens" : 42
}
}
La finalización de texto está disponible a través de los métodos __call__
y create_completion
de la clase Llama
.
Puede descargar modelos Llama
en formato gguf
directamente desde Hugging Face utilizando el método from_pretrained
. Necesitará instalar el paquete huggingface-hub
para usar esta función ( pip install huggingface-hub
).
llm = Llama . from_pretrained (
repo_id = "Qwen/Qwen2-0.5B-Instruct-GGUF" ,
filename = "*q8_0.gguf" ,
verbose = False
)
De forma predeterminada, from_pretrained
descargará el modelo en el directorio de caché de huggingface; luego podrá administrar los archivos del modelo instalado con la herramienta huggingface-cli
.
La API de alto nivel también proporciona una interfaz sencilla para completar el chat.
La finalización del chat requiere que el modelo sepa cómo formatear los mensajes en un solo mensaje. La clase Llama
hace esto usando formatos de chat prerregistrados (es decir, chatml
, llama-2
, gemma
, etc.) o proporcionando un objeto de controlador de chat personalizado.
El modelo formateará los mensajes en un solo mensaje usando el siguiente orden de prioridad:
chat_handler
si se proporcionachat_format
si se proporcionatokenizer.chat_template
de los metadatos del modelo gguf
(debería funcionar para la mayoría de los modelos nuevos, es posible que los modelos más antiguos no tengan esto)llama-2
Establezca verbose=True
para ver el formato de chat seleccionado.
from llama_cpp import Llama
llm = Llama (
model_path = "path/to/llama-2/llama-model.gguf" ,
chat_format = "llama-2"
)
llm . create_chat_completion (
messages = [
{ "role" : "system" , "content" : "You are an assistant who perfectly describes images." },
{
"role" : "user" ,
"content" : "Describe this image in detail please."
}
]
)
La finalización del chat está disponible a través del método create_chat_completion
de la clase Llama
.
Para la compatibilidad con OpenAI API v1, utilice el método create_chat_completion_openai_v1
que devolverá modelos pydantic en lugar de dicts.
Para restringir las respuestas del chat solo a JSON válido o a un esquema JSON específico, utilice el argumento response_format
en create_chat_completion
.
El siguiente ejemplo limitará la respuesta a cadenas JSON válidas únicamente.
from llama_cpp import Llama
llm = Llama ( model_path = "path/to/model.gguf" , chat_format = "chatml" )
llm . create_chat_completion (
messages = [
{
"role" : "system" ,
"content" : "You are a helpful assistant that outputs in JSON." ,
},
{ "role" : "user" , "content" : "Who won the world series in 2020" },
],
response_format = {
"type" : "json_object" ,
},
temperature = 0.7 ,
)
Para limitar aún más la respuesta a un esquema JSON específico, agregue el esquema a la propiedad de schema
del argumento response_format
.
from llama_cpp import Llama
llm = Llama ( model_path = "path/to/model.gguf" , chat_format = "chatml" )
llm . create_chat_completion (
messages = [
{
"role" : "system" ,
"content" : "You are a helpful assistant that outputs in JSON." ,
},
{ "role" : "user" , "content" : "Who won the world series in 2020" },
],
response_format = {
"type" : "json_object" ,
"schema" : {
"type" : "object" ,
"properties" : { "team_name" : { "type" : "string" }},
"required" : [ "team_name" ],
},
},
temperature = 0.7 ,
)
La API de alto nivel admite funciones y herramientas compatibles con OpenAI. Esto es posible a través del formato de chat de modelos functionary
previamente entrenados o mediante el formato de chat genérico chatml-function-calling
.
from llama_cpp import Llama
llm = Llama ( model_path = "path/to/chatml/llama-model.gguf" , chat_format = "chatml-function-calling" )
llm . create_chat_completion (
messages = [
{
"role" : "system" ,
"content" : "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions. The assistant calls functions with appropriate input when necessary"
},
{
"role" : "user" ,
"content" : "Extract Jason is 25 years old"
}
],
tools = [{
"type" : "function" ,
"function" : {
"name" : "UserDetail" ,
"parameters" : {
"type" : "object" ,
"title" : "UserDetail" ,
"properties" : {
"name" : {
"title" : "Name" ,
"type" : "string"
},
"age" : {
"title" : "Age" ,
"type" : "integer"
}
},
"required" : [ "name" , "age" ]
}
}
}],
tool_choice = {
"type" : "function" ,
"function" : {
"name" : "UserDetail"
}
}
)
Los distintos archivos convertidos a guff para este conjunto de modelos se pueden encontrar aquí. El funcionario puede llamar funciones de forma inteligente y también analizar los resultados de las funciones proporcionadas para generar respuestas coherentes. Todos los modelos v2 de funcionario admiten llamadas a funciones paralelas . Puede proporcionar functionary-v1
o functionary-v2
para chat_format
al inicializar la clase Llama.
Debido a discrepancias entre llama.cpp y los tokenizadores de HuggingFace, es necesario proporcionar HF Tokenizer para el funcionario. La clase LlamaHFTokenizer
se puede inicializar y pasar a la clase Llama. Esto anulará el tokenizador llama.cpp predeterminado utilizado en la clase Llama. Los archivos del tokenizador ya están incluidos en los respectivos repositorios HF que alojan los archivos gguf.
from llama_cpp import Llama
from llama_cpp . llama_tokenizer import LlamaHFTokenizer
llm = Llama . from_pretrained (
repo_id = "meetkai/functionary-small-v2.2-GGUF" ,
filename = "functionary-small-v2.2.q4_0.gguf" ,
chat_format = "functionary-v2" ,
tokenizer = LlamaHFTokenizer . from_pretrained ( "meetkai/functionary-small-v2.2-GGUF" )
)
NOTA : No es necesario proporcionar los mensajes predeterminados del sistema utilizados en Functionary, ya que se agregan automáticamente en el controlador de chat de Functionary. Por lo tanto, los mensajes deben contener solo los mensajes de chat y/o mensajes del sistema que brindan contexto adicional para el modelo (por ejemplo: fecha y hora, etc.).
Soportes de llama-cpp-python
como llama1.5 que permiten que el modelo de lenguaje lea información tanto de texto como de imágenes.
A continuación se muestran los modelos multimodales admitidos y sus respectivos controladores de chat (API de Python) y formatos de chat (API de servidor).
Modelo | LlamaChatHandler | chat_format |
---|---|---|
llama-v1.5-7b | Llava15ChatHandler | llava-1-5 |
llama-v1.5-13b | Llava15ChatHandler | llava-1-5 |
llama-v1.6-34b | Llava16ChatHandler | llava-1-6 |
sueño lunar2 | MoondreamChatHandler | moondream2 |
nanollava | NanollavaChatHandler | nanollava |
llama-3-vision-alfa | Llama3VisionAlphaChatHandler | llama-3-vision-alpha |
minicpm-v-2.6 | MiniCPMv26ChatHandler | minicpm-v-2.6 |
Luego necesitarás usar un controlador de chat personalizado para cargar el modelo de clip y procesar los mensajes e imágenes del chat.
from llama_cpp import Llama
from llama_cpp . llama_chat_format import Llava15ChatHandler
chat_handler = Llava15ChatHandler ( clip_model_path = "path/to/llava/mmproj.bin" )
llm = Llama (
model_path = "./path/to/llava/llama-model.gguf" ,
chat_handler = chat_handler ,
n_ctx = 2048 , # n_ctx should be increased to accommodate the image embedding
)
llm . create_chat_completion (
messages = [
{ "role" : "system" , "content" : "You are an assistant who perfectly describes images." },
{
"role" : "user" ,
"content" : [
{ "type" : "text" , "text" : "What's in this image?" },
{ "type" : "image_url" , "image_url" : { "url" : "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg" } }
]
}
]
)
También puede extraer el modelo de Hugging Face Hub utilizando el método from_pretrained
.
from llama_cpp import Llama
from llama_cpp . llama_chat_format import MoondreamChatHandler
chat_handler = MoondreamChatHandler . from_pretrained (
repo_id = "vikhyatk/moondream2" ,
filename = "*mmproj*" ,
)
llm = Llama . from_pretrained (
repo_id = "vikhyatk/moondream2" ,
filename = "*text-model*" ,
chat_handler = chat_handler ,
n_ctx = 2048 , # n_ctx should be increased to accommodate the image embedding
)
response = llm . create_chat_completion (
messages = [
{
"role" : "user" ,
"content" : [
{ "type" : "text" , "text" : "What's in this image?" },
{ "type" : "image_url" , "image_url" : { "url" : "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg" } }
]
}
]
)
print ( response [ "choices" ][ 0 ][ "text" ])
Nota : Los modelos multimodales también admiten la llamada de herramientas y el modo JSON.
Las imágenes se pueden pasar como URI de datos codificados en base64. El siguiente ejemplo demuestra cómo hacer esto.
import base64
def image_to_base64_data_uri ( file_path ):
with open ( file_path , "rb" ) as img_file :
base64_data = base64 . b64encode ( img_file . read ()). decode ( 'utf-8' )
return f"data:image/png;base64, { base64_data } "
# Replace 'file_path.png' with the actual path to your PNG file
file_path = 'file_path.png'
data_uri = image_to_base64_data_uri ( file_path )
messages = [
{ "role" : "system" , "content" : "You are an assistant who perfectly describes images." },
{
"role" : "user" ,
"content" : [
{ "type" : "image_url" , "image_url" : { "url" : data_uri }},
{ "type" : "text" , "text" : "Describe this image in detail please." }
]
}
]
llama-cpp-python
admite la decodificación especulativa que permite que el modelo genere terminaciones basadas en un modelo preliminar.
La forma más rápida de utilizar la decodificación especulativa es mediante la clase LlamaPromptLookupDecoding
.
Simplemente pase esto como modelo borrador a la clase Llama
durante la inicialización.
from llama_cpp import Llama
from llama_cpp . llama_speculative import LlamaPromptLookupDecoding
llama = Llama (
model_path = "path/to/model.gguf" ,
draft_model = LlamaPromptLookupDecoding ( num_pred_tokens = 10 ) # num_pred_tokens is the number of tokens to predict 10 is the default and generally good for gpu, 2 performs better for cpu-only machines.
)
Para generar incrustaciones de texto, utilice create_embedding
o embed
. Tenga en cuenta que debe pasar embedding=True
al constructor al crear el modelo para que funcionen correctamente.
import llama_cpp
llm = llama_cpp . Llama ( model_path = "path/to/model.gguf" , embedding = True )
embeddings = llm . create_embedding ( "Hello, world!" )
# or create multiple embeddings at once
embeddings = llm . create_embedding ([ "Hello, world!" , "Goodbye, world!" ])
Hay dos nociones principales de incrustaciones en un modelo estilo Transformer: nivel de token y nivel de secuencia . Las incrustaciones de nivel de secuencia se producen "agrupando" incrustaciones de nivel de token, generalmente promediandolas o usando el primer token.
Los modelos que están explícitamente orientados a incrustaciones generalmente devolverán incrustaciones a nivel de secuencia de forma predeterminada, una para cada cadena de entrada. Los modelos sin incrustación, como los diseñados para la generación de texto, normalmente devolverán solo incrustaciones a nivel de token, una para cada token en cada secuencia. Por lo tanto, la dimensionalidad del tipo de retorno será superior para las incorporaciones a nivel de token.
En algunos casos, es posible controlar el comportamiento de la agrupación utilizando el indicador pooling_type
en la creación del modelo. Puede garantizar incrustaciones a nivel de token de cualquier modelo usando LLAMA_POOLING_TYPE_NONE
. A la inversa, actualmente no es posible obtener un modelo orientado a la generación que produzca incrustaciones a nivel de secuencia, pero siempre se puede realizar la agrupación manualmente.
La ventana de contexto de los modelos Llama determina la cantidad máxima de tokens que se pueden procesar a la vez. De forma predeterminada, esto está configurado en 512 tokens, pero se puede ajustar según sus requisitos.
Por ejemplo, si desea trabajar con contextos más grandes, puede expandir la ventana de contexto configurando el parámetro n_ctx al inicializar el objeto Llama:
llm = Llama ( model_path = "./models/7B/llama-model.gguf" , n_ctx = 2048 )
llama-cpp-python
ofrece un servidor web que pretende actuar como un reemplazo directo de la API OpenAI. Esto le permite utilizar modelos compatibles con llama.cpp con cualquier cliente compatible con OpenAI (bibliotecas de idiomas, servicios, etc.).
Para instalar el paquete del servidor y comenzar:
pip install ' llama-cpp-python[server] '
python3 -m llama_cpp.server --model models/7B/llama-model.gguf
De manera similar a la sección anterior de Aceleración de hardware, también puede instalar con soporte para GPU (cuBLAS) de esta manera:
CMAKE_ARGS= " -DGGML_CUDA=on " FORCE_CMAKE=1 pip install ' llama-cpp-python[server] '
python3 -m llama_cpp.server --model models/7B/llama-model.gguf --n_gpu_layers 35
Navegue a http://localhost:8000/docs para ver la documentación de OpenAPI.
Para vincularse a 0.0.0.0
y habilitar conexiones remotas, use python3 -m llama_cpp.server --host 0.0.0.0
. De manera similar, para cambiar el puerto (el valor predeterminado es 8000), use --port
.
Probablemente también desee configurar el formato del mensaje. Para chatml, utilice
python3 -m llama_cpp.server --model models/7B/llama-model.gguf --chat_format chatml
Eso formateará el mensaje de acuerdo con cómo lo espera el modelo. Puede encontrar el formato del mensaje en la tarjeta del modelo. Para conocer posibles opciones, consulte llama_cpp/llama_chat_format.py y busque líneas que comiencen con "@register_chat_format".
Si tiene instalado huggingface-hub
, también puede usar el indicador --hf_model_repo_id
para cargar un modelo desde Hugging Face Hub.
python3 -m llama_cpp.server --hf_model_repo_id Qwen/Qwen2-0.5B-Instruct-GGUF --model ' *q8_0.gguf '
Hay una imagen de Docker disponible en GHCR. Para ejecutar el servidor:
docker run --rm -it -p 8000:8000 -v /path/to/models:/models -e MODEL=/models/llama-model.gguf ghcr.io/abetlen/llama-cpp-python:latest
Docker en termux (requiere root) es actualmente la única forma conocida de ejecutar esto en teléfonos; consulte el problema de soporte de termux
Referencia de API
La API de bajo nivel es un enlace directo ctypes
a la API C proporcionada por llama.cpp
. La API completa de bajo nivel se puede encontrar en llama_cpp/llama_cpp.py y refleja directamente la API C en llama.h.
A continuación se muestra un breve ejemplo que demuestra cómo utilizar la API de bajo nivel para tokenizar un mensaje:
import llama_cpp
import ctypes
llama_cpp . llama_backend_init ( False ) # Must be called once at the start of each program
params = llama_cpp . llama_context_default_params ()
# use bytes for char * params
model = llama_cpp . llama_load_model_from_file ( b"./models/7b/llama-model.gguf" , params )
ctx = llama_cpp . llama_new_context_with_model ( model , params )
max_tokens = params . n_ctx
# use ctypes arrays for array params
tokens = ( llama_cpp . llama_token * int ( max_tokens ))()
n_tokens = llama_cpp . llama_tokenize ( ctx , b"Q: Name the planets in the solar system? A: " , tokens , max_tokens , llama_cpp . c_bool ( True ))
llama_cpp . llama_free ( ctx )
Consulte la carpeta de ejemplos para obtener más ejemplos sobre el uso de la API de bajo nivel.
La documentación está disponible a través de https://llama-cpp-python.readthedocs.io/. Si encuentra algún problema con la documentación, abra un problema o envíe un PR.
Este paquete está en desarrollo activo y agradezco cualquier contribución.
Para comenzar, clone el repositorio e instale el paquete en modo editable/desarrollo:
git clone --recurse-submodules https://github.com/abetlen/llama-cpp-python.git
cd llama-cpp-python
# Upgrade pip (required for editable mode)
pip install --upgrade pip
# Install with pip
pip install -e .
# if you want to use the fastapi / openapi server
pip install -e .[server]
# to install all optional dependencies
pip install -e .[all]
# to clear the local build cache
make clean
También puede probar confirmaciones específicas de llama.cpp
verificando la confirmación deseada en el submódulo vendor/llama.cpp
y luego ejecutando make clean
y pip install -e .
de nuevo. Cualquier cambio en la API llama.h
requerirá cambios en el archivo llama_cpp/llama_cpp.py
para que coincida con la nueva API (es posible que se requieran cambios adicionales en otros lugares).