奇点机智Naturali

用深度学习网络搭建一个聊天机器人(下篇)

实现一个基于检索模型的机器人!

谁/为什么关注基于检索模型的机器人?

在本系列的上一篇博客中说到,基于检索模型的机器人有一个的回答集(repository),包含了预先定义的若干回答。与该模型相对应的产生式模型则是在不借助任何回答集的情况下产生一个全新的回答。

让我们更正式地定义基于检索模型的机器人:模型的输入为上下文(context)$c$和回答(response)$r$。模型会根据上下文为回答评分,评分最高的回答将被选择作为模型的输出。

你一定想问,在能够搭建一个产生式模型的情况下,为什么我们更想搭建一个基于检索的模型?诚然,产生式模型看起来更灵活,并且不需要预先定义的回答集。原因很简单:当下的产生式模型在实践中表现不佳。因为他们太灵活了,以至于他们非常容易犯语法错误、产生和问题不相关的回答、产生万金油式的回答或是与前文不一致的回答(我们在(上篇)中对这些问题有过简略讨论)。此外,产生式模型需要大量的训练数据。现今,工业界主流的系统大多仍是基于检索模型的,或是两种模型的结合。产生式模型是一个活跃的研究领域,但是我们才刚刚起步。如果现在的你想搭建一个聊天机器人,基于检索的模型应该能让你更有成就感 :)

UBUNTU对话语料库

在这篇博客中,我们将使用UBUNTU对话语料库Ubuntu Dialog Corpus)(papercode)。UBUNTU对话语料库UDC)是基于Ubuntu频道的对话日志,是最大的公开的对话数据集之一。

这篇文章已经深入介绍了这个数据集是如何创建的,因此本文不再加以赘述。不过我们可以大致了解一下数据集的结构,方便我们在模型中使用。

训练数据集包括了100万个样本,正负样本各占一半。每个样本由上下文(context)和回答(utterance)构成。上下文指的是从对话开始,截止到当前的内容,回答指的是对这段内容的回应。换而言之,上下文可以是若干句对话,而回答则是对这若干句对话的回应。正样本指的是该样本的上下文和回答是匹配的,对应地,负样本指的是二者是不匹配的——回答是从语料库的某个地方随机抽取的。下图是训练数据集的部分展示:

你会发现,这些样本看起来有点奇怪。事实上,是因为产生数据集的脚本使用NLTK为我们做了一系列的数据预处理工作——分词tokenized)、英文单词取词根stemmed)、英文单词变形的归类lemmatized)(例如单复数归类)等。此外,例如人名、地名、组织名、URL链接、系统路径等专有名词,NLTK也做了替代。这些预处理工作也不是非做不可,不过它们似乎让结果变好了:) 经过统计,上下文的平均长度大概是450个字符,回答的平均长度大概是80个字符。

产生数据集的脚本也能够生成测试数据集(见下图)。在测试数据集中,每一条记录(record)包括:1个上下文;1个真实回答;9个错误回答。本模型的目标就是让真实回答的评分最高,错误回答的评分低(这样模型就能选出正确回答了!)

介绍完数据集,大致说一下评测模型好坏的方法。有许多评测方法可以使用,而最常用的方法称为$Recall@K$ 。什么意思呢?模型会按照评分的从高到低,挑选K个回答。如果正确的回答在这K个当中,我们就认为这条测试样本预测正确。显然,K越大,事情越简单。对于刚才介绍的测试集,如果令$K=10$ ,则分类准确率为100%,因为所有的回答都被选进来了,正确的回答一定在其中!对应的,如果令$K=1$ ,则模型只有一次选择的机会,这对模型的精准程度要求很高。

在这里,我想提一下该数据集的特殊性以及和真实数据的区别。对于该数据集,机器人模型每次都对不同的回答打分,在训练阶段,有些回答机器人可能只见过一次。这意味着机器人的泛化能力要好,才能在面对测试集中许多从未见过的回答时表现良好。然而,在许多的现实系统中,机器人只需要处理数量有限的回答,即训练集中,每一种可能的回答,都会有若干条样本与此对应。因此,机器人不会被要求给从没见过的回答打分。这样事情就简单多了!因此现实中的基于检索模型的机器人,应该会比本模型的效果要好。

一些简单的基准线(baseline)

在介绍更复杂的深度学习的模型之前,先让我们再次明确一下我们的任务,并且搭建几个简单的baseline模型。这有助于了解我们能够对我们的模型抱有多大的期待 :)

我们将使用下面的函数来评估我们的$recall@k$指标:

# Evaluation
def evaluate_recall(y, y_test, k=1):
    num_examples = float(len(y))
    num_correct = 0
    for predictions, label in zip(y, y_test):
        if label in predictions[:k]:
            num_correct += 1
    return num_correct/num_examples

在这里,$y$是排序过后的预测值的list,$y$_$test$是真实的标签(label)。举例来说,有一个$y$是这样的:$[0,3,1,2,5,6,4,7,8,9]$,代表编号为0的回答得到了最高分,编号为9的回答最低分。因为我们的测试集的样本有10个回答,因此编号为0~9。如果$y$_$test=3$,即正确的回答为编号为3的回答,并且评测标准为$recall@1$,那么这条测试样本将被标注为错误;反之,如果是$recall@2$,那么这条样本则为正确。

直观来说,一个完全随机的预测模型,在$recall@1$时,正确率应该为10%,在$recall@2$时,正确率应为20%,以此类推。让我们写一个小程序验证一下:

# Random Predictor
def predict_random(context, utterances):
    return np.random.choice(len(utterances), 10, replace=False)
# Evaluate Random predictor
y_random = [predict_random(test_df.Context[x], test_df.iloc[x,1:].values) for x in range(len(test_df))]
for n in [1, 2, 5, 10]:
    print("Recall @ ({}, 10): {:g}".format(n, evaluate_recall(y_random, y_test, n)))
Recall @ (1, 10): 0.0937632
Recall @ (2, 10): 0.194503
Recall @ (5, 10): 0.49297
Recall @ (10, 10): 1

非常好!结果和我们预想的一样。当然了,我们并不满足于一个随机的预测模型。在那篇文章(见上)中,还讨论了另一个baseline,叫做tf-idf预测模型。tf-idf指的是词频-逆向文件频率(term frequency – inverse document frequency),衡量的是一个单词在一个语料库中的重要程度。更多关于tf-idf的细节我们将不再赘述(网上有许多相关资料),一言蔽之,相似内容的文档具有相似的tf-idf向量。直观来说,如果一个上下文和回答具有相似的词汇,那么它们更有可能是一对匹配的组合。至少这种估计会比随机的要靠谱。

当下,许多库(例如scikit-learn)都有tf-idf的内置函数,因此,使用起来并不困难。让我们搭建一个tf-idf的预测模型,看看它表现如何:

class TFIDFPredictor:
    def __init__(self):
        self.vectorizer = TfidfVectorizer()
 
    def train(self, data):
        self.vectorizer.fit(np.append(data.Context.values,data.Utterance.values))
 
    def predict(self, context, utterances):
        # Convert context and utterances into tfidf vector
        vector_context = self.vectorizer.transform([context])
        vector_doc = self.vectorizer.transform(utterances)
        # The dot product measures the similarity of the resulting vectors
        result = np.dot(vector_doc, vector_context.T).todense()
        result = np.asarray(result).flatten()
        # Sort by top results and return the indices in descending order
        return np.argsort(result, axis=0)[::-1]
# Evaluate TFIDF predictor
pred = TFIDFPredictor()
pred.train(train_df)
y = [pred.predict(test_df.Context[x], test_df.iloc[x,1:].values) for x in range(len(test_df))]
for n in [1, 2, 5, 10]:
    print("Recall @ ({}, 10): {:g}".format(n, evaluate_recall(y, y_test, n)))
Recall @ (1, 10): 0.495032
Recall @ (2, 10): 0.596882
Recall @ (5, 10): 0.766121
Recall @ (10, 10): 1

可以看到,tf-idf模型比随机模型表现好多了,但是这远远不够。事实上,我们刚才的假设是有问题的:第一,合适的回答没必要和上下文词汇相似;第二,tf-idf忽略了词汇的顺序,而这点很关键。使用基于神经网络的模型,我们应该会得到更好的结果。

对偶编码LSTM模型(DUAL ENCODER LSTM

在本小节中,我们将搭建一个对偶编码的LSTM深度学习模型,也叫作连体网络(Siamese network)。这种类型的网络只是解决此类问题的选择之一,也许不是最好的。大家当然可以发挥想象力,搭建各种各样的深度学习框架来尝试——这也是目前的研究热点。那么,为什么我们选择了对偶编码的模型呢?因为根据这个实验的结果,该模型表现良好。并且,由于我们已经有可以参照的基准程序(benchmark)了,我们就可以对重现该模型有一个合理的预估。当然,使用别的模型(例如attention-based的RNN模型)也会是个有趣的研究点。 我们搭建的对偶编码RNN模型结构如下(paper):

它的工作原理大致如下:

  1. 上下文(context)和回答(response)按照单词分割,然后每个单词用词向量代替。我们使用的词向量是Stanford的GloVe,它们在网络训练过程中也会被调优(图中没有展示词向量代替)

  2. 上下文和回答会以单词为粒度,送入RNN中(图中$c_i$和$r_i$可以认为是一个单词的词向量)。接着RNN会产生一个向量,可以认为其大致代表上下文和回答的“含义”(图中的$c$和$r$)我们可以指定这个向量的维度,假设现在我们指定为256维。

  3. 我们将$c$和一个矩阵$M$相乘,“预测”一个回答$r’$。如果$c$是一个256维的向量,那么$M$设定为256*256维的矩阵,这样乘出来的结果$r’$就是另一个256维的向量。可以认为$r’$是上下文$c$经过网络后,产生的回答。矩阵$M$在训练过程中会被学习。

  4. 我们衡量产生的回答$r’$和真实回答$r$之间的相似度。使用的方法为对二者进行点积(dot product)操作。点积结果越大,说明二者越相似,那么当前的回答$r$就会获得越高分。然后,我们会使用sigmoid函数,将点积结果转化为概率值。图中右侧的$σ(c^{T}Mr)$结合了步骤3和步骤4。

为了训练这个网络,我们需要定义一个损失函数loss function)。我们将使用在分类问题中常用的二元交叉熵binary cross-entropy)。我们用$y$代表“上下文-回答”的pair的真实标注(true label),$y$要么是1(真实回答),要么是0(错误回答);用$y’$代表预测出来的概率值,$y\in[0,1]$。那么,交叉熵损失值的计算方式如下:$L = −y * ln(y’) − (1−y) * ln(1−y’)$。这个公式的直观理解非常简单。如果$y=1$,则$L = -ln(y’)$,那么,如果$y’$离1很远,L的值就会很大,作为惩罚。如果$y=0$,则$L = -ln(1-y’)$,此时则是惩罚$y’$离0很远的情况。

我们的模型实现使用了numpypandasTensorflowTF Learn(也是Tensorflow的一部分,提供很多便于使用的函数)

在模型搭建之前,我们需要定义一些参数hyper-parameters):

# The maximum number of words to consider for the contexts
MAX_CONTEXT_LENGTH = 80
 
# The maximum number of words to consider for the utterances
MAX_UTTERANCE_LENGTH = 30
 
# Word embedding dimensionality
EMBEDDING_SIZE = 300
 
# LSTM Cell dimensionality
LSTM_CELL_SIZE = 256

限制上下文和回答句子的长度是为了使得模型训练得更快。根据之前介绍的对数据集的统计,80个单词大概能够截取到上下文的大部分内容,相应地,回答使用40个单词大概足够。我们让词向量的维数为300,因为预先训练(pre-trained)好的无论是word2vec还是GloVe都是300维的,这样设定方便我们直接使用它们。

接着,我们利用TF Learn的库函数,对数据做预处理。包括构建单词-索引表(vocab_processor)、将数据集从单词转换为索引(index);此外,我们还载入GloVe的词向量,并初始化单词索引-词向量表(initial_embeddings):将数据集中,在GloVe存在的单词替换为GloVe词向量,不存在的单词则初始化为$(-0.25,0.25)$之间的均匀分布。

# Preprocessing
# ==================================================
# Create vocabulary mapping
all_sentences = np.append(train_df.Context, train_df.Utterance)
vocab_processor = skflow.preprocessing.VocabularyProcessor(MAX_CONTEXT_LENGTH, min_frequency=5)
vocab_processor.fit(all_sentences)

# Transform contexts and utterances
X_train_context = np.array(list(vocab_processor.transform(train_df.Context)))
X_train_utterance = np.array(list(vocab_processor.transform(train_df.Utterance)))

# Generate training tensor
X_train = np.stack([X_train_context, X_train_utterance], axis=1)
y_train = train_df.Label

n_words = len(vocab_processor.vocabulary_)
print("Total words: {}".format(n_words))


# Load glove vectors
# ==================================================
vocab_set = set(vocab_processor.vocabulary_._mapping.keys())
glove_vectors, glove_dict = load_glove_vectors(os.path.join(FLAGS.data_dir, "glove.840B.300d.txt"), vocab_set)


# Build initial word embeddings
# ==================================================
initial_embeddings = np.random.uniform(-0.25, 0.25, (n_words, EMBEDDING_DIM)).astype("float32")
for word, glove_word_idx in glove_dict.items():
    word_idx = vocab_processor.vocabulary_.get(word)
    initial_embeddings[word_idx, :] = glove_vectors[glove_word_idx]

在搭建模型之前,我们需要先引入一个扩展内容。由于在实际测试时,对数据集进行“多截取,少补零”的规整化方式,可能会让我们损失一些精度。设想,如果一句话只有5个单词,而被补全到了80个单词,或是一句话有150个单词,却被截取到了80个单词,无论如何,都是不够好的。但是,在上文也提过,对数据进行切取,是为了加速训练过程。因此,我们需要一个trade-off。对于截取,我们仍然维持原状;对于补全,我们在送入RNN网络之前,会先计算出数据的原始长度(即最后一个非零index)。值得注意的是,之所以可以这么做,是因为tensorflow的RNN模块是支持变长输入数据的训练的。获取不大于最大长度的数据的实际长度的函数定义如下:

def get_sequence_length(input_tensor, max_length):
    """
    If a sentence is padded, returns the index of the first 0 (the padding symbol).
    If the sentence has no padding, returns the max length.
    """
    zero_tensor = np.zeros_like(input_tensor)
    comparsion = tf.equal(input_tensor, zero_tensor)
    zero_positions = tf.argmax(tf.to_int32(comparsion), 1)
    position_mask = tf.to_int64(tf.equal(zero_positions, 0))
    sequence_lengths = zero_positions + (position_mask * max_length)
    return sequence_lengths

接下来,我们可以开始搭建模型了!以下的操作都是以batch为单位进行的。基本步骤如下:

  1. 调用get_sequence_length函数,分别获取上下文和回答的实际长度;

  2. 使用先前构建的单词索引-词向量表,将上下文和回答替换为词向量;

  3. 将上下文和回答分别送入同一个RNN网络中训练,取RNN网络的最后一个state作为上下文和回答的encoding;

  4. 预测、计算概率值和loss。

这些步骤和之前的图解是一一对应的,代码如下:

def rnn_encoder_model(X, y):
    # Split input tensor into separare context and utterance tensor
    context, utterance = tf.split(1, 2, X, name='split')
    context = tf.squeeze(context, [1])
    utterance = tf.squeeze(utterance, [1])
    utterance_truncated = tf.slice(utterance, [0, 0], [-1, MAX_UTTERANCE_LENGTH])

    # Calculate the sequence length for RNN calculation
    context_seq_length = get_sequence_length(context, MAX_CONTEXT_LENGTH)
    utterance_seq_length = get_sequence_length(utterance, MAX_UTTERANCE_LENGTH)

    # Embed context and utterance into the same space
    with tf.variable_scope("shared_embeddings") as vs, tf.device('/cpu:0'):
        embedding_tensor = tf.convert_to_tensor(initial_embeddings)
        embeddings = tf.get_variable("word_embeddings", initializer=embedding_tensor)
        # Embed the context
        word_vectors_context = skflow.ops.embedding_lookup(embeddings, context)
        word_list_context = skflow.ops.split_squeeze(1, MAX_CONTEXT_LENGTH, word_vectors_context)
        # Embed the utterance
        word_vectors_utterance = skflow.ops.embedding_lookup(embeddings, utterance_truncated)
        word_list_utterance = skflow.ops.split_squeeze(1, MAX_UTTERANCE_LENGTH, word_vectors_utterance)

    # Run context and utterance through the same RNN
    with tf.variable_scope("shared_rnn_params") as vs:

        #lsy modified the forget_bias = 2.0
        cell = tf.nn.rnn_cell.LSTMCell(RNN_DIM, forget_bias=2.0)
        cell = tf.nn.rnn_cell.DropoutWrapper(cell,output_keep_prob=0.5)
        context_outputs, context_state = tf.nn.rnn(
            cell, word_list_context, dtype=dtypes.float32, sequence_length=context_seq_length)
        encoding_context = tf.slice(context_state, [0, cell.output_size], [-1, -1])
        vs.reuse_variables()
        utterance_outputs, utterance_state = tf.nn.rnn(
            cell, word_list_utterance, dtype=dtypes.float32, sequence_length=utterance_seq_length)
        encoding_utterance = tf.slice(utterance_state, [0, cell.output_size], [-1, -1])

    with tf.variable_scope("prediction") as vs:
        W = tf.get_variable("W",
                            shape=[encoding_context.get_shape()[1], encoding_utterance.get_shape()[1]],
                            initializer=tf.random_normal_initializer())
        b = tf.get_variable("b", [1])

        # We can interpret this is a "Generated context"
        generated_context = tf.matmul(encoding_utterance, W)
        # Batch multiply contexts and utterances (batch_matmul only works with 3-d tensors)
        generated_context = tf.expand_dims(generated_context, 2)
        encoding_context = tf.expand_dims(encoding_context, 2)
        scores = tf.batch_matmul(generated_context, encoding_context, True) + b
        # Go from [15,1,1] to [15,1]: We want a vector of 15 scores
        scores = tf.squeeze(scores, [2])
        # Convert scores into probabilities
        probs = tf.sigmoid(scores)

        # Calculate loss
        loss = tf.contrib.losses.logistic(scores, tf.expand_dims(y, 1))
        tf.scalar_summary("mean_loss", tf.reduce_mean(loss))

    return [probs, loss]

在定义好模型函数之后,我们调用TF Learn的方法,将模型函数包装起来,还可以设定一些诸如优化方法(optimazer)、学习速率(learning rate)、学习速率衰减函数(learning rate decay function)等参数。然后,令分类器启动,就可以开始训练了!

def evaluate_rnn_predictor(df):
    y_test = np.zeros(len(df))
    y = predict_rnn_batch(df.Context, df.iloc[:, 1:].values)
    for n in [1, 2, 5, 10]:
        print("Recall @ ({}, 10): {:g}".format(n, evaluate_recall(y, y_test, n)))


class ValidationMonitor(tf.contrib.learn.monitors.BaseMonitor):
    def __init__(self, print_steps=100, early_stopping_rounds=None, verbose=1, val_steps=1000):
        super(ValidationMonitor, self).__init__(
            print_steps=print_steps,
            early_stopping_rounds=early_stopping_rounds,
            verbose=verbose)
        self.val_steps = val_steps

    def _modify_summary_string(self):
        if self.steps % self.val_steps == 0:
            evaluate_rnn_predictor(validation_df)


def learning_rate_decay_func(global_step):
    return tf.train.exponential_decay(
        FLAGS.learning_rate,
        global_step,
        decay_steps=FLAGS.learning_rate_decay_every,
        decay_rate=FLAGS.learning_rate_decay_rate,
        staircase=True)

classifier = tf.contrib.learn.TensorFlowEstimator(
    model_fn=rnn_encoder_model,
    n_classes=1,
    continue_training=True,
    steps=FLAGS.num_steps,
    learning_rate=learning_rate_decay_func,
    optimizer=FLAGS.optimizer,
    batch_size=FLAGS.batch_size)

monitor = ValidationMonitor(print_steps=100, val_steps=1000)
classifier.fit(X_train, y_train, logdir='./tmp/tf/dual_lstm_chatbot/', monitor=monitor)

关于对测试集的检验函数,只需要调用我们定义好的classifier的predict_proba函数,就能便捷地做预测了。当然,在此之前,还需要将数据从单词转换为索引。事实上,测试和训练几乎可以共享之前定义的model,除此之外的一些区别,classifier会帮我们处理。

def predict_rnn_batch(contexts, utterances, n=1):
    num_contexts = len(contexts)
    num_records = np.multiply(*utterances.shape)
    input_vectors = []
    for context, utterance_list in zip(contexts, utterances):
        cvec = np.array(list(vocab_processor.transform([context])))
        for u in utterance_list:
            uvec = np.array(list(vocab_processor.transform([u])))
            stacked = np.stack([cvec, uvec], axis=1)
            input_vectors.append(stacked)
    batch = np.vstack(input_vectors)
    result = classifier.predict_proba(batch)[:, 0]
    result = np.split(result, num_contexts)
    return np.argsort(result, axis=1)[:, ::-1]

代码框架大致介绍到这,如果你对这个基于检索的对话系统模型感兴趣,希望自己试验一下,可以访问原作者的github得到更多资料。

在下期的博客中,我们将会推出基于产生式模型的聊天机器人介绍,敬请期待!

Naturali 奇点机智
Naturali 奇点机智

致力于让企业轻松创建语音交互体验,让对话与服务有效连接。语音对话平台“对话流”由奇点机智自主研发,利用其领先的语音识别、NLP、深度学习技术,为企业提供智能语音对话解决方案。

工程深度学习聊天机器人对话系统语料库
6
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

交叉熵技术

交叉熵(Cross Entropy)是Loss函数的一种(也称为损失函数或代价函数),用于描述模型预测值与真实值的差距大小

Dropout技术

神经网络训练中防止过拟合的一种技术

GloVe技术

Stanford开发的用于词向量表示的一个库/工具

基准技术

一种简单的模型或启发法,用作比较模型效果时的参考点。基准有助于模型开发者针对特定问题量化最低预期效果。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

损失函数技术

在数学优化,统计学,计量经济学,决策理论,机器学习和计算神经科学等领域,损失函数或成本函数是将一或多个变量的一个事件或值映射为可以直观地表示某种与之相关“成本”的实数的函数。

超参数技术

在机器学习中,超参数是在学习过程开始之前设置其值的参数。 相反,其他参数的值是通过训练得出的。 不同的模型训练算法需要不同的超参数,一些简单的算法(如普通最小二乘回归)不需要。 给定这些超参数,训练算法从数据中学习参数。相同种类的机器学习模型可能需要不同的超参数来适应不同的数据模式,并且必须对其进行调整以便模型能够最优地解决机器学习问题。 在实际应用中一般需要对超参数进行优化,以找到一个超参数元组(tuple),由这些超参数元组形成一个最优化模型,该模型可以将在给定的独立数据上预定义的损失函数最小化。

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

语料库技术

语料库一词在语言学上意指大量的文本,通常经过整理,具有既定格式与标记;事实上,语料库英文 "text corpus" 的涵意即为"body of text"。

分类问题技术

分类问题是数据挖掘处理的一个重要组成部分,在机器学习领域,分类问题通常被认为属于监督式学习(supervised learning),也就是说,分类问题的目标是根据已知样本的某些特征,判断一个新的样本属于哪种已知的样本类。根据类别的数量还可以进一步将分类问题划分为二元分类(binary classification)和多元分类(multiclass classification)。

聊天机器人技术

聊天机器人是经由对话或文字进行交谈的计算机程序。能够模拟人类对话,通过图灵测试。 聊天机器人可用于实用的目的,如客户服务或资讯获取。有些聊天机器人会搭载自然语言处理系统,但大多简单的系统只会撷取输入的关键字,再从数据库中找寻最合适的应答句。

word2vec技术

Word2vec,为一群用来产生词向量的相关模型。这些模型为浅而双层的神经网络,用来训练以重新建构语言学之词文本。网络以词表现,并且需猜测相邻位置的输入词,在word2vec中词袋模型假设下,词的顺序是不重要的。 训练完成之后,word2vec模型可用来映射每个词到一个向量,可用来表示词对词之间的关系。该向量为神经网络之隐藏层。 Word2vec依赖skip-grams或连续词袋(CBOW)来建立神经词嵌入。Word2vec为托马斯·米科洛夫(Tomas Mikolov)在Google带领的研究团队创造。该算法渐渐被其他人所分析和解释。

对话系统技术

对话系统大致被分成两类: 任务为导向的对话系统,帮助用户去完成特定任务,比如找商品,订住宿,订餐厅等。实现任务为导向的对话系统,主要有两类方式,流水线方法和端到端方法。非任务导向的对话系统,与用户进行互动并提供回答,简单的说,就是在开放领域的闲聊。实现非任务导向对话系统也主要可分为两类,生成方法和基于检索的方法。

词分割技术

词分割是将一串书面语言分成其组成单词的问题。在使用某种形式的拉丁字母的英语和许多其他语言中,空格是单词分隔符(单词分隔符)的良好近似,尽管这个概念具有局限性。

推荐文章
暂无评论
暂无评论~