本文是由多篇文章组成的系列教程中的第 1 篇,该系列教程介绍了如何在 Google Cloud Platform (GCP) 中使用 TensorFlow 1.x 和 AI Platform 实现机器学习推荐系统。此部分展示如何在开发系统上安装 TensorFlow 模型代码并在 MovieLens
数据集上运行模型。
本教程中的推荐系统使用加权交替最小二乘 (WALS) 算法。WALS 随附在 TensorFlow 1.x 代码库的 contrib.factorization 软件包中,用于对大型用户和项目评分矩阵进行因式分解。要详细了解 WALS,请查看概览。
本文详细介绍了模型的代码,包括数据预处理和在 TensorFlow 中执行 WALS 算法。
该系列包含以下部分:
- 概览
- 创建模型(第 1 部分)(本教程)
- 在 AI Platform 上训练和调整(第 2 部分)
- 应用于 Google Analytics 中的数据(第 3 部分)
目标
- 了解将 WALS 应用于矩阵因式分解所使用的 TensorFlow 代码的结构。
- 在本地运行示例 TensorFlow 代码,基于
MovieLens
数据集执行推荐。
费用
本教程使用 Cloud Storage 和 AI Platform 这两项收费服务。您可以使用价格计算器来估算预计使用量的费用。本教程的预计费用为 0.15 美元。如果您是 GCP 新用户,可能有资格申请免费试用。
准备工作
-
在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。
-
确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能。
- 启用 Compute Engine and AI Platform API。
运行 TensorFlow 模型
您可以在具有至少 7G 内存的 Compute Engine 实例上运行本部分中的步骤,如以下过程中所述。 或者,您可以在本地 macOS 或 Linux 系统上运行本部分中的步骤;这样的话,则无需创建 Compute Engine 实例。
创建 Compute Engine 实例
在 Google Cloud Console 中,转到虚拟机实例页面。
点击创建实例。
根据您的喜好命名实例,并选择一个地区。如果您还没有首选地区,请选择一个地理位置靠近您的地区。
在机器类型下拉列表中,选择 2 vCPU 和 n1-standard-2。
在访问权限范围部分中,选择允许对所有 API 的全面访问权限 (Allow Full Access To All APIs)。
点击创建。
安装代码
转到虚拟机实例页面。
在实例对应的行中,点击 SSH 以打开基于浏览器的终端,该终端以安全的方式连接到该实例。
在新终端窗口中,更新实例的软件代码库。
sudo apt-get update
安装
git
、bzip2
和unzip
。sudo apt-get install -y git bzip2 unzip
克隆示例代码库:
git clone https://github.com/GoogleCloudPlatform/tensorflow-recommendation-wals
安装 miniconda。示例代码需要 Python 2.7。
wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh bash Miniconda2-latest-Linux-x86_64.sh export PATH="/home/$USER/miniconda2/bin:$PATH"
安装 Python 软件包和 TensorFlow。在本教程中,将在 TensorFlow 的任意 1.x 版本上运行。
cd tensorflow-recommendation-wals conda create -y -n tfrec conda install -y -n tfrec --file conda.txt source activate tfrec pip install -r requirements.txt pip install tensorflow==1.15
下载
MovieLens
数据集。数据集具有多个版本。若要开发,建议使用
100k
版本,它包含 943 位用户对 1682 个项的 100000 个评分。请使用以下命令下载该版本:curl -O 'http://files.grouplens.org/datasets/movielens/ml-100k.zip' unzip ml-100k.zip mkdir -p data cp ml-100k/u.data data/
若要训练,则推荐
1m
数据集,它包含一百万个评分。1m
集的格式与100k
集略有不同。例如,评分文件以::
字符分隔。通过示例代码,您可以使用--delimiter
参数指定数据集使用此分隔符。curl -O 'http://files.grouplens.org/datasets/movielens/ml-1m.zip' unzip ml-1m.zip mkdir -p data cp ml-1m/ratings.dat data/
您还可对此项目使用
20m
数据集。该数据集以 CSV 文件提供。如果使用此数据集,则必须传递--headers
标志,因为该文件包含标头行。curl -O 'http://files.grouplens.org/datasets/movielens/ml-20m.zip' unzip ml-20m.zip mkdir -p data cp ml-20m/ratings.csv data/
了解模型代码
模型代码包含在 wals_ml_engine
目录中。代码的高级功能由以下文件实现:
mltrain.sh
- + 启动各种类型的 AI Platform 作业。此 shell 脚本可接受数据集文件位置的参数、用于分隔文件中的值的分隔符,以及数据文件是否具有标头行。最佳做法是创建一个自动配置和执行 AI Platform 作业的脚本。
task.py
- + 解析 AI Platform 作业的参数并进行训练。
model.py
- + 加载数据集。
- 根据数据创建两个稀疏矩阵:一个用于训练,一个用于测试。在训练用的稀疏评分矩阵上执行 WALS。
wals.py
- + 创建 WALS 模型。
- 执行 WALS 算法。
- 计算一组行/列因子和评分矩阵的均方根误差 (RMSE)。
模型预处理数据的方式
模型代码执行数据预处理,以创建稀疏评分矩阵并为矩阵因式分解做准备。这涉及到下列步骤:
模型代码从带分隔符的文本文件加载数据。每一行都包含一个评分。
ratings_df = pd.read_csv(input_file, sep=args['delimiter'], names=headers, header=header_row, dtype={ 'user_id': np.int32, 'item_id': np.int32, 'rating': np.float32, 'timestamp': np.int32, })
该代码为用户和项建立一组唯一 ID(从 0 开始编入索引)。这可保证唯一 ID 与稀疏评分矩阵的特定行和列索引相对应。
MovieLens 100k
数据使用基于 1 的 ID,其中唯一集的最小索引是 1。为了标准化,代码会从每个索引中减去 1。以下内容来自model.py
:ratings = ratings_df.as_matrix(['user_id', 'item_id', 'rating']) # deal with 1-based user indices ratings[:,0] -= 1 ratings[:,1] -= 1
1m
和20m
MovieLens
数据集会跳过一些用户 ID 和项 ID。这会产生一个问题:您必须将唯一用户 ID 集映射到等于 [0 ... num_users-1]
的索引集,并对项 ID 执行相同操作。项映射是使用以下[numpy](http://www.numpy.org/)
代码完成的。该代码会创建一个大小为 [0..max_item_id]
的数组来执行映射,因此如果最大项 ID 非常大,则此方法可能会占用过多内存。np_items = ratings_df.item_id.as_matrix() unique_items = np.unique(np_items) n_items = unique_items.shape[0] max_item = unique_items[-1] # map unique items down to an array 0..n_items-1 z = np.zeros(max_item+1, dtype=int) z[unique_items] = np.arange(n_items) i_r = z[np_items]
映射用户的代码与映射项的代码基本相同。
模型代码随机选择一个评分测试集。默认选择 10% 的评分用于测试集。这些评分会从训练集中移除,并将用于评估用户和项目因子的预测准确率。
test_set_size = len(ratings) / TEST_SET_RATIO test_set_idx = np.random.choice(xrange(len(ratings)), size=test_set_size, replace=False) test_set_idx = sorted(test_set_idx) ts_ratings = ratings[test_set_idx] tr_ratings = np.delete(ratings, test_set_idx, axis=0)
最后,该代码以坐标形式 (
coo_matrix
) 创建一个 scipy 稀疏矩阵,其中包括用户和推荐项的索引及评分。coo_matrix
对象充当稀疏矩阵的封装容器。它还可验证用户和评分索引,并检查预处理过程中是否出现错误。u_tr, i_tr, r_tr = zip(*tr_ratings) tr_sparse = coo_matrix((r_tr, (u_tr, i_tr)), shape=(n_users, n_items))
如何在 TensorFlow 中实现 WALS 算法
对数据进行预处理后,代码会将稀疏训练矩阵传递到 TensorFlow WALS 模型,以将其分解为行因子 X 和列因子 Y。
执行模型的 TensorFlow 代码实际上很简单,因为它依赖于 TensorFlow contrib.factorization_ops
模块中包含的 WALSModel
类。
SparseTensor
对象已初始化,其中用户 ID 和项 ID 用作索引,评分用作值。以下内容来自wals.py
:input_tensor = tf.SparseTensor(indices=zip(data.row, data.col), values=(data.data).astype(np.float32), dense_shape=data.shape)
数据变量是在预处理步骤中创建的训练评分的
coo_matrix
对象。该模型已实例化:
model = factorization_ops.WALSModel(num_rows, num_cols, dim, unobserved_weight=unobs, regularization=reg, row_weights=row_wts, col_weights=col_wts)
行因子和列因子张量由
WALSModel
类自动创建并进行检索,以便在矩阵因式分解后对其求值:# retrieve the row and column factors row_factor = model.row_factors[0] col_factor = model.col_factors[0]
训练过程使用
wals.py
中的simple_train
方法在 TensorFlow 会话中执行以下循环:row_update_op = model.update_row_factors(sp_input=input_tensor)[1] col_update_op = model.update_col_factors(sp_input=input_tensor)[1] sess.run(model.initialize_op) sess.run(model.worker_init) for _ in xrange(num_iterations): sess.run(model.row_update_prep_gramian_op) sess.run(model.initialize_row_update_op) sess.run(row_update_op) sess.run(model.col_update_prep_gramian_op) sess.run(model.initialize_col_update_op) sess.run(col_update_op)
执行
num_iterations
迭代之后,在会话中对行和列因子张量求值,从而为每个因子生成numpy
数组:# evaluate output factor matrices output_row = row_factor.eval(session=session) output_col = col_factor.eval(session=session)
这些因子数组用于计算评分测试集上的 RMSE。
这两个数组还会以 numpy
格式保存在输出目录中。
训练模型
在该场景中,训练模型涉及到将稀疏评分矩阵分解成用户因子矩阵 X 和推荐项因子矩阵 Y。所保存的用户和推荐项因子可用作推荐系统的基本模型。
该系统会将用户作为输入,从 X 中检索该用户的用户因子矢量,将该矢量与所有推荐项因子 Y 相乘,并根据预测评分返回前 N 个推荐项。
在本地训练模型
在本地训练模型对于开发目的很有用。它能让您快速测试代码更改并包含断点以轻松进行调试。如要在 Cloud Shell 或本地系统上运行模型,请使用 local
选项从 wals_ml_engine
目录运行 mltrain.sh
脚本。
cd wals_ml_engine
对于
MovieLens
100k
数据集,请指定100k
数据文件的路径:./mltrain.sh local ../data u.data
对于
MovieLens
1m
数据集,请添加--delimiter
选项并指定1m
数据文件的路径:./mltrain.sh local ../data ratings.dat --delimiter ::
对于
MovieLens
20m
数据集,请使用--delimiter
和--headers
选项:./mltrain.sh local ../data ratings.csv --headers --delimiter ,
训练作业输出会显示测试集上计算得出的 RMSE。对于 1m
数据集,如果使用源代码中指定的默认超参数,输出应如下所示:
INFO:tensorflow:Train Start: <timestamp> ... INFO:tensorflow:Train Finish: <timestamp> INFO:tensorflow:train RMSE = 1.29 INFO:tensorflow:test RMSE = 1.34
如需了解详情,请参阅第 2 部分。
RMSE 对应于测试集内的预测评分的平均误差。平均而言,该算法生成的每个评分均在 1m
数据集的测试集中实际用户评分的 ±1.29 范围内。如本系列的第 2 部分所示,WALS 算法使用经过调整的超参数时性能更好。
清理
如果您创建了 Compute Engine 实例用于运行 TensorFlow,则必须停止该实例,以避免对您的 GCP 帐号产生费用。本系列的第 2 部分不使用此实例。但是,第 3 部分需要使用 Compute Engine 实例。
关停 Compute Engine 实例
- 在 Cloud Console 中,打开 Compute Engine 虚拟机实例列表页面。
- 选择实例名称。
- 点击停止并确认操作。
删除项目
为了避免产生费用,最简单的方法是删除您为本教程创建的项目。
如需删除项目,请执行以下操作:
- 在 Cloud Console 中,转到管理资源页面。
- 在项目列表中,选择要删除的项目,然后点击删除。
- 在对话框中输入项目 ID,然后点击关闭以删除项目。
后续步骤
- 下一篇教程 TensorFlow 中的建议:在 AI Platform 上训练和调整(第 2 部分)介绍了如何在 AI Platform 上训练推荐模型和调整超参数。