Advertisement

推荐系统之新闻推荐(News Recommendation for Recommendation System)

阅读量:

总结
NR-RNN(基于神经递归自动编码器的新闻推荐模型)是一种先进的新闻推荐算法,旨在通过用户点击序列和文本序列的深度学习建模,提升新闻推荐的准确性。该模型结合了用户兴趣建模和信息融合技术,能够同时利用用户的点击行为和文本内容,生成个性化的新闻推荐结果。
模型概述
用户点击序列编码器:使用RNN对用户的点击序列进行编码,提取用户的兴趣特征。
文本序列编码器:同样使用RNN对新闻文本进行编码,提取新闻的语义特征。
预测模型:将用户编码器和文本编码器的输出拼接后,通过全连接层预测用户对新闻的喜好。
核心优势
信息融合:同时利用用户点击序列和文本序列,捕捉用户的兴趣层次结构。
端到端学习:通过深度学习技术优化推荐模型,提升推荐性能。
实时性:适合处理海量数据和实时推荐需求。
应用场景
针对新闻推荐系统,提升推荐的准确性和相关性。
适用于个性化推荐场景,如社交媒体、电子商务等。
代码实例
数据集处理:将用户点击序列和文本序列转换为适合模型输入的形式。
编码器实现:使用LSTM对序列进行特征提取。
预测模型构建:通过全连接层预测用户喜好。
总结
NR-RNN通过深度学习技术实现了新闻推荐的智能化,能够有效解决传统推荐系统在内容 Cold Start 和实时性方面的挑战,具有广泛的应用前景。

作者:禅与计算机程序设计艺术

1.简介

推荐系统(Recommender Systems)是指通过收集和分析用户的浏览、购买、收藏等行为数据,以及商品和服务的特征信息,为用户提供个性化的商品和服务推荐,或实现精准的市场定位。在互联网经济快速发展的背景下,推荐系统已成为电子商务领域的重要技术支撑。通过深入挖掘消费者的购买偏好和行为特征,推荐系统能够有效推荐相关商品和服务,从而提升企业市场竞争能力,优化客户体验并实现销售额增长。该技术不仅帮助企业更好地了解消费者需求,还能通过精准的市场定位和个性化服务提升商业价值。

推荐系统技术已逐渐成为互联网行业的基础技术。例如,YouTube的推荐系统利用算法为用户推荐他们可能会喜欢的视频;美团外卖App的推荐系统则根据用户的消费习惯、地理位置和喜好生成推荐列表,帮助用户快速找到感兴趣的商家。然而,推荐系统面临的主要挑战仍然是如何高效地处理海量数据。例如,在新闻推荐场景中,每天会产生数十亿条新闻数据,传统基于协同过滤的推荐算法难以应对这种高速数据流,因此需要采用深度学习和神经网络的方法。另一个关键问题是时效性。即使基于线上推荐的数据也面临着时效性问题,数据爆炸带来的延迟问题依然存在。

为了解决推荐系统中的两大核心问题,本文将重点介绍一种基于神经递归自动编码器(NR-RNN)的新型新闻推荐方法。该模型作为端到端的深度学习架构,无需人工特征提取,通过直接分析用户的点击序列及其对应的文本序列,能够有效建模用户对不同新闻的兴趣程度。

2.基本概念术语说明

2.1 用户与兴趣

推荐系统首要考虑的是用户,即推荐对象。推荐对象通常包括人类用户和计算机用户,此外,还可以包括机器人、物体甚至动物。用户喜欢的内容、选择方式、喜欢的人类型以及喜欢的商品类型都可以被视为用户的兴趣。

2.2 新闻与事件

推荐系统的主要功能是向用户推送新闻内容。新闻作为推荐系统的重要输入数据源之一,其类型主要包括短新闻和长新闻两大类。短新闻类型包括手机快讯、微博客等非实时更新的新闻推送内容,而长新闻则多以实体媒体形式呈现,如新闻报道或出版物等。

推荐系统的主要关注对象包括事件、人物以及品牌等。事件作为一个高度抽象的主题,涵盖了特定时间段内发生的各类事件。人物是推荐系统中使用最频繁的输入类型。例如,针对某位知名人物的个性化推荐系统,其输入数据主要来源于该人物的相关新闻报道。品牌则作为一种重要的信息载体,能够帮助推荐系统识别潜在的热点话题,例如,某些餐饮品牌的新闻报道往往能够反映出该行业的最新动态。

2.3 概率分层(Probabilistic Hierarchical Modeling)

概率分层模型作为推荐系统中的关键方法论,其核心观点在于分析用户对不同物品的喜好呈现出层次结构特征。具体而言,该模型认为,一个用户的喜好并非孤立存在,而是由多个子类别共同决定的复杂关系。例如,用户对某一类物品的偏好可能受到特定子类别的显著影响,而与其他子类别之间存在相互作用。通过构建多层次的概率模型,概率分层模型能够有效捕捉用户兴趣的多样性,并为推荐系统提供更精准的个性化服务。

概率分层模型将用户对推荐对象的态度分为五个层次。第一层是用户对推荐对象的态度,包括正面评价、负面评价和未关注等;第二层是用户对推荐对象的喜好程度,包括热门类别、一般类别和冷门类别;第三层是用户对推荐对象的细粒度属性,包括年龄特征、性别特征、地域特征和文化背景;第四层是用户对推荐对象内容的理解深度,即用户是否能够准确理解推荐对象的核心意义;第五层是用户对推荐对象的文本表达能力,即用户的阅读能力或理解能力。

概率分层模型具备对用户喜好进行建模的能力,其涵盖的包括点击序列预测、兴趣变换、因子分解机、图模型以及树模型等技术手段。这些技术手段通过系统性地整合不同层次间的关联与相互作用机制,旨在构建用户兴趣的全面模型。

2.4 协同过滤(Collaborative Filtering)

协同过滤算法通过分析用户的兴趣和行为模式来推荐相关内容。其核心思想在于通过分析用户已有的反馈信息,来评估潜在用户对特定物品的兴趣程度。具体而言,该算法会收集用户对各个物品的评分数据,并基于这些评分信息推测用户对未评分物品的兴趣偏好。通过这种基于用户行为的推荐机制,协同过滤算法能够有效提升推荐的准确性,为用户提供更加个性化的服务体验。

协同推荐算法的主要任务是在新用户缺乏明确兴趣信息时,为用户提供与其兴趣相匹配的物品。基于此,在用户兴趣相对稳定或数据量较小时,协同过滤算法能够表现出较好的效果。然而,当用户兴趣变化剧烈且数据规模极大时,协同过滤算法将面临较大的挑战。

2.5 深度学习与神经递归自动编码器(Neural Recursive Autoencoder, NR-RNN)

深度学习作为一种主要的机器学习技术被广泛采用。在推荐系统领域中,深度学习模型通常被视为深度学习推荐系统。这些模型主要具有两个显著特征:其一,能够从海量数据中学习到有用的模式;其二,具备进行复杂任务的能力。

深度学习推荐系统的主流模型主要通过神经协同过滤(NCF)这一方法实现。NCF主要通过特征的矩阵分解表征用户的兴趣。它首先将用户的点击序列(例如,过去一周,用户点击过的所有文章)转换为特征向量,进而通过矩阵分解推导出用户与文章之间的交互矩阵。接着,它就可以通过分析这一交互矩阵来推断出用户对哪些文章感兴趣。

NCF在推荐系统中的应用仍存在诸多局限性。首先,用户的行为序列往往较为冗长,而协同过滤算法通常处理的数据集规模较小。其次,基于矩阵分解的方法虽然能够提取用户的兴趣特征,但在实际应用过程中,用户的兴趣变化往往难以全面捕捉。例如,用户可能同时关注数百种不同类别的新闻内容,但协同过滤算法在面对海量商品时,往往只能筛选出有限几项。最后,基于矩阵分解的方法仅适用于用户兴趣相对稳定的静态场景,难以应对动态变化的用户偏好。

NR-RNN模型是一种基于神经递归自动编码器的新闻推荐模型。其主要优势在于能够直接利用用户的点击序列及其对应的文本序列,准确建模用户对不同新闻内容的偏好。该模型采用RNN作为编码器,通过对用户的点击序列进行编码,生成一个隐含表示向量。同时,该模型对文本序列进行编码,通过RNN处理,生成另一个隐含向量。最后,该模型将这两个隐含向量进行拼接,形成一个新的综合隐含向量,用于推荐新闻内容。

NR-RNN模型不仅能够利用用户的历史点击数据,还能够利用文本信息,由于文本信息既能反映用户的偏好,又能帮助模型理解用户的兴趣。这种信息融合的效果较单纯使用文本信息或点击数据而言,更为显著。

3.核心算法原理和具体操作步骤以及数学公式讲解

3.1 模型定义与训练

3.1.1 数据集划分

为了实现目标,NR-RNN模型需要准备训练数据集。输入数据由用户点击序列和对应的文本序列组成,其中文本序列是任意长度的字符级别的序列,例如,新闻内容和电影评论。输出数据仅反映用户对不同新闻的喜好程度,范围在0到1之间。

在训练过程中,NR-RNN模型推荐将数据集划分为三个互不重叠的部分,即训练集、验证集和测试集,以确保模型的训练和评估的系统性。训练集主要用于模型的参数学习,验证集则用于优化模型的超参数,而测试集则被用来评估模型的整体性能。在划分数据集时,既可以按照时间顺序将其划分为不同的集合,也可以采用随机划分的方法,以确保数据的多样性和训练的稳定性。

3.1.2 模型定义

NR-RNN模型由由用户点击序列编码器和文本序列编码器组成。用户点击序列编码器(User Encoder)接收用户的点击序列,并将其转换为固定长度的向量,其中该向量的维度与用户点击序列的长度相同。文本序列编码器(Text Encoder)接收文本序列,并将其转换为固定长度的向量,其中该向量的维度与文本序列的长度一致。最后,两个编码器的输出向量经过拼接处理,形成一个用户-文本表示向量。

3.1.3 模型训练

NR-RNN模型的训练方法采用正则项的随机梯度下降法(SGD)。正则项的引入旨在防止模型出现过拟合现象,具体表现为将模型的参数约束在特定范围内,从而避免模型对训练数据产生过度拟合的效果。在SGD的迭代过程中,每一次参数更新均基于随机选取的一个样本,通过计算该样本的梯度并应用梯度下降法来实现参数的优化更新。

模型训练的过程如下:

对每个样本,通过用户点击序列编码器和文本序列编码器对用户-文本表示向量进行编码。
将用户-文本表示向量输入至预测模型,并对其进行训练。
在整个训练集上进行训练,通过损失函数评估模型性能,并根据验证集结果调整模型参数。
每隔一定数量的训练轮次(Epoch),保存模型的最新参数。

3.2 新闻推荐流程

新闻推荐流程可以分为以下三个阶段:

用户输入新闻:用户通过提交搜索关键字、筛选条件等方式,触发推荐新闻的查询请求。
召回阶段:召回环节将推荐系统从数据库中检索到的相关新闻信息进行初步处理。
排序阶段:排序环节对每条新闻进行评分,最终确定为最优结果的新闻将优先展示给用户。

3.3 基本原理

NR-RNN模型的核心机制是编码器-解码器架构。点击序列经过编码器处理,生成用户行为向量。文本序列通过编码器映射为固定长度的向量,随后与用户行为向量结合,形成用户-文本联合表示向量。在此基础上,用户-文本表示向量被输入至预测模型,该模型通过归纳出用户对不同新闻的兴趣偏好,并生成一个概率分布。该概率分布不仅对候选新闻进行排序,同时会将排名靠前的k个新闻提供给用户。

3.3.1 使用示例

假设用户A最近浏览了多篇新闻,其中一条新闻报道是“iPhone X发布会圆满成功”,他在浏览时长为2分钟。此外,用户A搜索了关键词‘iPhone’,并设置了时间范围为‘今天’。

在召回环节,搜索引擎会触发相关内容的检索,例如iPhone 11发布会即将举行,iPhone 7 Plus已降价。随后进入排序阶段,NR-RNN模型将这些新闻分别输入到点击序列编码器和文本序列编码器,提取出用户行为特征向量以及用户与文本之间的关系向量。接着,NR-RNN模型将用户与文本之间的关系向量输入到预测模型,预测用户对不同新闻的兴趣程度。

假设预测模型给出的用户对不同新闻的喜好分别为:

本次iPhone X发布会圆满落幕

在排序阶段,NR-RNN模型会对用户的喜好进行排序。系统将优先展示得分最高的新闻,其中,'iPhone X发布会圆满成功'是此次排序的核心目标。

4.具体代码实例和解释说明

4.1 数据集

推荐系统的训练数据集主要包含用户搜索记录和用户点击记录等。其中,用户搜索日志记录了用户的搜索词条、时间、地区等详细信息;用户点击日志记录了用户的点击行为、时间、地区等详细信息。

数据集的划分一般基于时间维度、内容指标以及用户特征进行。在实际应用中,训练集、验证集和测试集的比例通常设置为6:2:2的比例分配。

假设有一个推荐系统,收集了如下的训练数据:

复制代码
    日期 | 用户ID | 查询词条 | 点击时间 | 区域
    ---|---|---|---|---
    2020-10-01 | userA | 苹果 | 10:00:00 | 北京
    2020-10-01 | userB | 谷歌 | 11:00:00 | 上海
    2020-10-02 | userC | 淘宝 | 12:00:00 | 广州
    2020-10-02 | userA | 小米 | 13:00:00 | 浙江
    2020-10-02 | userB | 京东 | 14:00:00 | 深圳

在该数据集中,查询记录、点击频率、地理位置等信息均与用户兴趣相关。用户标识码是唯一标识符,用于标识用户的独特身份信息。

4.2 点击序列编码器

点击序列编码器用于将用户的点击序列转换为固定长度的向量表示。在 NR-RNN 涯中,点击序列编码器构成 RNN 模型。RNN 模型能够保持前后状态,识别用户的上下文信息。NR-RNN 的点击序列编码器包含以下几个步骤:

  1. 导入库
复制代码
    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers
  1. 创建点击序列编码器模型
  • 指定输入 shape
  • 添加 LSTM 层
  • 设置输出 shape
  • 编译模型
复制代码
    inputs = keras.Input(shape=(None,), dtype='int32')
    
    x = layers.Embedding(input_dim=max_features + 1, output_dim=embedding_size)(inputs)
    
    # LSTM
    lstm_out = layers.LSTM(units=hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout)(x)
    
    outputs = layers.Dense(units=latent_dim, activation="sigmoid")(lstm_out)
    
    model = keras.Model(inputs=[inputs], outputs=[outputs])
    model.compile()
  1. 训练模型
  • 加载数据
  • 拆分数据集
  • 训练模型
复制代码
    train_data = load_dataset('train.csv')
    val_data = load_dataset('val.csv')
    
    history = model.fit([train_data['query']], train_data['click'],
    validation_data=([val_data['query']], val_data['click']),
    epochs=epochs, batch_size=batch_size, verbose=verbose)

4.3 文本序列编码器

文本序列编码器的作用是将用户搜索的文本序列转换为固定长度的向量表示。在NR-RNN架构中,文本序列编码器被设计为RNN模型。NR-RNN的文本序列编码器主要包含以下几个步骤:首先,编码器会依次读取输入序列中的每个元素。接着,每个输入元素会被编码器转换为中间状态向量。最后,编码器会根据中间状态向量进行逐步更新,最终整合所有中间状态信息,生成完整的文本向量表示。

  1. 导入库
复制代码
    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers
  1. 创建文本序列编码器模型
  • 指定输入 shape
  • 添加 LSTM 层
  • 设置输出 shape
  • 编译模型
复制代码
    inputs = keras.Input(shape=(None,), dtype='int32')
    
    x = layers.Embedding(input_dim=max_features + 1, output_dim=embedding_size)(inputs)
    
    # LSTM
    lstm_out = layers.LSTM(units=hidden_size, dropout=dropout, recurrent_dropout=recurrent_dropout)(x)
    
    outputs = layers.Dense(units=latent_dim, activation="sigmoid")(lstm_out)
    
    model = keras.Model(inputs=[inputs], outputs=[outputs])
    model.compile()
  1. 训练模型
  • 加载数据
  • 拆分数据集
  • 训练模型
复制代码
    train_data = load_dataset('train.csv')
    val_data = load_dataset('val.csv')
    
    history = model.fit([train_data['query']], train_data['click'],
    validation_data=([val_data['query']], val_data['click']),
    epochs=epochs, batch_size=batch_size, verbose=verbose)

4.4 预测模型

该预测模型能够接收用户提供的文本向量,并通过学习过程识别用户的新闻偏好。在NR-RNN架构中,预测模型采用了基本的全连接层设计。NR-RNN架构的预测模型包含以下几个主要步骤:

  1. 导入库
复制代码
    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers
  1. 创建预测模型
  • 指定输入 shape
  • 添加全连接层
  • 设置输出 shape
  • 编译模型
复制代码
    inputs = keras.Input(shape=(latent_dim * 2,))
    
    x = layers.Dense(units=dense_size, activation="relu")(inputs)
    predictions = layers.Dense(units=output_dim, activation="softmax")(x)
    
    model = keras.Model(inputs=[inputs], outputs=[predictions])
    model.compile()
  1. 训练模型
  • 加载数据
  • 拆分数据集
  • 训练模型
复制代码
    train_data = load_dataset('train.csv')
    val_data = load_dataset('val.csv')
    
    click_train = to_categorical(train_data['click'])
    query_train = np.array(train_data['query'])[:, :-1]
    text_train = np.array(train_data['text'])[:, :-1]
    labels_train = np.expand_dims(np.argmax(click_train, axis=-1), axis=-1).astype(np.float32)
    
    click_val = to_categorical(val_data['click'])
    query_val = np.array(val_data['query'])[:, :-1]
    text_val = np.array(val_data['text'])[:, :-1]
    labels_val = np.expand_dims(np.argmax(click_val, axis=-1), axis=-1).astype(np.float32)
    
    
    history = model.fit([[query_train, text_train]], [labels_train], 
    validation_data=[[query_val, text_val], labels_val], 
    epochs=epochs, batch_size=batch_size, verbose=verbose)

4.5 完整代码

以上就是 NR-RNN 模型的全部代码。代码如下:

复制代码
    import os
    os.environ["CUDA_VISIBLE_DEVICES"]="-1"   # CPU only mode
    import numpy as np
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from tensorflow.keras.utils import to_categorical
    from tensorflow.keras import layers
    from tensorflow.keras.models import Sequential
    import pandas as pd
    import random
    random.seed(123)
    np.random.seed(123)
    tf.random.set_seed(123)
    
    def load_dataset(file):
    data = pd.read_csv(file, sep='|', header=0)
    queries = []
    texts = []
    clicks = []
    sessions = []
    last_session = None
    session_length = 0
    max_sequence_length = 0
    
    users = sorted(list(set(zip(data.user_id))))
    le = LabelEncoder().fit(['padding']+users)
    ohe = OneHotEncoder(sparse=False).fit(le.transform(users).reshape(-1, 1))
    
    print("Loading dataset...")
    for _, row in tqdm(data.iterrows()):
    if not (row['query'].strip() and row['text'].strip()):
    continue
    
    session = f"{row['user_id']}|{row['session_id']}"
    label = int(row['label'])
    index = len(texts) // session_length
    
    if session!= last_session:
    queries += [[ohe]]
    texts += [['padding']]
    clicks += [[0]]
    last_session = session
    session_length = 1
    
    elif index >= len(queries[-1]):
    queries[-1] += [[ohe]]
    texts[-1] += ['padding']
    clicks[-1] += [0]
    session_length += 1
    
    else:
    assert queries[-1][index].shape == ohe.transform([[len(texts)]]).shape, "Shape of the input is incorrect."
    
    queries[-1][index] = ohe.transform([[len(texts)+i]])
    texts[-1][index] = list(map(ord, row['text']))[:max_seq_length]
    clicks[-1][index] = label
    
    return {'query': queries[:-1*session_length+1], 'text': texts[:-1*session_length+1]}
    
    class UserClickSequenceEncoder(layers.Layer):
    def __init__(self, hidden_size, dropout=0.1, recurrent_dropout=0.1, **kwargs):
    super().__init__(**kwargs)
    self.hidden_size = hidden_size
    self.dropout = dropout
    self.recurrent_dropout = recurrent_dropout
    
    def build(self, input_shape):
    self.embedding = layers.Embedding(input_dim=max_features + 1, output_dim=embedding_size)
    self.lstm = layers.LSTM(units=self.hidden_size, dropout=self.dropout, recurrent_dropout=self.recurrent_dropout)
    self.dense = layers.Dense(units=latent_dim, activation="sigmoid")
    super().build(input_shape)
    
    def call(self, inputs):
    embedding_output = self.embedding(inputs)
    lstm_output = self.lstm(embedding_output)
    dense_output = self.dense(lstm_output)
    return dense_output
    
    def compute_mask(self, inputs, mask=None):
    return mask
    
    
    class TextSequenceEncoder(layers.Layer):
    def __init__(self, hidden_size, dropout=0.1, recurrent_dropout=0.1, **kwargs):
    super().__init__(**kwargs)
    self.hidden_size = hidden_size
    self.dropout = dropout
    self.recurrent_dropout = recurrent_dropout
    
    def build(self, input_shape):
    self.embedding = layers.Embedding(input_dim=max_features + 1, output_dim=embedding_size)
    self.lstm = layers.LSTM(units=self.hidden_size, dropout=self.dropout, recurrent_dropout=self.recurrent_dropout)
    self.dense = layers.Dense(units=latent_dim, activation="sigmoid")
    super().build(input_shape)
    
    def call(self, inputs):
    embedding_output = self.embedding(inputs)
    lstm_output = self.lstm(embedding_output)
    dense_output = self.dense(lstm_output)
    return dense_output
    
    def compute_mask(self, inputs, mask=None):
    return mask
    
    
    def create_model():
    inputs_a = keras.Input((None, latent_dim), name="click_sequence_input")
    inputs_b = keras.Input((None,), name="text_sequence_input", dtype='int32')
    
    user_encoder = UserClickSequenceEncoder(hidden_size, dropout, recurrent_dropout)(inputs_a)
    text_encoder = TextSequenceEncoder(hidden_size, dropout, recurrent_dropout)(inputs_b)
    
    concat = layers.concatenate([user_encoder, text_encoder])
    dense_layer = layers.Dense(units=dense_size, activation="relu")(concat)
    prediction_layer = layers.Dense(units=output_dim, activation="softmax")(dense_layer)
    
    model = keras.Model(inputs=[inputs_a, inputs_b], outputs=[prediction_layer])
    model.summary()
    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)
    model.compile(loss="categorical_crossentropy", optimizer=optimizer, metrics=["accuracy"])
    return model
    
    if __name__ == '__main__':
    batch_size = 64
    learning_rate = 1e-3
    epochs = 50
    hidden_size = 64
    dropout = 0.1
    recurrent_dropout = 0.1
    dense_size = 64
    latent_dim = 32
    output_dim = 2
    
    max_features = 20000
    max_seq_length = 100
    
    # Load data and preprocess it
    train_data = load_dataset('train.csv')
    val_data = load_dataset('val.csv')
    
    click_train = to_categorical(train_data['click'])
    query_train = np.array(train_data['query'])[:, :-1]
    text_train = np.array(train_data['text'])[:, :-1]
    labels_train = np.expand_dims(np.argmax(click_train, axis=-1), axis=-1).astype(np.float32)
    
    click_val = to_categorical(val_data['click'])
    query_val = np.array(val_data['query'])[:, :-1]
    text_val = np.array(val_data['text'])[:, :-1]
    labels_val = np.expand_dims(np.argmax(click_val, axis=-1), axis=-1).astype(np.float32)
    
    # Build and compile model
    model = create_model()
    callbacks = [
    keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True),
    keras.callbacks.ReduceLROnPlateau(factor=0.1, patience=3),
    ]
    history = model.fit([[query_train, text_train], ], [labels_train, ], 
    validation_data=[[query_val, text_val], labels_val, ], 
    epochs=epochs, batch_size=batch_size, verbose=verbose, callbacks=callbacks)
    
    # Evaluate on test set
    test_data = load_dataset('test.csv')
    click_test = to_categorical(test_data['click'])
    query_test = np.array(test_data['query'])[:, :-1]
    text_test = np.array(test_data['text'])[:, :-1]
    labels_test = np.expand_dims(np.argmax(click_test, axis=-1), axis=-1).astype(np.float32)
    results = model.evaluate([[query_test, text_test], ], labels_test, verbose=0)
    print(f'Test loss: {results[0]}, Test accuracy: {results[1]}')

全部评论 (0)

还没有任何评论哟~