Este trabalho tenta reproduzir os resultados de A Neural Conversational Model (também conhecido como chatbot do Google). Ele usa um RNN (modelo seq2seq) para previsões de frases. Isso é feito usando python e TensorFlow.
A parte do corpus de carregamento do programa é inspirada no neuralconvo Torch de macournoyer.
Por enquanto, DeepQA oferece suporte ao seguinte corpus de diálogo:
--corpus opensubs
.--corpus scotus
. Consulte as instruções para instalação.--corpus ubuntu
. Consulte as instruções para instalação.Para agilizar o treinamento, também é possível usar embeddings de palavras pré-treinados (graças a Eschnou). Mais informações aqui.
O programa requer as seguintes dependências (fáceis de instalar usando pip: pip3 install -r requirements.txt
):
Você também pode precisar baixar dados adicionais para fazer o nltk funcionar.
python3 -m nltk.downloader punkt
O conjunto de dados Cornell já está incluído. Para os outros conjuntos de dados, observe os arquivos leia-me em suas respectivas pastas (dentro data/
).
A interface web requer alguns pacotes adicionais:
Uma instalação do Docker também está disponível. Instruções mais detalhadas aqui.
Para treinar o modelo, basta executar main.py
. Depois de treinado, você pode testar os resultados com main.py --test
(resultados gerados em 'save/model/samples_predictions.txt') ou main.py --test interactive
(mais divertido).
Aqui estão alguns sinalizadores que podem ser úteis. Para obter mais ajuda e opções, use python main.py -h
:
--modelTag
: permite dar um nome ao modelo atual para diferenciá-los durante o teste/treinamento.--keepAll
: use este sinalizador ao treinar se, durante o teste, você quiser ver as previsões em diferentes etapas (pode ser interessante ver o programa mudar de nome e idade conforme o progresso do treinamento). Aviso: Pode ocupar muito espaço de armazenamento rapidamente se você não aumentar a opção --saveEvery
.--filterVocab 20
ou --vocabularySize 30000
: Limite o tamanho do vocabulário e otimize o desempenho e o uso de memória. Substitua as palavras usadas menos de 20 vezes pelo token
e defina um tamanho máximo de vocabulário.--verbose
: ao testar, imprimirá as sentenças à medida que forem computadas.--playDataset
: mostra alguns exemplos de diálogo do conjunto de dados (pode ser usado em conjunto com --createDataset
se esta for a única ação que você deseja realizar). Para visualizar o gráfico computacional e o custo com o TensorBoard, basta executar tensorboard --logdir save/
.
Por padrão, a arquitetura de rede é um codificador/decodificador padrão com duas camadas LSTM (tamanho oculto de 256) e um tamanho de incorporação para o vocabulário de 32. A rede é treinada usando ADAM. O comprimento máximo da frase é definido em 10 palavras, mas pode ser aumentado.
Depois de treinado, é possível conversar com ele através de uma interface mais amigável. O servidor examinará o modelo copiado para save/model-server/model.ckpt
. Na primeira vez que quiser usá-lo, você precisará configurá-lo com:
export CHATBOT_SECRET_KEY= " my-secret-key "
cd chatbot_website/
python manage.py makemigrations
python manage.py migrate
Então, para iniciar o servidor localmente, use os seguintes comandos:
cd chatbot_website/
redis-server & # Launch Redis in background
python manage.py runserver
Após o lançamento, a interface deverá estar disponível em http://localhost:8000/. Se você deseja implantar o programa em um servidor, use python manage.py runserver 0.0.0.0
. Mais informações aqui.
Surpreendentemente, é possível obter alguns resultados após apenas 1 ou 2 horas de treinamento (em uma GeForce GT 740M), reduzindo drasticamente a sequência de entrada para 5 palavras e a saída para 3 (mais os tokens go
e eos
) e usando um pequeno tamanho de incorporação (algo como 25). Desde então modifiquei o código e agora o comprimento da saída deve corresponder ao da entrada, mas você ainda pode reproduzir os resultados originais, usando esta versão. Claro, a rede não será muito tagarela:
Q: Hi
A: Hi.
Q: What is your name ?
A: Laura.
Q: What does that mean ?
A: I dunno.
Q: How old are you ?
A: thirty-five.
Q: Will Google hire me ?
A: No.
Q: Tell me the alphabet
A: Fuck you.
Q: That's not nice
A: Yeah.
Aqui está um caso em que ele falha:
Q: Who is Laura ?
A: My brother.
Q: Say 'goodbye'
A: Alright.
Q: What is cooking ?
A: A channel.
Q: Can you say no ?
A: No.
Q: Two plus two
A: Manny...
Com frases mais longas, a rede é muito mais lenta para treinar. Após 250.000 iterações com maxLength = 10, a rede ainda fornece respostas evasivas (respondendo a maioria das perguntas abertas com 'Não sei'), mas parece ter integrado alguma semântica básica:
Q: When are the fireworks ?
A: Tomorrow.
Q: What color ?
A: Gray.
Q: Which apple ?
A: That's the first one.
Q: What time is it ?
A: Eleven o'clock.
Q: Who is Skywalker ?
A: She's a freelance bio-exorcist.
Q: Who is John ?
A: The old man.
Q: Who is Jenny ?
A: The man who killed herself.
Q: When were you born ?
A: Soon.
Como mostrado nas últimas questões, a rede ainda faz alguma confusão entre os géneros e o presente/futuro. Também tentei algumas questões filosóficas mais profundas com mais ou menos sucesso.
Q: What is the purpose of being intelligent ?
A: The man are obsolete.
Q: What is immoral ?
A: The truth.
Q: What is morality ?
A: The worst.
Q: What is the purpose of existence ?
A: It 's private.
Q: What happens if machines can think ?
A: I think I'll just lie with you.
O modelo que treinei é bastante limitado pelo tamanho de incorporação que coloquei e pelo seu tamanho, e pelo tamanho do corpus de treinamento. Seu 'vetor de pensamento' também é provavelmente pequeno demais para responder ao seguinte:
Q: My name is David. What is my name ?
A: Debbie.
Q: My name is John. What is my name ?
A: Carl Smith.
Q: How many legs does a cat have ?
A: Four.
Q: How many legs does a spider have ?
A: Four.
Q: Do you prefer football or soccer ?
A: Whiskey.
Ele também parece se ajustar demais, pois às vezes apenas exibe frases de seu conjunto de treinamento não relacionadas à pergunta. Adicionar alguma desistência deve reduzir o problema.
Q: I play tennis. What do I play ?
A: I'm going to get laid.
Q: What color is the sky ?
A: One of the deputies is everywhere.
Nota: Os links não funcionam mais.
Você pode encontrar um modelo pré-treinado aqui , treinado no corpus padrão. Para usá-lo:
DeepQA/save/
save/model-pretrainedv2/dataset-cornell-old-lenght10-filter0-vocabSize0.pkl
para data/samples/
../main.py --modelTag pretrainedv2 --test interactive
. Graças a Nicholas C., aqui (original) estão alguns modelos pré-treinados adicionais (compatíveis com TF 1.2) para diversos conjuntos de dados. A pasta também contém o conjunto de dados pré-processado para Cornell, OpenSubtitles, Ubuntu e Scotus (para mover dentro data/samples/
). Eles são obrigatórios se você não quiser processar os conjuntos de dados sozinho.
Se você tiver uma GPU de última geração, não hesite em brincar com os hiperparâmetros/corpus para treinar um modelo melhor. Pelas minhas experiências, parece que a taxa de aprendizagem e a taxa de abandono têm o maior impacto nos resultados. Além disso, se você quiser compartilhar seus modelos, não hesite em entrar em contato comigo e eu os adicionarei aqui.
Além de tentar um modelo maior/mais profundo, há muitas pequenas melhorias que podem ser testadas. Não hesite em enviar uma solicitação pull se você implementar um desses. Aqui estão algumas ideias:
loop_function
de tf.nn.seq2seq.rnn_decoder
, não deve ser muito difícil adicionar. Depois disso, deverá ser possível brincar com a temperatura SoftMax para obter previsões mais conservadoras ou exóticas.embedding_rnn_seq2seq
por embedding_attention_seq2seq
em model.py
.Q:Sentence 1. Sentence 2. => A:Sentence X. Sentence Y.
poderíamos gerar 3 novas amostras: Q:Sentence 1. Sentence 2. => A:Sentence X.
, Q:Sentence 2. => A:Sentence X. Sentence Y.
e Q:Sentence 2. => A:Sentence X.
Aviso: outras combinações como Q:Sentence 1. => A:Sentence X.
não funcionarão porque quebraria a transição 2 => X
que liga a pergunta ao responder)
e
podem ser adicionados para que o codificador saiba quando o interlocutor está mudando. Não tenho certeza se o modelo seq2seq simples seria suficiente para capturar dependências de longo prazo entre sentenças. Adicionar um sistema de balde para agrupar comprimentos de entrada semelhantes pode melhorar muito a velocidade de treinamento.