Um exemplo da abordagem RWKV para modelos de idiomas escritos em ferrugem por alguém que sabe muito pouco sobre redes de matemática ou neurais. A versão inicial foi muito, muito, muito baseada nas informações surpreendentes e no Python Exemplo aqui: https://johanwind.github.io/2023/03/23/rwkv_details.html
Veja também o repositório do RWKV Creator: https://github.com/blinkdl/chatrwkv/
Se carregar no modo de 32 bits, ele usa muita memória. O modelo 3B usa em torno de 11 GB de RAM e o 7B pode se encaixar em uma máquina de 32 GB, você está disposto a fechar outros aplicativos ou lidar com algumas trocas. Mesmo o carregamento no modo de 8 bits usa uma quantidade razoável de memória, mas diminuirá assim que o carregamento for concluído.
Você precisará de ferrugem e carga configurada: https://www.rust-lang.org/learn/get-started
Você precisará baixar um modelo RWKV. Aqui está um link para você começar (cerca de 820 MB): https://huggingface.co/blinkdl/rwkv-4-pile-430m/resolve/main/rwkv-4-pile-430m-20220808-8066.pth
Também o tokenizer aqui: https://github.com/blinkdl/chatrwkv/blob/main/20b_tokenizer.json
Os arquivos do modelo pytorch podem ser carregados diretamente. Se os arquivos terminarem com .pt ou .pth ele será carregado como um modelo Pytorch. Se terminar com .st ou .safetensors , será carregado como SafeTetensors. NOTA : O suporte a Pytorch é atualmente experimental e pode não funcionar corretamente. Você provavelmente apenas receberá um erro imediatamente se houver um problema, por isso não deve ser perigoso tentar essa abordagem. Se desejar, você pode desativar o recurso torch e criar suporte apenas para arquivos de formato de SafeTetens.
Depois disso, você deve ser capaz de cargo run --release . Você pode tentar compilar sem --release , mas é provável que tudo seja incrivelmente lento. Experimente também cargo run --release -- --help para ver as opções de linha de comando.
Nota : o padrão é usar todos os núcleos lógicos, consulte as opções de linha de comando.
Opcionalmente, você pode converter o arquivo .pth Model em formato SafeTeSors. Veja utils/pth_to_safetensors.py por exemplo. Para fazer isso, você precisará dos pacotes safetensors e torch Python configurados. Eu sugiro fazer isso em um ambiente virtual. Atualmente, não há muita vantagem para esta etapa, pois os arquivos da tocha podem ser carregados diretamente na versão atual.
Atualmente, o GGML Support precisa de uma versão corrigida do ggml e ggml-sys do projeto llama-rs .
A Cargo.toml é configurada para apontar para o ramo correto no meu garfo, mas isso desaparecerá assim que as alterações necessárias forem mescladas no GGML. Naturalmente, este repositório será atualizado, mas lembre -se de que seus compilos podem começar a falhar eventualmente se você estiver tentando usar uma versão mais antiga, pois eventualmente essa filial será removida.
Nota: Esta parte está meio desatualizada agora. Eu ainda recomendo ler os links abaixo. Observe também que essa descrição é baseada em uma versão mais simples do modelo RWKV com apenas quatro estados por camada. A versão completa tem cinco.
Aqui está uma descrição (possivelmente errada) de alto nível das etapas envolvidas na avaliação do modelo. Você precisará consultar a fonte no smolrwkv/src/simple/model.rs para fazer sentido.
Além disso, considere fortemente lê -las primeiro:
A propósito, Curiosidade: "Tensor" parece muito chique, mas é basicamente apenas uma matriz. Um tensor unidimensional é apenas uma matriz unidimensional, um tensor bidimensional dimensional é uma matriz bidimensional. Eles podem ter propriedades especiais (como ser imutável), mas isso não importa para entender o conceito em geral. Se você conhece as matrizes, já tem a ideia geral de tensores.
Para avaliar um token:
x a partir de ln0 .x para cada camada sequencialmente, usando o x a camada gerada para a próxima.x que foi se alimentado.ln1 a x e alimente -o para a mistura de tempo. Isso usa o tensor da parte FFN do modelo.tm_state do estado da camada e chame -o de last_x . (Por quê? Quem sabe!)tm_num e tm_den como last_num , last_den .tm_[state,num,den] , portanto, atualize o estado da camada com eles.x que resultou dos cálculos.x da mistura de tempo para x ( x += time_mixing_x ).ln2 a x e alimente -o para canalizar a mistura. Isso usa tensores da parte da rede de feed para frente do modelo.cm_state do estado da camada e chame -o de last_x .cm_state , então atualize o estado da camada.x que resultou do cálculo da mistura de canais.x da mistura de canal para x .x que foi o resultado depois de avaliar a última camada.O modelo tem uma lista de tokens que "conhece". Às vezes, um token é igual a uma palavra, às vezes é apenas parte de uma palavra. Geralmente, há um grande número de tokens, na faixa de 30.000 a 60.000. Acredito que os atuais modelos RWKV têm 50.277 tokens. De qualquer forma, você receberá uma lista de 50.277 números de pontos flutuantes depois de executar o modelo.
O valor mais alto dessa lista é o token que o modelo prevê é a continuação mais provável e assim por diante. Se você gerou uma lista classificada dos 10-40 melhores probabilidades de token e selecionar uma aleatoriamente, obterá uma saída razoavelmente razoável, relativamente falando. É justo dizer que um pequeno modelo de 430m não produz a saída mais razoável em geral.
Boa explicação de como lidar com a próxima etapa depois de ter a lista de probabilidades: https://huggingface.co/blog/how-to-generate
Há várias coisas de matemática complicadas envolvidas na avaliação do modelo, mas a única coisa que realmente importa é a multiplicação da matriz ( pardot na fonte). No caso do RWKV, a multiplicação do vetor de matriz (uma matriz 2D multiplicada com uma matriz 1D). > 90% do tempo gasto na avaliação do modelo está nessas chamadas de multiplicação de matriz.
No modo não-GGML, o manuseio de matemática/matriz aqui usa o ndarray CRATE. Ele fornece uma função .dot , no entanto, isso nunca calculará uma multiplicação de vetor de matriz em paralelo, mesmo que o suporte de encadeamento de reivindicações de caixa. Como esse cálculo é muito crítico para o desempenho, acabei escrevendo minha própria função para dividir o cálculo em pedaços e executá -lo em paralelo. Consulte as funções no módulo dumdot em smolrwkv/src/util.rs .
O fato de você receber uma lista de probabilidades de volta e nenhuma "resposta" definitiva do modelo parece um contra -argumento decente à idéia de que os LLMs são ou podem estar conscientes de alguma forma. Quando você olha para a saída de um LLM, muitas vezes você nem verá o token mais provável. Além disso, é divertido: quando você alimenta um prompt para um modelo, ele cria uma lista de probabilidades, assim como quando você está pedindo uma resposta. No entanto, essas probabilidades são jogadas fora, exceto o resultado após o processamento do último token de prompt.
Rápido em negrito. Então, são as cobras ou cães dos dragões? O mundo pode 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
Em uma descoberta chocante, o cientista descobriu um rebanho de dragões que vivem em um vale remoto e anteriormente inexplorado, no Tibete. Ainda mais surpreendente para os pesquisadores foi o fato de os dragões falarem chineses perfeitos.
Todos esses dragões falavam dialetos diferentes e esses dialetos não correspondem à língua nativa dos cães.
Na tentativa de decifrar o que esses dragões falavam, eles chamavam os dragões e descobriram que sua linguagem era diferente do humano.
"Os dragões entenderam as palavras humanas e as línguas mais precisamente humanas. Os dragões falavam a linguagem humana. Eles também entenderam as regras para os chineses", disse a equipe de pesquisa a Mongabay.
Ao conduzir a pesquisa, eles esperam esclarecer a misteriosa história dos dragões nas regiões remotas e remotas do mundo, especialmente no Tibete.
O projeto de pesquisa, publicado na revista Open Science, também mostra que os dragões são, de fato, répteis ou cobras de árvores.
Dragão, não cobra
Segundo a equipe de pesquisa, os dragões encontrados no Tibete são uma raça de cães, não um réptil.
Embora a equipe de pesquisa ainda não pudesse apresentar nenhuma explicação sobre o motivo pelo qual esses dragões vivem no Tibete, acreditava -se anteriormente que eles provavelmente estavam presentes em terras próximas ao platô tibetano.
"Os dragões vivem lá como parte do grande platô de Qinghai-Tibet, que é quase completamente não perturbado e todo o platô de Qinghai-Tibet foi gradualmente convertido em um estado agrícola. Portanto, eles têm um padrão distinto de mastigar as árvores, e provavelmente os animais não são grandes demais para serem mantidos na natureza", explicaram os pesquisadores.