llm.int8() – 8-bit Matrix Multiplication for Transformers at Scale

llm.int8() – 8-bit Matrix Multiplication for Transformers at Scale llm.int8() – 8-bit Matrix Multiplication for Transformers at Scale

llm.int8() - 8-bit Matrix Multiplication for Transformers at Scalelink image 8

Este caderno foi traduzido automaticamente para torná-lo acessível a mais pessoas, por favor me avise se você vir algum erro de digitação..

Na postagem LLMs quantization, explicamos a importância da quantização dos LLMs para economizar memória. Também explicamos que há uma forma de quantização que é a quantização de ponto zero, que consiste em transformar os valores dos parâmetros dos pesos linearmente, mas isso tem o problema da degradação dos modelos de linguagem a partir do momento em que eles ultrapassam 2,7 bilhões de parâmetros.

llm.int8()-degradação

Quantização de vetoreslink image 9

Como a quantização de todos os parâmetros dos modelos produz erros nos modelos de idiomas grandes, o que eles propõem no artigo llm.int8() é realizar a quantização de vetores, ou seja, separar as matrizes dos pesos em vetores, de modo que alguns desses vetores possam ser quantizados em 8 bits, enquanto outros não. Assim, aqueles que podem ser quantizados em 8 bits são quantizados e as multiplicações de matriz são realizadas no formato INT8, enquanto os vetores que não podem ser quantizados são mantidos no formato FP16 e as multiplicações são realizadas no formato FP16.

Vamos dar uma olhada em um exemplo

Suponha que tenhamos a matriz

llm.int8()-A

e queremos multiplicá-lo pela matriz

llm.int8()-B

Definimos um valor limite e todas as colunas da primeira matriz que têm um valor maior do que esse limite são deixadas no formato FP16; as linhas equivalentes às linhas da primeira matriz na segunda matriz também são deixadas no formato FP16.

Explicando melhor, como a segunda e a quarta colunas da primeira matriz (colunas amarelas) têm valores maiores que um determinado limite, a segunda e a quarta linhas da segunda matriz (linhas amarelas) são deixadas no formato FP16.

No caso de haver valores limiares na segunda matriz, o mesmo seria feito, por exemplo, se na segunda matriz uma linha tivesse um valor maior que um limiar, ela seria deixada no formato FP16, e essa coluna na primeira matriz seria deixada no formato FP16.

As linhas e colunas restantes que não são deixadas no formato FP16 são quantizadas em 8 bits e as multiplicações são realizadas no formato INT8.

Portanto, dividimos a primeira matriz em duas matrizes

llm.int8()-A_separated

E a segunda matriz nas duas matrizes

llm.int8()-B_separated

Multiplicamos as matrizes em INT8 em um lado

llm.int8()-AxB-int8

e aqueles no formato FP16, por outro lado

llm.int8()-AxB-fp16

Como pode ser visto, a multiplicação das matrizes no formato INT8 nos dá uma matriz de tamanho 3x2, e a multiplicação das matrizes no formato FP16 nos dá outra matriz de tamanho 3x2, de modo que, se as somarmos

llm.int8()-fp16+int8

É interessante notar que ele apresenta o mesmo resultado como se tivéssemos multiplicado as matrizes originais.

llm.int8()-AxB

Para ver por que isso acontece, se desenvolvermos o produto vetorial das duas matrizes originais

llm.int8()-AxB-explained

Vemos que a separação que fizemos não traz problemas.

Portanto, podemos concluir que é possível separar linhas e colunas de matrizes para realizar multiplicações de matrizes. Essa separação será feita quando qualquer elemento da linha ou coluna for maior que um valor limite, de modo que as linhas ou colunas que não tiverem um valor maior que esse limite serão codificadas em INT8, ocupando apenas um byte, e as linhas ou colunas que tiverem um elemento maior que esse limite serão passadas para FP16, ocupando 2 bytes. Dessa forma, não teremos problemas de arredondamento, pois os cálculos que fizermos em INT8 serão feitos com valores que não ultrapassem o intervalo de 8 bits.

Valor limiar αlink image 10

Como dissemos, vamos separar em linhas e colunas que tenham algum elemento maior que um valor limite, mas qual valor limite devemos escolher? Os autores do artigo fizeram experimentos com vários valores e determinaram que o valor limite deveria ser α=6. Acima desse valor, eles começaram a obter degradações nos modelos de linguagem.

Uso de llm.int8()link image 11

Vamos ver como quantificar um modelo com llm.int8() com a biblioteca de transformadores. Para fazer isso, você precisa ter o bitsandbytes instalado.

pip install bitsandbytes
      ```
      

Carregamos um modelo de parâmetro 1B duas vezes, uma vez da maneira normal e a segunda vez quantificando-o com llm.int8().

	
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
checkpoint = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint).to(device)
model_8bit = AutoModelForCausalLM.from_pretrained(checkpoint, device_map="auto", load_in_8bit=True)
Copy
	
The `load_in_4bit` and `load_in_8bit` arguments are deprecated and will be removed in the future versions. Please, pass a `BitsAndBytesConfig` object in `quantization_config` argument instead.

Vemos a quantidade de memória que cada um dos modelos ocupa

	
model.get_memory_footprint()/(1024**3), model_8bit.get_memory_footprint()/(1024**3)
Copy
	
(4.098002195358276, 1.1466586589813232)

Como pode ser visto, o modelo quantizado ocupa muito menos memória.

Vamos agora fazer um teste de geração de texto com os dois modelos.

	
input_tokens = tokenizer("Hello my name is Maximo and I am a Machine Learning Engineer", return_tensors="pt").to(device)
input_tokens.input_ids
Copy
	
tensor([[ 1, 15043, 590, 1024, 338, 5918, 4200, 322, 306, 626,
263, 6189, 29257, 10863, 261]], device='cuda:0')

Vemos o resultado com o modelo normal

	
import time
t0 = time.time()
max_new_tokens = 50
outputs = model.generate(
input_ids=input_tokens.input_ids,
attention_mask=input_tokens.attention_mask,
max_length=input_tokens.input_ids.shape[1] + max_new_tokens,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
print(time.time() - t0)
Copy
	
Hello my name is Maximo and I am a Machine Learning Engineer. I am currently working at [Company Name] as a Machine Learning Engineer. I have a Bachelor's degree in Computer Science from [University Name] and a Master's degree in Computer Science from [University Name]. I
1.7616662979125977

E agora com o modelo quantizado

	
t0 = time.time()
max_new_tokens = 50
outputs = model_8bit.generate(
input_ids=input_tokens.input_ids,
attention_mask=input_tokens.attention_mask,
max_length=input_tokens.input_ids.shape[1] + max_new_tokens,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
print(time.time() - t0)
Copy
	
Hello my name is Maximo and I am a Machine Learning Engineer. I am currently working at [Company Name] as a Machine Learning Engineer. I have a Bachelor's degree in Computer Science from [University Name] and a Master's degree in Computer Science from [University Name]. I
9.100712776184082

Vemos duas coisas: por um lado, obtemos o mesmo texto na saída, portanto, com um modelo muito menor, podemos obter a mesma saída; no entanto, o modelo quantizado leva muito mais tempo para ser executado, portanto, se você precisar usar esse modelo em tempo real, isso não seria aconselhável.

Isso é contraditório, porque poderíamos pensar que um modelo menor teria que ser executado mais rapidamente, mas temos que pensar que, na realidade, os dois modelos, o normal e o quantizado, executam as mesmas operações, apenas um executa todas as operações em FP32 e o outro as executa em INT8 e FP16, mas o modelo quantizado tem que procurar linhas e colunas com valores maiores que o valor limite, separá-las, executar as operações em INT8 e FP16 e, em seguida, juntar os resultados novamente, de modo que o modelo quantizado leva mais tempo para ser executado.

Continuar lendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

Você já conversou com um LLM e ele lhe respondeu algo que parece ter bebido café de máquina a noite toda? 😂 Isso é o que chamamos de alucinação no mundo dos LLMs! Mas não se preocupe, pois não é que seu modelo de linguagem esteja louco (embora às vezes possa parecer isso 🤪). A verdade é que os LLMs podem ser um pouco... criativos quando se trata de gerar texto. Mas graças ao DoLa, um método que usa camadas de contraste para melhorar a viabilidade dos LLMs, podemos evitar que nossos modelos de linguagem se transformem em escritores de ficção científica 😂. Nesta publicação, explicarei como o DoLa funciona e mostrarei um exemplo de código para que você possa entender melhor como tornar seus LLMs mais confiáveis e menos propensos a inventar histórias. Vamos salvar nossos LLMs da loucura e torná-los mais úteis! 🚀

Últimos posts -->

Você viu esses projetos?

Subtify

Subtify Subtify

Gerador de legendas para vídeos no idioma que você desejar. Além disso, coloca uma legenda de cor diferente para cada pessoa

Ver todos os projetos -->

Quer aplicar IA no seu projeto? Entre em contato!

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Ver todos os contêineres -->

Quer aplicar IA no seu projeto? Entre em contato!

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

Dataset com piadas em inglês

opus100

Dataset com traduções de inglês para espanhol

netflix_titles

Dataset com filmes e séries da Netflix

Ver mais datasets -->