Un ejemplo del enfoque de RWKV para los modelos de idiomas escritos en Rust por alguien que sabe muy poco sobre las redes matemáticas o neuronales. La versión inicial se basó mucho en la increíble información y el ejemplo de Python aquí: https://johanwind.github.io/2023/03/23/rwkv_details.html
Vea también el repositorio del creador de RWKV: https://github.com/blinkdl/chatrwkv/
Si se carga en modo de 32 bits, usa mucha memoria. El modelo 3B utiliza alrededor de 11 GB de RAM y el 7b uno podría caber en una máquina de 32 GB, está dispuesto a cerrar otras aplicaciones o tratar algunos intercambios. Incluso la carga en el modo de 8 bits usa una buena cantidad de memoria, pero desplegará una vez que se haya completado la carga.
Necesitarás óxido y configuración de carga: https://www.rust-lang.org/learn/get-started
Deberá descargar un modelo RWKV. Aquí hay un enlace para comenzar (alrededor de 820 MB): https://huggingface.co/blinkdl/rwkv-4-pile-430m/resolve/main/rwkv-4-pile-430m-20220808-8066.pth.pth
También el tokenizador aquí: https://github.com/blinkdl/chatrwkv/blob/main/20b_tokenizer.json
Los archivos del modelo Pytorch se pueden cargar directamente. Si los archivos terminan con .pt o .pth , se cargará como un modelo Pytorch. Si termina con .st o .safetensors entonces se cargará como Safetensors. Nota : El soporte de Pytorch es actualmente experimental y puede no funcionar correctamente. Es probable que reciba un error inmediatamente si hay un problema, por lo que no debería ser peligroso probar ese enfoque. Si lo desea, puede deshabilitar la función torch y solo crear soporte para archivos de formato Safetensors.
Después de eso, deberías poder cargo run --release . Puede intentar compilar sin --release pero es probable que todo sea increíblemente lento. Pruebe también cargo run --release -- --help para ver las opciones de línea de comandos.
Nota : El valor predeterminado es usar todos los núcleos lógicos, consulte las opciones de línea de comandos.
Opcionalmente, puede convertir el archivo del modelo .pth en formato Safetensors. Mire utils/pth_to_safetensors.py para un ejemplo. Para hacer esto, necesitará los paquetes safetensors y torch Python configurados. Sugiero hacer esto en un entorno virtual. Actualmente no hay una gran ventaja en este paso, ya que los archivos de antorcha se pueden cargar directamente en la versión actual.
El soporte GGML actualmente necesita una versión parcheada de ggml y ggml-sys del proyecto llama-rs .
El Cargo.toml está configurado para apuntar a la rama correcta en mi bifurcación, pero esto desaparecerá una vez que los cambios necesarios se fusionen en GGML. Naturalmente, este repositorio se actualizará, pero tenga en cuenta que sus compilaciones pueden comenzar a fallar eventualmente si está tratando de usar una versión anterior, ya que eventualmente se eliminará esa rama.
Nota: Esta parte está un poco anticuada ahora. Sin embargo, todavía recomiendo leer los enlaces a continuación. Tenga en cuenta también que esa descripción se basa en una versión más simple del modelo RWKV con solo cuatro estados por capa. La versión completa tiene cinco.
Aquí hay una descripción (posiblemente incorrecta) de alto nivel de los pasos involucrados en la evaluación del modelo. Deberá consultar la fuente en smolrwkv/src/simple/model.rs para que esto tenga sentido.
Además, considere fuertemente leerlos primero:
Por cierto, un hecho divertido: "Tensor" suena realmente elegante, pero básicamente es solo una matriz. Un tensor unidimensional es solo una matriz unidimensional, un tensor dimensional bidimensional es una matriz bidimensional. Pueden tener propiedades especiales (como ser inmutable), pero eso no importa para comprender el concepto en general. Si conoce matrices, ya tiene la idea general de tensores.
Para evaluar un token:
x de ln0 .x a cada capa secuencialmente, usando la capa x generada para la siguiente.x que se alimentó.ln1 a x y alimente a la mezcla de tiempo. Esto usa tensor de la parte FFN del modelo.tm_state desde el estado de la capa y llámelo last_x . (¿Por qué? ¡Quién sabe!)tm_num y tm_den como last_num , last_den .tm_[state,num,den] así que actualice su estado de capa con estos.x que resultó de los cálculos.x desde el tiempo Mezcla a x ( x += time_mixing_x ).ln2 a x y alimente a la mezcla de canales. Esto utiliza tensores de la parte de red Feed Forward del modelo.cm_state desde el estado de la capa y llámelo last_x .cm_state , así que actualice el estado de la capa.x que resultó del cálculo de mezcla de canales.x desde la mezcla de canales a x .x que fue el resultado después de evaluar la última capa.El modelo tiene una lista de tokens que "sabe". A veces, un token es igual a una palabra, a veces es solo parte de una palabra. Por lo general, hay una gran cantidad de tokens, en el rango de 30,000-60,000. Creo que los modelos RWKV actuales tienen 50,277 tokens. De todos modos, obtendrá una lista de 50,277 números de punto flotante después de ejecutar el modelo.
El valor más alto de esa lista es el token que el modelo predice es la continuación más probable, etc. Si generó una lista ordenada de las 10-40 más o menos probabilidades de tokens y selecciona una al azar, obtendrá una salida bastante razonable, relativamente hablando. Justo decir que un pequeño modelo de 430m no produce la salida más razonable en general.
Buena explicación de cómo manejar el siguiente paso una vez que tenga la lista de probabilidades: https://huggingface.co/blog/how-to-generate
Hay varias cosas matemáticas complicadas involucradas en la evaluación del modelo, pero lo único que realmente importa es la multiplicación de matriz ( pardot en la fuente). En el caso de RWKV, es la multiplicación del vector matriz (una matriz 2D multiplicada con una matriz 1D). > El 90% del tiempo dedicado a evaluar el modelo está en esas llamadas de multiplicación de matriz.
En modo no GGM, el manejo de matemáticas/matriz aquí usa la caja ndarray . Proporciona una función .dot , sin embargo, esto nunca calculará una multiplicación de vector matriz en paralelo a pesar de que la caja afirma que el soporte de roscado. Debido a que este cálculo es tan crítico para el rendimiento, terminé escribiendo mi propia función para dividir el cálculo en trozos y ejecutarlo en paralelo. Vea las funciones en el módulo dumdot en smolrwkv/src/util.rs .
El hecho de que obtenga una lista de probabilidades y ninguna "respuesta" definitiva del modelo parece un contraargumento decente a la idea de que los LLM son o podrían ser conscientes de alguna manera. Cuando miras la salida de un LLM, muchas veces ni siquiera vas a ver el token más probable. Además, un hecho divertido: cuando alimenta un aviso a un modelo, se le ocurre una lista de probabilidades como cuando le pide una respuesta. Sin embargo, esas probabilidades se desechan, excepto el resultado después de procesar la última token de inmediato.
Aviso en negrita. Entonces, ¿son las serpientes o perros de los dragones? ¡El mundo puede nunca saber!
* Loading tokenizer from: ./20B_tokenizer.json
* Loading model from: ./RWKV-4-Pile-430M-20220808-8066.safetensors
* Discovering model structure.
- Loading layer 1/24
[...]
- Loading layer 24/24
* Loading non-layer tensors.
* Loaded: layers=24, embed=1024, vocab=50277
En un hallazgo impactante, los científicos descubrieron una manada de dragones que vivían en un valle remoto y previamente inexplorado, en el Tíbet. Aún más sorprendente para los investigadores fue el hecho de que los Dragones hablaban chino perfecto.
Todos estos dragones hablaban diferentes dialectos y estos dialectos no coincidían con el idioma nativo de los perros.
En un intento por descifrar lo que hablaban estos dragones, llamaron a los dragones y descubrieron que su lenguaje era diferente de los humanos.
"Los dragones entendieron las palabras humanas y más precisamente lenguas humanas. Los dragones hablaban el lenguaje humano. También entendieron las reglas para los chinos", dijo el equipo de investigación a Mongabay.
Al realizar la investigación, esperan arrojar luz sobre la misteriosa historia de los dragones en las remotas regiones remotas del mundo, especialmente en el Tíbet.
El proyecto de investigación, publicado en la revista Open Science, también muestra que los dragones son, de hecho, reptiles, o también conocidos como serpientes de árboles.
Dragón, no serpiente
Según el equipo de investigación, los dragones encontrados en el Tíbet son una raza de perros, no un reptil.
Si bien el equipo de investigación aún no pudo encontrar ninguna explicación de por qué estos dragones viven en el Tíbet, se creía previamente que probablemente estaban presentes en una tierra cerca de la meseta tibetana.
"Los dragones viven allí como parte de la gran meseta de Qinghai-Tibet que está casi completamente intacta y toda la meseta de Qinghai-Tibet se convirtió gradualmente en un estado agrícola. Por lo tanto, tienen un patrón distintivo de masticación en los árboles, y probablemente los animales no son demasiado grandes para mantenerse en la naturaleza", explicaron los investigadores.