Este trabajo intenta reproducir los resultados de A Neural Conversational Model (también conocido como el chatbot de Google). Utiliza un RNN (modelo seq2seq) para predicciones de oraciones. Se realiza utilizando Python y TensorFlow.
La parte del corpus de carga del programa está inspirada en el Torch neuralconvo de macournoyer.
Por ahora, DeepQA admite el siguiente corpus de diálogo:
--corpus opensubs
.--corpus scotus
. Consulte las instrucciones de instalación.--corpus ubuntu
. Consulte las instrucciones de instalación.Para acelerar el entrenamiento, también es posible utilizar incrustaciones de palabras previamente entrenadas (gracias a Eschnou). Más información aquí.
El programa requiere las siguientes dependencias (fácil de instalar usando pip: pip3 install -r requirements.txt
):
Es posible que también necesites descargar datos adicionales para que nltk funcione.
python3 -m nltk.downloader punkt
El conjunto de datos de Cornell ya está incluido. Para los otros conjuntos de datos, mire los archivos Léame en sus respectivas carpetas (dentro data/
).
La interfaz web requiere algunos paquetes adicionales:
También está disponible una instalación de Docker. Instrucciones más detalladas aquí.
Para entrenar el modelo, simplemente ejecute main.py
Una vez entrenado, puede probar los resultados con main.py --test
(resultados generados en 'save/model/samples_predictions.txt') o main.py --test interactive
(más divertido).
Aquí hay algunas banderas que podrían ser útiles. Para obtener más ayuda y opciones, use python main.py -h
:
--modelTag
: permite dar un nombre al modelo actual para diferenciarlos al realizar pruebas/entrenamiento.--keepAll
: use esta bandera cuando entrene si durante la prueba desea ver las predicciones en diferentes pasos (puede ser interesante ver que el programa cambia de nombre y edad a medida que avanza el entrenamiento). Advertencia: Puede ocupar rápidamente mucho espacio de almacenamiento si no aumenta la opción --saveEvery
.--filterVocab 20
o --vocabularySize 30000
: limita el tamaño del vocabulario y optimiza el rendimiento y el uso de la memoria. Reemplace las palabras utilizadas menos de 20 veces por el token
y establezca un tamaño máximo de vocabulario.--verbose
: al realizar la prueba, imprimirá las oraciones a medida que se calculan.--playDataset
: muestra algunos ejemplos de diálogo del conjunto de datos (se puede usar junto con --createDataset
si esta es la única acción que desea realizar). Para visualizar el gráfico computacional y el costo con TensorBoard, simplemente ejecute tensorboard --logdir save/
.
De forma predeterminada, la arquitectura de red es un codificador/decodificador estándar con dos capas LSTM (tamaño oculto de 256) y un tamaño de incrustación para el vocabulario de 32. La red se entrena utilizando ADAM. La longitud máxima de la oración está establecida en 10 palabras, pero se puede aumentar.
Una vez entrenado, es posible chatear con él usando una interfaz más fácil de usar. El servidor mirará el modelo copiado en save/model-server/model.ckpt
. La primera vez que quieras usarlo, necesitarás configurarlo con:
export CHATBOT_SECRET_KEY= " my-secret-key "
cd chatbot_website/
python manage.py makemigrations
python manage.py migrate
Luego, para iniciar el servidor localmente, use los siguientes comandos:
cd chatbot_website/
redis-server & # Launch Redis in background
python manage.py runserver
Después del lanzamiento, la interfaz debería estar disponible en http://localhost:8000/. Si desea implementar el programa en un servidor, utilice python manage.py runserver 0.0.0.0
en su lugar. Más información aquí.
Sorprendentemente, es posible obtener algunos resultados después de sólo 1 o 2 horas de entrenamiento (en una GeForce GT 740M), reduciendo drásticamente la secuencia de entrada a 5 palabras y la salida a 3 (más los tokens go
y eos
) y usando un pequeño tamaño de incrustación (algo así como 25). Desde entonces modifiqué el código y ahora la longitud de salida debe coincidir con la de entrada, pero aún puedes reproducir los resultados originales usando esta versión. Por supuesto, la red no será muy conversadora:
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.
A continuación se muestra un caso en el que falla:
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...
Con sentencias más largas, la red es mucho más lenta de entrenar. Después de 250000 iteraciones con maxLength=10, la red todavía da principalmente respuestas evasivas (respondiendo la mayoría de las preguntas abiertas con "No sé") pero parece haber integrado algo de 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 se muestra en las últimas preguntas, la red todavía genera cierta confusión entre los géneros y el presente/futuro. También intenté algunas cuestiones filosóficas más profundas con mayor o menor éxito.
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.
El modelo que entrené está bastante limitado por el tamaño de incrustación que puse y por su tamaño, y por el tamaño del corpus de entrenamiento. Su 'vector de pensamiento' probablemente también sea demasiado pequeño para responder al tipo de siguiente:
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.
También parece sobreajustarse ya que a veces simplemente saca oraciones de su conjunto de entrenamiento que no están relacionadas con la pregunta. Agregar algo de abandono debería reducir el 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: Los enlaces ya no funcionan.
Puedes encontrar un modelo previamente entrenado aquí. , entrenado del corpus predeterminado. Para usarlo:
DeepQA/save/
save/model-pretrainedv2/dataset-cornell-old-lenght10-filter0-vocabSize0.pkl
a data/samples/
../main.py --modelTag pretrainedv2 --test interactive
. Gracias a Nicholas C., aquí (original) hay algunos modelos preentrenados adicionales (compatibles con TF 1.2) para diversos conjuntos de datos. La carpeta también contiene el conjunto de datos preprocesados para Cornell, OpenSubtitles, Ubuntu y Scotus (para mover dentro data/samples/
). Son necesarios si no desea procesar los conjuntos de datos usted mismo.
Si tiene una GPU de alta gama, no dude en jugar con los hiperparámetros/corpus para entrenar un modelo mejor. Según mis experimentos, parece que la tasa de aprendizaje y la tasa de abandono tienen el mayor impacto en los resultados. Además si quieres compartir tus modelos no dudes en contactarme y lo agregaré aquí.
Además de probar un modelo más grande/profundo, hay muchas pequeñas mejoras que podrían probarse. No dude en enviar una solicitud de extracción si implementa una de ellas. Aquí hay algunas ideas:
loop_function
de tf.nn.seq2seq.rnn_decoder
, no debería ser demasiado difícil agregarlo. Después de eso, debería ser posible jugar con la temperatura SoftMax para obtener predicciones más conservadoras o exóticas.embedding_rnn_seq2seq
por embedding_attention_seq2seq
en model.py
.Q:Sentence 1. Sentence 2. => A:Sentence X. Sentence Y.
podríamos generar 3 nuevas muestras: Q:Sentence 1. Sentence 2. => A:Sentence X.
, Q:Sentence 2. => A:Sentence X. Sentence Y.
y Q:Sentence 2. => A:Sentence X.
Advertencia: otras combinaciones como Q:Sentence 1. => A:Sentence X.
no funcionarán porque rompería la transición 2 => X
que vincula la pregunta con la respuesta)
y
para que el codificador sepa cuándo está cambiando el interlocutor. Sin embargo, no estoy seguro de que el modelo seq2seq simple sea suficiente para capturar dependencias a largo plazo entre oraciones. Agregar un sistema de cubos para agrupar longitudes de entrada similares podría mejorar en gran medida la velocidad del entrenamiento.