(9-1)序列建模和注意力机制:序列建模

推荐系统是利用用户的历史行为数据和其他相关信息,为用户提供个性化的推荐内容的系统。在机器学习领域,序列建模和注意力机制在推荐系统中也有着重要的应用。序列建模是对序列数据中的每个元素进行建模和预测,而注意力机制是一种增强序列建模的技术,允许模型关注与当前预测最相关的部分。这两个概念在自然语言处理和机器学习中扮演着重要的角色,为处理序列数据和提高模型性能提供了有力的工具。在本章的内容中,将详细讲解基于序列建模和注意力机制实现推荐系统的知识和用法。

9.1  序列建模

序列建模是指对于一个序列(如文本、语音、时间序列等)中的每个元素进行建模和预测。在自然语言处理中,序列建模通常用于语言生成、机器翻译、语音识别等任务。其中,最常见的序列建模方法是循环神经网络(Recurrent Neural Network,RNN)和其变种,如长短时记忆网络(Long Short-Term Memory,LSTM)和门控循环单元(Gated Recurrent Unit,GRU)等。这些模型能够在处理序列数据时保留先前的信息,并对序列中的每个元素进行建模和预测。在本章前面的内容中,已经讲解了使用循环神经网络建模的知识,接下来将讲解使用长短时记忆网络和门控循环单元建模的知识。

9.1.1  使用长短期记忆网络(LSTM)建模

长短期记忆网络(LSTM)是一种特殊类型的循环神经网络(RNN),专门设计用于解决序列建模问题。与传统的RNN相比,LSTM通过引入记忆单元和门控机制,可以更好地捕捉和处理长期依赖关系,从而在处理长序列时表现更出色。

LSTM中的核心组件是记忆单元(memory cell),它类似于一个存储单元,负责存储和传递信息。记忆单元具有自我更新的能力,可以选择性地遗忘或保留先前的信息。这通过三个门控来实现:遗忘门(forget gate)、输入门(input gate)和输出门(output gate)。其中遗忘门决定是否从记忆单元中删除先前的信息,输入门决定是否将当前的输入信息添加到记忆单元中,而输出门决定何时从记忆单元中读取信息并输出到下一层或模型的输出。这些门控机制通过学习得到,并且它们的输出是由激活函数(通常是sigmoid函数)进行控制的。

在LSTM中,每个时间步都有一个隐藏状态(hidden state),它类似于RNN中的输出,但也包含了记忆单元的信息。隐藏状态可以被传递到下一个时间步,从而帮助模型捕捉序列中的时间依赖关系。

推荐系统旨在根据用户的历史行为和偏好,向他们推荐个性化的项目或内容。短期记忆网络(LSTM)在推荐系统中有广泛的应用,面是LSTM在推荐系统中的一些常见应用:

  1. 用户兴趣建模:LSTM可以用于对用户的兴趣进行建模,通过分析用户历史行为序列(如浏览记录、购买记录等),LSTM可以学习到用户的兴趣和偏好。这样,推荐系统可以根据用户的兴趣预测其可能的兴趣和未来行为,从而提供个性化的推荐。
  2. 会话推荐:LSTM可以用于建模用户的会话数据,即用户在一个特定时间段内的行为序列。通过对用户会话数据进行建模,LSTM可以捕捉用户在会话中的兴趣演化过程,推测用户当前的需求,并提供相应的推荐。这有助于提供更加实时和个性化的推荐体验。
  3. 多模态推荐:在某些推荐场景下,除了用户的行为序列外,还可能存在其他类型的数据,如用户的社交网络数据、文字评论等。LSTM可以用于将这些不同模态的数据进行整合和建模,从而更好地理解用户的兴趣和需求,并提供多模态的个性化推荐。

例如下面是一个简单的例子,功能是使用库Keras实现基于LSTM的推荐系统。

源码路径:daima/9/changduan.py

import numpy as np
from keras.models import Sequential
from keras.layers import LSTM, Dense

# 假设我们有一个用户行为序列数据集,每个序列包含5个项目
# 输入数据的形状为 [样本数, 时间步长, 特征维度]
# 目标数据的形状为 [样本数, 1]

# 创建示例数据
X_train = np.random.random((1000, 5, 10))  # 输入数据
y_train = np.random.randint(0, 2, (1000, 1))  # 目标数据

# 创建LSTM模型
model = Sequential()
model.add(LSTM(32, input_shape=(5, 10)))  # LSTM层,隐藏单元数为32
model.add(Dense(1, activation='sigmoid'))  # 输出层,二元分类

# 编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# 训练模型
model.fit(X_train, y_train, epochs=10, batch_size=32)

# 在实际应用中,你可以使用更大规模的数据集和更复杂的模型结构来获得更好的性能。

# 使用模型进行预测
X_test = np.random.random((10, 5, 10))  # 测试数据
predictions = model.predict(X_test)

# 打印预测结果
print(predictions)

在上述代码中,使用了一个简单的LSTM模型来对用户行为序列进行建模,并通过二元分类预测用户的兴趣。模型的输入数据是一个3D张量,形状为[样本数,时间步长,特征维度],其中样本数表示序列的数量,时间步长表示序列的长度,特征维度表示每个时间步的特征数。模型的输出是一个预测的概率值,代表用户的兴趣。执行后会输出:

# 自定义商品数据集
# 假设我们有5个商品,用整数表示,如下所示:
# 商品A: 0, 商品B: 1, 商品C: 2, 商品D: 3, 商品E: 4
# 创建示例数据,假设有3个用户,每个用户浏览的商品ID列表长度为4
X_train = np.array([
    [[0], [1], [2], [3]],
    [[2], [1], [3], [4]],
    [[4], [0], [2], [1]]
])  # 输入数据

y_train = np.array([
    [0, 0, 1, 0, 0],  # 目标数据,用户1对商品C感兴趣
    [0, 1, 0, 0, 0],  # 目标数据,用户2对商品B感兴趣
    [0, 0, 1, 0, 0]   # 目标数据,用户3对商品C感兴趣
])

需要注意的是,这只是一个简单的例子,实际的推荐系统可能需要更复杂的数据预处理、特征工程、模型调参等步骤来优化模型性能。此外,还可以根据具体的推荐系统需求添加其他组件,如用户特征、项目特征等,以提高推荐的个性化程度。例如下面是一个商品推荐系统实例,我们自定义了消费者用户行为数据集,如浏览历史、购买历史等。

源码路径:daima/9/zhang.py

(1)首先注释说明商品数据集的定义,其中每个商品用一个整数表示。然后创建了示例数据集,包括3个用户的浏览历史和目标数据。X_train表示输入数据,其中每个用户的浏览历史是一个4个时间步长的序列。y_train是目标数据,表示每个用户对5个商品的兴趣。对应代码如下所示。

# 自定义商品数据集
# 假设我们有5个商品,用整数表示,如下所示:
# 商品A: 0, 商品B: 1, 商品C: 2, 商品D: 3, 商品E: 4
# 创建示例数据,假设有3个用户,每个用户浏览的商品ID列表长度为4
X_train = np.array([
    [[0], [1], [2], [3]],
    [[2], [1], [3], [4]],
    [[4], [0], [2], [1]]
])  # 输入数据

y_train = np.array([
    [0, 0, 1, 0, 0],  # 目标数据,用户1对商品C感兴趣
    [0, 1, 0, 0, 0],  # 目标数据,用户2对商品B感兴趣
    [0, 0, 1, 0, 0]   # 目标数据,用户3对商品C感兴趣
])

(2)定义并编译了LSTM模型,在模型中包括一个LSTM层和一个输出层。LSTM层的隐藏单元数为32,输入形状为(4, 1),表示每个用户的浏览历史长度为4,每个时间步长有1个特征。输出层使用softmax激活函数进行多分类,输出的类别数为5。然后,使用categorical_crossentropy作为损失函数,adam作为优化器进行模型的编译。最后,使用示例数据集进行模型训练。对应代码如下所示。

# 创建LSTM模型
model = Sequential()
model.add(LSTM(32, input_shape=(4, 1)))  # LSTM层,隐藏单元数为32
model.add(Dense(5, activation='softmax'))  # 输出层,使用softmax进行多分类,5表示商品数量

# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 训练模型
model.fit(X_train, y_train, epochs=10, batch_size=1)

(3)使用训练好的模型进行预测。输入测试数据X_test表示两个用户的浏览历史。然后,使用模型的predict方法获取预测结果,并打印输出预测结果。对应代码如下所示。

# 使用模型进行预测
X_test = np.array([
    [[1], [2], [0], [4]],  # 用户4的浏览历史
    [[3], [2], [4], [1]]   # 用户5的浏览历史
])  # 测试数据

predictions = model.predict(X_test)

# 打印预测结果
print(predictions)

(4)使用库matplotlib.pyplot绘制可视化预测结果柱状图。首先循环遍历每个用户的预测结果,并使用plt.bar函数绘制柱状图,其中labels表示商品标签,user_prediction表示对应用户的兴趣概率。然后,设置x轴和y轴的标签,以及图表的标题。最后,通过plt.show()显示绘制的柱状图。循环会为每个用户生成一个柱状图窗口,以展示其对不同商品的兴趣概率。对应代码如下所示。

# 绘制柱状图
labels = ['A', 'B', 'C', 'D', 'E']  # 商品标签
users = ['用户4', '用户5']  # 用户标签

for i, user_prediction in enumerate(predictions):
    plt.bar(labels, user_prediction, alpha=0.5)
    plt.xlabel('商品')
    plt.ylabel('兴趣概率')
    plt.title(users[i] + '推荐系统预测结果')
    plt.show()

执行后会输出如下训练过程和预测结果,并分别绘制用户4和用户5的推荐预测结果,如图9-1所示。

Epoch 1/10
3/3 [==============================] - 5s 13ms/step - loss: 1.6135 - accuracy: 0.0000e+00
Epoch 2/10
3/3 [==============================] - 0s 8ms/step - loss: 1.5741 - accuracy: 0.0000e+00
Epoch 3/10
3/3 [==============================] - 0s 9ms/step - loss: 1.5377 - accuracy: 0.3333
Epoch 4/10
3/3 [==============================] - 0s 7ms/step - loss: 1.5055 - accuracy: 0.3333
Epoch 5/10
3/3 [==============================] - 0s 10ms/step - loss: 1.4677 - accuracy: 0.3333
Epoch 6/10
3/3 [==============================] - 0s 8ms/step - loss: 1.4336 - accuracy: 0.3333
Epoch 7/10
3/3 [==============================] - 0s 8ms/step - loss: 1.4013 - accuracy: 0.3333
Epoch 8/10
3/3 [==============================] - 0s 6ms/step - loss: 1.3677 - accuracy: 0.3333
Epoch 9/10
3/3 [==============================] - 0s 10ms/step - loss: 1.3386 - accuracy: 0.3333
Epoch 10/10
3/3 [==============================] - 0s 9ms/step - loss: 1.3043 - accuracy: 0.3333
1/1 [==============================] - 1s 1s/step
[[0.1505128  0.27936116 0.26785    0.18100722 0.12126882]
 [0.13248134 0.32124883 0.27755395 0.15943882 0.10927714]]

上面的每个输出向量的维度对应于商品数量,每个值表示对应商品的兴趣概率。例如,对于第一个用户,模型预测其对商品A、B、C、D、E的兴趣概率分别为0.15051280.27936116、0.267850.181007220.12126882。注意,这些概率值表示用户对不同商品的兴趣程度,并且可以根据概率大小进行商品推荐。在这个例子中,模型预测第二个用户对商品C的兴趣概率较高,可能会将商品C推荐给该用户。

对用户4的预测结果

对用户5的预测结果

图9-1  可视化状图

注意:在推荐系统中,LSTM通常作为一个模块嵌入到更大的推荐系统框架中。除了LSTM之外,还可以结合其他技术和算法,如协同过滤、深度神经网络等,以构建更加强大和准确的推荐系统。

9.1.2  使用门控循环单元建模

门控循环单元(Gated Recurrent Unit,简称GRU)是一种用于序列数据建模的循环神经网络(RNN)变体。它是为了解决传统循环神经网络(如简单循环单元RNN和长短期记忆网络LSTM)中存在的梯度消失和梯度爆炸问题而提出的。GRU引入了门控机制,通过使用更新门和重置门来控制信息的流动和保留。这些门控机制使得GRU能够更好地捕捉长期依赖关系,并具有较少的参数和计算成本。

在下面列出了门控循环单元的核心公式:


GRU模型的建模过程类似于LSTM,可以通过堆叠多个GRU层来构建更深层的模型。然后,可以使用这些模型进行序列数据的预测、生成和分类等任务。在实践中,GRU在语言建模、机器翻译、推荐系统等领域取得了广泛的应用。例如下面是一个使用门控循环单元建模实现的电影推荐系统实例,我们自定义了电影数据集。

源码路径:daima/9/men.py

(1)创建自定义的电影数据集,对应代码如下所示。

X_train = np.array([
    [["复仇者联盟"], ["肖申克的救赎"], ["盗梦空间"], ["好看小说"]],
    [["盗梦空间"], ["肖申克的救赎"], ["好看小说"], ["黑暗骑士"]],
    [["黑暗骑士"], ["复仇者联盟"], ["盗梦空间"], ["肖申克的救赎"]]
])

y_train = np.array([
    [0, 0, 1, 0, 0],  # 目标数据,用户1对电影C感兴趣
    [0, 1, 0, 0, 0],  # 目标数据,用户2对电影B感兴趣
    [0, 0, 1, 0, 0]   # 目标数据,用户3对电影C感兴趣
])

(2)使用OneHotEncoder进行独热编码,对应代码如下所示。

encoder = OneHotEncoder(sparse=False)
X_train_encoded = encoder.fit_transform(X_train.reshape(-1, 1))

(3)创建GRU模型,对应代码如下所示。

model = Sequential()
model.add(GRU(32, input_shape=(4, X_train_encoded.shape[1])))  # GRU层,隐藏单元数为32
model.add(Dense(5, activation='softmax'))  # 输出层,使用softmax进行多分类,5表示电影数量

(4)编译模型,对应代码如下所示。

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

(5)训练模型,对应代码如下所示。

model.fit(X_train_encoded.reshape(X_train.shape[0], X_train.shape[1], -1), y_train, epochs=10, batch_size=1)

(6)使用模型进行预测,对应代码如下所示。

X_test = np.array([
    [["肖申克的救赎"], ["盗梦空间"], ["复仇者联盟"], ["黑暗骑士"]],
    [["好看小说"], ["盗梦空间"], ["黑暗骑士"], ["肖申克的救赎"]]
])

X_test_encoded = encoder.transform(X_test.reshape(-1, 1))
predictions = model.predict(X_test_encoded.reshape(X_test.shape[0], X_test.shape[1], -1))

(7)将预测结果可视化为柱状图,对应代码如下所示。

fig, ax = plt.subplots(len(predictions), 1, figsize=(8, 6*len(predictions)))

for i, pred in enumerate(predictions):
    movie_names = ["复仇者联盟", "肖申克的救赎", "盗梦空间", "好看小说", "黑暗骑士"]
    ax[i].bar(movie_names, pred)
    ax[i].set_ylabel('Probability')
    ax[i].set_title(f'User {i+1} Predictions')

plt.show()

本实例演示了使用GRU模型对用户观看的电影列表进行推荐的过程。首先,通过独热编码将电影名称转换为数值特征。然后,构建一个包含GRU层和输出层的模型,并使用训练数据进行训练。接下来,使用模型对测试数据进行预测,并将预测结果可视化为柱状图,以展示对每个用户的电影兴趣预测概率。

执行后会输出如下训练过程和预测结果,并分别绘制用户4和用户5的推荐预测结果,如图9-2所示。柱状图中的每个柱子代表一个用户的预测结果,柱状图会展示每个电影的预测概率,并以用户编号作为标题。

Epoch 1/10
3/3 [==============================] - 4s 11ms/step - loss: 1.6613 - accuracy: 0.0000e+00
Epoch 2/10
3/3 [==============================] - 0s 7ms/step - loss: 1.6205 - accuracy: 0.0000e+00
Epoch 3/10
3/3 [==============================] - 0s 6ms/step - loss: 1.5826 - accuracy: 0.0000e+00
Epoch 4/10
3/3 [==============================] - 0s 6ms/step - loss: 1.5490 - accuracy: 0.0000e+00
Epoch 5/10
3/3 [==============================] - 0s 6ms/step - loss: 1.5123 - accuracy: 0.3333
Epoch 6/10
3/3 [==============================] - 0s 8ms/step - loss: 1.4746 - accuracy: 0.3333
Epoch 7/10
3/3 [==============================] - 0s 5ms/step - loss: 1.4392 - accuracy: 0.3333
Epoch 8/10
3/3 [==============================] - 0s 5ms/step - loss: 1.4033 - accuracy: 0.3333
Epoch 9/10
3/3 [==============================] - 0s 6ms/step - loss: 1.3676 - accuracy: 0.6667
Epoch 10/10
3/3 [==============================] - 0s 9ms/step - loss: 1.3344 - accuracy: 0.6667
1/1 [==============================] - 1s 787ms/step
[[0.16000953 0.26189715 0.268382   0.14260867 0.16710268]
 [0.15517528 0.26621416 0.26299798 0.1514298  0.16418278]]

图9-2  可视化状图

未完待续

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值