Prévia do material em texto
STEPHEN WOLFRAM
O que faz o
ChatGPT
e como funciona
Ficha Técnica
Título: O Que Faz o ChatGPT e Como Funciona
Título original: What Is ChatGPT Doing ... and Why Does It Work?
Autor: Stephen Wolfram
Editora: Rita Fazenda
Tradução: António Portugal
Revisão: Sebastião Veloso
Paginação: Carla Paulo
Capa: Maria Manuel Lacerda
ISBN: 9789896618322
CASA DAS LETRAS
uma editora do grupo Leya
Rua Cidade de Córdova, n.º 2
2610-038 Alfragide – Portugal
Tel. (+351) 21 427 22 00
Fax. (+351) 21 427 22 01
© 2023 Stephen Wolfram. Originalmente publicado em língua inglesa por
Wolfram Media 100 Trade Center Dr. 6th Floor, Champaign Illinois 61820,
USA. Esta edição é publicada por acordo com DropCap Inc.
Todos os direitos reservados de acordo com a legislação em vigor.
www.leya.pt
http://www.leya.pt/
Índice
Capa
Ficha Técnica
Prefácio
O QUE É QUE O CHATGPT ESTÁ A FAZER… E PORQUE É QUE
FUNCIONA
Ele só Adiciona uma Palavra de Cada Vez
De Onde Vêm as Probabilidades?
O que é um Modelo?
Modelos para Tarefas Semelhantes a Humanos
Redes Neurais
Aprendizagem Automática e o Treino de Redes Neurais
A Prática e o Conhecimento Fundamental do Treino de Redes
Neurais
«É Certo que uma Rede Grande o Suficiente Pode Fazer Qualquer
Coisa!»
O Conceito de Embeddings
Por dentro do ChatGPT
Treinar o ChatGPT
Para Além do Treino Básico
O que é que possibilita ao ChatGPT funcionar?
Espaço de Significado e as «Leis de Newton» da Semântica
A Gramática Semântica e o Poder da Linguagem Computacional
Então… O que é que o ChatGPT está a Fazer, e Porque é que
Funciona?
Agradecimentos
clbr://internal.invalid/book/OEBPS/cover.xhtml
O WOLFRAM|ALPHA COMO A FORMA DE TRAZER OS
SUPERPODERES DO CONHECIMENTO COMPUTACIONAL PARA
O CHATGPT
ChatGPT e Wolfram|Alpha
Um Exemplo Básico
Mais alguns Exemplos
O Caminho a Seguir
Recursos Adicionais
Por opção decidimos não traduzir as legendas/palavras dos quadros
constantes do livro porque os resultados obtidos pelo autor foram
conseguidos utilizando o Inglês e seriam obrigatoriamente diferentes se fosse
em Português.
PREFÁCIO
Este curto livro é uma tentativa de explicar, a partir dos primeiros
princípios, o que é o ChatGPT e como funciona. De certa forma é uma
história sobre Tecnologia. Mas é também uma história sobre Ciência. Assim
como sobre Filosofia. Para conseguir contar esta história teremos de reunir
um leque de ideias e descobertas feitas ao longo de vários séculos.
Para mim é emocionante ver tantas coisas que me interessam há muito
tempo juntarem-se numa explosão de progresso repentino. Desde
comportamentos complexos de programas simples, até à essência da
linguagem e do sentido; e também dos aspetos práticos de grandes sistemas
de computadores – todos estes fazem parte da história do ChatGPT.
O ChatGPT é baseado no conceito de redes neurais – concebido nos anos
40 como uma idealização do modo de funcionamento dos cérebros. Eu
mesmo programei a minha primeira rede neural em 1983 – e não fazia nada
de interessante. Mas passados 40 anos, com computadores que são
efetivamente um milhão de vezes mais rápidos, com milhares de milhões de
páginas de texto na Internet, e uma série de inovações no ramo da engenharia;
a situação é bastante diferente. E – para a surpresa de todos – uma rede neural
que é um milhar de milhão de vezes maior do que aquela que eu tinha em
1983 é capaz de fazer aquela coisa que era pensada ser unicamente humana:
de gerar linguagem humana com sentido.
Este livro consiste em dois artigos que eu escrevi pouco depois da estreia
do ChatGPT. O primeiro é uma explicação do ChatGPT e da sua capacidade
de fazer a coisa muito humana de gerar linguagem. O segundo é um olhar
sobre a possibilidade do ChatGPT ser capaz de utilizar ferramentas
computacionais para ir além daquilo que os humanos conseguem fazer e, em
particular, de ser capaz de aproveitar os «superpoderes» de conhecimentos
computacionais do nosso sistema Wolfram|Alpha.
O ChatGPT ainda só foi lançado há três meses e ainda estamos a perceber
as suas implicações, tanto práticas assim como intelectuais. Mas, para já, a
sua chegada é um lembrete que mesmo depois de tudo ser inventado e
descoberto, as surpresas ainda são possíveis.
Stephen Wolfram
Fevereiro de 2023
O QUE É QUE O CHATGPT ESTÁ A FAZER … E PORQUE É QUE
FUNCIONA
Ele só Adiciona uma Palavra de Cada Vez
O facto de o ChatGPT conseguir gerar algo que aparenta ser escrito por
um humano é notável e inesperado. Mas como é que o faz? E como é que
funciona? O meu objetivo é de dar uma ideia geral daquilo que se passa
dentro do ChatGPT – e depois explorar porque é que consegue criar aquilo
que podemos considerar texto com sentido tão bem. Devo dizer desde já que
me vou focar no panorama geral daquilo que se passa – e apesar de
mencionar alguns pormenores de engenharia, não os vou aprofundar muito.
(E a essência do que vou dizer aplica-se tão bem a outros «modelos de
linguagem grande» [em inglês large language model ou LLMs] actuais como
ao ChatGPT).
A primeira coisa a explicar é que o ChatGPT, fundamentalmente, está a
tentar produzir uma «continuação razoável» do texto que ele tenha produzido
até esse momento, onde «razoável» significa «o que seria esperado escrever
depois de ler o que está escrito em milhares de milhões de páginas Web, etc.»
Digamos que temos a frase: «A melhor coisa sobre inteligência artificial
(IA) é a sua capacidade de». Imaginemos analisar milhares de milhões de
páginas de texto escrito por humanos (por exemplo na Internet e em livros
digitalizados) e encontrar todas as instâncias desta mesma frase – e depois
verificar quais palavras a sucedem e com que frequência. O ChatGPT
efetivamente faz algo deste género, exceto que (como explicarei) não o faz
com texto literal; ele procura coisas que de certa forma «coincidem em
significado». Mas o resultado final que produz é uma lista ordenada de
palavras que podem continuar a frase juntamente com «probabilidades»:
O mais notável é que quando o ChatGPT faz algo como escrever um
ensaio, o que está, essencialmente, é perguntar-se repetidamente «dado o
texto até este momento, qual deverá ser a próxima palavra?» – e adiciona
uma palavra de cada vez. (Mais precisamente, como explicarei, ele adiciona
um token, que pode ser apenas parte de uma palavra, e é por isso que por
vezes consegue «inventar novas palavras».)
Então, a cada passo ele obtém uma lista de palavras e as suas respetivas
probabilidades. Mas qual destas é que deve ser escolhida para acrescentar ao
ensaio (ou o quer que seja) que esteja a escrever? É possível pensar que devia
ser a palavra «melhor classificada» (i.e. a palavra que tem a maior
«probabilidade» associada). E é neste momento que começamos a ver um
pouco de vudu a emergir. Porque, por alguma razão – que talvez um dia
venhamos a ter conhecimento científico para a perceber –, se escolhermos
sempre a palavra melhor classificada recebemos, tipicamente, um texto
«sintético», que aparenta nunca «mostrar qualquer tipo de criatividade» (e às
vezes repete-se totalmente). Mas, se por vezes escolhermos palavras pior
classificadas (ao acaso) temos um texto que fica «mais natural».
O facto de existir aleatoriedade significa que, utilizando a mesma pergunta
várias vezes, é provável receber respostas diferentes de cada vez. E,
mantendo a ideia de vudu, existe um parâmetro chamado «temperatura» que
determina com que frequência é que se recorre às palavras pior classificadas,
e, para a criação de ensaios, acontece que uma «temperatura» de 0.8 aparenta
ser a melhor. (É importante sublinhar que não há nenhuma teoria a ser usada
para este valor; é uma questão de tentativa-erro e ver que este valor é o
melhor na prática. E, por exemplo, o conceito de «temperatura» existe porque
estão a ser usadas distribuições exponenciais, conhecidas da Física
Estatística, mas não há nenhuma ligação «física» – pelo menos tanto quanto
sabemos)
Antes de continuar, devo explicar que, para efeitos de exposição, na maior
parte dos casos, não vou utilizar o sistema completo do ChatGPT;de
que o objetivo é de continuar o texto de forma «razoável» e com base naquilo
que viu no treino (o que consiste em ver milhares de milhões de páginas de
Internet, etc.). Então, em qualquer ponto, tem uma certa quantidade de texto –
e o seu objetivo é arranjar uma escolha apropriada para o próximo token a
adicionar.
Funciona em três fases simples. Primeiro, pega na sequência de tokens que
correspondem ao texto que já tem e encontra um embedding (i.e. um vetor de
números) que os representa. Depois, opera neste embedding – na «forma
padrão das redes neurais», com valores a «ecoarem» por camadas sucessivas
na rede – para produzir um novo embedding (i.e. um novo vetor de números).
Após isto, seleciona a parte final de cada vetor e a partir dele gera um vetor
de aproximadamente 50.000 valores que, por sua vez, se transformam nas
probabilidades para os diferentes tokens possíveis. (E sim, acontece que há
mais ou menos o mesmo número de tokens usados e de palavras mais comuns
na língua inglesa, mas apenas cerca de 3000 destes tokens são palavras
completas, o resto são fragmentos de palavras).
Um ponto crítico é que cada parte deste processo é implementada por uma
rede neural cujos pesos são determinados por um treino da rede de ponta-a-
ponta. Por outras palavras, à exceção da arquitetura geral nada é «definido
explicitamente»; é tudo «aprendido» a partir dos dados de treino.
Há, no entanto, muitos detalhes na forma como a arquitetura é configurada
– refletindo todo o tipo de experiências e conhecimento de redes neurais. E –
apesar de isto ser ir ler as letra pequenas – eu acho que é útil falar sobre
alguns destes detalhes, pelo menos para ficar com uma ideia de o que é
necessário para fazer algo como o ChatGPT.
Primeiro vem o módulo de embedding. Temos aqui um esquema em
representação Wolfram para o módulo para o GPT-2:
A entrada é um vetor de n tokens (representados, como na secção anterior,
por números inteiros de 1 a cerca de 50.000). Cada um destes tokens é
convertido (por uma rede neural de uma camada) num vetor de embedding
(om o valor de 768 elementos no GPT-2 e de 12.288 para o CPT-3 do
ChatGPT). Entretanto, há uma «via secundária» que pega na sequência de
posições (números inteiros) para os tokens e, a partir desses inteiros, cria
outro vetor de embedding. Finalmente, os vetores de embedding do valor do
token e de posição são somados – produzindo a sequência final de vetores de
embedding do modelo de embedding.
Porque é que adicionamos o valor do token e de posição? Não acho que
haja uma ciência em particular para justificar isto. É só que várias coisas
foram experimentadas e esta é a que parece funcionar. E faz parte do
conhecimento fundamental de redes neurais que – de certa forma – desde que
a configuração seja «aproximadamente certa» geralmente é possível chegar
aos detalhes ao fazer treino suficiente, mesmo sem precisar de «compreender,
em termos de de engenharia», como é que a rede neural se conseguiu
configurar.
Isto é o que o módulo de embedding faz ao operar na string hello hello
hello hello hello hello hello hello hello hello bye bye bye bye bye bye bye
bye bye bye:
Os elementos do vetor de embedding para cada token estão dispostos ao
longo da página e ao longo de cada linha vemos primeiro uma série de
embeddings de «hello» seguidos de uma série de embeddings de «bye». A
segunda página é o embedding posicional – com o seu aspeto um pouco
aleatório sendo apenas aquilo que «aprendeu» (neste caso no GPT-2).
Muito bem. Então depois do módulo de embedding temos o «evento
principal» do transformador: a sequência dos chamados «blocos de atenção»
(12 para o GPT-2 e 96 para o GPT-3 do ChatGPT). É tudo muito complicado
– e faz lembrar os típicos sistemas de engenharia grandes e difíceis de
aprender, ou, já agora, os sistemas biológicos. Mas de qualquer das formas,
está aqui um esquema de representação dum «bloco de atenção» (para o GPT-
2):
Dentro de cada um destes «blocos de atenção» há uma coleção de «heads
(cabeças) de atenção» (12 para o GPT-2 e 96 para o GPT-3 do ChatGPT) –
cada uma das quais funciona de forma independente em diferentes partes dos
vetores de embedding. (E, sim, não temos nenhuma razão em particular de
porque dividir o vetor de embedding é uma boa ideia, ou o que cada uma
destas partes «significa»; é só uma daquelas coisas que «funciona»).
Muito bem. Então, o que é que estes heads de atenção fazem? Basicamente
são uma forma de «olhar para trás» numa sequência de tokens (i.e. no texto
produzido até este ponto), e «aglomerar o passado» de uma forma que seja
útil para encontrar o próximo token. Na primeira secção falámos de usar as
probabilidades de 2-grams para escolher palavras com base nas suas
antecessoras imediatas. O que o mecanismo de «atenção» nos
transformadores faz é permitir que se «considere» palavras muito mais
antecessoras – captando potencialmente a forma de como, por exemplo,
verbos se referem a nomes comuns que aparecem muito mais cedo na frase.
A um nível mais detalhado, o que a head de atenção faz é combinar
pedaços dos vetores de embedding associados a diferentes tokens com certos
pesos. E assim, por exemplo, os 12 heads de atenção no primeiro bloco (no
GPT-2) têm os seguintes padrões («olha-para-o-início-da-sequência-de-
tokens») de pesos padrões de «pesos de combinação» para o string «hello,
bye» já mencionado:
Depois de ser processado pelos heads de atenção, o «vetor de embedding
com pesos reajustados» (com tamanho de 768 para o GPT-2 e 12 288 para o
GPT-3 do ChatGPT) passa por uma camada da rede neural «totalmente
conectada». É difícil perceber o que se passa nesta camada. Mas fica aqui um
gráfico da matriz 768x768 que usa (neste caso o GTP-2):
Pegando em médias móveis de 64x64, algumas estruturas (um tanto
aleatórias) começam a aparecer:
O que é que determina esta estrutura? Em última instância, é
presumivelmente algum tipo de «codificação de rede neural» de
características da linguagem humana. Mas, para já, o que essas características
poderão ser é uma incógnita. Estamos, de facto, a «abrir o cérebro do
ChatGPT» (ou pelo menos do GPT-2) e a descobrir que, sim, é complicado lá
dentro e, sim, não percebemos o que se passa lá dentro – apesar de, no fim de
contas, ele estar a produzir linguagem humana reconhecível.
Muito bem. Então depois de passar por um bloco de atenção, temos um
vetor de embedding novo – que é sucessivamente passado por novos blocos
de atenção (um total de 12 para o GPT-2; 96 para o GPT-3). Cada um tem o
seu padrão particular de «atenção» e de pesos «totalmente conectados». Aqui
estão as sequências de pesos de atenção do primeiro head de atenção do GPT-
2 para a entrada de «hello, bye»:
E aqui estão as «matrizes» (de médias móveis) para as camadas totalmente
conectadas:
Curiosamente, apesar destas «matrizes de pesos» de blocos de atenção
diferentes parecerem muito semelhantes, as distribuições de tamanhos de
pesos podem ser um pouco diferentes (e nem sempre são Gaussianas):
Portanto depois de passar por todos estes blocos de atenção qual é o efeito
do transformador? Essencialmente é de transformar a coleção original de
embeddings de uma sequência de tokens para uma coleção final. E a forma
particular de como o ChatGPT funciona é de pegar no último embedding
desta coleção e depois descodificá-la numa lista de probabilidades para que
token deverá aparecer depois.
Isto é, de um modo geral o que se passa dentro do ChatGPT. Pode parecer
complicado (no mínimo devido às suas «escolhas de engenharia» um pouco
arbitrárias), mas, os elementos que estão de facto envolvidos são
surpreendentemente simples. Porque, no fim de contas, estamos a lidar com
uma rede neural feita de «neurónios artificiais», cada um a fazer uma
operação simples de pegar numa coleção de entradas numéricas, e, depois,
combiná-las com certos pesos.
A entrada original do ChatGPT é um vetor de números (os vetores de
embedding dos tokens até esse ponto), e o que acontece quando o ChatGPT
«corre» para produzir um novo token é que estes números«ecoam» pelas
camadas da rede neural, com cada neurónio «a fazer a sua cena» e a enviar o
resultado para os neurónios da camada seguinte. Não há loops ou «voltar a
trás». Tudo apenas «avança» pela rede.
É uma configuração muito diferente dum sistema computacional típico –
como uma máquina de Turing – de onde resultados são repetidamente
«reprocessados» pelos mesmos componentes computacionais. Aqui – pelo
menos na criação de um token de saída particular – cada elemento
computacional (i.e. neurónio) é usado apenas uma vez.
Mas há, de certa forma, um «loop exterior» que reutiliza elementos
computacionais mesmo no ChatGPT. Porque quando o ChatGPT vai gerar um
novo token, ele «lê» sempre (i.e. recebe como entrada) toda a sequência de
tokens que veio antes, incluindo tokens que ele próprio «escreveu». E
podemos pensar nesta configuração como uma forma – pelo menos no nível
mais exterior – de «loop de feedback», embora seja uma em que cada iteração
é visivelmente explicita como um token que aparece no texto gerado por si
mesmo.
Mas voltemos ao núcleo do ChatGPT: a rede neural que está a ser utilizada
repetidamente para gerar cada token. De certa forma, é muito simples: uma
coleção de neurónios idênticos e artificiais, e que em certa partes desta rede
são só camadas («totalmente conectadas») de neurónios em que cada
neurónio e cada camada está conectado (com um certo peso) a cada neurónio
da camada anterior. Porém, devido particularmente com a sua arquitetura de
transformadores, o ChatGPT tem partes com mais estrutura, em que só
neurónios específicos em camadas diferentes estão conectados. (Claro que
podemos ainda assim dizer que «todos os neurónios estão conectados» – mas
alguns têm só o peso a zero).
Para além disto, ainda há aspetos da rede neural do ChatGPT que não são
naturalmente pensados como sendo apenas camadas «homogéneas». E, por
exemplo – como o sumário icónico acima indica –, dentro de um bloco de
atenção há sítios onde «várias cópias são feitas» dos dados recebidos, cada
um passando depois por um «caminho de processamento» diferente,
envolvendo, potencialmente, um número diferente de camadas, e só depois
recombinando-se. Mas apesar disto ser uma representação conveniente
daquilo que se passa, em princípio é sempre possível pensar em «preencher
densamente» as camadas, mas tendo alguns pesos a zero.
Se olharmos para o caminho mais longo que atravessa o ChatGPT, há
cerca de 400 camadas (nucleares) envolvidas – de certa forma não é um
número gigante. Mas há milhões de neurónios – com um total de 175
milhares de milhões de conexões e assim 175 milhares de milhões de pesos.
E é importante apercebemo-nos de que cada vez que o ChatGPT gera um
token novo, tem de fazer uma calculação que envolva cada um destes pesos.
Em termos de implementação, esses cálculos podem ser organizados «por
camada» em operações de matriz altamente paralelas que podem ser
convenientemente feitas numa GPU. Mas para cada token produzido tem de
haver 175 milhares de milhões de cálculos feitos (e no final mais uns
quantos) – portanto, sim, não é surpreendente que possa demorar um pouco
para gerar um texto longo com o ChatGPT.
Mas no fim de contas, o impressionante é que todas estas operações – tão
simples como são individualmente – conseguem de alguma forma fazer um
trabalho muito bom «semelhante a humanos» de gerar texto. Temos de,
novamente, enfatizar que (pelo menos tanto quanto sabemos) não há
nenhuma «razão teórica fundamental» para que algo assim funcione. De
facto, como discutiremos, acho que temos de ver isto como uma descoberta
científica – potencialmente surpreendente – que dentro de uma rede neural
como a do ChatGPT é possível captar a essência daquilo que os cérebros
humanos são capazes de fazer ao gerar texto.
Treinar o ChatGPT
Muito bem. Portanto, já temos uma ideia de como o ChatGPT funciona
assim que está preparado. Mas como é que foi preparado? Como é que todos
os 175 milhares de milhões de pesos na sua rede neural foram determinados?
Basicamente são o resultado de um treino de escala muito grande, baseado
num corpus de texto gigante – na internet, livros, etc. – escrito por humanos.
Como dissemos, mesmo fornecendo todos estes dados de treino, não é óbvio
que a rede neural consiga produzir texto «semelhante a humanos» com
sucesso. E, mais uma vez, parece que é necessário que existam peças de
engenharia precisas para que isso aconteça. Mas as grandes surpresas – e
descobertas – do ChatGPT é o facto de ser uma realidade possível, e que é –
efetivamente – uma rede neural com «apenas» 175 milhares de milhões de
pesos que consegue fazer um «modelo razoável» do texto que os humanos
escrevem.
Atualmente, há muito texto escrito por humanos que existe em formato
digital. A Web pública tem pelo menos vários milhares de milhões de páginas
escritas-por-humanos, com talvez um total de um bilião de palavras. E se
incluirmos as páginas de Web não públicas, os números podem ser pelo
menos 100 vezes maiores. Até agora, mais de 5 milhões de livro digitalizados
estão disponíveis (dos cerca de 100 milhões de livros alguma vez
publicados), adicionando outras 100 milhares de milhões de palavras, ou à
volta disso. E isto sem incluir o texto exto gerado pelo discurso em vídeos,
etc. (Como uma comparação pessoal, todo o material que publiquei ao longo
da minha vida contabiliza um pouco menos de 3 milhões de palavras, e nos
últimos 30 anos escrevi cerca de 15 milhões de palavras de email, e ao todo
escrevi talvez 50 milhões de palavras – e só nos últimos anos já falei mais de
10 milhões de palavras em transmissões ao vivo. E, sim, vou treinar um robô
[bot] a partir de tudo isto).
Então, muito bem, tendo todos estes dados, como é que se treina uma rede
neural a partir deles? O processo básico é muito parecido com o que
discutimos nos exemplos simples já mencionados. Apresenta-se um lote de
exemplos e depois ajustam-se os pesos da rede para minimizar o erro
(«perda») que a rede faz nesses exemplos. O principal problema da
«retropropagação» a partir do erro é que, cada vez que é utilizada, cada peso
da rede muda pelo menos um pouco, e há muitos pesos para atualizar. (O
«cálculo de retorno» real é tipicamente apenas um pequeno fator constante
mais difícil do que o cálculo de avanço.)
Com GPU modernos, é fácil calcular os resultados de lotes de milhares de
exemplos em simultâneo. Mas no que toca a realmente atualizar os pesos na
rede neural, com os métodos atuais, basicamente é necessário fazê-lo lote a
lote. (E, sim, isto é provavelmente onde os nossos cérebros – com os seus
elementos de computação e memória combinada – têm, para já, uma
vantagem de arquitetura).
Mesmo em casos aparentemente simples de aprendizagem de funções
numéricas que discutimos antes, descobrimos que muitas vezes temos de usar
milhões de exemplos para treinar uma rede com sucesso, pelo menos de raiz.
Portanto quantos exemplos precisaremos para treinar um modelo de
linguagem «semelhante a humanos»? Não parece haver nenhuma forma
fundamentalmente «teórica» de saber. Mas na prática o ChatGPT foi treinado
com sucesso com umas poucas milhares de milhões de palavras de texto.
Alguns dos textos foram-lhe dados várias vezes, alguns apenas uma vez.
Mas de alguma forma «recebeu o que precisava» do texto fornecido. Mas
dado este volume de texto do qual se pode aprender, quão grande tem de ser a
rede neural para «aprender bem»? Mais uma vez, não temos ainda uma forma
fundamentalmente teórica de o dizer. Em última análise – como falaremos em
seguida – , a linguagem humana e o que os humanos dizem habitualmente
têm, ao que tudo indica, um definido «conteúdo algorítmico total». Mas a
próxima questão é quão eficiente a rede neural será a implementar um
modelo baseado nesse conteúdo algorítmico. E, de novo, não sabemos –
apesar do sucesso do ChatGPT sugerir que é razoavelmente eficiente.
E no fim de contas, podemos reparar que o ChatGPT faz o que faz a usar
umas quantas centenas de milhares de milhões de pesos – comparável em
número com o total de palavras(ou tokens) de dados de treino que lhe foram
dados. De certa forma, é talvez mais surpreendente (apesar de empiricamente
observado também em análogos do ChatGPT mais pequenos) que o
«tamanho da rede» que parece funcionar melhor é comparável ao «tamanho
dos dados de treino». Afinal, é óbvio que todo o texto da Web e dos livros,
etc., não está directamente armazenado «dentro do ChatGPT». Porque o que
está de facto dentro do ChatGPT é um monte de números – com um pouco
menos de 10 dígitos de precisão – que são algum tipo de codificação da
estrutura agregada de todo esse texto.
Por outras palavras, podemo-nos perguntar qual é o «conteúdo informativo
efetivo» da linguagem humana e o que é tipicamente dito com ela. Existe um
corpus bruto de exemplos de linguagem. E depois há a representação na rede
neural do ChatGPT. Essa representação é muito provavelmente longe da
representação «mínima algorítmica» (como iremos discutir). Mas é a
representação que é facilmente utilizável pela rede neural. E nesta
representação parece não haver muita compressão dos dados de treino; parece
ser necessário, em média, um pouco menos do que um peso da rede neural
para conter o «conteúdo de informação» duma palavra dos dados de treino.
Quando corremos o ChatGPT para gerar texto estamos, basicamente, a
usar cada peso uma vez. Portanto se existirem n pesos, temos uma ordem de n
passos computacionais para fazer – apesar de, em prática, muitos deles
podem ser feitos em simultâneo em GPU. Mas se precisarmos de n palavras
dos pertencentes de treino para configurar esses pesos, então a partir do que
dissemos antes, podemos concluir que vamos precisar de cerca de n passos
computacionais para fazer o treino da rede – que é a razão pela qual, com
métodos atuais, acaba por ser necessário falar de esforços de treino de
milhares de milhões de dólares.
Para Além do Treino Básico
A maior parte do esforço no treino do ChatGPT é gasto em «mostrar-lhe»
grandes quantidades de texto existente de páginas da Web, livros, etc. Mas
acontece que há também outra parte – aparentemente muito importante.
Assim que ele acaba o seu «treino bruto» a partir do corpus original que
lhe foi mostrado, a rede neural do ChatGPT está pronta para começar a gerar
o seu próprio texto, a partir do texto de entrada, etc. Mas, ainda que estes
resultados possam parecer razoáveis, eles tendem a «perder-se» em formas
pouco semelhantes a humanos – em particular com excertos mais longos. Isto
não é algo que seja imediatamente detetável, por exemplo, ao empregar
estatística tradicional no texto. No entanto, é algo que os humanos facilmente
conseguem notar ao ler o texto.
Para além disso, uma ideia chave na construção do ChatGPT foi ir mais
longe após a «leitura passiva» de coisas como a internet: ter humanos a
interagir ativamente com o ChatGPT, ver o que ele produz, e efetivamente
dar-lhe feedback para ele saber «como ser um bom bot de conversa». Mas,
como é que uma rede neural usa feedback? O primeiro passo é simplesmente
ter humanos a avaliar os resultados de uma rede neural. Mas, depois, outra
rede neural é feita para tentar prever essas avaliações. Agora este modelo de
previsão pode correr – essencialmente como uma função de perda – na rede
original, permitindo que essa rede seja «afinada» pelo feedback que recebeu
de humanos. E os resultados, em prática, parecem ter um grande efeito no
sucesso do sistema em produzir saídas «semelhantes a humanos».
Em geral, é interessante o quão pouco temos de «picar» a rede
«originalmente treinada» para a fazer ir numa direção particular. Poder-se-ia
pensar que para que a rede se comportasse como se «aprendesse algo novo»,
seria preciso correr um algoritmo de treino, ajustando pesos, e afins.
Mas esse não é o caso. Em vez disso, parece ser suficiente dizer ao
ChatGPT algo uma vez – como parte do texto de entrada que lhe damos – e
depois consegue usar o que lhe foi dito quando gera texto. E mais uma vez, o
facto de isto funcionar é, na minha opinião, uma pista importante em
compreender o que o ChatGPT «está, de facto, a fazer» e como ele se
relaciona com a estrutura da linguagem e pensamento humanos.
Há certamente algo bastante humano nisto: que, assim que ele tem o pré-
treino todo feito, podemos-lhe dizer uma coisa uma só vez e ele é capaz de se
«lembrar» – pelo menos durante «tempo suficiente» para gerar texto com essa
informação uma vez. Então o que é que está a acontecer num caso destes?
Pode ser que «tudo o que se pode dizer-lhe já esteja lá dentro algures» – e só
se estaria a guiá-lo ao sítio certo. Mas isso não parece plausível. Em vez
disso, o que parece mais provável é que, sim, os elementos já lá estão, mas os
detalhes são definidos por algo como «a trajetória entre esses elementos» e é
isso que estamos a introduzir quando lhe dizemos algo.
E, de facto, tal como em humanos, se lhe dissermos algo bizarro e
inesperado, que não se enquadra completamente na estrutura que conhece, o
Chat GPT não parece capaz de «integrar» isso. Só consegue «integrar» se for
montado de uma forma simples em cima da estrutura que já tem.
Vale a pena mencionar, mais uma vez, que há inevitavelmente «limites
algorítmicos» para o que a rede neural consegue «captar». Damos-lhe regras
«superficiais» como «isto é assim», etc., e a rede neural é, muito
provavelmente, capaz de as representar e reproduzir sem problemas – e, de
facto, o que ela «já sabe» da linguagem dá lhe um padrão imediato para
seguir. Mas, tentamos dar-lhe regras de computação «profunda» que
potencialmente envolvam passos computacionalmente irredutíveis e já não
funciona. (Relembremo-nos que a cada passo está simplesmente a «feed-
forward os dados» na sua rede, nunca faz loops, exceto, em virtude de gerar
novos tokens).
Claro que a rede consegue aprender a resposta a certas computações
«irredutíveis» específicas. Mas, assim que há um número de possibilidades
combinatórias, nenhuma abordagem do «tipo pesquisa-de-tabela» funciona. E
assim, tal como nos humanos, está na altura de as redes neurais «estenderem
a mão» e usarem ferramentas computacionais. (E, sim, o Wolfram|Alpha e a
Wolfram Language são especialmente adequadas porque foram feitas para
«falar sobre coisas no mundo», tal como nas redes neurais de modelos de
linguagem).
O que é que possibilita ao ChatGPT funcionar?
A linguagem humana – e o processo do pensamento envolvido em gerá-la
– tem desde sempre representado uma espécie de pináculo de complexidade.
E, de facto, parece notável que cérebros humanos – com os seus «meros» 100
milhares de milhões de neurónios (e talvez 100 biliões de conexões) possam
ser responsáveis por ela. Talvez se possa imaginar que há algo mais nos
cérebros do que as suas redes de neurónios – como uma nova camada de
física por descobrir. Mas, agora com o ChatGPT temos uma nova informação
importante: sabemos que uma rede neural pura, com aproximadamente o
mesmo número de conexões que o número de neurónios que existem no
cérebro, é capaz de fazer um trabalho surpreendentemente bom de gerar
linguagem humana.
E, sim, mesmo assim é um sistema grande e complexo – com
aproximadamente a mesma quantidade de pesos de rede neural como há
palavras de texto disponíveis no mundo. Mas, de certa forma, aparenta ser
difícil de acreditar que toda a riqueza da linguagem e as coisas de que é capaz
de «dizer» possam ser encapsuladas num sistema tão finito. Parte do que se
passa é, sem dúvida, uma reflexão do fenómeno ubíquo (que ficou evidente
no exemplo da regra 301) de que processos computacionais podem de facto
amplificar a complexidade aparente de sistemas, mesmo quando as suas
regras subjacentes são simples. Mas, na verdade, como discutimos antes,
redes neurais do género da que é usada no ChatGPT tendem a ser construídas
especificamente para resistir ao efeito deste fenómeno – e a sua
irredutibilidade computacional associada – de forma a tornar o seu treino
mais acessível.
Portanto como é que uma coisa como o ChatGPT consegue chegar tão
longe com linguagem? A resposta básica, acho eu, é quea linguagem é, a um
nível fundamental, de alguma forma mais simples do que parece. E isto
significa que o ChatGPT – mesmo com a sua estrutura de rede neural
relativamente simples – é capaz de «captar a essência» da linguagem humana
e o pensamento por detrás dela. E, além disso, no seu treino, o ChatGPT é, de
alguma forma, capaz de «descobrir implicitamente» quaisquer regularidades
na linguagem (e no seu pensamento) que fazem isto possível.
O sucesso do ChatGPT, na minha opinião, está a dar-nos provas de uma
parte fundamental e importante da ciência: está a sugerir que podemos
esperar que haja novas «leis de linguagem» importantes – e, efetivamente,
«eis de pensamento» – por descobrir. No ChatGPT – construído como sendo
uma rede neural – essas leis são, na melhor das hipóteses, implícitas. Mas, se
fossemos capazes de tornar estas leis explicitas, há o potencial de fazer o tipo
de coisas que o ChatGPT faz de forma mais direta e eficiente – e
transparente.
Então, muito bem, o que é que podem ser estas leis? Em última instância,
elas têm de nos dar algum tipo de receita de como a linguagem – e as coisas
que dizemos com ela – é composta. Mais tarde discutiremos como «olhar
para o interior do ChatGPT» é capaz de nos dar algum tipo de pistas acerca
disto, e como aquilo que sabemos sobre fazer linguagem computacional
sugere um caminho a seguir. Mas, primeiro vamos discutir dois exemplos
muito conhecidos do que são as «leis da linguagem» – e como elas se
relacionam com o funcionamento do ChatGPT.
A primeira é a sintaxe da linguagem. Linguagem não é apenas um
amontoado de palavras aleatórias. Em vez disso, há regras de gramática
(razoavelmente) definitivas de como diferentes palavras podem ser colocadas
juntas: por exemplo, em inglês, nomes comuns podem ser precedidos por
adjetivos e seguidos de verbos, mas tipicamente não pode haver dois nomes
próprios lado-a-lado. Tais estruturas gramáticas podem (pelo menos
aproximadamente) ser captadas por uma série de regras que definem como se
constrói o que são chamadas de «árvores de análise»:
O ChatGPT não tem nenhum tipo de «conhecimento» explícito de tais
regras. Mas, de alguma forma, no seu treino ele «descobre-as» implicitamente
– e depois aparenta ser bom a segui-las. Portanto como é que isto funciona? A
um nível mais «geral» não é claro. Mas para ter algum tipo de compreensão,
talvez seja mais instrutivo olhar para um exemplo mais simples.
Consideremos a «linguagem» formada de sequências de «(» e de «)», com
uma gramática que especifica que os parêntesis devem estar sempre
equilibrados, como representado numa árvore de análise como esta:
Conseguimos treinar uma rede neural de modo que consiga produzir as
sequências de parêntesis de forma «gramaticalmente correta»? Há várias
formas de lidar com sequências em redes neurais, mas vamos usar redes de
transformadores, tal como o ChatGPT. E tendo uma rede transformadora
simples, podemos começar a dar-lhe sequências de parêntesis gramaticamente
corretas como exemplos de treino. Uma subtileza (que também aparece na
criação de linguagem humana do ChatGPT) é que para além dos nossos
«tokens de conteúdo» (neste caso «(» e «)») temos de incluir um token de
«End», que é gerado para indicar que a saída não deve continuar (i.e. para o
ChatGPT, que já chegou ao «fim da história»).
Se configurarmos uma rede de transformadores com apenas um bloco de
atenção com oito cabeças e vetores de características de tamanho 128 (o
ChatGPT também usa vetores de características de tamanho 128, mas, tem 96
blocos de atenção, cada um com 96 cabeças) não parece ser capaz de
aprender muito sobre a linguagem de parêntesis. Mas com dois blocos de
atenção, o processo de aprendizagem parece convergir – pelo menos após
cerca de 10 milhões de exemplos lhe serem dados (e, como é comum em
redes de transformadores, mostrar-lhe ainda mais exemplos parece só piorar o
seu desempenho).
Portanto, com esta rede, podemos pedir, de forma análoga ao ChatGPT,
quais são as probabilidades de qual ser o próximo token numa sequência de
parêntesis:
No primeiro caso, a rede tem «quase a certeza» que a sequência não pode
acabar aqui – o que é bom, porque se o fizesse, os parêntesis ficariam
desequilibrados. No entanto, no segundo caso, «reconhece corretamente» que
a sequência pode acabar aqui, embora também «indique» que é possível
«recomeçar», pondo um «(»; presumivelmente, seguido de um «)». Mas,
oops, mesmo com os seus cerca de 40.0000 pesos treinados, diz que há uma
probabilidade de 15% de ter um «(» como próximo token – o que não está
correto porque isso leva necessariamente a um parêntesis desequilibrado.
Aqui está o que recebemos se pedirmos à rede quais são os resultados de
maior probabilidade para sequências progressivamente mais longas de «(»:
E, sim, até certa altura a rede não tem problemas nenhuns. Mas depois
começa a falhar. É uma coisa muito típica de se ver numa situação «precisa»
como esta com uma rede neural (ou com aprendizagem automática no geral).
Casos que humanos «conseguem resolver num instante» a rede neural
também o consegue. Mas, em casos que seja necessário fazer algo «mais
algorítmico» (e.g., explicitamente contar os parêntesis para ver se já estão
fechados) a rede neural tende a ser, de alguma forma, «computacionalmente
demasiado superficial» para o fazer fiavelmente. (Já agora, mesmo o
ChatGPT atual tem dificuldades em completar sequências longas de
parêntesis corretamente).
Então o que é que isto significa para coisas como o ChatGPT e a sintaxe
de uma linguagem como o inglês? A linguagem dos parêntesis é «austera» – e
muito mais «algorítmica». Mas em inglês é muito mais realista ser capaz de
«adivinhar» o que se encaixa gramaticalmente com base na escolha de
palavras e outras pistas. E, sim, a rede neural é muito melhor neste caso –
mesmo que por vezes ela possa falhar em alguns aspetos mais «formalmente
corretos» mas que os humanos também podem falhar. Mas o ponto principal é
que, de facto, há uma estrutura sintática geral na linguagem – com toda a
regularidade que isso implica – e de certa forma limita «quanto» é que a rede
neural tem de aprender. E uma observação-chave «do tipo-de-ciência-natural»
é que a arquitetura transformadora das redes neurais como o ChatGPT
aparentam ser capazes de aprender com sucesso o tipo de estruturas sintáticas
encapsuladas que tendem a existir (pelo menos com algum tipo de
aproximação) em todas as linguagens humanas.
Sintaxe dá nos um tipo de restrição na linguagem. Mas há claramente
mais. Uma frase como «eletrões curiosos comem teorias azuis para peixes» é
gramaticalmente correta, mas não é algo que é esperado de se dizer e não
seria considerada um sucesso se o ChatGPT a gerasse – porque, bem,
admitindo os significados normais das palavras que a compõem, não faz
sentido.
Mas há uma forma geral de verificar se uma frase faz sentido? Não há uma
teoria geral tradicional para isso. Mas é aceitar pensar que o ChatGPT tenha
implicitamente «desenvolvido uma teoria» depois de ser treinado com
milhares de milhões de frases da internet, etc. (presumivelmente com
sentido).
O que é que pode ser esta teoria? Bem, há uma pequena parte que já
sabemos há dois milénios, e é a lógica. E, certamente, na sua forma silogística
como Aristóteles a descobriu, a lógica é a forma de dizer que frases que
seguem certos padrões são razoáveis e e vice-versa. Assim, por exemplo, é
razoável dizer que «todos os X são Y. Isto não é um Y, portanto não é um X».
(Como em «todos os peixes são azuis. Isto não é um azul, portanto não é um
peixe.») E, da mesma forma que podemos imaginar de uma forma colorida
Aristóteles a descobrir o silogismo ao examinar montes de exemplos de
retórica («estilo-aprendizagem-automática»), podemos imaginar que no treino
do ChatGPT, a rede neural foi capaz de «descobrir o silogismo» ao olhar para
montes de textos na internet, etc. (E, sim, enquanto se pode esperar que o
ChatGPT produza texto que contenha «inferências corretas» baseadas em
coisas como a lógica silogística, a históriaé bem diferente quando se trata de
lógica formal mais sofisticada – e penso que se pode esperar que falhe aqui
pelo mesmo tipo de razões que falha na correspondência de parênteses.)
Mas para além do exemplo limitado da lógica, o que é que se pode dizer
sobre como construir (ou reconhecer) sistematicamente texto com sentido
plausível? Sim, há coisas como o Mad Libs® que utiliza «modelos de
frases». Mas de algum modo, o ChatGPT tem implicitamente uma forma
muito mais geral de o fazer. E talvez não há nada a dizer sobre como pode ser
feito para além de «de alguma forma acontece quando se tem 175 mil milhões
de pesos de redes neurais». Mas eu suspeito fortemente que há uma história
muito mais simples e muito mais interessante.
1. Regra 30 é um automato celular elementar criado por Stephen Wolfram
em 1983. (N. do T.)
Espaço de Significado e as «Leis de Newton» da Semântica
Já discutimos acima que dentro do ChatGPT qualquer excerto é
efetivamente representado por um vetor de números que podemos pensar
como sendo as coordenadas dum ponto numa espécie de «espaço de
características linguísticas». Portanto, quando o ChatGPT continua um
excerto isto corresponde a traçar uma trajetória neste espaço de características
linguísticas. Mas agora podemo-nos perguntar o que faz com que esta
trajetória corresponda a um texto que consideramos coerente. E talvez possa
haver algum equivalente às «Leis de Newton para a Semântica» que definem
– pelo menos restringem – como os pontos no espaço de características
linguísticas se podem mover e mesmo assim manter «significado»?
Então, como é que é este espaço de características linguísticas? Temos
aqui um exemplo de como palavras soltas (neste caso nomes comuns em
inglês) podem estar distribuídas se projetarmos este espaço de características
em 2D:
Vimos anteriormente outro exemplo baseado em palavras que representam
plantas e animais. Mas o objetivo em ambos os casos é que as palavras que
sejam «semanticamente semelhantes» são colocadas próximas umas das
outras.
Como outro exemplo, temos aqui como palavras que correspondem a
diferentes partes da fala ficam dispostas:
É claro que uma determinada palavra, em geral, não tem apenas «um
significado» (ou que corresponda a apenas a uma parte da fala). Olhando para
a forma como as frases que incluem uma palavra disposta no espaço de
características, podemos muitas vezes «separar» diferentes significados –
como no exemplo seguinte para a palavra «crane» (pássaro ou máquina?):
Muito bem. Então é, no mínimo, plausível pensar neste espaço de
características como colocando «palavras com significados próximos»
vizinhas umas das outras. Mas que tipo de estrutura adicional é que podemos
identificar neste espaço? Haverá, por exemplo, algum tipo de noção de
«transporte paralelo» que possa refletir «um plano» no espaço? Uma forma
de perceber isto, é olhando para analogias:
E, sim, mesmo quando projetamos para 2D, muitas vezes há «indícios de
superficialidade», embora não sejam vistos universalmente.
Então e as trajetórias? Podemos olhar para a trajetória que um texto de
entrada dado ao ChatGPT segue no espaço de características – e depois
podemos ver como o ChatGPT a continua:
De facto, não há nenhuma lei de Newton «geometricamente óbvia» aqui. E
isso não é surpreendente; seria de esperar que isto fosse uma história
consideravelmente mais complicada. E, por exemplo, não é obvio que,
mesmo havendo uma «lei de Newton da Semântica» a ser encontrada, qual
seria o tipo de embedding (ou até quais as variáveis) em que ela será mais
naturalmente enunciada.
Na imagem acima, mostrámos vários passos na «trajetória» – onde a cada
passo estamos a escolher a palavra que o ChatGPT considera a mais provável
(o caso da «temperatura zero»). Mas também podemos perguntar num
determinado ponto que palavras podem «vir a seguir» e com que
probabilidades:
E o que vemos neste caso é que há um «leque» de palavras de alta
probabilidade que parece ir numa direção mais ou menos definida no espaço
de características. O que acontece se continuarmos? Aqui estão os sucessivos
«leques» que aparecem à medida que «avançamos» ao longo da trajetória:
Aqui está uma representação 3D, para um total de 40 passos:
E, sim, isto parece confuso – e não nos em ajuda nada para a ideia de
acreditar que se possa identificar a «lei de Newton para a Semântica» como a
«matemática-física» ao estudar empiricamente «o que o ChatGPT faz lá
dentro». Mas talvez estejamos a olhar para as «variáveis erradas» (ou para o
sistema de coordenadas errado) e, se ao menos olhássemos para o sistema
certo, veríamos imediatamente que o ChatGPT está a fazer algo «matemático-
físico-simples» como seguir geodésicas. Mas, por agora, não estamos prontos
para «descodificar empiricamente» o que o ChatGPT «descobriu» de como a
linguagem humana é «construída» a partir do seu «comportamento interno».
A Gramática Semântica e o Poder da Linguagem Computacional
O que é preciso para produzir linguagem «humana com sentido»? No
passado, poderíamos ter assumido que não podia ser nada menos do que o
cérebro humano. Mas agora sabemos que pode ser feito, de forma bastante
respeitável, pela rede neural do ChatGPT. Mesmo assim, talvez isto seja o
mais longe que conseguimos chegar, não haverá nada mais simples – ou mais
compreensível por humanos – que irá funcionar. Mas suspeito que o sucesso
do ChatGPT revela implicitamente um facto científico importante: que, na
verdade, há muito mais estrutura e simplicidade para linguagem humana
coerente do que alguma vez soubemos – e que no final de contas é capaz de
haver regras relativamente simples que descrevem como essa linguagem pode
ser construída.
Como mencionámos anteriormente, a gramática sintática fornece regras
sobre a forma como as palavras correspondentes a coisas, como as diferentes
partes da fala, podem ser agrupadas na linguagem humana. Mas para lidar
com o significado temos de ir mais longe. E uma versão de como o fazer é
pensar não só numa gramática sintática para a língua, mas também numa
gramática semântica.
Para efeitos de sintaxe, identificamos coisas como nomes e verbos. Mas
para efeitos de semântica, precisamos de «classificações mais restritas».
Assim, por exemplo, podemos identificar o conceito de «movimento» e o
conceito de um «objeto» que «mantém a sua identidade independentemente
da localização». Há uma infinidade de exemplos específicos de cada um
destes «conceitos semânticos». Mas, para efeitos da nossa gramática
semântica, teremos apenas um tipo de regra geral que basicamente diz que os
«objetos» podem «mover-se». Há muito a dizer sobre como tudo isto pode
funcionar (algumas das quais eu já disse antes). Mas vou contentar-me com
apenas algumas observações que indicam parte do potencial do caminho a
seguir.
É importante mencionar que, mesmo que uma frase seja perfeitamente
aceitável de acordo com a gramática semântica, isso não significa que já
tenha sido realizada (ou que possa ser a vir realizada) na prática. «O elefante
viajou até à Lua» passaria sem dúvida o teste da nossa gramática semântica,
mas ainda não foi realizada (pelo menos para já) no nosso mundo – apesar de
ser perfeitamente aceitável num mundo ficcional.
Quando começamos a falar sobre «gramática semântica» rapidamente nos
perguntamos «o que está por detrás dela?» Que «modelo do mundo» está a
assumir? A gramática sintática é só a construção de linguagem a partir de
palavras. Mas, uma gramática semântica tem de envolver necessariamente
algum tipo de «modelos do mundo» – algo que serve como um «esqueleto»
sobre o qual a linguagem pode ser construída.
Até há pouco tempo, poderíamos imaginar que a linguagem (humana)
seria a única forma geral de descrever o nosso «modelo do mundo». Já há
alguns séculos, começaram a formalizar-se tipos específicos de coisas
baseadas, em particular, na matemática. Mas, agora há uma abordagem muito
mais universal à formalização: a linguagem computacional.
E, sim, esse tem sido o meu grande projeto ao longo de mais de quatro
décadas(agora incorporado na Wolfram Language): desenvolver uma
representação simbólica precisa que possa falar o mais universalmente
possível das coisas no mundo, assim como de coisas abstratas que nos
interessam. E, por exemplo, temos representações simbólicas para cidades e
moléculas e imagens e redes neurais, e temos conhecimentos incorporados
sobre como computar sobre essas coisas.
E, depois de décadas de trabalho, conectámos várias áreas desta forma.
Mas, no passado, não lidámos particularmente com o «discurso do dia a dia».
Na frase «comprei dois quilos de maçãs», podemos facilmente representar (e
fazer cálculos nutricionais e mais) os «dois quilos de maçãs». Mas não temos
(ainda) uma representação simbólica para «[eu] Comprei».
Está tudo conectado à ideia da gramática semântica – e ao objetivo de ter
um «kit de construção» simbólico genérico para conceitos, que nos daria
regras para o que pode ligar-se ao quê, e, assim, para o «percurso» do que
podemos transformar em linguagem humana.
Mas vamos supor que temos esta «linguagem de discurso simbólico». O
que é que faríamos com ela? Podíamos começar por fazer coisas como gerar
«texto com sentido local». Mas o que provavelmente queríamos, no fim de
contas, seriam mais resultados «com sentido global» – o que significa mais
«computação» sobre o que pode, de facto, existir ou acontecer no mundo (ou
talvez num mundo ficcional consistente).
Agora em Wolfram Language temos uma quantidade gigante de
conhecimento computacional integrado sobre muitos tipos de coisas. Mas
para uma linguagem de discurso simbólico completa, teríamos de construir
«cálculos» adicionais sobre coisas gerais no mundo: se um objeto move de A
para B e de B para C, então ele moveu-se de A para C, etc.
Com uma linguagem de discurso simbólico podíamos usá-la para fazer
«afirmações independentes». Mas também podemos usá-la para perguntar
questões sobre o mundo, «ao estilo Wolfram|Alpha». Ou podemos usá-la para
afirmar coisas que «queremos que aconteçam», presumivelmente com algum
mecanismo de atuação externo. Ou podemos usá-la para fazer afirmações –
talvez sobre o mundo real, ou talvez sobre algum mundo específico que
estamos a considerar, fictício ou não.
Linguagem humana é fundamentalmente imprecisa, sobretudo porque não
está «ligada» a uma implementação computacional específica, e o seu
significado é basicamente definido apenas por um «contrato social» entre os
seus utilizadores. Mas a linguagem computacional tem por natureza uma
certa precisão fundamental – porque, no fim, especifica o que pode ser
sempre «executado sem ambiguidade num computador». A linguagem
humana consegue ser, usualmente, um pouco vaga. (Quando dizemos
«planeta» isto inclui os exoplanetas ou não, etc.?) Mas na linguagem
computacional temos de ser claros e precisos em todas as distinções que
fazemos.
É muitas vezes conveniente aproveitar a linguagem humana comum para
criar nomes em linguagem computacional. Mas os significados que têm na
linguagem computacional são necessariamente precisos – e podem ou não
abranger uma conotação específica no uso típico de linguagem humana.
Como é que se deve descobrir a «ontologia» fundamental adequada a uma
linguagem de discurso simbólico geral? Bem, não é fácil. Talvez seja por que
se fez tão pouco desde os princípios primitivos que Aristóteles teceu há mais
de dois milénios. Mas ajuda muito que atualmente saibamos tanto sobre como
pensar sobre o mundo computacionalmente (e ajuda ter uma «metafísica
fundamental» do nosso Physics Project e a ideia do ruliad2).
Mas o que é que isto significa no contexto do ChatGPT? A partir do seu
treino, o ChatGPT foi efetivamente capaz de «juntar» uma certa quantidade
(bastante impressionante) do que equivale a uma gramática semântica. Mas o
seu próprio sucesso dá-nos uma razão para pensar que será possível construir
algo mais completo em forma de linguagem computacional. E, ao contrário
do que descobrimos até agora sobre as entranhas do ChatGPT, podemos
esperar que seja possível conceber a linguagem computacional de modo que
seja facilmente compreensível para os humanos.
Quando falamos de gramática semântica, podemos fazer a analogia com a
lógica silogística. No início, a lógica silogística era essencialmente uma
coleção de regras sobre afirmações expressas em linguagem humana. Mas
(sim, dois milénios depois) quando a lógica formal foi desenvolvida, as
construções básicas originais da lógica silogística passaram a ser utilizadas
para construir enormes «torres formais» que incluem, por exemplo, o
funcionamento dos circuitos digitais modernos. E, assim, podemos esperar
que o mesmo aconteça com a gramática semântica mais geral. Primeiro,
poderá apenas ser capaz de lidar com padrões simples, expressos, por
exemplo, como texto. Mas assim que a sua estrutura de linguagem
computacional esteja totalmente construída, podemos esperar que seja capaz
de ser usada para erguer torres altas de «lógica semântica generalizada», que
nos permitem trabalhar de forma precisa e formal com todas as coisas que
nunca nos foram acessíveis antes, exceto apenas a um «nível de rés do chão»
através da linguagem humana com toda a sua imprecisão.
Podemos pensar na construção da linguagem computacional – e da
gramática semântica – como uma representação de uma espécie de
compressão final na representação das coisas. Porque nos permite falar sobre
a essência do que é possível, sem, por exemplo, lidar com todos os «idiomas»
que existem na linguagem humana normal. E podemos ver a grande
vantagem do ChatGPT como sendo algo semelhante: porque também, de
certa forma, conseguiu «chegar» ao ponto onde consegue «juntar linguagem
de uma forma com sentido semântico» sem se preocupar com diferentes
idiomas possíveis.
Então o que é que aconteceria se aplicássemos o ChatGPT a uma
linguagem computacional subjacente? A linguagem computacional pode
descrever o que é possível. Mas o que ainda pode ser adicionado é um sentido
daquilo que «é popular» – baseado, por exemplo, em ler todo esse conteúdo
da internet. Mas depois – no fundo – operar com uma linguagem
computacional significa que algo como o ChatGPT tem acesso imediato e
fundamental ao que equivale a ferramentas definitivas para fazer uso de
computações potencialmente irredutíveis. E isso torna-o num sistema que não
só consegue «gerar texto razoável», mas também consegue esperar resolver
tudo o que seja necessário sobre se o texto produzido faz afirmações
«corretas» sobre o mundo – ou sobre o que quer que seja que é suposto estar
a falar.
2. Conceito introduzido por Stephen Wolfram que define o resultado de
seguir todas as regras computacionais possíveis de todas as formas
possíveis.(N. do T.)
Então… O que é que o ChatGPT está a Fazer, e Porque é que Funciona?
O conceito básico do ChatGPT é, de certa forma, bastante simples.
Começar com uma amostra grande de texto criado por humanos na internet,
etc. Depois treinar uma rede neural para gerar texto que é «desse género». E,
em particular, fazê-lo capaz de começar a partir de um «texto de entrada» e
depois continuar com texto que seja «parecido com aquele com que foi
treinado».
Como vimos, a rede neural do ChatGPT é feita de elementos muito
simples – embora sejam milhares de milhões. E o funcionamento básico da
rede neural é também muito simples, consistindo essencialmente de cruzar
uma nova entrada derivada do texto que gerou até esse ponto «uma vez pelos
seus elementos» (sem qualquer loops, etc.) para cada palavra (ou parte de
palavra) nova que gera.
Mas o que é notável – e inesperado – é que este processo pode produzir
texto que é «parecido» com sucesso com o que existe na internet, em livros,
etc. E não só é coerente com linguagem humana, como também «diz coisas»
que «seguem o texto de entrada» fazendo uso de conteúdo que «leu». Não diz
sempre coisas que «fazem sentido globalmente» (ou que correspondam a
computações corretas) – porque (sem, por exemplo, ter acesso aos
«superpoderes computacionais» do Wolfram|Alpha) o ChatGPT está apenas a
dizer coisas quelhe «parecem corretas» baseadas nas coisas que «pareciam
corretas» no seu material de treino.
A engenharia específica do ChatGPT tornou-o bastante atraente. Mas, em
última instância, está «meramente» a ir buscar «uma linha de texto coerente»
a partir de «estatísticas de senso comum» que acumulou (pelo menos até
conseguir usar ferramentas externas). Mas é extraordinário que os resultados
sejam tão semelhantes a humanos. E, como já disse, isto sugere algo que é
pelo menos cientificamente muito importante: que a linguagem humana (e os
padrões de pensamento por detrás dela) é, de alguma forma, mais simples e
mais «formal» na sua estrutura do que achávamos. O ChatGPT descobriu isto
implicitamente. Mas potencialmente podemos expor isto explicitamente, com
gramática semântica, linguagem computacional, etc.
O que o ChatGPT faz quando gera texto é impressionante – e os resultados
normalmente são muito parecidos ao que humanos produziriam. Então isso
significa que o ChatGPT está a funcionar como um cérebro? A sua estrutura
rede-neural-artificial subjacente foi modelada numa idealização do cérebro. E
parece ser muito provável que, quando nós humanos geramos linguagem,
muitos dos aspetos do que está a acontecer sejam bastante semelhantes.
No que toca a treino (também conhecido como aprendizagem), as
diferenças de «hardware» entre o cérebro e os computadores atuais (assim
como, talvez, algumas ideias algorítmicas) levam a que o ChatGPT use uma
estratégia que é provavelmente muito diferente (e de alguma forma muito
menos eficiente) do que a do cérebro usa. E há ainda outra coisa: ao contrário
da computação algorítmica típica, o ChatGPT não tem «loops» internos ou
«recomputação de dados». E isso limita inevitavelmente a sua capacidade
computacional – mesmo em relação a computadores atuais, mas
definitivamente em relação ao cérebro.
Não é claro como «resolver esse problema» e manter a habilidade de
treinar o sistema com uma eficiência razoável. Mas fazê-lo permitirá
presumivelmente que um futuro ChatGPT faça ainda mais «coisas
semelhantes ao cérebro». Claro que há várias coisas que os cérebros não
fazem muito bem – particularmente no que diz respeito a computações
irredutíveis. E para estas tanto cérebros e criações como o Chat GPT têm de
procurar «ferramentas externas» – como a Wolfram Language.
Mas, para já, é emocionante ver o que o ChatGPT já é capaz de fazer. De
certa forma, é um ótimo exemplo do facto científico fundamental de que
números muito grandes de elementos computacionais simples conseguem
fazer coisas notáveis e inesperadas. Mas também nos dá o que é talvez o
melhor ímpeto que já tivemos nos últimos dois mil anos na compreensão do
que são o caráter e princípios fundamentais dessa característica central da
condição humana que é a linguagem humana e os processos de pensamento
que a sustentam.
Agradecimentos
Há cerca de 43 anos que acompanho o desenvolvimento das redes neurais
e durante esse tempo interagi com muitas pessoas sobre elas. Entre elas –
algumas de há muito tempo, outras recentemente e outras ao longo de muitos
anos – estão: Giulio Alessandrini, Dario Amodei, Etienne Bernard, Taliesin
Beynon, Sebastian Bodenstein, Greg Brockman, Jack Cowan, Pedro
Domingos, Jesse Galef, Roger Germundsson, Robert Hecht-Nielsen, Geoff
Hinton, John Hopfield, Yann LeCun, Jerry Lettvin, Jerome Louradour,
Marvin Minsky, Eric Mjolsness, Cayden Pierce, Tomaso Poggio, Matteo
Salvarezza, Terry Sejnowski, Oliver Selfridge, Gordon Shaw, Jonas Sjöberg,
Ilya Sutskever, Gerry Tesauro e Timothee Verdier. Pela ajuda para este artigo,
gostaria de agradecer em particular a Giulio Alessandrini e Brad Klee.
O WOLFRAM|ALPHA COMO A FORMA DE TRAZER OS
SUPERPODERES DO CONHECIMENTO COMPUTACIONAL PARA
O CHATGPT
ChatGPT e Wolfram|Alpha
É sempre extraordinário quando as coisas «simplesmente funcionam» de
repente. Aconteceu-nos com o Wolfram|Alpha em 2009. Aconteceu com o
nosso Physics Project em 2020. E está a acontecer agora com o ChatGPT do
OpenAI.
Eu tenho andado a seguir a tecnologia de redes neurais há muitos anos
(cerca de 43, na verdade). E, mesmo seguindo os avanços dos últimos anos,
considero o desempenho do ChatGPT realmente notável. Finalmente, e
subitamente, temos um sistema capaz de gerar texto sobre quase tudo – e que
é muito comparável ao que humanos possam escrever. É impressionante e
útil. E, como discutirei mais tarde, acho que o seu sucesso está provavelmente
a dizer-nos coisas muito fundamentais sobre o pensamento humano.
Mas, apesar do ChatGPT ser uma conquista notável na automatização de
grandes coisas semelhantes às dos humanos, nem tudo o que é útil de se fazer
é assim tão «semelhante ao que é feito por humanos». Algumas destas coisas
são mais formais e estruturadas. E, de facto, uma das grandes conquistas da
nossa civilização nos últimos séculos tem sido a construção de paradigmas
matemáticos, as ciências exatas – e agora, o mais importante, a computação –
e de criar uma torre de capacidades bastante diferentes do que o pensamento
humano puro é capaz.
Eu próprio tenho estado bastante envolvido no paradigma computacional
há muitas décadas, na busca singular de construir uma linguagem
computacional representar de forma simbólica tantas coisas do nosso mundo
quanto possível. E ao fazer isto o meu objetivo tem sido de construir um
sistema que consiga «assistir computacionalmente» – e melhorar – o que eu e
outros queremos fazer. Eu penso nas coisas como um humano. Mas também
posso recorrer imediatamente à Wolfram Language e ao Wolfram|Alpha para
usar um tipo de «superpoder computacional» único que me permite fazer todo
o tipo de coisas sobre-humanas.
É uma forma de trabalhar tremendamente poderosa. E a questão é que não
é só importante para nós, humanos. É igualmente, se não mais, importante
para IA semelhantes a humanos – dando-lhes imediatamente aquilo que
podemos considerar como superpoderes de conhecimento computacional, que
potenciam o poder não-humano da computação estruturada e do
conhecimento estruturado.
Acabámos de começar a explorar o que isto significa para o ChatGPT. Mas
é bastante claro que coisas magnificas são possíveis. O Wolfram|Alpha faz
algo muito diferente do que o ChatGPT, de forma muito diferente. Mas têm
uma interface em comum: a linguagem natural. E isso significa que o
ChatGPT pode «conversar com» o Wolfram|Alpha tal como os humanos
fazem – com o Wolfram|Alpha a transformar a linguagem natural que recebe
do ChatGPT numa linguagem computacional precisa e simbólica na qual
pode aplicar o seu poder de conhecimento computacional.
Nas últimas décadas tem havido uma dicotomia em pensar sobre IA como
uma «abordagem estatística», como o ChatGPT faz, e uma «abordagem
simbólica», que é o ponto de partida do Wolfram|Alpha. Mas agora – graças
ao sucesso do ChatGPT –, assim como todo o trabalho que temos feito em
ensinar o Wolfram|Alpha a compreender linguagem natural –, há finalmente a
oportunidade de combinar ambas as abordagens para fazer algo muito mais
forte do que qualquer uma delas poderia alcançar sozinha.
Um Exemplo Básico
Na sua essência o ChatGPT é um sistema que gera saídas linguísticas que
«seguem um certo padrão» daquilo que existe na internet e em livros e outros
materiais usados no seu treino. E o que é notável é o quão semelhante a um
texto humano a saída é, não só a pequena-escala, mas também em ensaios
inteiros. Tem coisas coerentes a dizer, utiliza conceitos que aprendeu, muitas
vezes de formas interessantes e inesperadas. O que produz é sempre
«estaticamente plausível», pelo menos, a nível linguístico. Mas – por
impressionante que isso seja – isso certamente não significa que todos os
factos e computações que o ChatGPT apresenta com confiança estejam
necessariamente corretos.
Temos aqui um exemplo em que reparei (e, sim, o ChatGPT tem uma certa
aleatoriedade intrínseca, por isso, se tentar isto, provavelmente não obterá o
mesmo resultado):
Parece muito convincente. Mas acontece que está errado, como o
Wolfram|Alpha nos pode dizer:
Reconheçamos,no entanto, que este é exatamente o tipo de coisa que o
Wolfram|Alpha é bom a fazer: algo que pode ser transformado num cálculo
preciso que pode ser feito com base no seu conhecimento estruturado e
comprovado.
Mas o engraçado é que podemos pensar no Wolfram|Alpha a ajudar
automaticamente o ChatGPT nisto. Podemos perguntar em código ao
Wolfram|Alpha a pergunta (também podemos usar o API da internet, etc.):
Agora, fazemos outra vez a mesma pergunta ao ChatGPT, mas com este
resultado colado:
Muito educadamente, o ChatGPT aceita esta correção, e se fizermos a
pergunta mais uma vez ele dá-nos a resposta certa. Obviamente, podia haver
uma forma mais direta de comunicar de trás para a frente com o
Wolfram|Alpha, mas é engraçado de ver que até esta abordagem simples de
linguagem natural, basicamente, já funciona.
Mas porque é que o Chat GPT erra nesta pergunta em particular? Se
tivesse visto especificamente a distância entre Chicago e Tóquio algures no
seu treino (e.g. da internet), teria a resposta certa. Mas este é um caso em que
o tipo de generalização que uma rede neural pode fazer facilmente – digamos,
a partir de muitos exemplos de distâncias entre cidades – não será suficiente;
é necessário um algoritmo computacional.
A forma como o Wolfram|Alpha funciona é bastante diferente. Pega em
linguagem natural e depois – assumindo que é possível – converte-a em
linguagem computacional precisa (i.e. Wolfram Language), neste caso:
As coordenadas das cidades e algoritmos para calcular distâncias entre elas
estão integradas no conhecimento computacional da Wolfram Language. E,
sim, a Wolfram Language tem uma quantidade enorme de conhecimento
computacional integrado – o resultado de décadas de trabalho da nossa parte,
com uma curadoria cuidadosa do que é agora uma vasta coleção de dados,
continuamente atualizados, implementando (e muitas vezes inventando)
métodos e modelos e algoritmos – e sistematicamente construindo uma
linguagem computacional coerente para tudo.
Mais alguns Exemplos
O Chat GPT e o Wolfram|Alpha funcionam de formas muito diferentes e
têm pontos fortes muito diferentes. Mas no interesse de compreender onde o
ChatGPT pode aproveitar os pontos fortes do Wolfram|Alpha, vamos discutir
alguns casos onde o ChatGPT sozinho se engana. Uma área onde o ChatGPT
tende a ter dificuldades – tal como os humanos – é a matemática.
É uma resposta em estilo de ensaio interessante. Mas o resultado está
errado:
Mas se o ChatGPT «consultasse» o Wolfram|Alpha chegaria à resposta
certa. Vamos tentar algo mais complicado:
À primeira vista, este resultado parece ótimo, e acreditaria nele facilmente.
No entanto, acontece que está errado, como o Wolfram|Alpha pode dizer:
E, sim, fazer trabalhos de casa de matemática com o ChatGPT (sem poder
consultar o Wolfram|Alpha) é provavelmente uma má ideia. Pode dar uma
resposta muito plausível:
Mas sem «perceber realmente a matemática» é basicamente impossível
que o ChatGPT chegue à resposta certa fiavelmente. E, neste caso, a resposta
está novamente errada:
Ainda assim, o ChatGPT pode até inventar uma explicação muito plausível
de «como chegou a sua resposta» (não que seja de todo como, de facto, «lá
chegou»). E, de forma muito encantadora (e interessante), a explicação que
nos dá tem erros muito semelhantes aos que um humano que não percebesse
matemática também poderia dar:
Há todo o tipo de situações onde «não perceber o que as coisas realmente
significam» pode causar problemas:
Isto parece convincente. Mas não está correto:
O ChatGPT parece ter aprendido corretamente os dados verdadeiro algures
– mas não «os compreende» o suficiente para conseguir classificá-los
corretamente:
E, sim, podemos imaginar uma forma de «corrigir este bug em particular».
Mas a questão é que a ideia fundamental de um sistema de IA baseado numa
linguagem generativa como o ChatGPT não se adequa a situações em que há
questões computacionais estruturadas a resolver. De outa forma, seria
necessário corrigir um número quase infinito de «bugs» para remendar o que
uma fração quase infinitésima do Wolfram|Alpha consegue fazer na sua
forma estruturada.
E quanto mais complexa fica a «cadeia computacional», mais provável é
ter de recorrer ao Wolfram|Alpha para chegar à resposta certa. Aqui o
ChatGPT produz uma resposta bastante confusa:
E, como o Wolfram|Alpha nos diz, a conclusão a que chega está errada
(como ele, de certa forma, já «sabia»):
No que toca a dados específicos (e.g., dados quantitativos) – mesmo de
forma bruta – as coisas muitas vezes tendem a ser mais uma «história do
Wolfram|Alpha». Aqui está um exemplo, inspirado por um teste favorito de
longa data do Wolfram|Alpha: «Quantos perus existem na Turquia?»:
Novamente isto parece (inicialmente) totalmente plausível, e até cita uma
fonte relevante. Acontece, porém, que esses dados são basicamente
«inventados»:
Ainda assim, o que é muito bom é que podemos «pedir» ao ChatGPT
«factos para verificar»:
Agora damos estes ao API do Wolfram|Alpha:
Agora podemos pedir ao ChatGPT para corrigir a sua resposta original,
injetando estes dados (até mostrando em negrito onde corrigiu):
A capacidade de «injetar factos» é particularmente boa quando as coisas
envolvem dados em tempo real (ou que sejam dependentes de localização,
etc.) ou cálculos. O ChatGPT não nos responde imediatamente a isto:
Mas está aqui uma saída relevante do API do Wolfram|Alpha:
E, se dermos esta informação ao ChatGPT, vai conseguir gerar um
resultado simpático em «estilo de ensaio»:
Às vezes há uma interação interessante entre o computacional e o humano.
Aqui fazemos uma pergunta engraçada ao Wolfram|Alpha (e até verifica se
queremos «soft»):
O ChatGPT inicialmente fica um pouco confuso com o conceito de
volume:
Mas depois parece «aperceber-se» que essa quantidade de gelado é
ridícula:
O Caminho a Seguir
A aprendizagem automática é um método poderoso e, particularmente na
última década, tem tido uns casos de sucesso notáveis – dos quais o ChatGPT
é o mais recente. Reconhecimento de Imagens. Escrita por voz. Tradução. Em
cada um destes casos, e em muitos mais, um limiar foi alcançado –
normalmente de forma muito repentina. E alguma tarefa passou de
«basicamente impossível» para «bastante fazível».
Mas os resultados essencialmente nunca são «perfeitos». Talvez algo
funciona bem 95% das vezes. Mas por mais que se tente, os outros 5%
continuam difíceis de alcançar. Mas o ponto-chave é que muitas vezes, para
todos os tipos de utilizações relevantes, os 95% é «suficientemente bom».
Talvez é porque a saída é algo que não tenha uma «resposta correta». Talvez é
porque estamos a tentar mostrar possibilidades que um humano – ou um
sistema algorítmico – mais tarde, pode aperfeiçoar.
É realmente notável que uma rede neural de umas-centenas-de-milhares-
de-milhões-de-parâmetros que gera texto, um token de cada vez, consegue
fazer o tipo de coisas que o ChatGPT faz. E dado este sucesso dramático – e
inesperado – podemos pensar que se continuássemos e «treinássemos uma
rede grande o suficiente», conseguíamos fazer tudo com ela. Mas não é assim
que funciona. Factos fundamentais sobre a computação – e nomeadamente o
conceito de irredutibilidade computacional – tornam claro que, no fim de
contas, não conseguimos. Mas o que é mais relevante é o que já aconteceu na
história de aprendizagem automática. Vai haver um novo avanço (como o
ChatGPT). E as melhorias não vão parar. Mas o que é muito mais importante
é que se vão encontrar casos de utilização que tenham sucesso com o que
possa ser feito, e não sejam bloqueados com o que não possa ser.
E, sim, haverá muitos casos onde o «ChatGPT em bruto» pode ajudar na
escrita das pessoas, fazer sugestões ou gerar texto que seja útil para vários
tipos de documentos ou interações. Mas no que toca a estabelecer coisas que
têm de ser perfeitas, a aprendizagem automática não é a forma de o fazer –
assim como os humanos também não o são.
E é exatamente isso que estamos a ver nos exemplos acima. O ChatGPT éótimo nas «partes semelhantes a humanos», onde não é preciso uma «resposta
certa». Mas quando é «posto à prova» para responder a algo preciso, falha
muitas vezes. Mas a questão aqui é que há uma ótima forma de resolver esse
problema – conectar o ChatGPT ao Wolfram|Alpha e todos os seus
«superpoderes» de conhecimento computacional.
Dentro do Wolfram|Alpha, tudo está a ser transformado em linguagem
computacional, e em código preciso de Wolfram Language, que, de certa
forma, tem de ser «perfeito» para que seja útil de forma fiável. Mas o ponto
crucial é que o ChatGPT não precisa de gerar isto. Pode produzir a sua
linguagem natural normal, e depois o Wolfram|Alpha pode usar a sua
capacidade de compreender linguagem natural para a traduzir em Wolfram
Language exacta.
De muitas formas, pode-se dizer que o ChatGPT nunca «realmente
entende» as coisas; simplesmente «sabe como gerar coisas úteis». Mas é uma
história diferente com o Wolfram|Alpha. Porque assim que converte algo para
Wolfram Language, o que lá tem é uma representação completa, precisa e
formal, a partir da qual pode calcular coisas de forma fiável. Escusado será
dizer que há várias coisas de «interesse humano» para as quais não temos
representações computacionais formais – apesar de ainda assim ser possível
falar delas, mas, talvez, com imprecisão em linguagem natural. E para estas, o
ChatGPT está sozinho, com as suas capacidades impressionantes.
Mas, tal como nós, humanos, há vezes em que o ChatGPT precisa de um
«power assist» mais formal e preciso. A questão é que não tem de ser «formal
e preciso» para pedir o que quer. Porque o Wolfram|Alpha consegue
comunicar com o que equivale à linguagem nativa do ChatGPT – a
linguagem natural. E o Wolfram|Alpha pode tratar de «adicionar a
formalidade e precisão» quando faz a conversão para a sua linguagem nativa
– a Wolfram Language. É uma situação muito boa, que eu acho que tem um
grande potencial prático.
E esse potencial não se limita às aplicações típicas de chatbot ou de
geração de texto. Estende-se a coisas como fazer ciência de dados ou outras
formas de trabalho computacional (ou programação). De certa forma, é uma
forma imediata de obter o melhor dos dois mundos: o mundo humano do
ChatGPT e o mundo computacionalmente preciso da Wolfram Language.
E se o ChatGPT aprendesse diretamente a Wolfram Language? Bem, sim,
poderia fazer isso, e de facto já começou. E eu espero que eventualmente algo
como o ChatGPT seja capaz de operar diretamente na Wolfram Language, e
que seja muito poderoso ao fazê-lo. É uma situação interessante e única,
possibilitada pelo carácter da Wolfram Language como uma linguagem
computacional em grande escala que pode falar de modo geral sobre coisas
no mundo e em outros lugares em termos computacionais.
Todo o conceito da Wolfram Language é pegar em coisas que nós humanos
pensamos e ser capaz de representá-las e trabalhar com elas
computacionalmente. As linguagens de programação comuns têm como
objetivo fornecer processos de dizer aos computadores especificamente o que
fazer. A Wolfram Language – no seu papel como uma linguagem
computacional completa – é algo muito maior do que isso. Na verdade, o
objetivo é ser uma linguagem na qual tanto humanos como computadores
possam «pensar computacionalmente».
Há muitos séculos, quando a notação matemática foi inventada,
proporcionou pela primeira vez um meio simplificado para «pensar
matematicamente» sobre as coisas. A sua invenção levou à Álgebra e ao
Cálculo, e finalmente a todas as várias ciências matemáticas. O objetivo da
Wolfram Language é fazer algo semelhante para o pensamento
computacional, mas desta vez não só para os humanos – e para permitir todos
os campos «computacionais X» que possam ser abertos pelo paradigma
computacional.
Eu mesmo beneficiei muito por ter a Wolfram Language como uma
«linguagem para pensar», e tem sido maravilhoso ver nas últimas décadas
tantos avanços a serem feitos como resultado de pessoas «a pensar em termos
computacionais» através da Wolfram Language. E quanto ao ChatGPT? Pode
entrar nisso também. Ainda não tenho certeza de como isto tudo vai
funcionar. Mas não se trata do ChatGPT aprender a fazer a computação que a
Wolfram Language já sabe fazer. É sobre o ChatGPT aprender a usar a
Wolfram Language como as pessoas usam. É sobre o ChatGPT criar o
análogo de «ensaios criativos», mas agora escritos não em linguagem natural,
mas em linguagem computacional.
Há muito tempo que discuto o conceito de ensaios computacionais escritos
por humanos – que comunicam numa mistura de linguagem natural e
computacional. Agora é uma questão do ChatGPT ser capaz de escrevê-los –
e de ser capaz de usar a Wolfram Language como uma forma de fornecer
«comunicação coerente», não só para humanos, mas também para
computadores. E, sim, há um ciclo de feedback potencialmente interessante
que envolve a execução do código da Wolfram Language. Mas o ponto
crucial é que a riqueza e fluxo de «ideias» representadas pelo código da
Wolfram Language é – ao contrário de uma linguagem de programação
comum – algo muito mais próximo do que o ChatGPT conseguiu
«magicamente» trabalhar em linguagem natural.
Ou, de outra forma, a Wolfram Language – assim como a linguagem
natural – é algo expressivo o suficiente para que se possa imaginar escrever
um «texto de entrada» com significado para o ChatGPT. Sim, a Wolfram
Language pode ser executada diretamente num computador. Mas se for
utilizada como o texto de entrada do ChatGPT, pode ser usada para
«expressar uma ideia» cuja «história» pode ser continuada. Pode descrever
alguma estrutura computacional, deixando o ChatGPT «brincar» com o que
se pode dizer computacionalmente sobre essa estrutura que poderá – de
acordo com o que aprendeu ao ler tantas coisas escritas por humanos – ser
«interessante a humanos».
Há todo o tipo de possibilidades excitantes, subitamente abertas pelo
sucesso inesperado do ChatGPT. Mas, por enquanto, há a oportunidade
imediata de dar ao ChatGPT superpoderes de conhecimento computacional
através do Wolfram|Alpha. Assim, pode não só produzir «resultados
plausíveis semelhantes a humanos», mas também, resultados que aproveitam
toda a torre de computação e conhecimento que está encapsulada na
Wolfram|Alpha e na Wolfram Language.
Recursos Adicionais
«What Is ChatGPT Doing … and Why Does It Work?»Versão online
com código executável
wolfr.am/SW-ChatGPT
«Machine Learning for Middle Schoolers»(por Stephen Wolfram)
Uma curta introdução aos conceitos básicos de aprendizagem automática
wolfr.am/ML-for-middle-schoolers
Introduction to Machine Learning (por Etienne Bernard)
Um guia para aprendizagem automática moderna com código executável
impresso: wolfr.am/IML-book; online: wolfr.am/IML
Wolfram Machine Learning
Capacidades de aprendizagem automática na Wolfram Language
wolfr.am/core-ML
Machine Learning at Wolfram U
Aulas e cursos interativos sobre aprendizagem automática a uma série de
níveis diferentes
wolfr.am/ML-courses
«How Should We Talk to AIs?» (por Stephen Wolfram)
Um curto ensaio de 2015 sobre comunicar com IA em linguagem natural e
computacional
wolfr.am/talk-AI
A Wolfram Language wolfram.com/language
Wolfram|Alpha wolframalpha.com
http://wolfr.am/SW-ChatGPT
http://wolfr.am/ML-for-middle-schoolers
http://wolfr.am/IML-book
http://wolfr.am/
http://wolfr.am/core-ML
http://wolfr.am/ML-courses
http://wolfram.com/language
Link online para todos os recursos:
wolfr.am/ChatGPT-resources
http://wolfr.am/ChatGPT-resources
https://wolfr.am/ChatGPT-resources
https://wolfr.am/ChatGPT-resources
Ficha Técnica
Prefácio
O QUE É QUE O CHATGPT ESTÁ A FAZER… E PORQUE É QUE FUNCIONA
Ele só Adiciona uma Palavra de Cada Vez
De Onde Vêm as Probabilidades?
O que é um Modelo?
Modelos para Tarefas Semelhantes a Humanos
Redes Neuronais
Aprendizagem Automática e o Treino de Redes Neuronais
A Prática e o Conhecimento Fundamental do Treino de Redes Neuronais
«É Certo que uma Rede Grande o Suficiente Pode Fazer Qualquer Coisa!»
O Conceito de EmbeddingsPor dentro do ChatGPT
Treinar o ChatGPT
Para Além do Treino Básico
O que é que possibilita ao ChatGPT funcionar?
Espaço de Significado e as «Leis de Newton» da Semântica
A Gramática Semântica e o Poder da Linguagem Computacional
Então… O que é que o ChatGPT está a Fazer, e Porque é que Funciona?
Agradecimentos
O WOLFRAM|ALPHA COMO A FORMA DE TRAZER OS SUPERPODERES DO CONHECIMENTO COMPUTACIONAL PARA O CHATGPT
ChatGPT e Wolfram|Alpha
Um Exemplo Básico
Mais alguns Exemplos
O Caminho a Seguir
Recursos Adicionaisem vez
disso, vou utilizar o sistema mais simples do GPT-2, que tem a característica
simpática de ser pequeno o suficiente para ser capaz de correr num
computador de desktop normal. Assim, para essencialmente tudo o que eu
demostrar, consigo incluir código explícito em Wolfram Language que
podemos correr nos computadores que temos em casa.
Por exemplo, temos aqui como obter a tabela de probabilidades acima.
Primeiro temos de obter a rede neural «modelo de linguagem» subjacente:
Mais tarde veremos o interior desta rede neural e falaremos de como
funciona. Mas por enquanto podemos simplesmente aplicar este «modelo de
rede» como uma caixa negra ao texto que temos até agora e pedir as
primeiras 5 palavras, ordenadas por probabilidade, que o modelo diz que
devem continuar a frase:
Isto pega no resultado anterior e transforma-o no formato explícito
«dataset»:
Se «aplicarmos o modelo» repetidamente – a cada passo adicionando a
palavra que tem a melhor probabilidade (especificada neste código como a
decisão do modelo) isto é o que acontece:
O que é que acontece se se prolongar mais? Neste caso (de «temperatura»
zero) o que recebemos rapidamente torna-se bastante confuso e repetitivo:
E se em vez de escolhermos sempre a palavra com maior «probabilidade»
escolhermos às vezes, de forma aleatória, uma das outras palavras possíveis
(com uma «frequência» correspondente à «temperatura» de 0.8)?
Conseguimos mais uma vez construir um texto:
Cada vez que se se faz isto, as escolhas aleatórias serão diferentes, e assim
o texto será diferente – como se pode verificar nestes cinco exemplos:
É de salientar que até no primeiro passo há várias «próximas palavras»
possíveis para se escolher (à «temperatura» de 0.8), no entanto as suas
probabilidades caem muito rapidamente (e sim, a linha reta neste gráfico log-
log corresponde a uma relação muito típica das estatísticas gerais de
linguagem):
Portanto, o que acontece se continuarmos? Temos aqui um exemplo. É
melhor que o método de melhor-palavra (temperatura zero), mas é, no
mínimo, um bocado estranho:
Isto foi feito com o modelo mais simples do GPT-2 (de 2019). Com o
modelo GPT-3, que é maior e mais recente, os resultados são melhores.
Temos aqui os resultados com o método melhor-palavra (temperatura zero)
gerados com a mesma «pergunta», mas com o maior modelo do GPT-3:
E temos aqui um exemplo à «temperatura de 0.8»:
De Onde Vêm as Probabilidades?
Portanto, o ChatGPT escolhe sempre a próxima palavra com base em
probabilidades. Mas de onde vêm essas probabilidades? Comecemos com um
problema mais simples. Vamos considerar gerar um texto em inglês uma letra
de cada vez (em vez de ser uma palavra de cada vez). Como é que
conseguimos calcular qual deve ser a probabilidade de cada letra?
Uma coisa simples que podemos fazer é utilizar um excerto em inglês e
calcular a frequência de cada letra diferente. Por exemplo, este código conta
as letras no artigo da Wikipédia, em inglês, sobre «Gatos» (cats):
E este para «Cães» (dogs):
* Nota aos leitores: o efeito de folha rasgada é utilizada pelo autor
(Stephen Wolfram) como um setting de programação.
E este para «Cães» (dogs):
Os resultados são semelhantes, mas não são iguais («o» é sem dúvida mais
comum no artigo de «dogs» porque essa letra ocorre na palavra «dogs»).
Mesmo assim, se utilizássemos uma amostra de texto em inglês grande o
suficiente, seriam de esperar resultados constantes:
Eis um exemplo daquilo que recebemos se só gerarmos uma sequência de
letras com as probabilidades acima:
Podemos separar isto em «palavras» ao acrescentar espaços como se
fossem letras com uma certa probabilidade:
Podemos fazer um trabalho ligeiramente melhor de criar «palavras»,
forçando uma distribuição de «tamanho de palavras» de acordo com a que
existe em inglês:
Não obtivemos nenhuma «palavra real» neste exemplo, mas os resultados
estão a ficar ligeiramente melhores. No entanto, para conseguir continuar a
melhorar esta ideia, temos de fazer mais do que escolher cada letra de cada
vez de forma aleatória. Por exemplo sabemos que quando temos a letra «q», a
próxima letra tem de ser um «u».
Temos aqui um gráfico com as probabilidades para as letras individuais:
E temos aqui um outro gráfico que mostra as probabilidades de pares de
letras («2-grams») em texto em inglês. As primeiras letras possíveis estão ao
longo das colunas do gráfico e as segundas ao longo das linhas:
E assim conseguimos ver, por exemplo, que a coluna do «q» está em
branco (probabilidade zero) exceto na linha do «u». Muito bem, então agora
em vez de gerar as nossas «palavras» uma letra de cada vez, vamos gerá-las
duas letras de cada vez, usando estas probabilidades «2-grams». Temos aqui
um exemplo do resultado – que por acaso até tem algumas «palavras reais»
em inglês:
Com uma quantidade suficientemente grande de texto em inglês
conseguimos estimativas bastante boas, não só para probabilidades de letras
isoladas ou de pares de letras (2-grams), mas também para maiores
quantidades de letras. E se gerarmos «palavras aleatórias» com
probabilidades n-gram progressivamente maiores, conseguimos ver que elas
ficam de forma gradual «mais realistas».
Mas agora vamos assumir – mais ou menos como o ChatGPT faz – que
estamos a lidar com palavras inteiras, e não com letras. Existem cerca de
40.000 palavras em inglês razoavelmente comuns. E ao olhar para o corpus
de texto inglês (digamos uns milhões de livros com um total de uns milhares
de milhões de palavras), conseguimos uma estimativa de quão comum cada
palavra é. Ao usar isto conseguimos começar a gerar «frases» em que cada
palavra é escolhida independentemente e de forma aleatória, com a mesma
probabilidade com que aparece no corpus. Está aqui um exemplo do que
obtemos:
Não é surpreendente que isto seja absurdo. Então, como é que o
conseguimos melhorar? Tal como com as palavras, podemos começar por não
só ter uma probabilidade para cada palavra, mas também, probabilidades para
pares, ou -grams, de palavras maiores. Fazendo isto para pares temos aqui
cinco exemplos do que obtemos começando com a palavra «cat»:
Está a ficar ligeiramente mais «composto». Até seria de esperar que se
utilizarmos -grams suficientemente grandes chegaríamos àquilo que é
basicamente um ChatGPT – no sentido que teríamos algo que conseguisse
gerar sequências de palavras com o tamanho de um ensaio com as
«probabilidades gerais de ensaios corretas». Mas há um problema:
simplesmente não existe, nem perto do suficiente, texto em inglês escrito para
conseguir deduzir essas probabilidades.
Num web crawl é capaz de haver algumas centenas de milhares de milhões
de palavras; em todos os livros digitalizados é capaz de haver mais uma
centena de milhares de milhões de palavras. Mas para as 40.000 palavras
comuns, só o número de 2-grams possíveis já é de 1,6 milhares de milhão – e
o número de 3-grams possíveis é de 60 biliões. Portanto não há forma de
estimar as probabilidades, mesmo todas as palavras a partir do todo o texto
que está disponível. Quando chegamos a «excertos de ensaios» de 20
palavras, o número de possibilidades é maior que o número de partículas no
universo, portanto nunca seria possível escrevê-las todas.
Portanto o que é que se pode fazer? A ideia geral é fazer um modelo que
nos possibilita estimar as probabilidades de que sequências de palavras
devem ocorrer – mesmo que nós nunca as tenhamos visto explicitamente no
corpus do texto utilizado. No centro do ChatGPT está precisamente um
chamado «modelo de linguagem grande» (LLM) que foi construido para
fazer uma boa estimativa dessas probabilidades.
O que é um Modelo?
Digamos que (tal como Galileu no final do século XVI) nós queremos
saber quanto tempo é que uma bola de canhão lançada de cada andar da Torre
de Pisa demora a chegar ao chão. Bem, podíamos simplesmente medir cada
um dos casos e fazer uma tabela dos resultados. Ou podemos fazer aquilo que
é a essência da Ciência Teórica: criar um modelo que, através de algum
processo, seja capaz de calculara resposta em vez de termos de nos lembrar
do resultado de cada caso.
Vamos supor que temos dados (um pouco idealizados) de quanto tempo a
bola de canhão demora a cair de cada andar:
Como é que descobrimos quanto tempo é que vai demorar a cair de um
andar que não tenhamos os dados explícitos do tempo de queda? Neste caso
em particular, podemos usar as leis da Física que conhecemos para o resolver.
Mas digamos que tudo o que temos são os dados e não as leis da Física
subjacentes que os governam. Então podemos fazer uma suposição
matemática, tal como usar uma linha reta como um modelo:
É possível escolher várias linhas retas. Mas esta é a que, em média, mais
se adapta aos dados que temos. E através desta linha conseguimos estimar o
tempo de queda a partir de qualquer piso.
Como é que sabíamos que devíamos usar uma linha reta neste caso? De
certa forma, não sabíamos. É apenas algo matematicamente simples, e
estamos habituados ao facto de que muitos dos dados que medimos se
ajustam bem a coisas que são matematicamente simples. Podemos tentar algo
que seja matematicamente mais complexo – digamos a+bx+cx2 – e, neste
caso, adequa-se melhor:
No entanto, isto pode correr muito mal. Como neste caso onde isto é o
melhor que conseguimos fazer com a+ +c sin(x):
É importante perceber que nunca existe um «modelo sem modelo».
Qualquer modelo tem uma estrutura subjacente particular – e depois uma
série de «interruptores ajustáveis» (i.e. parâmetros que se podem definir) para
se adaptarem aos dados. E no caso do ChatGPT, há muitos destes
«interruptores» – de facto, há 175 milhares de milhão.
Mas o mais notável aqui é que a estrutura subjacente do ChatGPT – com
«apenas» esse número de parâmetros – é o suficiente para fazer um modelo
capaz de calcular as probabilidades da próxima-palavra «bem o suficiente»
para nos dar textos com tamanho razoavelmente longo.
Modelos para Tarefas Semelhantes a Humanos
O exemplo dado em cima envolve a criação de um modelo para dados
numéricos que essencialmente vêm da Física – para os quais há vários
séculos que já sabemos que «matemática simples se aplica». Mas para o
ChatGPT temos de fazer um modelo de texto em linguagem-humana, do tipo
que é produzido por um cérebro humano. E para algo assim não temos (pelo
menos para já) nada como «matemática simples». Portanto como seria um
modelo disso?
Antes de falarmos de linguagem, comecemos por outra tarefa humana:
reconhecer imagens. Como um exemplo simples disto vamos considerar
imagens de dígitos (e, sim, este é um exemplo clássico de aprendizagem
automática):
Uma coisa que que se pode fazer é arranjar uma série de imagens de
exemplo para cada dígito:
Depois, para descobrir se uma imagem que nos é dada como entrada
(input) corresponde a um dígito em particular podemos fazer uma
comparação explicita de pixel-a-pixel com as amostras que temos. Mas, como
humanos, parece que fazemos algo melhor – porque nós conseguimos
reconhecer dígitos, mesmo, por exemplo, quando estes são escritos à mão, e
têm todo o tipo de distorções e modificações:
Quando fizemos o modelo para os dados numéricos acima fomos capazes
de pegar num valor numérico x que nos foi dado e simplesmente calcular a +
b x para um a e um b particulares. Portanto, se nós tratarmos o nível de
cinzento de cada pixel como uma variável xi, existe alguma função de todas
essas variáveis que – quando avaliadas – nos dizem qual é o dígito na
imagem? Acontece que é possível construir uma função assim. Mas, não
surpreendentemente, não é particularmente simples. E um exemplo normal
envolve à volta de meio milhão de operações matemáticas.
Mas, no fim, se dermos esta coleção de valores de pixéis da imagem a esta
função, o resultado que temos é o número que corresponde ao dígito de que
temos uma imagem. Depois falaremos sobre como uma função destas pode
ser construída e da ideia de redes neurais. Mas para já vamos tratar desta
função como uma caixa negra, onde de um lado entram imagens de, por
exemplo, dígitos escritos à mão (como vetores dos valores dos pixéis) e do
outro lado saem os números a que os correspondem:
Mas o que é que de facto se passa aqui? Digamos que desfocamos
progressivamente um dígito. Durante um bocado a nossa função continua a
«reconhecer» o «2». Mas a certa altura «perde-o» e começa a dar a resposta
«errada»:
Mas porque é que nos dá uma resposta errada? Neste caso nós sabemos
que todas as imagens são de um «2» que está cada vez mais desfocado. Mas
se o nosso objetivo é ter um modelo de o que um humano faria no que toca ao
reconhecimento de imagens, a verdadeira questão é de nos perguntarmos o
que um humano faria se lhe fossem apresentadas as imagens mais desfocadas
sem saber de onde é que elas vêm.
E temos um «bom modelo» se os resultados que recebemos da nossa
função estiverem de acordo com o que um humano diria tipicamente. E o
facto científico não trivial é que, para uma tarefa de reconhecimento de
imagem como esta, agora sabemos como construir funções que fazem isto.
Conseguimos «provar matematicamente» que elas funcionam? Bem, não.
Porque para fazer isso teríamos de ter uma teoria matemática daquilo que os
humanos fazem. Pegando na imagem do «2» e mudando alguns pixéis, é
possível pensar que com só uns pixéis «fora do lugar» devíamos continuar a
considerar a imagem um «2». Mas quão longe devemos levar esta ideia? Isto
é uma questão da perceção da visão humana. E, sim, a resposta seria diferente
para abelhas ou polvos – e potencialmente completamente diferente para
supostos extraterrestres.
Redes Neurais
Muito bem. Então como é que os nossos modelos típicos, como o de
reconhecimento de imagens, funcionam? A abordagem mais popular – e a
mais bem-sucedida – utiliza redes neurais. Inventadas – de uma forma
surpreendentemente semelhante ao seu uso atualmente – na década dos 1940,
as redes neurais podem ser consideradas como idealizações de como os
cérebros parecem funcionar.
Em cérebros humanos há cerca de 100 milhares de milhões de neurónios
(células nervosas), cada uma capaz de produzir um impulso elétrico até cerca
de mil vezes por segundo. Os neurónios estão conectados numa rede
complexa, em que cada neurónio tem ramificações que lhe permitem passar
sinais elétricos para, talvez, milhares de outros neurónios. E, fazendo uma
aproximação, o facto de cada neurónio produzir um sinal elétrico a um dado
momento depende de que impulsos recebeu de outros neurónios – com
diferentes ligações a contribuírem com diferentes «pesos».
Quando nós «vemos uma imagem», o que está a acontecer é que quando
os fotões da imagem chegam às células («fotorrecetores») na parte de trás dos
nossos olhos, elas produzem sinais elétricos em neurónios. Estes estão
ligados a outros neurónios e, eventualmente, os sinais passam por toda uma
sequência de camadas de neurónios. E é neste processo que nós
«reconhecemos» a imagem, eventualmente «criando o pensamento» de que
estamos a «ver um 2» (e talvez no fim fazer qualquer coisa como dizer a
palavra «dois» em voz alta).
A função «caixa-negra» da secção anterior é uma versão «matematizada»
de uma rede neural deste tipo. Acontece que tem 11 camadas (mas só quatro
«camadas centrais»):
Não há nada que seja particularmente «justificado teoricamente» nesta
rede neural; é apenas algo que – em 1998 – foi construído como uma peça de
engenharia e que tem funcionado. (Claro que isto não é muito diferente de
como nós descrevemos como os nossos cérebros têm vido a evoluir ao longo
do tempo).
Muito bem. Mas como é que uma rede neural como esta «reconhece
coisas»? A chave é a ideia de atractores. Imaginemos que temos imagens de 1
e de 2 manuscritos:
Nós queremos que, de alguma forma, todos os 1 «sejam atraídos para um
sítio» e que todos os 2 «sejam atraídos para um sítio diferente». Ou, dito de
outra forma, se uma imagem é de alguma forma «mais perto de ser um 1» do
que um 2, queremos que ela vá parar ao «sítio dos 1» e vice-versa.
Como analogia direta, digamos que temos um certo número de posições
num plano, indicados por pontos(podem ser, por exemplo, localizações de
cafés). E depois podemos imaginar que, começando em qualquer ponto no
plano queremos chegar ao ponto mais próximo (i.e. queremos chegar sempre
ao café mais próximo). Podemos representar isto dividindo o plano em
regiões («bacia de atração») separadas por «bacias hidrográficas» idealizadas:
Podemos pensar neste tipo de implementação como um tipo de «tarefa de
reconhecimento» em que não estamos a fazer algo como identificar que digito
«mais se parece» com uma certa imagem – mas, antes estamos simplesmente,
e muito diretamente, a ver a que ponto é que um outro ponto está mais
próximo.
(A configuração do «diagrama de Voronoi» que estamos a mostrar aqui
separa pontos num espaço euclidiano 2D; pode-se considerar que a tarefa de
reconhecimento de dígitos faz algo muito semelhante – mas num espaço
dimensional de 784 dimensões formado do nível de cinzento de todos os
pixéis de cada imagem.)
Então como é que fazemos uma rede neural «realizar uma tarefa de
reconhecimento»? Consideremos este caso simples:
O nosso objetivo é de receber uma «entrada» que corresponda a uma
posição {x.y} – e depois «reconhecer» a qual dos três pontos é que se
encontra mais próxima. Ou, por outras palavras, nós queremos uma rede
neural que calcule a função de {x.y} assim:
Enão como é que fazemos isto com uma rede neural? Em última análise
uma rede neural é uma coleção conectada de «neurónios» idealizados–
geralmente organizados em camadas – um exemplo simples sendo:
Cada «neurónio» é efetivamente configurado para avaliar uma função
numérica simples. E para «utilizar» a rede basta fornecer números (como as
nossas coordenadas x e y) na camada superior, e depois ter neurónios em cada
camada a «avaliar as suas funções» e continuar a fornecer os seus resultados
pela rede – eventualmente produzindo o resultado final depois da última
camada:
Na configuração tradicional (inspirada na Biologia) cada neurónio
efetivamente tem um certo número de «conexões de entrada» vindas dos
neurónios da camada anterior, sendo atribuído um «peso» a cada conexão
(que pode ser um número positivo ou negativo). O valor de um dado neurónio
é calculado por multiplicar os valores dos «neurónios anteriores» pelos seus
pesos associados e depois fazendo a soma total destes valores com uma
constante adicional – e, finalmente, aplicando uma função de «limiar» (ou de
«ativação»). Em termos matemáticos, se um neurónio tem como entradas x=
{x1,x2,…}, então calculamos f[w.x+b], onde os pesos w e a constante b são
de um modo geral escolhidos para serem diferentes para cada neurónio na
rede neural; mas a função f é, geralmente, sempre a mesma.
O cálculo de w.x+b é apenas uma questão de multiplicação e adição de
matrizes. A função de «ativação» f introduz não-linearidade (que em última
instância leva a comportamento não trivial). Há várias funções de ativação
que são normalmente usadas; neste caso utilizaremos a função Rampa (ou
ReLU):
Para cada tarefa que queremos que a rede neural execute (ou,
equivalentemente, para cada função que queremos que ela avalie) teremos
escolhas diferentes de pesos. (E – como falaremos mais tarde – estes pesos
normalmente são determinados ao «treinar» a rede neural usando
aprendizagem automática a partir de exemplos das saídas [outputs) que
queremos).
Em última instância, todas a redes neurais correspondem apenas a uma
função matemática – embora seja difícil de a escrever. Para o exemplo acima
seria:
A rede neural do ChatGPT também corresponde apenas a uma função
matemática como esta – mas com efetivamente milhares de milhões de
parâmetros.
Mas voltemos a neurónios individuais. Estão aqui alguns exemplos de
funções que um neurónio com duas entradas (representando as coordenadas x
e y) conseguem calcular com várias escolhas de pesos e constantes (e com a
Rampa como função de ativação):
E para a rede neural maior acima? Bem, isto é o que ela calcula:
Não é exatamente «correto», mas está perto da função «ponto mais
próximo» que mostrámos acima.
Vamos ver o que acontece com outras redes neurais. Em cada caso, como
explicaremos mais tarde, estamos a utilizar aprendizagem automática para
encontrar qual a melhor escolha para os pesos. Depois estamos a mostrar aqui
o que é que a rede neural, com os respetivos pesos, calcula.
De um modo geral, as redes neurais maiores são melhores a aproximar os
valores que queremos. E a resposta que queremos tipicamente está no «centro
da bacia de atração». Mas nas fronteiras – onde as redes neurais «tem mais
dificuldades em se decidirem» – as coisas ficam menos exatas.
Com esta simples «tarefa de reconhecimento» matemática é obvio qual é a
«resposta certa». Mas no problema de reconhecimento de dígitos escritos à
mão, não é assim tão claro. E se alguém escrevesse um «2» tão mal que ele
pareceria um «7», etc.? Mesmo assim, podemos perguntar como é que uma
rede neural distingue dígitos – e isto dá nos uma indicação:
Podemos dizer «matematicamente» como é que a rede neural faz as suas
distinções? Não. Ela está só a «fazer o que uma rede neural faz». Mas
acontece que isto normalmente está de acordo com as distinções que um
humano faz.
Vamos pegar num exemplo mais elaborado. Digamos que temos imagens
de gatos e de cães. E temos uma rede neural que foi treinada para as
distinguir. Aqui está o que ela pode fazer em alguns exemplos:
Agora é ainda menos claro qual é a «resposta certa». E se tivermos um cão
vestido com um fato de gato, etc.? Qualquer que seja a entrada, a rede neural
vai dar-nos uma resposta, e de uma forma razoavelmente consistente de como
um humano a daria. Como já disse em cima, isso não é um facto que
possamos «derivar dos primeiros princípios». É só algo que se verificou
empiricamente ser verdade, pelo menos em certos domínios. Mas é uma das
principais razões pelas quais as redes neurais são úteis: são capazes de
alguma forma de capturar a «forma-humana» de fazer coisas.
Olhemos para uma imagem de um gato e perguntemo-nos «porque é que é
um gato?». Talvez começamos por dizer «bem, dá para ver as suas orelhas
pontiagudas, etc.» Mas não é fácil de explicar como é que reconhecemos a
imagem como um gato. É só algo que o nosso cérebro deduziu de alguma
forma. Mas para um cérebro não há (pelo menos para já) uma forma de
«entrar» e ver como é que essa dedução foi feita. E para uma rede neural
(artificial)? Bem, é bastante claro o que é que cada «neurónio» faz quando a
rede recebe uma imagem de um gato. Mas até ter uma visualização básica é
difícil de se fazer.
Na última rede que utilizámos para o problema do «ponto mais próximo»
que há pouco falámos existem 17 neurónios. Na rede de reconhecimento de
dígitos escritos à mão há 2.190. E na rede que estamos a usar para reconhecer
gatos e cães há 60.650. Normalmente seria bastante difícil de visualizar
aquilo que é um espaço dimensional de 60.650 dimensões. Mas como esta
rede está configurada para funcionar com imagens, muitas das suas camadas
de neurónios estão organizadas em vetores, como os vetores de pixéis que
recebe.
Se considerarmos a típica imagem de um gato
depois conseguimos representar os estados dos neurónios na primeira
camada como uma coleção de imagens derivadas desta primeira – muitas das
quais podem ser interpretadas como sendo coisas como «o gato sem o plano
de fundo», ou, «o contorno do gato»:
Pela 10.ª camada já fica mais difícil de perceber o que se passa:
Mas, de um modo geral, podemos dizer que a rede neural está a
«selecionar certas características» (talvez as orelhas pontiagudas é uma
dessas), e usa-as para determinar do que é a imagem. Mas essas
características são aquelas para as quais temos nomes – como «orelhas
pontiagudas»? Na maior parte dos casos não.
Estarão os nossos cérebros a utilizar características semelhantes? Na
verdade, não sabemos. Mas é notável que as primeiras camadas de uma rede
neural como a que temos aqui parecem pegar em aspetos (como os contornos
de objetos) que parecem ser similares aqueles que nós sabemos que são
reconhecidospelo primeiro nível de processamento visual dos nossos
cérebros.
Mas digamos que queremos uma «teoria de reconhecimento de gatos» em
redes neurais. Podemos dizer: «Olha, esta rede em particular consegue fazê-
lo» – e isso dá-nos imediatamente uma ideia do «quão difícil é o problema»
(e, por exemplo, a quantidade de neurónios ou camadas necessárias). Mas,
pelo menos para já, não temos uma forma de «dar uma descrição narrativa»
daquilo que a rede está a fazer. E talvez é porque é verdadeiramente
irredutível do ponto de vista computacional e não há uma forma geral de
descobrir o que faz, exceto seguindo explicitamente cada passo. Ou se calhar
é só que ainda não «percebemos a ciência» e ainda não identificámos as «leis
naturais» que nos permitem resumir aquilo que se está a passar.
Vamos encontrar o mesmo tipo de problemas quando falarmos da criação
de linguagem com o ChatGPT. E, mais uma vez, não é claro se há formas de
«resumir o que faz». Mas a riqueza e o detalhe da linguagem (e a nossa
experiência com ela) pode permitir-nos chegar mais afundo do que com
imagens.
Aprendizagem Automática e o Treino de Redes Neurais
Até agora temos andado a falar de redes neurais que «já sabem» como
fazer tarefas particulares. Mas o que faz as redes neurais tão úteis (e
presumidamente também os cérebros) é que, não só conseguem, em princípio,
fazer todo o tipo de tarefas, mas também podem ser progressivamente
«treinadas a partir de exemplos» para fazer essas tarefas.
Quando fazemos uma rede neural para distinguir gatos de cães, não temos
de expressamente escrever um programa que (digamos) explicitamente
procura bigodes; em vez disso apenas, mostramos uma série de exemplos do
que são gatos e do que são cães, e depois regulamos a rede para «aprender
automaticamente» como os distinguir.
O objetivo é que a rede treinada «generalize» a partir dos exemplos que
lhe são dados. Tal como vimos acima, não é que a rede simplesmente
reconheça os padrões de pixéis de uma imagem de gato particular que lhe foi
dada; mas antes, a rede, de alguma forma, consegue distinguir imagens com
base naquilo que nós consideramos ser algum tipo de «gatez geral».
Então como é que o treino de uma rede neural realmente funciona?
Essencialmente o que estamos a tentar fazer sempre é encontrar os pesos que
fazem com que a rede neural consiga reproduzir com sucesso os exemplos
que lhe demos. E depois confiamos que a rede neural consiga «interpolar»
(ou «generalizar») «de entre» destes exemplos de forma «razoável».
Vamos olhar para um problema ainda mais simples do que o do ponto-
mais-próximo acima. Vamos tentar que uma rede neural aprenda a seguinte
função:
Para esta tarefa, precisamos de uma rede com apenas uma entrada e uma
saída, como esta:
Mas que pesos, etc, devemos utilizar? Com cada conjunto de pesos
possíveis, a rede vai calcular algum tipo de função. E, por exemplo, isto é o
que ela faz com uma série de pesos aleatórios:
E, sim, conseguimos ver claramente que em nenhum destes casos ela
chega perto de reproduzir a função que queremos. Então como é que
encontramos os pesos que conseguem reproduzir a função?
A ideia básica consiste em fornecer muitos exemplos de «entrada – saída»
«a partir dos quais aprende» – e depois tentar encontrar os pesos que
conseguem reproduzir os resultados desses exemplos. Temos aqui o resultado
de fazer este processo com progressivamente mais exemplos:
A cada passo neste «treino» os pesos são progressivamente ajustados – e
vemos que eventualmente temos uma rede que consegue reproduzir a função
que queremos com sucesso. Então como é que ajustamos os pesos? A ideia
básica é que a cada passo vemos «quão longe estamos» da função a que
queremos chegar – e depois temos de atualizar os pesos de forma a ficarmos
mais perto.
Para encontrar «quão longe estamos», calculamos o que normalmente é
chamada de «função de perda» (ou, às vezes, «função de custo»). Aqui
estamos a usar uma função de perda simples (L2) que é só a soma dos
quadrados das diferenças entre os valores que recebemos e os valores reais. E
o que vemos é que à medida que o nosso método de treino avança, a função
de perda diminui progressivamente (seguindo uma certa «curva de
aprendizagem» que é diferente de tarefa para tarefa) – até chegarmos a um
ponto em que a rede consegue reproduzir a função que queremos com
sucesso (ou pelos menos uma boa aproximação):
Muito bem. Então a última parte essencial para explicar é como os pesos
são ajustados para reduzir a função de perda. Como dissemos, a função de
perda dá-nos uma «distância» entre os valores que temos e os valores reais.
Mas os «valores que temos» são determinados a cada passo pela versão atual
da rede neural – e pelos pesos nela. Mas imaginemos que os pesos são
variáveis – digamos wi. Queremos encontrar como ajustar os valores destas
variáveis para minimizar a perda que depende deles.
Por exemplo, imaginemos (numa simplificação incrível de redes neurais
tipicamente usadas) que temos só dois pesos w1 e w2. Depois podemos ter
uma perda que como função de w1 e w2 se parece assim:
A análise numérica dá-nos uma série de técnicas de encontrar o mínimo
em casos destes. Mas uma abordagem típica é a de simplesmente seguir
progressivamente o caminho que segue o maior declive decrescente dos w1e
w2 anteriores:
Como água a descer uma montanha, tudo o que é garantido é que este
processo vai acabar num mínimo local da superfície («um lago de
montanha»); pode muito bem não atingir o mínimo global final.
Não é obvio que seria possível encontrar o caminho com o maior declive
decrescente na «topografia do mapa dos pesos». Mas o Cálculo vem salvar o
dia. Como mencionámos acima, é possível pensar numa rede neural como o
cálculo de uma função matemática – que depende nas suas entradas e nos
seus pesos. Mas agora consideremos a diferenciação em relação a esses
pesos. Acontece que, efetivamente, a Regra da Cadeia de cálculo deixa-nos
«desvendar» as operações feitas por camadas sucessivas da rede neural.
Como resultado podemos – pelos menos numa aproximação local –
«inverter» a operação da rede neural e progressivamente encontrar pesos que
minimizam a perda associada à saída.
A imagem acima mostra-nos o tipo de minimização que podemos ter de
fazer no caso irrealisticamente simples de apenas 2 pesos. Mas acontece que,
mesmo que haja muitos mais pesos (o ChatGPT usa 175 mil milhões), ainda é
possível fazer essa minimização pelo menos com algum tipo de aproximação.
E, de facto, o grande avanço em «aprendizagem profunda» que ocorreu em
2012 foi associado à descoberta que, de certa forma, é mais fácil de fazer uma
minimização (pelo menos aproximada) quando há muitos pesos envolvidos
do que quando há poucos.
Por outras palavras – de forma algo contraintuitiva – pode ser mais fácil
resolver problemas mais complicados com redes neurais do que problemas
mais simples. E, de forma geral, a razão disso aparenta ser que, quando se
tem muitas «variáveis de peso», tem-se um espaço de alta dimensão com
«muitas direções diferentes» que podem chegar ao mínimo – enquanto que
com menos variáveis, é mais fácil acabar por ficar preso num mínimo local
(«lago de montanha») do qual não há «direção para sair».
Vale a pena notar que nos casos típicos há muitos tipos de coleções
diferentes de pesos resultarão em redes neurais com praticamente o mesmo
desempenho. E, usualmente, no treino de redes neurais há muitas escolhas
aleatórias feitas – que levam a soluções «diferentes-mas-equivalentes», como
estas:
Mas para cada «solução diferente» temos comportamentos, pelo menos,
ligeiramente diferentes. E se pedirmos, digamos, uma «extrapolação» fora da
região de onde demos os exemplos de treino, temos resultados
dramaticamente diferentes:
Mas qual destes está «correto»? Não há mesmo forma de dizer. São todos
«consistentes com os dados observados». Mas correspondem a diferentes
formas «inatas» de «pensar» sobre o que fazer «fora da caixa». E, para nós
humanos, algumas podem parecer «mais razoáveis» do que outras.
A Práticae o Conhecimento Fundamental do Treino de Redes Neurais
Especialmente na última década, tem havido vários avanços na arte do
treino de redes neurais. E, sim, é basicamente uma arte. Por vezes –
especialmente em retrospetiva – pode-se ver um vislumbre de uma
«explicação científica» para alguma coisa que esteja a ser feita. Mas, na
maioria das vezes, as coisas foram descobertas por tentativa-erro,
acrescentando ideias e truques que têm construído progressivamente um
conhecimento fundamental significativo de como trabalhar com redes
neurais.
Há várias peças-chave. Primeiro, há a questão de que arquitetura da rede
neural deve ser utilizada para uma determinada tarefa. Depois temos a
questão crucial de como é que se vai arranjar os dados para treinar a rede
neural. E, cada vez mais, não se trata de treinar uma rede neural de raiz: em
vez disso, uma rede nova pode incorporar diretamente uma outra rede que já
esteja treinada, ou, pelo menos, pode usar essa rede para gerar mais exemplos
de treino para si mesma.
Podemos achar que para cada tipo específico de tarefa precisamos de um
tipo de arquitetura de rede neural diferente. Mas o que se tem vindo a
descobrir é que a mesma arquitetura, muitas das vezes, parece funcionar para
tarefas que aparentam ser muito diferentes. De certa forma isto faz lembrar a
ideia de uma computação universal (e o meu Princípio da Equivalência
Computacional), mas, como irei abordar mais tarde, acho que é mais uma
demostração do facto de as tarefas que tipicamente pomos as redes neurais a
fazer são «semelhantes às tarefas humanas» – e as redes neurais conseguem
captar «processos bastantes gerais semelhantes aos processos humanos».
No início das redes neurais, tendia a haver a ideia de que uma rede neural
devia «fazer o mínimo possível». Por exemplo, na conversão de áudio para
texto achava-se que primeiro se devia analisar o áudio, dividi-lo em fonemas,
etc. Mas, o que se descobriu é que – pelo menos para «tarefas semelhantes às
tarefas humanas» – é geralmente melhor simplesmente treinar a rede neural
com o «problema de ponta a ponta», deixando-a «descobrir» as características
intermédias, codificações, etc, necessárias sozinha.
Havia também a ideia de que se devia introduzir componentes individuais
complicados na rede neural, para a deixar de facto «implementar
explicitamente ideias algorítmicas específicas». Mas mais uma vez, isto
acabou por não valer a pena; em vez disso, é melhor lidar com componentes
muito simples e deixá-los «organizarem-se a si mesmos» (embora geralmente
seja em formas que não conseguimos compreender) para conseguir
(presumivelmente) o equivalente àquelas ideias algorítmicas.
Isto não quer dizer que não há «ideias estruturais» que são relevantes para
as redes neurais. Assim, por exemplo, ter vetores 2D de neurónios com
conexões locais aparenta ser, pelo menos, muito útil nas fases iniciais de
processamento de imagens. E ter padrões de conectividade que se concentram
em «olhar para trás em sequências» parecer ser útil – como veremos mais
tarde – em lidar com coisas como a linguagem humana, como por exemplo
no ChatGPT.
Mas uma característica importante nas redes neurais é que – como em
computadores no geral – no fim de contas só estão a lidar com dados. E redes
neurais atuais – com abordagens de treino de redes neurais atuais – lidam
especificamente com vetores de números. Mas durante o processamento,
esses vetores podem ser completamente reorganizados e remodelados. E,
como exemplo, a rede acima que usámos para identificar os dígitos começa
com um vetor 2D «semelhante a uma imagem», «engrossando» rapidamente
em vários canais, mas depois «destilando» num vetor 1D que acaba por
conter elementos representando os possíveis dígitos de saída:
Muito bem. Mas, como é que se pode saber o quão grande uma rede vai ter
de ser para uma tarefa em particular? É uma espécie de arte. De certa forma, a
coisa mais importante é saber «quão difícil uma tarefa é». Mas para tarefas
humanas isso é tipicamente muito difícil de estimar. Sim, é capaz de haver
uma forma sistemática de fazer a tarefa de forma muito «mecânica» com um
computador. Mas é difícil de saber se há o que podem ser considerados
truques ou atalhos que nos permitem fazer a tarefa, pelo menos, «a um nível
quase-humano» muito mais facilmente. Pode ser necessário enumerar uma
árvore de jogo gigante para jogar um certo jogo mecanicamente; mas é
possível haver uma forma muito mais fácil («heurística») de chegar ao
mesmo «nível de jogo humano».
Quando estamos a lidar com redes neurais minúsculas e tarefas simples, às
vezes é possível ver explicitamente que «não é possível chegar lá a partir
daqui». Por exemplo, aqui está a melhor que conseguimos fazer para a tarefa
da secção anterior com algumas redes neurais pequenas:
E o que vemos é que se a rede é pequena demais, ela simplesmente não
consegue reproduzir a função que queremos. Mas a partir dum um certo
tamanho deixa de ter esse problema – ou pelo menos se for treinada tempo
suficiente com exemplos suficientes. E, já agora, estas imagens ilustram uma
parte do conhecimento fundamental de redes neurais: muitas vezes é possível
usar uma rede mais pequena se houver um «aperto» no meio que força tudo a
passar num número de neurónios intermédios reduzidos. (Também vale a
pena mencionar que redes «sem camadas intermédias» – ou os chamados
«perceptron» – só são capazes aprender o que são essencialmente funções
lineares – mas assim que há pelo menos uma camada intermédia, em
princípio, é sempre possível aproximar qualquer função arbitrária, ou pelo
menos é se houver neurónios suficientes. No entanto, para que treinar a rede
seja fazível, tipicamente é necessário qualquer tipo de regularização ou
normalização).
Muito bem. Então digamos que já decidimos que rede neural vamos
utilizar. Agora há o problema de como arranjar os dados para treinar a rede. E
muitos dos desafios à volta de redes neurais – e de aprendizagem automática
no geral – estão centrados em adquirir e preparar os dados de treino
necessários. Em muitos casos («aprendizagem supervisionada») queremos ter
exemplos explícitos de entradas e as suas saídas esperadas. Assim, por
exemplo, é possível querer imagens identificadas pelo seu conteúdo ou outro
atributo das mesmas. E talvez seja necessário passar por cada imagem
específica – e com grande esforço – para fazer esta identificação. Mas muitas
vezes é possível aproveitar algo que já foi feito, ou usar isso como uma
espécie de proxy. E assim, por exemplo, é possível usar os alt tags que são
dados para imagens Web. Ou, numa área diferente, pode-se usar as legendas
que foram criadas para vídeos. Ou – para o treino de tradução de texto –
pode-se usar versões paralelas de páginas Web ou de outros documentos que
existam em várias linguagens.
Quantos dados é que são necessários para mostrar a uma rede neural para
que fique treinada para uma tarefa em particular? Mais uma vez, é difícil de
estimar a partir dos primeiros princípios. Certamente os requisitos podem-se
reduzir dramaticamente usando «aprendizagem por transferência» para
«transferir» peças como listas de características importantes que já foram
aprendidas noutra rede. Mas geralmente redes neurais precisam de «ver
muitos exemplos» para ficarem bem treinadas. Pelo menos para algumas
tarefas é uma parte importante do conhecimento fundamental que temos
sobre redes neurais é que os exemplos podem ser muito repetitivos. E, de
facto, é uma estratégia padrão mostrar a uma rede neural todos os exemplos
que tenhamos vezes sem conta. Em cada uma destas «rondas de treino» (ou
«épocas») a rede neural vai estar num estado ligeiramente diferente, e, de
alguma forma, «relembrá-la» de exemplos particulares é útil para a fazer
«memorizar esse exemplo». (E, sim, é de alguma forma análogo à utilidade
da repetição na memória humana).
Mas muitas vezes estar só a repetir o mesmo exemplo vezes sem conta não
é o suficiente. É também necessário mostrar à rede neural variações do
mesmo exemplo. E é uma característicado conhecimento fundamental sobre
as redes neurais que essas variações de «melhoramento de dados» não têm de
ser sofisticadas para serem úteis. Alterando imagens ligeiramente com
processos simples pode, essencialmente, torná-las em «novos exemplos» para
efeitos de treino de redes neurais. E, de forma semelhante, quando não se tem
mais vídeos reais, etc., para treinar veículos autónomos, pode-se arranjar
dados correndo simulações em modelos de ambientes virtuais, como os de
jogos de computador, sem todos os detalhes dos cenários do mundo real.
E então algo como o ChatGPT? Bem, é uma rede neural que tem a
particularidade que consegue fazer «aprendizagem não supervisionada»,
facilitando obter exemplos para treinar. Lembremo-nos de que a tarefa básica
do ChatGPT é de descobrir como continuar um excerto que lhe foi dado.
Portanto para lhe arranjar «exemplos de treino» basta pegar num texto,
ocultar o fim e dar-lhe o que sobra como «entrada de treino» – e em que a
«saída» é a parte que se ocultou. Discutiremos isto com mais detalhe mais
tarde, mas o importante é que – ao invés de, digamos, aprender o que está
numa imagem – não é necessário «identificação explicita»; o ChatGPT
consegue, de facto, simplesmente aprender diretamente a partir do texto que
lhe é dado.
Muito bem. Então e o processo de aprendizagem da rede neural? No fim
de contas é uma questão de determinar que pesos conseguem melhor capturar
os exemplos que lhe foram dados. E há todo o tipo de escolhas detalhadas e
«definições de hiperparâmetros» (assim chamados porque os pesos podem ser
vistos como parâmetros) que podem ser usadas para ajustar como isto é feito.
Há diferentes escolhas de funções de perda (soma dos quadrados, soma de
valores absolutos, etc.). Existem diferentes formas de minimizar a perda
(quão longe andar em cada passo no espaço dos pesos, etc.). E ainda há
questões como qual o tamanho do «lote» de exemplos a mostrar para obter
cada estimativa sucessiva da perda que se está a tentar minimizar. E, sim, é
possível aplicar aprendizagem automática (como fazemos, por exemplo, em
Wolfram Language) para automatizar a aprendizagem automática – e para
escolher coisas como os hiperparâmetros automaticamente.
Mas, no final, o processo de treino pode ser caracterizado por se verificar
como a perda diminuiu progressivamente (como neste monitor de progresso
em Wolfram Language para um pequeno treino):
E o que é típico de se observar é que a perda diminui inicialmente, mas
eventualmente estabiliza num valor qualquer. Se este valor for
suficientemente pequeno, então pode-se considerar o treino um sucesso; caso
contrário é provavelmente um sinal de que se deve tentar mudar a arquitetura
da rede.
É possível saber quanto tempo é que a «curva de aprendizagem» deve
demorar a estabilizar? Como em tantas outras coisas, parece haver relações
escalares da lei de potência que dependem do tamanho da rede neural e da
quantidade de dados que se está a utilizar. Mas no geral conclui-se que treinar
uma rede neural é difícil – e é preciso muito esforço computacional. E, na
prática, a maioria do esforço é gasto a fazer operações com vetores de
números, que é o que as unidades de processamento gráfico (GPU) são boas a
fazer – e é por isso que o treino de redes neurais normalmente está limitado
pela disponibilidade de GPU.
No futuro, haverá formas fundamentalmente melhores de treinar redes
neurais – ou no geral aquilo que elas fazem? Quase de certeza que sim, penso
eu. A ideia fundamental das redes neurais é de criar «tecido computacional»
flexível a partir de grandes quantidades de componentes simples
(essencialmente idênticos) – e de conseguir com que este «tecido» seja capaz
de ser modificado progressivamente para aprender com exemplos. Em redes
neurais atuais estamos essencialmente a utilizar ideias de cálculo – aplicadas
a números reais – para fazer essas modificações progressivas. Mas é cada vez
mais claro que ter números de alta precisão não é necessário; oito bits ou
menos é capaz de ser o suficiente até com os métodos atuais.
Com sistemas computacionais como autómatos celulares, que basicamente
operam paralelamente em vários bits individuais, nunca foi claro como fazer
este tipo de modificações progressivas, mas não há razão para não se achar
que é possível. De facto, tal como aconteceu com «o grande avanço em
aprendizagem profunda de 2012» é possível que tal modificação possa ser
mais fácil em casos mais complicados do que nos mais simples.
Redes neurais – talvez um pouco como cérebros – estão preparadas para o
que é essencialmente uma rede de neurónios fixos, com aquilo que é
modificado («peso») sendo o valor das conexões entre eles. (Talvez em
cérebros mais jovens há um número significativo de conexões novas a
aparecer). Mas apesar deste sistema ser conveniente na biologia, não é claro
se é sequer perto de ser a melhor hipótese para alcançar as funcionalidades
que precisamos. E algo que envolve o equivalente de reestruturação de redes
progressivas (talvez uma reminiscência do nosso Physics Project) pode ser
muito melhor.
E mesmo no âmbito das redes existentes existe uma limitação crucial: o
treino de redes neurais é feito de forma fundamentalmente sequencial, com os
efeitos de cada lote de exemplos a serem propagados para trás de forma a
atualizar os pesos. E, de facto, com o hardware atual – mesmo tendo em conta
as GPU – a maior parte duma rede neural está «inativa» durante a maior parte
de tempo de treino, com apenas uma parte a ser atualizada. E, de certa forma,
isto é devido ao facto de os nossos computadores tenderem a ter memória que
é independente das suas unidades centrais de processamento (CPU). Mas o
que acontece nos cérebros isto é presumivelmente diferente – com cada
«elemento de memória» (i.e. os neurónios) a ser, também, um possível
elemento de computação. E se pudéssemos construir o nosso hardware futuro
com essa capacidade, o treino de redes neurais é capaz de ficar muito mais
eficiente.
«É Certo que uma Rede Grande o Suficiente Pode Fazer Qualquer
Coisa!»
As capacidades de algo como o ChatGPT parecem ser tão impressionantes
que se pode imaginar que se se pudesse «continuar» e treinar redes neurais
cada vez maiores, eventualmente elas seriam capazes de «fazer tudo». E se
estivermos preocupados com as coisas que já estão acessíveis imediatamente
ao pensamento humano, é bem possível que já imaginemos isto. Mas a lição
dos últimos séculos da história da ciência é que há coisas que conseguimos
perceber por processos formais, mas que não estão acessíveis imediatamente
ao pensamento humano.
A matemática não trivial é um grande exemplo disto. Mas o caso geral é,
de facto, a computação. E o verdadeiro problema é o fenómeno de
irredutibilidade computacional. Há alguns cálculos que podemos pensar que
precisam de muitos passos, mas que, de facto, podem ser «reduzidos» para
algo mais imediato. Mas a descoberta de irredutibilidade computacional
implica que este processo nem sempre funciona. E que em vez disso há
processos – provavelmente como o abaixo – em que para perceber o que
acontece, se requer inevitavelmente seguir cada passo computacional:
O tipo de coisas que normalmente fazemos com os nossos cérebros é
presumivelmente escolhido especificamente para evitar irredutibilidade
computacional. É preciso um esforço especial para fazer matemática nos
nossos cérebros. E é praticamente impossível «pensar» nos passos do
funcionamento de processos não triviais apenas no nosso cérebro.
Mas é claro que para isso temos os computadores. E com computadores
nós conseguimos facilmente fazer coisas demoradas e computacionalmente
irredutíveis. E a chave é que, no geral, não há atalhos para estas coisas.
Sim, podíamos memorizar vários exemplos específicos do que acontece
em algum sistema computacional em particular. E, talvez, conseguimos ver
alguns padrões («computacionalmente redutíveis») que nos permitissem
algum tipo de generalização. Mas a questão é que irredutibilidade
computacional significa que nunca podemos garantir queo inesperado não
aconteça – e que só fazendo explicitamente a computação é que percebemos
o que de facto acontece em qualquer caso em particular.
E, no fim de contas, existe uma tensão fundamental entre a capacidade de
aprendizagem e a irredutibilidade computacional. Aprendizagem envolve, no
fundo, a compressão de dados ao aproveitar regularidades. Mas a
irredutibilidade computacional implica que em última instância há um limite
para as regularidades que possam existir.
Na prática, pode-se imaginar construir aparelhos computacionais – como
autómatos celulares ou máquinas de Turing – em sistemas treináveis como
redes neurais. E, de facto, tais aparelhos podem servir de boas «ferramentas»
para a rede neural – como o Wolfram|Alpha pode ser uma boa ferramenta
para o ChatGPT. Mas a irredutibilidade computacional implica que não se
pode confiar que se possa «entrar» nesses aparelhos e fazê-los aprender.
Ou dito de outra forma, há um equilíbrio entre a aptidão e a capacidade de
treinar: quanto mais se quer que um sistema faça «verdadeiro uso» das suas
capacidades computacionais, mais se vê a sua a irredutibilidade
computacional, e irá ser menos treinável. E quanto mais treinável for, menos
será capaz de fazer computações sofisticadas.
(Para o ChatGPT, na sua implementação atual, a situação é muito mais
extrema, porque a rede neural usada para gerar cada token de saída é uma
rede puramente «feed-forward» e sem loops, e assim não tem a capacidade de
fazer qualquer tipo de computação com «estruturas de controlo» não trivial).
É claro que nos podemos perguntar se é de verdadeiramente importante ser
capaz de fazer computações irredutíveis. E, de facto, durante a maior parte da
história humana não foi particularmente importante. Mas o mundo moderno
foi construído com base numa engenharia que utiliza, no mínimo, cálculos
matemáticos – e, cada vez mais, também computações mais gerais. E se
olharmos para a natureza, ela está cheia de computação irredutível – que
estamos aos poucos a compreender e imitar para usos tecnológicos.
Sim, uma rede neural consegue reparar em todo o tipo de regularidades na
natureza que nós também seriamos capazes de reparar através do
«pensamento humano sem qualquer ajuda». Mas se quisermos descobrir
coisas que são do âmbito da ciência matemática ou computacional, a rede
neural não será capaz de o fazer – a menos que «utilize como ferramenta» um
sistema computacional «normal».
Mas há algo potencialmente confuso acerca disto tudo. No passado, havia
várias tarefas – incluindo escrever ensaios – que eram assumidas como, de
alguma forma, «fundamentalmente demasiado difíceis» para computadores. E
agora que as vemos a serem feitas por inteligências artificiais como o
ChatGPT tendemos a achar que os computadores têm de ter ficado muito
mais poderosos – em particular, ultrapassando coisas que já eram
basicamente capazes de fazer (como computar progressivamente o
comportamento de sistemas computacionais como os autómatos celulares).
Mas esta não é a conclusão correta a tirar. Processos computacionais
irredutíveis ainda são computacionalmente irredutíveis, e continuam a ser
fundamentalmente difíceis para computadores – mesmo quando os
computadores conseguem computar os seus passos individuais facilmente. E,
em vez disso, o que devíamos concluir é que tarefas – como escrever ensaios
– que nós humanos conseguimos fazer, mas que não achávamos que
computadores conseguissem fazer, são, de certa forma, computacionalmente
mais fáceis do que pensávamos.
Por outras palavras, a razão pela qual uma rede neural pode ser bem-
sucedida em escrever um ensaio é porque escrever um ensaio acaba por ser
um problema «computacionalmente menos complexo» do que pensávamos.
E, de certa forma, isto aproxima-nos de «ter uma teoria» de como nós,
humanos, conseguimos fazer coisas como escrever ensaios, ou de, em geral,
lidar com linguagem.
Se tivermos uma rede neural grande o suficiente então sim, poderíamos ser
capazes de fazer tudo o que os humanos fazem com facilidade. Mas não
seriamos capazes de captar o que a natureza consegue fazer no geral – ou que
as ferramentas que criamos a partir da natureza conseguem fazer. E é o uso
dessas ferramentas – tanto práticas como conceptuais – que nos tem
permitido nos últimos séculos transcender as fronteiras do que é acessível ao
«pensamento humano puro» e captar para fins humanos mais do que existe no
mundo físico e no universo computacional.
O Conceito de Embeddings
As redes neurais – pelo menos como existem agora – baseiam-se
fundamentalmente em números. Portanto, se nós as vamos usar para algo
como texto temos de arranjar alguma forma de representar texto com
números. E é certo que podemos começar por dar um número a cada palavra
do dicionário (que é essencialmente o que o ChatGPT faz). Mas há uma ideia
importante – que é essencial, por exemplo para o ChatGPT – que vai para
além disso. Que é a ideia de «embeddings». Pode-se pensar em embeddings
como uma forma de representar a «essência» de qualquer coisa com um vetor
de números – com a propriedade de que «coisas próximas» são representadas
por números próximos.
Assim, por exemplo, podemos pensar que um embedding de palavras
como uma tentativa de distribuir palavras numa espécie de «espaço de
significado» em que palavras que de alguma forma estejam «próximas em
significado» apareçam próximas no embedding. Os embeddings que são de
facto usados –, por exemplo, no ChatGPT – tendem a abranger listas de
números muito grandes. Mas se fizermos uma projeção em 2D, podemos
mostrar exemplos de como palavras são distribuídas no embedding:
E, sim, o que vemos é que isto consegue captar muito bem impressões
típicas do quotidiano. Mas como é que se consegue construir um embedding
destes? A ideia geral é de ver quantidades de texto muito grandes (neste caso
5 milhares de milhão de páginas de Internet) e depois ver «quão similares»
são os «ambientes» em que cada palavra diferente surge. Por exemplo,
«jacaré» e «crocodilo» aparecem indistintamente em frases muito
semelhantes, o que significa que ficam muito próximas no embedding. Mas
«nabo» e «águia» não tendem a aparecer em frases semelhantes, portanto, são
colocadas longe uma da outra no embedding.
Mas como é que se implementa uma coisa deste género usando redes
neurais? Comecemos por falar de embeddings não para palavras mas para
imagens. Queremos encontrar alguma forma de caracterizar imagens em
listas de números de forma que «imagens que podemos considerar
semelhantes» recebem listas de números semelhantes.
Como é que devemos «considerar imagens semelhantes»? Bem, se as
imagens, por exemplo, são de dígitos manuscritos, então podemos
«considerar duas imagens semelhantes» se elas forem do mesmo dígito. Já
falámos de uma rede neural que foi treinada para reconhecer dígitos
manuscritos. E podemos pensar que esta rede neural está configurada de
modo que a sua saída sejam 10 caixotes, um para cada dígito.
Mas, e se «intercetarmos» o que se passa no interior da rede neural antes
da decisão final de «é um “4”»? Podemos esperar que no interior da rede
neural haja números que caracterizam as imagens como sendo
«maioritariamente um 4, mas um pouco um 2» e afins. E a ideia é de pegar
nestes números e utilizá-los num embedding.
O conceito é o seguinte. Em vez de tentarmos caracterizar diretamente
«que imagem está próxima de que outra», pegamos numa tarefa bem definida
(neste caso, o reconhecimento de dígitos) para a qual podemos obter dados de
treino explícitos – e depois usamos o facto de que, ao realizar esta tarefa, a
rede neural tem, implicitamente, de tomar o equivalente a «decisões de
proximidade». Assim, em vez de falar explicitamente sobre a «proximidade
das imagens», estamos apenas a falar sobre a questão concreta de que dígito é
que uma imagem representa, e depois «deixamos à rede neural» a tarefa de
determinar implicitamente o que isso implica sobre a «proximidade das
imagens».
Então, como é que isto funciona exatamente para a rede de
reconhecimento de dígitos?Podemos pensar na rede como sendo constituída
por 11 camadas sucessivas, que podemos resumir por forma de ícones da
seguinte forma (com as funções de ativação apresentadas como camadas
separadas):
No início estamos a fornecer à primeira camada imagens reais,
representadas por vetores 2D de valores de pixéis. E no fim estamos a receber
– da última camada – um vetor de 10 valores, que podemos pensar como a
«certeza» de que a rede tem da imagem representar cada dígito de 0 a 9.
Ao fornecer a imagem os valores obtidos dos neurónios na última
camada são:
Por outras palavras, a rede neural está, nesta altura, «incrivelmente certa»
de que esta imagem é um 4 – e para obter o resultado «4», só temos de
escolher a posição do neurónio com o maior valor.
Mas e se olharmos para o passo anterior? A última operação na rede é a
chamada softmax, que tenta «forçar a certeza». Mas antes de isso ser
aplicado, os valores dos neurónios são:
O neurónio «4» continua a ter o valor numérico mais alto. Mas também há
informação que podemos retirar dos outros neurónios. E podemos esperar que
esta lista de números pode, de certa forma, caracterizar a «essência» da
imagem – e daqui temos algo que podemos usar como ebedding. Assim, por
exemplo, cada um dos 4 aqui tem uma «assinatura» (ou «feature
embedding») ligeiramente diferente – todas muito diferentes das dos 8’s:
Essencialmente, estamos a usar 10 números para caracterizar as nossas
imagens. Mas muitas vezes é melhor usar muito mais que isso. E, por
exemplo, na nossa rede de reconhecimento de dígitos conseguimos ter um
vetor de 500 números ao usar a camada anterior. E este é provavelmente um
vetor razoável para usar como «embedding de imagens».
Se quisermos fazer uma visualização explícita do «espaço de imagens»
para dígitos manuscritos, precisamos de «reduzir a dimensão», efetivamente
projetando o vetor de 500 dimensões que temos num espaço 3D:
Acabámos de falar sobre criar uma caracterização (portanto um
embedding) para imagens, efetivamente baseada em identificar semelhanças
entre imagens, ao determinar se elas correspondem ao mesmo dígito
manuscrito (de acordo com os nossos dados de treino). E conseguimos fazer o
mesmo de uma forma muito mais geral para imagens se tivermos dados de
treino que identificam, por exemplo, qual dos 5000 tipos de objetos mais
comuns (cão, gato, cadeira, …) é que a imagem representa. E desta forma
conseguimos fazer um embedding de imagens que está «ancorado» pela
nossa identificação de objetos comuns, mas que «generaliza à volta dessa
âncora» de acordo com o comportamento da rede neural. E a questão é que na
medida em que esse comportamento esteja de acordo com a forma como nós,
humanos, compreendemos e interpretamos imagens, isto acaba por ser um
embedding que «nos parece correto», e, na prática, é útil para fazer tarefas
«com julgamentos semelhantes a humanos».
Muito bem. Então como é adaptamos este tipo de abordagem para
encontrar embeddings para palavras? A chave é começar duma tarefa a partir
da qual conseguimos facilmente treinar. E a tarefa padrão para isto é a
«previsão de palavras». Imaginemos que nos é dado «the ___ cat». Com base
num corpus de texto grande (como é todo o texto da Internet), quais são as
probabilidades de palavras diferentes que podem «preencher o espaço em
branco»? Ou, alternativamente, é nos dado «___ black ___» quais são as
probabilidades para diferentes palavras «adjacentes»?
Como é que se coloca este problema numa rede neural? Em última análise,
temos de formular tudo em termos de números. E a forma de fazer isto, é de
dar um número a cada uma das, aproximadamente, 50.000 palavras mais
comuns da língua inglesa. Portanto, por exemplo, «the» pode ser 914, e «cat»
(com um espaço antes) pode ser 3542. (Estes são de facto os números usados
pelo GPT-2). Portanto para o nosso problema de «the ___ cat», a nossa
entrada poderá ser {914, 3542}. Como deverá ser a nossa saída? Bem, deve
ser uma lista de, aproximadamente, 50.000 números que nos dão
efetivamente as probabilidades para cada palavra de «preenchimento»
possível. E, mais uma vez, para encontrar um embedding, queremos
«intercetar» o «interior» da rede neural mesmo antes de «chegar a uma
conclusão» – e depois pegar na lista de números que aí ocorrem, e podemos
pensar nisso como uma «caracterização da cada palavra».
Muito bem. Então como é que são estas características? Nos últimos 10
anos tem havido uma sequência de diferentes sistemas desenvolvidos
(word2vec, GloVe, BERT, GPT, ...), cada uma baseada numa abordagem de
rede neural diferente. Mas no fim de contas, todas elas pegam em palavras e
caracterizam-nas em listas de centenas de números.
Na sua forma bruta, estes «vetores de embedding» são muito pouco
informativos. Por exemplo, isto é o que o GPT-2 produz como vetores de
embedding brutos para três palavras especificas:
Se medirmos as distâncias entre estes vetores, podemos encontrar coisas
como a «proximidade» das palavras. Mais tarde discutiremos em mais detalhe
o que podemos considerar o significado «cognitivo» de tais embeddings. Mas
para já o ponto principal é que temos uma forma de tornar palavras em
coleções de números «compatíveis com rede neurais».
Mas, na verdade, conseguimos fazer mais do que caracterizar palavras por
coleções de números; também podemos fazer isto para sequências de
palavras, ou mesmo para blocos de texto. E é assim que o ChatGPT lida com
as coisas lá dentro. Pega no texto que já tem e cria um vetor de embedding
que o representa. Depois tem como objetivo encontrar as probabilidades para
palavras diferentes ocorrer a seguir. Por fim, representa a sua resposta numa
lista de números que essencialmente dão as probabilidades de cada uma das,
aproximadamente, 50.000 palavras possíveis.
(Estritamente falando, o ChatGPT não lida com palavras, mas sim com
tokens – unidades linguísticas convenientes que podem ser palavras inteiras,
ou podem ser apenas pedaços como «pre» ou «ing» ou «ized». Trabalhar com
tokens torna mais fácil para o ChatGPT lidar com palavras raras, compostas e
não inglesas, e, às vezes, para o bem ou para o mal, inventar novas palavras).
Por dentro do ChatGPT
Muito bem. Estamos finalmente preparados para falar do que está dentro
do ChatGPT. E, sim, em última instância, é uma rede neural gigante –
atualmente uma versão da chamada rede GPT-3 com 175 milhares de milhões
de pesos. Em vários aspetos, esta é uma rede neural muito parecida com as
outras que discutimos. Mas é uma rede neural que particularmente
configurada para lidar com linguagem. E a sua característica mais notável é
uma arquitetura de redes neurais chamadas «transformadores».
Nas primeiras redes neurais discutidas acima cada neurónio em qualquer
camada estava conectado a todos os neurónios da camada anterior (pelo
menos com um peso qualquer). Mas este tipo de rede totalmente conectada é
(presumivelmente) um exagero se estivermos a trabalhar dados que tenham
uma estrutura particular e conhecida. Assim, por exemplo, nas fases iniciais
de tratamento de imagens, é típico utilizar as chamadas redes neurais
convulsionais («convnets, de convolutional neural nets em inglês), em que os
neurónios são distribuídos em grelha semelhante com a grelha de pixéis na
imagem – e conectados apenas aos neurónios adjacentes na grelha.
A ideia de transformadores é de fazer algo semelhante às sequências de
tokens que constituem uma peça de texto. Mas, em vez de definir uma região
fixa na sequência onde pode haver conexões, os transformadores introduzem
a noção de «atenção» – e a ideia de «prestar mais atenção» a certas partes da
sequência. Um dia, talvez fará sentido começar com uma rede neural genérica
e depois fazer toda a personalização no treino. Mas, pelo menos para já,
parece ser fundamental, na prática, «modularizar» as coisas – como fazem os
transformadores e, provavelmente, como o nosso cérebro também o faz.
Muito bem. Então o que é que o ChatGPT (ou, melhor, o que é que a rede
GPT-3, na qual o ChatGPT se baseia) faz de verdade? Relembremo-nos