使用TensorFlow.js的AI聊天机器人五:创建电影对话聊天机器人

目录

设置UpTensorFlow.js代码

康奈尔电影报价数据集

通用句子编码器

电影聊天机器人在行动

终点线

下一步是什么?


TensorFlow + JavaScript。现在,最流行、最先进的AI框架支持地球上使用最广泛的编程语言因此,让我们在Web浏览器中通过深度学习使文本和NLP(自然语言处理)聊天机器人神奇地发生,使用TensorFlow.js通过WebGL加速GPU!

您是否想过看电影会是什么样子?玩场景并参与对话?让我们通过AI实现它!此处为上一篇文章链接

在这个项目中,我们将建立一个聊天机器人,像电影一样说话,并适当地回应我们。为了使这项工作奏效,我们将使用一个名为通用句子编码器(USE)的TensorFlow库来找出对键入的消息的最佳响应。

设置UpTensorFlow.js代码

该项目在单个网页中运行。我们将包括TensorFlow.jsUSE,这是一个经过预先训练的基于转换器的语言处理模型。我们将添加几个输入元素,供用户在聊天机器人中键入消息并读取其响应。两个附加的实用函数,dotProductzipWith,从USE自述的例子,将帮助我们确定句子相似度。

<html>
    <head>
        <title>AI Chatbot from Movie Quotes: Chatbots in the Browser with TensorFlow.js</title>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/universal-sentence-encoder"></script>
    </head>
    <body>
        <h1 id="status">Movie Dialogue Bot</h1>
        <p id="bot-text"></p>
        <input id="question" type="text" />
        <button id="submit">Send</button>
        <script>
        function setText( text ) {
            document.getElementById( "status" ).innerText = text;
        }

        // Calculate the dot product of two vector arrays.
        const dotProduct = (xs, ys) => {
          const sum = xs => xs ? xs.reduce((a, b) => a + b, 0) : undefined;

          return xs.length === ys.length ?
            sum(zipWith((a, b) => a * b, xs, ys))
            : undefined;
        }

        // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
        const zipWith =
            (f, xs, ys) => {
              const ny = ys.length;
              return (xs.length <= ny ? xs : xs.slice(0, ny))
                  .map((x, i) => f(x, ys[i]));
            }

        (async () => {
            // Your Code Goes Here
        })();
        </script>
    </body>
</html>

康奈尔电影报价数据集

我们的聊天机器人将学会使用康奈尔电影报价数据集中的电影报价进行响应。它包含超过20万条对话消息。为了获得更好的性能,我们将选择一个随机子集来响应每个消息。我们需要解析的两个文件是movie_lines.txtmovie_conversations.txt,以便我们可以创建引号和匹配响应的集合。

让我们遍历每个会话以填充问题/提示数组和匹配的响应数组。这两个文件都使用字符串" +++$+++ "作为分隔符,代码如下所示:

let movie_lines = await fetch( "web/movie_lines.txt" ).then( r => r.text() );

let lines = {};
movie_lines.split( "\n" ).forEach( l => {
    let parts = l.split( " +++$+++ " );
    lines[ parts[ 0 ] ] = parts[ 4 ];
});

let questions = [];
let responses = [];
let movie_conversations = await fetch( "web/movie_conversations.txt" ).then( r => r.text() );
movie_conversations.split( "\n" ).forEach( c => {
    let parts = c.split( " +++$+++ " );
    if( parts[ 3 ] ) {
        let phrases = parts[ 3 ].replace(/[^L0-9 ]/gi, "").split( " " ).filter( x => !!x ); // Split & remove empty lines
        for( let i = 0; i < phrases.length - 1; i++ ) {
            questions.push( lines[ phrases[ i ] ] );
            responses.push( lines[ phrases[ i + 1 ] ] );
        }
    }
});

通用句子编码器

通用编码器句USE)是“[预先训练]模型编码文本转换成512维的嵌入。有关USE及其体系结构的完整说明,请参阅本系列前面的改进的情绪检测文章。

USE易于使用。在定义网络模型之前,让我们在代码中加载它,并使用其QnA双编码器,该编码器将为我们提供所有查询和所有答案的全句嵌入。这应该比单词嵌入更好。我们可以使用它来确定最合适的报价和回复。

// Load the universal sentence encoder
setText( "Loading USE..." );
let encoder = await use.load();
setText( "Loaded!" );
const model = await use.loadQnA();

电影聊天机器人在行动

因为这些句子嵌入已经将相似性编码到其向量中,所以我们不需要训练单独的模型。我们需要做的就是弄清楚哪个电影报价与用户提交的消息最相似,以便我们得到答复。这是通过使用QnA编码器完成的。将所有引号放入编码器可能需要很长时间,否则会使我们的计算机超负荷运行。因此,现在,我们将为每个聊天消息选择200个引号的随机子集来解决此问题。

document.getElementById( "submit" ).addEventListener( "click", async function( event ) {
    let text = document.getElementById( "question" ).value;
    document.getElementById( "question" ).value = "";

    // Run the calculation things
    const numSamples = 200;
    let randomOffset = Math.floor( Math.random() * questions.length );
    const input = {
        queries: [ text ],
        responses: questions.slice( randomOffset, numSamples )
    };
    let embeddings = await model.embed( input );
    tf.tidy( () => {
        const embed_query = embeddings[ "queryEmbedding" ].arraySync();
        const embed_responses = embeddings[ "responseEmbedding" ].arraySync();
        let scores = [];
        embed_responses.forEach( response => {
            scores.push( dotProduct( embed_query[ 0 ], response ) );
        });
        let id = scores.indexOf( Math.max( ...scores ) );
        document.getElementById( "bot-text" ).innerText = responses[ randomOffset + id ];
    });
    embeddings.queryEmbedding.dispose();
    embeddings.responseEmbedding.dispose();
});

就像那样,您已经有了一个可以与您交谈的聊天机器人。

 

终点线

这是使此聊天机器人生效的代码:

<html>
    <head>
        <title>AI Chatbot from Movie Quotes: Chatbots in the Browser with TensorFlow.js</title>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/universal-sentence-encoder"></script>
    </head>
    <body>
        <h1 id="status">Movie Dialogue Bot</h1>
        <p id="bot-text"></p>
        <input id="question" type="text" />
        <button id="submit">Send</button>
        <script>
        function setText( text ) {
            document.getElementById( "status" ).innerText = text;
        }

        // Calculate the dot product of two vector arrays.
        const dotProduct = (xs, ys) => {
          const sum = xs => xs ? xs.reduce((a, b) => a + b, 0) : undefined;

          return xs.length === ys.length ?
            sum(zipWith((a, b) => a * b, xs, ys))
            : undefined;
        }

        // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
        const zipWith =
            (f, xs, ys) => {
              const ny = ys.length;
              return (xs.length <= ny ? xs : xs.slice(0, ny))
                  .map((x, i) => f(x, ys[i]));
            }

        (async () => {
            let movie_lines = await fetch( "web/movie_lines.txt" ).then( r => r.text() );

            let lines = {};
            movie_lines.split( "\n" ).forEach( l => {
                let parts = l.split( " +++$+++ " );
                lines[ parts[ 0 ] ] = parts[ 4 ];
            });

            let questions = [];
            let responses = [];
            let movie_conversations = await fetch( "web/movie_conversations.txt" ).then( r => r.text() );
            movie_conversations.split( "\n" ).forEach( c => {
                let parts = c.split( " +++$+++ " );
                if( parts[ 3 ] ) {
                    let phrases = parts[ 3 ].replace(/[^L0-9 ]/gi, "").split( " " ).filter( x => !!x ); // Split & remove empty lines
                    for( let i = 0; i < phrases.length - 1; i++ ) {
                        questions.push( lines[ phrases[ i ] ] );
                        responses.push( lines[ phrases[ i + 1 ] ] );
                    }
                }
            });

            // Load the universal sentence encoder
            setText( "Loading USE..." );
            let encoder = await use.load();
            setText( "Loaded!" );
            const model = await use.loadQnA();

            document.getElementById( "question" ).addEventListener( "keyup", function( event ) {
                // Number 13 is the "Enter" key on the keyboard
                if( event.keyCode === 13 ) {
                    // Cancel the default action, if needed
                    event.preventDefault();
                    // Trigger the button element with a click
                    document.getElementById( "submit" ).click();
                }
            });

            document.getElementById( "submit" ).addEventListener( "click", async function( event ) {
                let text = document.getElementById( "question" ).value;
                document.getElementById( "question" ).value = "";

                // Run the calculation things
                const numSamples = 200;
                let randomOffset = Math.floor( Math.random() * questions.length );
                const input = {
                    queries: [ text ],
                    responses: questions.slice( randomOffset, numSamples )
                };
                let embeddings = await model.embed( input );
                tf.tidy( () => {
                    const embed_query = embeddings[ "queryEmbedding" ].arraySync();
                    const embed_responses = embeddings[ "responseEmbedding" ].arraySync();
                    let scores = [];
                    embed_responses.forEach( response => {
                        scores.push( dotProduct( embed_query[ 0 ], response ) );
                    });
                    let id = scores.indexOf( Math.max( ...scores ) );
                    document.getElementById( "bot-text" ).innerText = responses[ randomOffset + id ];
                });
                embeddings.queryEmbedding.dispose();
                embeddings.responseEmbedding.dispose();
            });
        })();
        </script>
    </body>
</html>

 

下一步是什么?

在本文中,我们建立了一个聊天机器人,可以与某人进行对话。但是有什么比对话更好的呢?那...独白呢?

在本系列的最后一篇文章中,我们将使用TensorFlow.js在浏览器中构建一个莎士比亚独白生成器。

https://www.codeproject.com/Articles/5282694/AI-Chatbots-With-TensorFlow-js-Creating-a-Movie-Di

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值