从0到1实践设计深度学习推荐系统。
本项目参考SparrowRecSys实现。
SparrowRecSys是一个电影推荐系统,名字SparrowRecSys(麻雀推荐系统),取自“麻雀虽小,五脏俱全”之意。项目是一个基于maven的混合语言项目,同时包含了TensorFlow,Spark,Jetty Server等推荐系统的不同模块。希望你能够利用SparrowRecSys进行推荐系统的学习,并有机会一起完善它。
受极客时间邀请开设 深度学习推荐系统实战 课程,详细讲解了SparrowRecSys的所有技术细节,覆盖了深度学习模型结构,模型训练,特征工程,模型评估,模型线上服务及推荐服务器内部逻辑等模块。
-
Java 8
-
Scala 2.11
-
Python 3.6+
-
TensorFlow 2.0+
将项目用IntelliJ打开后,找到RecSysServer
,右键点选Run
,然后在浏览器中输入http://localhost:6010/
即可看到推荐系统的前端效果。
15
16
项目数据来源于开源电影数据集MovieLens,项目自带数据集对MovieLens数据集进行了精简,仅保留1000部电影和相关评论、用户数据。全量数据集请到MovieLens官方网站进行下载,推荐使用MovieLens 20M Dataset。
SparrowRecSys技术架构遵循经典的工业级深度学习推荐系统架构,包括了离线数据处理、模型训练、近线的流处理、线上模型服务、前端推荐结果显示等多个模块。以下是SparrowRecSys的架构图:
-
Word2vec (Item2vec)
-
DeepWalk (Random Walk based Graph Embedding)
-
Embedding MLP
-
Wide&Deep
-
Nerual CF
-
Two Towers
-
DeepFM
-
DIN(Deep Interest Network)
-
[FFM] Field-aware Factorization Machines for CTR Prediction (Criteo 2016)
-
[GBDT+LR] Practical Lessons from Predicting Clicks on Ads at Facebook (Facebook 2014)
-
[FM] Fast Context-aware Recommendations with Factorization Machines (UKON 2011)
-
[DCN] Deep & Cross Network for Ad Click Predictions (Stanford 2017)
-
[PNN] Product-based Neural Networks for User Response Prediction (SJTU 2016)
-
[DIN] Deep Interest Network for Click-Through Rate Prediction (Alibaba 2018)
-
[Wide & Deep] Wide & Deep Learning for Recommender Systems (Google 2016)
-
[DIEN] Deep Interest Evolution Network for Click-Through Rate Prediction (Alibaba 2019)
-
[DSSM] Learning Deep Structured Semantic Models for Web Search using Clickthrough Data (UIUC 2013)
-
[FNN] Deep Learning over Multi-field Categorical Data (UCL 2016)
-
[DeepFM] A Factorization-Machine based Neural Network for CTR Prediction (HIT-Huawei 2017)
-
[NFM] Neural Factorization Machines for Sparse Predictive Analytics (NUS 2017)
brew install scala@2.11
scala@2.11 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have scala@2.11 first in your PATH run:
echo 'export PATH="/usr/local/opt/scala@2.11/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/usr/local/opt/scala@2.11/bin:$PATH"' >> ~/.zshrc
问题:安装包下多了一个idea目录(软连接),导致项目编译时报存在多个scala-library.jar包。
解决:删掉idea目录即可。
下载链接:https://www.scala-lang.org/download/2.11.12.html
下载该包: scala-2.11.12.msi Windows (msi installer) 109.82M
配置环境变量:
- 新建系统变量SCALA_HOME: D:\Program Files (x86)\scala
- PATH: D:\Program Files (x86)\scala\bin
验证:
scala -version
hadoop集群采用apache hadoop 2.7.2版本
注:hadoop有多种运行模式:本地运行模式、伪分布运行环境、完全分布式运行环境。本项目搭建完全分布式运行环境。
1)准备3台客户机(关闭防火墙、静态ip、主机名称)
2)安装JDK
3)配置环境变量
4)安装Hadoop
5)配置环境变量
6)配置集群
7)单点启动
8)配置ssh
9)群起并测试集群
-
Hadoop下载地址:
https://archive.apache.org/dist/hadoop/common/hadoop-2.7.2/
将安装包下载到 /opt/software -
安装路径:/opt/module
tar -zxvf hadoop-2.7.2.tar.gz -C /opt/module/ -
将Hadoop添加到环境变量和验证
vim /etc/profileexport HADOOP_HOME=/opt/module/hadoop-2.7.2
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbinsource /etc/profile
hadoop version
-
重要目录:
- bin:存放对Hadoop相关服务(HDFS,YARN)进行操作的脚本
- etc:Hadoop的配置文件目录,存放Hadoop的配置文件
- lib:存放Hadoop的本地库(对数据进行压缩解压缩功能)
- sbin:存放启动或停止Hadoop相关服务的脚本
- share:存放Hadoop的依赖jar包、文档、和官方案例
每台机分别执行:hostnamectl set-hostname rec-hadoop01/rec-hadoop02/rec-hadoop03
rec-hadoop01 | rec-hadoop02 | rec-hadoop03 | |
---|---|---|---|
HDFS | NameNode/DataNode | DataNode | SecondaryNameNode/DataNode |
YARN | NodeManager | ResourceManager/NodeManager | NodeManager |
Hadoop配置文件分两类:默认配置文件和自定义配置文件,只有用户想修改某一默认配置值时,才需要修改自定义配置文件,更改相应属性值。
要获取的默认文件 | 文件存放在Hadoop的jar包中的位置 |
---|---|
[core-default.xml] | hadoop-common-2.7.2.jar/ core-default.xml |
[hdfs-default.xml] | hadoop-hdfs-2.7.2.jar/ hdfs-default.xml |
[yarn-default.xml] | hadoop-yarn-common-2.7.2.jar/ yarn-default.xml |
[mapred-default.xml] | hadoop-mapreduce-client-core-2.7.2.jar/ mapred-default.xml |
core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml四个配置文件存放在$HADOOP_HOME/etc/hadoop这个路径上,用户可以根据项目需求重新进行修改配置。
-
配置core-site.xml
<!-- 指定HDFS中NameNode的地址 --> <property> <name>fs.defaultFS</name> <value>hdfs://rec-hadoop01:9000</value> </property>
<property> <name>hadoop.tmp.dir</name> <value>/opt/module/hadoop-2.7.2/tmp</value> </property>
-
hadoop-env.sh
export JAVA_HOME=/opt/module/jdk1.8.0_181
-
hdfs-site.xml
<property> <name>dfs.replication</name> <value>3</value> </property> <!-- 指定Hadoop辅助名称节点主机配置 --> <property> <name>dfs.namenode.secondary.http-address</name> <value>rec-hadoop03:50090</value> </property>
-
yarn-env.sh
export JAVA_HOME=/opt/module/jdk1.8.0_181
-
yarn-site.xml
<!-- Reducer获取数据的方式 --> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <!-- 指定YARN的ResourceManager的地址 --> <property> <name>yarn.resourcemanager.hostname</name> <value>rec-hadoop02</value> </property> <!-- 日志聚集功能使能 --> <property> <name>yarn.log-aggregation-enable</name> <value>true</value> </property> <!-- 日志保留时间设置3天 --> <property> <name>yarn.log-aggregation.retain-seconds</name> <value>259200</value> </property> <!-- 日志链接跳转地址 --> <property> <name>yarn.log.server.url</name> <value>http://rec-hadoop03:19888/jobhistory/logs</value> </property>
-
mapred-env.sh
export JAVA_HOME=/opt/module/jdk1.8.0_181
-
mapred-site.xml
cp mapred-site.xml.template mapred-site.xml vim mapred-site.xml <!-- 指定MR运行在Yarn上 --> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> <!-- 历史服务器端地址 --> <property> <name>mapreduce.jobhistory.address</name> <value>rec-hadoop03:10020</value> </property> <!-- 历史服务器web端地址 --> <property> <name>mapreduce.jobhistory.webapp.address</name> <value>rec-hadoop03:19888</value> </property>
hadoop namenode -format
hadoop-daemon.sh start namenode
jps
hadoop-daemon.sh start datanode
jps
cd ~/.ssh
ssh-keygen -t rsa
然后敲(三个回车),就会生成两个文件id_rsa(私钥)、id_rsa.pub(公钥)
ssh-copy-id rec-hadoop01
ssh-copy-id rec-hadoop02
ssh-copy-id rec-hadoop03
注意:以上步骤需要在3台主机上分别执行
known_hosts | 记录ssh访问过计算机的公钥(public key) |
---|---|
id_rsa | 生成的私钥 |
id_rsa.pub | 生成的公钥 |
authorized_keys | 存放授权过得无密登录服务器公钥 |
cd etc/hadoop/slaves
vim slaves
增加:
rec-hadoop01
rec-hadoop02
rec-hadoop03
如果集群是第一次启动,需要格式化NameNode(注意格式化之前,一定要先停止上次启动的所有namenode和datanode进程,然后再删除data和log数据)
cd /opt/module/hadoop-2.7.2
bin/hdfs namenode -format
启动HDFS:
sbin/start-dfs.sh
jps
启动YARN:
sbin/start-yarn.sh
**注意:NameNode和ResourceManger如果不是同一台机器,不能在NameNode上启动 YARN,应该在ResouceManager所在的机器上启动YARN。 **
查看目录:
hadoop fs -ls /
或: hdfs dfs -ls /
创建目录:
hadoop fs -mkdir -p /user/root/input
或:hdfs dfs -mkdir -p /user/root/input
上传文件:
hadoop fs -put wcinput/wc.input /user/root/input
或:hdfs dfs -put wcinput/wc.input /user/root/input
文件所在路径:
/opt/module/hadoop-2.7.2/tmp/dfs/data/current
下载文件:
hadoop fs -get /user/root/input/wc.input ./
删除文件:
hadoop fs -rm -r /user/root/output
-
各个服务组件逐一启动/停止
- 分别启动/停止HDFS组件
hadoop-daemon.sh start / stop namenode / datanode / secondarynamenode - 启动/停止YARN
yarn-daemon.sh start / stop resourcemanager / nodemanager - 启动历史服务器
sbin/mr-jobhistory-daemon.sh start historyserver
查看JobHistory:http://rec-hadoop03:19888/jobhistory
- 分别启动/停止HDFS组件
-
各个模块分开启动/停止(配置ssh是前提)(常用)
- 整体启动/停止HDFS
start-dfs.sh / stop-dfs.sh - 整体启动/停止YARN
start-yarn.sh / stop-yarn.sh
- 整体启动/停止HDFS
hadoop fs -mkidr -p /test/input
hadoop fs -put wcinput/wc.input /test/input
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.2.jar wordcount /test/input /test/wcoutput
hadoop fs -cat /test/wcoutput/part-r-00000
doop 1
hadoop 1
hello 1
mapreduce 1
world 1
yarn 1
hdfs:
http://rec-hadoop01:50070/dfshealth.html#tab-overview
yarn:
http://rec-hadoop02:8088/cluster/cluster
http://rec-hadoop03:19888/jobhistory
spark采用2.4.3版本
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-mllib -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-mllib_${scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
采用该方式,在windows环境下启动spark,会报错:Could not locate executable null\bin\winutils.exe in the Hadoop binaries
解决:需要安装hadoop在windows下的支持插件:
下载资源:
1)http://archive.apache.org/dist/hadoop/core/ 找对应版本
2)https://github.com/cdarlint/winutils
在Path下配置好对应的bin路径即可。(如果未生效,可尝试重启电脑)
tar -zxvf spark-2.4.3-bin-hadoop2.7.tgz -C /opt/module
1)修改 hadoop 配置文件/opt/module/hadoop/etc/hadoop/yarn-site.xml
<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是 true -->
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<!--是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认是 true -->
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
2)修改 conf/spark-env.sh,添加 JAVA_HOME 和 YARN_CONF_DIR 配置
mv spark-env.sh.template spark-env.sh
...
export JAVA_HOME=/opt/module/jdk1.8.0_181
YARN_CONF_DIR=/opt/module/hadoop-2.7.2/etc/hadoop
bin/spark-submit --class org.apache.spark.examples.SparkPi --master yarn --deploy-mode cluster ./examples/jars/spark-examples_2.11-2.4.3.jar 10
bin/spark-submit --class com.sparrowrecsys.offline.spark.embedding.Embedding --master yarn --deploy-mode cluster ./examples/jars/SparrowRecSysZero2One.jar file:///opt/module/spark-2.4.3/resources/ratings.csv /opt/module/spark-2.4.3/resources/item2vecEmb.csv 10
-
修改 spark-defaults.conf.template 文件名为 spark-defaults.conf
mv spark-defaults.conf.template spark-defaults.conf
-
修改 spark-default.conf 文件,配置日志存储路径
spark.eventLog.enabled true
spark.eventLog.dir hdfs://rec-hadoop01:9000/directory
注意:需要启动 hadoop 集群,HDFS 上的目录需要提前存在。
sbin/start-dfs.sh
hadoop fs -mkdir /directory
-
修改 spark-env.sh 文件, 添加日志配置
export SPARK_HISTORY_OPTS=" -Dspark.history.ui.port=18080 -Dspark.history.fs.logDirectory=hdfs://rec-hadoop01:9000/directory -Dspark.history.retainedApplications=30"
参数 1 含义:WEB UI 访问的端口号为 18080 参数 2 含义:指定历史服务器日志存储路径 参数 3 含义:指定保存 Application 历史记录的个数,如果超过这个值,旧的应用程序信息将被删除,这个是内存中的应用数,而不是页面上显示的应用数。
-
修改 spark-defaults.conf
spark.yarn.historyServer.address=rec-hadoop01:18080
spark.history.ui.port=18080 -
启动历史服务
sbin/start-history-server.sh
https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html
下载安装文件:Miniconda3-py37_4.9.2-Linux-x86_64.sh
执行:
bash Miniconda3-py37_4.9.2-Linux-x86_64.sh
dnf group install "Development Tools"
conda create -n sparrowRec python=3.7
conda activate sparrowRec
pip install --upgrade tensorflow -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
pip install jupyter notebook
jupyter notebook --generate-config
将会在用户主目录下生成.jupyter文件夹,其中jupyter_notebook_config.py就是刚刚生成的配置文件
输入 ipython,进入ipyhon命令行
输入
In [1]: from notebook.auth import passwd
In [2]: passwd()
这里要求你输入以后登录使用的密码,然后生成一个秘钥,记得保存好秘钥,以免丢失。
Enter password:
Verify password:
Out[2]: 'argon2:$argon2id$v=19$m=10240,t=10,p=8$zQmpCHcCTHa625NSKha7Qw$ncLzWZudQNa0/I07PwcskQ'
修改用户主目录下~/.jupyter/jupyter_notebook_config.py文件
取消c.NotebookApp.password = ''"注释,并将生成的秘钥复制进去
c.NotebookApp.password = 'argon2:$argon2id$v=19$m=10240,t=10,p=8$zQmpCHcCTHa625NSKha7Qw$ncLzWZudQNa0/I07PwcskQ'
取消下面几项注释,并注释修改ip、端口、不自动打开浏览器
c.NotebookApp.ip='*' #×允许任何ip访问
c.NotebookApp.open_browser = False
c.NotebookApp.port =8888 #可自行指定一个端口, 访问时使用该端口
c.NotebookApp.allow_remote_access = True
c.NotebookApp.allow_root = True
jupyter notebook
[W 19:09:17.996 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 19:09:17.999 NotebookApp] 启动notebooks 在本地路径: /root
[I 19:09:18.000 NotebookApp] Jupyter Notebook 6.2.0 is running at:
[I 19:09:18.000 NotebookApp] http://rec-hadoop03:8888/
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
官网可能比较慢,可采用阿里云加速:
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
docker version
sudo systemctl start docker
sudo systemctl enable docker
登录阿里云,搜索“容器镜像服务”,找到镜像加速器的对应系统版本,按说明操作即可。
如centos:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://hnah5dzx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
vim /etc/docker/daemon.json
添加:
"bip":"172.200.0.1/24"
注:如果多台机器上都装了docker,这个网段需不一样:如:"bip":"172.201.0.1/24"、"bip":"172.202.0.1/24"
重启:
systemctl restart docker