小编近来要做用户推荐相关的一些工作,根据调研,目前用于搜索、推荐等的算法以阿里妈妈、美团等团队的DIN等算法为主,因此需要祭出神经网络这样的武器,但奈何公司的大数据基础建设仍有待提高,直接使用高维度的item变量及用户变量进行模型开发可能会面临一定的工程难度,因此考虑使用循环神经网络的方法,将用户的点击页、浏览页作为一个个词,并用来评估用户下一步对产品、活动的兴趣点,而且LSTM的实现相对来讲也比较简单,不管是python的tensorflow还是keras都有现成的到layer的封装。笔者考虑到团队内部主要是Java为主的开发团队,只能先把Python那一套完整的东西放到一边,试试看spark+scala是不是能够将LSTM跑通。
目前与spark、scala/JAVA集成最好的应该是skymind公司开源的Deeplearning4j(https://deeplearning4j.org/cn/spark ),其中的scalanet称得上是为scala工程师构建的keras,deeplearning4j是一款非常优秀的开源软件依赖,非常适合java工程师进行神经网络模型开发,与此同时,与spark和scala的集成也堪称优秀,笔者在进行代码开发时重点参考了https://blog.youkuaiyun.com/wangongxi/article/details/60775940的一系列文章。
同时,为了使用scala跑通LSTM模型,更是参考了wangongxi博客里面的LSTM文本分类的java代码,文本进行分词后再进行one-hot,进入lstm的识别层并进行embeding处理成低维向量,再做循环神经网络的训练,对于笔者后续要开展的用户推荐,只需要将分词替换为用户的历史浏览和历史点击,再将文本分类label替换成用户未来一段时间对产品和活动页面的点击和浏览评分即可形成一套用户产品推荐的LSTM系统,因此,考虑到数据的安全性,本篇仍以文本的情感分类对deeplearning4j系统进行说明,java同学可以直接移步wangongxi博客,笔者采用的文本与其完全一致,均为http://spaces.ac.cn/archives/3414/的文本,在此感谢两位大神的付出。
0、首先给出模型建立使用的依赖,依赖共有三个部分,一部分是针对spark的,主要有建立spark的Session和JavaRDD,需要说明的是,deeplearning4j在模型训练时,需要使用java的sparkcontext和JAVARDD;另一部分是用于分词的结巴分词依赖,com.huaban.analysis.jieba.JiebaSegmenter,关于java分词的内容,在网上有很多资料,本处就不赘述;第3部分是关于Deeplearning4j的依赖,包括其本身以及nd4j的依赖。
import org.apache.spark.sql.SparkSession
import org.apache.spark.api.java.{JavaRDD, JavaSparkContext}
import org.deeplearning4j.nn.api.OptimizationAlgorithm
import org.deeplearning4j.nn.conf.{BackpropType, NeuralNetConfiguration}
import org.deeplearning4j.nn.conf.layers.{RnnOutputLayer,LSTM,EmbeddingLayer,GravesLSTM}
import org.deeplearning4j.optimize.listeners.ScoreIterationListener
import org.deeplearning4j.spark.impl.multilayer.SparkDl4jMultiLayer
import org.deeplearning4j.spark.impl.paramavg.ParameterAveragingTrainingMaster
import org.nd4j.linalg.activations.Activation
import org.nd4j.linalg.api.ndarray.INDArray
import org.nd4j.linalg.dataset.DataSet
import org.nd4j.linalg.factory.Nd4j
import com.huaban.analysis.jieba.JiebaSegmenter
import org.nd4j.linalg.lossfunctions.LossFunctions
import org.deeplearning4j.nn.conf.inputs.InputType
import org.nd4j.linalg.learning.config.Adam
import org.nd4j.evaluation.classification.Evaluation
import scala.collection.mutable.ArrayBuffer
1、建立sparksession,需要说明的是给出了一个JavaSC,还有一个spark本身的SparkSeesion,这两个可以同时使用,spark主要便于读取csv,javasc则用于后面的模型训练,同时导入了分词的对象
val spark:SparkSession = {SparkSession
.builder()
.master("local")
.appName("Spark LSTM Emotion Analysis")
.getOrCreate()
}
import spark.implicits._
val JavaSC = JavaSparkContext.fromSparkContext(spark.sparkContext)
val segmenter = new JiebaSegmenter
2、读取csv并进行分词形成需要的JAVARDD
def getTrainingData(spark: SparkSession): JavaRDD[DataSet] = {
//Get data. For the sake of this example, we are doing the following operations:
// File -> String -> List<String> (split into length "sequenceLength" characters) -> JavaRDD<String> -> JavaRDD<DataSet>
//较好的评价
val goodCSV = spark.read.format("csv").load("/home/lorry/下载/pos.csv").toDF("describe")
//较差的评价
val badCSV = spark.read.format("csv").load("/home/lorry/下载/neg.csv").toDF("describe")
//设置正则
val regEx = """[`~!@#$%^&*()+=|{}':;',『』[\-]《》\\[\\][\"][ ]\[\][0123456789].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]"""
val signPattern = regEx.r
val targetColumns = goodCSV.columns
//在rdd中对评论进行分词并给出标签
val goodRDD = goodCSV.select(targetColumns.head, targetColumns.tail: _*).rdd.map(x => {
val word: String = x(0).asInstanceOf[String]
val wordSplit = segmenter.sentenceProcess(signPattern.replaceAllIn(word.trim, "")).toArray().mkString(" ")
("正面", wordSplit)
}
).filter(row => (row._2.size > 0))
//在rdd中对评论进行分词并给出标签
val badRDD = badCSV.selec