diff --git a/2.tex b/2.tex index b82d455..b3969a4 100644 --- a/2.tex +++ b/2.tex @@ -28,7 +28,7 @@ %文档信息/同时也用于生成报告封面 \author{李志星\\ 15060025} \date{2016年6月20日} -\title{\Huge MLlib中Logistic Regression的应用} +\title{\Huge 基于Spark MLlib的手写数字识别\newline \Large Logistic Regression的应用} @@ -91,7 +91,7 @@ tabsize=3 \begin{figure}[h!] \centering \includegraphics[width=8cm]{LG_arch.png} -\caption{Logistic Regression示意图} +\caption{Logistic Regression原理示意图} \label{LG_arch} \end{figure} @@ -120,7 +120,7 @@ tabsize=3 \section{实验过程} \subsection{数据集} -本报告用到的数据集是MNIST的手写识别数据集,原始数据集中包含***************个文件,分别是训练数据和测试数据的特征值和类标号。这些文件存储的都是二进制格式,处理起来比较不方便,因此我在网上又找了一些经过别人处理过了的版本,它把数据转换成txt文件,一个文本文件对应一个样本,文件名表示了类标号和序号,文件里面包含一个32*32的0/1矩阵,矩阵中每一个点可以看成是手写图像中对应的一个像素点(如下图*)。训练数据和测试数据中分别有400个样本左右,虽然样本量有些小,但是对于体验一下Spark机器学习算法的还是可以的。 +本报告用到的数据集是MNIST的手写识别数据集,原始数据集分为多个文件,分别是训练数据和测试数据的特征值和类标号。这些文件存储的都是二进制格式,处理起来比较不方便,因此我在网上又找了一些经过别人处理过了的版本,它把数据转换成txt文件,一个文本文件对应一个样本,文件名表示了类标号和序号,文件里面包含一个32*32的0/1矩阵,矩阵中每一个点可以看成是手写图像中对应的一个像素点(如下图*)。训练数据和测试数据中分别有400个样本左右,虽然样本量有些小,但是对于体验一下Spark机器学习算法的还是可以的。 \begin{figure}[h!] \centering @@ -137,7 +137,7 @@ tabsize=3 \end{figure} \subsection{代码} -如前言中所述,MLlib中有两个用于机器学习的包mllib和ml,根据应用趋势和其官方网站的建议,我采用了ml。Spark本身使用Scala语言编写的,但是它同样为Java、Python和R提供了几乎一致的接口,在本次报告中我使用的python。详细代码见文件***.py。代码解释如下: +如前言中所述,MLlib中有两个用于机器学习的包mllib和ml,根据应用趋势和其官方网站的建议,我采用了ml。Spark本身使用Scala语言编写的,但是它同样为Java、Python和R提供了几乎一致的接口,在本次报告中我使用的python。代码解释如下: \subsubsection{导入依赖} 此段代码导入需要用到的包,包括数据处理的Vectors、算法训练的 LogisticRegression、算法评估BinaryClassificationEvaluator以及其他的一些用于和Spark操作的包。 @@ -174,9 +174,6 @@ def load_data(data_folder): data_in_line = list() for j in range(32): line_str=fr.readline() -\end{python} -\newpage -\begin{python} for k in range(32): data_in_line.append(int(line_str[k])) label = filename.split('.')[0].split("_")[0] @@ -186,7 +183,7 @@ def load_data(data_folder): \end{python} \subsubsection{模型训练} -再加载完训练数据后,即可用LogisticRegression来对其进行训练。新建LogisticRegression对象时可以指定一些参数,我在这里制定了最大迭代数和正则化参数。调用LogisticRegression的fit函数即可生成相应的LogisticRegressionModel。 +在加载完训练数据后,即可用LogisticRegression来对其进行训练。新建LogisticRegression对象时可以指定一些参数,我在这里指定了最大迭代数和正则化参数。调用LogisticRegression的fit函数即可生成相应的LogisticRegressionModel。 \begin{python} train_df = load_data("train") @@ -196,7 +193,6 @@ lrModel = lr.fit(train_df) \subsubsection{模型评估} 利用测试数据对训练得到的模型进行评估,BinaryClassificationEvaluator用于评估二分类结果,我最后利用其提供的两个指标areaUnderROC和areaUnderPR中的areaUnderROC评价了一下该模型。areaUnderROC是ROC曲线右下角部分占正方形格子的面积比例,该值越大说明分类的效果越好。 -\newpage \begin{python} test_df = load_data("test") predictions = lrModel.transform(test_df) @@ -206,10 +202,10 @@ print("Test Error = %g " % (1.0 - accuracy)) \end{python} \section{实验结果} -在本次试验中,我分别设置最大迭代次数为0,5,10,来观察算法的训练效果。利用训练得到模型在测试数据上预测得到DataFrame predictions,然后调用predictions的show()方法,该方法会打印出前20个结果,一共五列,分别是label,features,rawPrediction,probability和prediction。label和features这两个列是加载的测试数据的类标号和特征向量。rawPrediction,probability和prediction是利用模型对测试数据进行预测得到的,我查了一下相关文档,rawPrediction和probability都是一个向量,其维数就是类标号的个数,rawPrediction字面上的意思是原始的预测,直观的讲就是每个类的置信度(confidence),并且这个向量中的所有元素相加得到的和是0,probability是在给定rawPrediction的条件概率(该样本属于每个类的可能性),其计算方法根据所采用的分类算法而不同。在Logistic Regression中是这样计算的 1/(1+exp(-rawPrediction)。prediction是最后对样本的预测,它是对rawPrediction利用argmax()函数得到的,也就是取对应rawPrediction最大的那个类。 +在本次试验中,我分别设置最大迭代次数为0,5,10,来观察算法的训练效果。利用训练得到模型在测试数据上预测得到DataFrame predictions,然后调用predictions的show()方法,该方法会打印出前20个结果,一共五列,分别是label,features,rawPrediction,probability和prediction。label和features这两个列是加载的测试数据的类标号和特征向量。rawPrediction,probability和prediction是利用分别对训练数据训练以及模型对测试数据进行预测得到的,我查了一下相关文档,rawPrediction和probability都是一个向量,其维数就是类标号的个数,rawPrediction字面上的意思是原始的预测,直观的讲就是每个类的置信度(confidence),并且这个向量中的所有元素相加得到的和是0,probability是在给定rawPrediction的条件概率(该样本属于每个类的可能性),其计算方法根据所采用的分类算法而不同。在Logistic Regression中是这样计算的 1/(1+exp(-rawPrediction)。prediction是最后对样本的预测,它是对rawPrediction利用argmax()函数得到的,也就是取对应rawPrediction最大的那个类。 \begin{itemize} -\item maxIter=0时,算法给每个样本都预测为0,这样就有一半的测试样本是错误的,最后的areaUnderROC为0.5。\newline +\item maxIter=0时,算法没有进行迭代,因为测试数据中有0和1的样本数是一样的,因此它会设置每个类标号的概率为0.5,算法把每个样本都预测为0,这样就有一半的测试样本是错误的,最后的areaUnderROC为0.5。\newline \begin{figure}[h!] \centering \subfigure{ @@ -224,7 +220,7 @@ print("Test Error = %g " % (1.0 - accuracy)) \end{figure} -\item maxIter=5时,areaUnderROC为0.5。\newline +\item maxIter=5时,areaUnderROC为0.9979。\newline \begin{figure}[h!] \centering \subfigure{ @@ -239,7 +235,7 @@ print("Test Error = %g " % (1.0 - accuracy)) \end{figure} -\item maxIter=10时,areaUnderROC为0.5。\newline +\item maxIter=10时,areaUnderROC为0.9993。\newline \begin{figure}[h!] \centering \subfigure{ @@ -262,15 +258,14 @@ print("Test Error = %g " % (1.0 - accuracy)) \begin{itemize} \item 参数设置,算法一开始都是一些基本的对参数的设置,比如迭代次数,规则化参数,是否对数据标准化等等。例如: -\begin{figure}[h!] -\centering -\includegraphics[width=16cm]{setMaxIter.jpg} -\caption{setMaxIter} -\label{setMaxIter} -\end{figure} -\item train()方法进行训练。\newline -首先是对训练数据集进行统计便于后续的处理。\newline -\newpage +\begin{lstlisting}[escapeinside=''] + @Since("1.2.0") +def setMaxIter(value: Int):this.type = set(maxIter,value) +setDefault(maxIter -> 100) +... +\end{lstlisting} + +\item train()方法进行训练。首先是对训练数据集进行统计便于后续的处理。\newline \begin{lstlisting}[escapeinside=''] val (summarizer, labelSummarizer) = { //'此处用于生成相应的统计数据' @@ -308,7 +303,6 @@ if (!$(fitIntercept) && numClasses == 2 && histogram(0) == 0.0) { \end{lstlisting} 上面两段代码也是判断训练数据中的样本是否都是属于正样本否者负样本,但是模型函数中如果不需要截距的话,那么本次训练可能就会出现问题,所以它会进行警告。 -\newpage \begin{lstlisting} val optimizer = if ($(elasticNetParam) == 0.0 || $(regParam) == 0.0) { new BreezeLBFGS[BDV[Double]]($(maxIter), 10, $(tol)) @@ -320,7 +314,6 @@ if (!$(fitIntercept) && numClasses == 2 && histogram(0) == 0.0) { 这段代码用来选择算法的优化器,在mllib的实现中,Logistic Regression有两种实现:LogisticRegressionWithSGD和LogisticRegressionWithLBFGS,并且官方推荐使用LogisticRegressionWithLBFGS。而在最新的ml的版本中,已经看不到SGD版本的了,他根据用户传参情况使用LBFGS或者OWLQN。 至此,算法的主要逻辑已经分析的差不多了,剩余的就是对模型函数的系数和截距的计算了,比如: -\newpage \begin{lstlisting} val rawCoefficients = state.x.toArray.clone() var i = 0 @@ -337,14 +330,15 @@ if ($(fitIntercept)) { } \end{lstlisting} \end{itemize} - +\newpage \section{总结} -通过本次实验,我对Spark尤其是其MLlib库有了初步的了解。在如今大数据盛行的时代,Saprk有广泛的应用场景:流处理、交互式SQL查询和机器学习等。尤其是在机器学习方面,它基于内存的处理架构很适合机器学习的迭代运算。对于Spark来说,15年最重要的变化应该是DataFrame的引入,它能够适应更广泛的数据处理要求,也吸引了更多的使用者。而随着DataFrame,起初的机器学习库mllib也逐渐迁移到基于DataFrame接口的库ml。在本次实验中,我感受到的有以下几点: +通过本次实验,我对Spark尤其是其MLlib库有了初步的了解。在如今大数据盛行的时代,Saprk有广泛的应用场景:流处理、交互式SQL查询和机器学习等。尤其是在机器学习方面,它基于内存的处理架构很适合机器学习的迭代运算。对于Spark来说,2015年最重要的变化应该是DataFrame的引入,它能够适应更广泛的数据处理要求,也吸引了更多的使用者。而随着DataFrame,起初的机器学习库mllib也逐渐迁移到基于DataFrame接口的库ml。在本次实验中,我感受到的有以下几点: \begin{itemize} \item Spark官方文档很完善,并且讲述的也很详细,对我这样的Spark初学者来说有很大的帮助。 \item Spark对API的支持很棒,虽然Spark使用scala开发的,但是它还提供了几乎一致的针对Java、python和R的接口,这能使更多语言背景的开发者轻松的使用Saprk进行开发。 -\item 机器学习库工具比较完善,虽然目前Saprk MLlib实现的知识一些常用的算法,但是它却提供了很多的工具类,比如能够方便地对数据进行切分,拆分出训练数据和测试数据,对于训练的模型也提供了能够进行专业评估的工具类。因此 用Spark开发机器学习应用很方便,效率很快。 +\item 机器学习库工具比较完善,虽然目前Saprk MLlib实现的只是一些常用的算法,但是它却提供了很多的工具类,比如能够方便地对数据进行切分,拆分出训练数据和测试数据,对于训练的模型也提供了能够进行专业评估的工具类。因此 用Spark开发机器学习应用很方便,效率很快。 \end{itemize} + 很感谢谭老师给我们布置这样的作业,让我接触到了Spark,为我以后的研究工作储备了更多的方法。否则我很难有机会主动地去接触这些新鲜的大数据技术,通过对Spark的了解熟悉,我也对软件工程中的软件设计和架构有了进一步的理解。总之,通过本次报告,我受益匪浅。 \end{spacing} \end{document} diff --git a/报告3-&&&在Spark的实现.tex b/3.tex similarity index 93% rename from 报告3-&&&在Spark的实现.tex rename to 3.tex index 9fdcd5a..37502c3 100644 --- a/报告3-&&&在Spark的实现.tex +++ b/3.tex @@ -1,4 +1,18 @@ -\documentclass[a4paper,12pt,UTF8,titlepage]{ctexart} +%\documentclass[a4paper,12pt,UTF8,titlepage]{ctexart} + +\documentclass[12pt,a4paper,titlepage]{article} +\usepackage{xltxtra,fontspec,xunicode} +\usepackage[slantfont,boldfont]{xeCJK} + +\setmainfont{STSong} % 设置文档默认字体 + +\usepackage{setspace}%使用间距宏包 +\usepackage{indentfirst} +\setlength{\parindent}{2em} + + +\usepackage{titlesec} +\titleformat*{\section}{\centering\huge\bfseries} %页边距 \usepackage{geometry} @@ -8,6 +22,7 @@ \usepackage{fancyhdr} \pagestyle{fancy} \lhead{李志星 15060025 } +\date{2016年6月20日} \chead{KNN在Spark上的实现} \rhead{\leftmark} @@ -24,6 +39,7 @@ \begin{document} +\begin{spacing}{1.5} \maketitle \section{实验内容} @@ -135,7 +151,7 @@ for x in testData: print "error rate is %f(%d/%d)" % (1.0 * errorCount / count,errorCount,count) \end{python} \section{实验结果} -本次报告分别从K值、距离算法和Spark 特性三个方面对实现的KNN算法进行测试: +本次报告分别从K值和距离算法两个方面对实现的KNN算法进行测试: \subsection{K值的影响} k = 10: error rate is 0.021142(20/946) cost time : 1491 @@ -152,8 +168,30 @@ for x in testData: - k = 1 : error rate is 0.011628(11/946) cost time : 1512 +error rate is 0.011628(11/946) + +error rate is 0.017970(17/946) +error rate is 0.013742(13/946) + +error rate is 0.014799(14/946) + +error rate is 0.014799(14/946) + + +error rate is 0.015856(15/946) + + +error rate is 0.019027(18/946) + + +error rate is 0.021142(20/946) + + +error rate is 0.026427(25/946) + + +error rate is 0.027484(26/946) \subsection{距离算法的影响} @@ -163,5 +201,5 @@ for x in testData: 1. api使用不熟悉,比如dataframe,vector的数据类型,得利用输出多次测试,才晓得咋使用。map, reduce等等 2. driver programe 和worker program - +\end{spacing} \end{document} \ No newline at end of file