• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • XGBoost4J-Spark 1.0.0運行流程與排坑指南

    標簽: Spark和他的小伙伴們  xgboost  spark  xgboost4j  xgboost4j-spark

    0.前言

    XGBoost4J-Spark能夠讓我們在Spark上玩XGBoost,對于海量數據來說應該是很有用的。這篇文章主要介紹了將其官網提供的Demo部署在Linux上運行的全過程。通過此Demo在Spark上用XGBoost完成iris數據集的多分類任務。

    此次選用的是最新的穩定版XGBoost4J-Spark 1.0.0,之前0.81版本的Windows部署可以參考這里。不過其實都是互通的,兩邊都看看也無妨。我這里會將我選擇、填坑時的思路全部記錄下來,需要注意的地方我會用這樣進行標注,以供你參考,(●´З`●)。

    1.確認版本

    作為最基礎的demo,要考慮的版本包括:

    • XGBoost4J-Spark
    • Scala
    • Spark
    • Python
    • Hadoop
    • Java

    在安裝之前一定要根據自己的配置選擇合適的版本,確保兩兩之間版本契合,否則后面會報一堆錯。我選擇的版本如下:

    模塊 版本號
    XGBoost4J-Spark 1.0.0
    Scala 2.11.8
    Spark 2.4.5
    Python 3.5.2
    Hadoop 2.6
    Java 1.8.0

    具體考量如下:首先是選擇了當前的最新穩定版——1.0.0的XGBoost4J-Spark,然后在它的官網文檔里發現0.9之后的版本僅支持Spark2.4+了,具體原因摘抄在下面:

    XGBoost4J-Spark now requires Apache Spark 2.4+. Latest versions of XGBoost4J-Spark uses facilities of org.apache.spark.ml.param.shared extensively to provide for a tight integration with Spark MLLIB framework, and these facilities are not fully available on earlier versions of Spark.

    但我Spark是卑微的2.2.0,只能重新裝一個高版本了。然后選擇了Spark 2.4.5 Prebuild for Apache Hadoop 2.6。這里Hadoop的版本2.6.0就確定好了,好在Hadoop和Spark互通這塊網上排坑指南比較多,在實際操作時這塊也沒出問題,甚至我用的是hadoop-2.6.0-cdh5.7.0也沒啥問題,好評。然后這里有個點請注意一下,在Spark下載界面有這么一段話:

    Note that, Spark is pre-built with Scala 2.11 except version 2.4.2, which is pre-built with Scala 2.12.

    所以對于Spark 2.4.5來說,給咱們的jars是基于Scala 2.11的(當然你也可以選擇 Pre-built with Scala 2.12 and user-provided Apache Hadoop這個版本,然而我試了一下發現在spark-submit這個版本的時候坑太多了,比起填這個坑還是轉Scala2.11簡單點,遂棄之)。
    于是Scala的大版本也確定好了,在選擇Scala的時候小心每個小版本里也有很多更迭,導致一些方法找不到,最后在嘗試過很多小版本后敲定了Scala 2.11.8,至少在這個Demo里沒有表現出特別的問題。
    另外提一嘴Python,版本需要2.7+,盡量就Python 3+就完事了,不然會在訓練的時候報錯ImportError: No module named argparse,從而導致出現XGBoostError: XGBoostModel training failed這種詭異的錯誤。
    JDK就是1.8.0,沒啥好說的,也沒出問題,就寫在這以防有老哥要看。

    2.Maven配置

    要注意各個版本的一一對應,要查包的對應版本的話請在MvnRepository里查找關鍵字。
    這里直接放整體的pom.xml:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.taipark.xgboost</groupId>
      <artifactId>sonarAnalysis</artifactId>
      <version>1.0</version>
      <inceptionYear>2008</inceptionYear>
      <properties>
        <scala.version>2.11.8</scala.version>
      </properties>
    
      <repositories>
        <repository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </repository>
      </repositories>
    
      <pluginRepositories>
        <pluginRepository>
          <id>scala-tools.org</id>
          <name>Scala-Tools Maven2 Repository</name>
          <url>http://scala-tools.org/repo-releases</url>
        </pluginRepository>
      </pluginRepositories>
    
      <dependencies>
        <dependency>
          <groupId>org.scala-lang</groupId>
          <artifactId>scala-library</artifactId>
          <version>${scala.version}</version>
        </dependency>
        <dependency>
          <groupId>ml.dmlc</groupId>
          <artifactId>xgboost4j-spark_2.11</artifactId>
          <version>1.0.0</version>
        </dependency>
        <dependency>
          <groupId>org.apache.spark</groupId>
          <artifactId>spark-sql_2.11</artifactId>
          <version>2.4.5</version>
        </dependency>
        <dependency>
          <groupId>org.apache.spark</groupId>
          <artifactId>spark-mllib_2.11</artifactId>
          <version>2.4.5</version>
        </dependency>
      </dependencies>
    
      <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
          <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <executions>
              <execution>
                <goals>
                  <goal>compile</goal>
                  <goal>testCompile</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <scalaVersion>${scala.version}</scalaVersion>
              <args>
                <arg>-target:jvm-1.5</arg>
              </args>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-eclipse-plugin</artifactId>
            <configuration>
              <downloadSources>true</downloadSources>
              <buildcommands>
                <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
              </buildcommands>
              <additionalProjectnatures>
                <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
              </additionalProjectnatures>
              <classpathContainers>
                <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
                <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
              </classpathContainers>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <reporting>
        <plugins>
          <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <configuration>
              <scalaVersion>${scala.version}</scalaVersion>
            </configuration>
          </plugin>
        </plugins>
      </reporting>
    </project>
    

    3.代碼

    配置好之后就要開始寫代碼了,代碼在xgboost的文檔里說的其實還是蠻清楚的,這里把完整的能運行的代碼放出來理解一下:
    注:代碼是用Scala編寫的。
    首先是import:

    import org.apache.spark.ml.feature.{StringIndexer, VectorAssembler}
    import org.apache.spark.sql.SparkSession
    import org.apache.spark.sql.types.{DoubleType, StringType, StructField, StructType}
    import ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier
    

    創建SparkSession:

        val spark = SparkSession.builder().getOrCreate()
    

    根據數據集設置Schema:

    	val schema = new StructType(Array(
    	      StructField("sepal length", DoubleType, true),
    	      StructField("sepal width", DoubleType, true),
    	      StructField("petal length", DoubleType, true),
    	      StructField("petal width", DoubleType, true),
    	      StructField("class", StringType, true)
    	    ))
    

    導入數據,使其與Schema一一對應,這里注意數據在轉為csv的時候不要使用UTF-8之類的編碼,而是使用Windows默認編碼,不然會導致XGBoost識別分類數量錯誤從而報有關num_class的錯誤:

        val dataPath = args(0)
        val rawInput = spark.read.schema(schema).csv(dataPath)
    

    這里的class列是用String表示的,我們要將其轉化為Double類型,可以使用StringIndexer來轉換:

       val stringIndexer = new StringIndexer()
          .setInputCol("class")
          .setOutputCol("classIndex")
          .fit(rawInput)
       val labelTransformed = stringIndexer.transform(rawInput).drop("class")
    

    將轉換后的列classIndex替換之前的列class:

        val vectorAssembler = new VectorAssembler()
          .setInputCols(Array("sepal length","sepal width","petal length","petal width"))
          .setOutputCol("features")
        val xgbInput = vectorAssembler.transform(labelTransformed)
          .select("features","classIndex")
    

    將數據八二分為訓練集與測試集:

        val splitXgbInput = xgbInput.randomSplit(Array(0.8, 0.2))
        val trainXgbInput = splitXgbInput(0)
        val testXgbInput = splitXgbInput(1)
    

    設置XGBoost的參數,需要特別注意的是num_workers的值需要小于等于之后傳進spark-submit的master的值,即XGBoost用到的線程要小于Spark啟的線程

    	val xgbParam = Map(
    	      "eta" -> 0.1f,
    	      "max_depth" -> 2,
    	      "objective" -> "multi:softprob",
    	      "num_class" -> 3,
    	      "num_round" -> 100,
    	      "num_workers" -> 2
    	    )
    

    創建XGBoost函數,并且展示了另一種設置參數的方法,這里需要注意只要你是用分布式進行訓練,那么setTreeMethod(“approx”)是一定要設置的,不然最后在訓練的時候JVM會報Core dump written

        //創建xgb函數,指定特征向量與標簽
        val xgbClassifier = new XGBoostClassifier(xgbParam)
          .setFeaturesCol("features")
          .setLabelCol("classIndex")
        xgbClassifier.setMaxDepth(2)
        xgbClassifier.setTreeMethod("approx")
    

    參數設置完畢,開始訓練:

    	val xgbClassificationModel = xgbClassifier.fit(trainXgbInput)
    

    進行預測:

    	val result = xgbClassificationModel.transform(testXgbInput)
    

    展示并停止:

    	result.show(1000)
    
        spark.stop()
    

    最后再放一個完整的代碼:

    package com.taipark.xgboost
    
    import org.apache.spark.ml.feature.{StringIndexer, VectorAssembler}
    import org.apache.spark.sql.SparkSession
    import org.apache.spark.sql.types.{DoubleType, StringType, StructField, StructType}
    import ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier
    
    object IrisAnalysis {
      def main(args: Array[String]): Unit = {
        //創建SparkSession
        val spark = SparkSession.builder()
          .getOrCreate()
    
        //設置schema
        val schema = new StructType(Array(
          StructField("sepal length", DoubleType, true),
          StructField("sepal width", DoubleType, true),
          StructField("petal length", DoubleType, true),
          StructField("petal width", DoubleType, true),
          StructField("class", StringType, true)
        ))
    
        //導入數據
        val dataPath = args(0)
        val rawInput = spark.read.schema(schema).csv(dataPath)
    
        //將class由string轉為double
        val stringIndexer = new StringIndexer()
          .setInputCol("class")
          .setOutputCol("classIndex")
          .fit(rawInput)
        val labelTransformed = stringIndexer.transform(rawInput).drop("class")
    
        //拼合組成整體數據集
        val vectorAssembler = new VectorAssembler()
          .setInputCols(Array("sepal length","sepal width","petal length","petal width"))
          .setOutputCol("features")
        val xgbInput = vectorAssembler.transform(labelTransformed)
          .select("features","classIndex")
    
        //將數據切分為訓練集與測試集
        val splitXgbInput = xgbInput.randomSplit(Array(0.8, 0.2))
        val trainXgbInput = splitXgbInput(0)
        val testXgbInput = splitXgbInput(1)
    
        //設置xgb參數
        val xgbParam = Map(
          "eta" -> 0.1f,
          "max_depth" -> 2,
          "objective" -> "multi:softprob",
          "num_class" -> 3,
          "num_round" -> 100,
          "num_workers" -> 2
        )
    
        //創建xgb函數,指定特征向量與標簽
        val xgbClassifier = new XGBoostClassifier(xgbParam)
          .setFeaturesCol("features")
          .setLabelCol("classIndex")
        xgbClassifier.setMaxDepth(2)
        xgbClassifier.setTreeMethod("approx")
    
        //開始訓練
        val xgbClassificationModel = xgbClassifier.fit(trainXgbInput)
    
        //預測
        val result = xgbClassificationModel.transform(testXgbInput)
    
        //展示
        result.show(1000)
    
        spark.stop()
      }
    
    }
    

    4.運行

    打包后上傳Linux服務器,需要一并上傳的內容包括:

    • 數據集.csv
    • 打包好的jar包
    • xgboost4j_2.11-1.0.0.jar
    • xgboost4j-spark_2.11-1.0.0.jar

    后面兩個jar包需要單獨上傳上去,這兩個文件應該在Maven的倉庫里,可以用IDEA找,或者用Everything直接在Windows里找。

    首先需要將數據集放在HDFS里,然后運行spark-submit:

    ./spark-submit \
    --master local[2] \
    --class com.taipark.xgboost.IrisAnalysis \
    --jars /home/hadoop/lib/xgboost4j-spark_2.11-1.0.0.jar,/home/hadoop/lib/xgboost4j_2.11-1.0.0.jar \
     /home/hadoop/lib/sonarAnalysis-1.0.jar hdfs://hadoop000:8020/tai/iris.csv
    

    其中傳入的第一個local[2]的2要大于等于之前設置的num_workers,這個之前說過了。其他的根據你自己放的位置引就可以了。
    最后給個跑出來的結果:
    在這里插入圖片描述
    如果對你有用,就給個關注吧,(●´З`●)

    版權聲明:本文為qq_36329973原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_36329973/article/details/105868413

    智能推薦

    Centos7部署jenkins(排坑指南)

    背景     原以為只是yum安裝然后啟動一下,結果遇到了好幾個問題,應了那句老話:紙上得來終覺淺,絕知此事要躬行。 部署 1.安裝jdk 2.安裝maven 3.安裝jenkins 啟動jenkins后瀏覽器訪問8080端口 查看默認管理員密碼,輸入密碼 cat /var/lib/jenkins/secrets/initialAdminPassword 輸入默認的密碼后,就一...

    hive 導出數據之一列多行,轉為一行多列

    需求:提取數據 說明:原數據是一列多行,需要轉化為一行多列 待查詢表為:temp_05 待查詢數據為: 待查詢數據如圖: 需要提取的數據表頭如下: 預定日期 昨日價格 前天價格 2018-02-01 2018-02-02 2018-02-03 2018-02-04 可用提數 SQL 數據如圖: 以下為嘗試過程 數據如圖: 數據如圖: 數據如圖: 數據如圖:...

    asp.net做一個簡易的聊天室

    要求: 結果: 關鍵代碼: Default.aspx Default.aspx.cs Default2.aspx Default2.aspx.cs Default3.aspx Default3.aspx.cs Default4.aspx...

    動態SQL和多表關聯-筆記

    《動態SQL與多表關聯》筆記 學習目標 能夠使用動態SQL完成SQL拼接 能夠使用resultMap完成多表查詢 能夠使用一對一查詢 能夠使用一對多查詢 (注:多對多其實就是兩個一個多) 映射文件:為什么要resultMap 目標 定義結果映射 使用結果映射 回顧 在mybatis中有2種配置文件: 核心配置文件,如:sqlMapConfig.xml 實體類映射文件,如:UserMapper.xm...

    【OpenGL C++ UE4】獲取模型頂點及面索引數據,并優化存儲結構供UE4繪制

    目錄 一、功能需求 二、成果 三、環境配置 四、詳細步驟 4.1 Max制作三棱錐并處理 4.2 核心代碼 4.2.1 傳入結構體數據 4.2.2 頂點去重、更新索引 4.2.3 輸出本地CSV文件 4.3 UE4繪制 一、功能需求 想必你肯定會問我一個問題,UE4直接導入模型不好么? 哈哈,前提是在做畢設時,導師提供的只有頂點與面索引數據,沒有模型。 下文詳細介紹了畢設開發中的難點,涉...

    猜你喜歡

    解決Pyinstaller打包numpy和pandas庫文件過大問題

    解決Pyinstaller壓縮numpy和pandas庫文件過大問題 文件包類型和網上的方法 Windows下docker的安裝 在docker下實現打包     今天是2021年的第一天,先祝各位小伙伴現年快樂哈。最近因為做了一個項目,需要打包文件,文件中包含了numpy和pandas庫,結果打包出來幾百行的代碼居然要900m,人都傻了,翻遍了全網找解決方...

    【混沌工程】基于ChaosBlade實現網絡故障模擬

    一、前言 很久之前曾基于linux內核自帶的TC和netem模擬一些公網中遇到的極端情況(延遲、丟包、重復、損壞和亂序等),驗證了我們傳輸程序的健壯性! 具體細節可見這篇老博客: https://blog.csdn.net/u013128262/article/details/84784663 最近在復現kafka生產端一個timeout異常場景時,發現之前方案時因為內核和OS版本問題有些差異而無...

    使用FileZilla連接時超時,無法連接到服務器

    用FileZilla連接服務器時,顯示錯誤: 解決方法: 檢查基本的內容 主機是否寫錯 端口是否自定義,默認21 檢查用戶名和密碼是否錯誤 如果連接的是公司內網 使用ping命令,測試一下是否能收到數據 收不到則需要開啟VPN,再ping,看是否能接收數據(請老鐵們用自己最合適的方法解決) 如果開啟VPN后能接收數據,則可以連接一下服務器,如果不行(怎么可能不行),則跳轉3并依次嘗試 開啟VPN后...

    反匯編:結構體拷貝傳參

    一、結構體拷貝傳參 二、引用和常引用傳參 三、大結構體做形參/數組拷貝...

    精品国产乱码久久久久久蜜桃不卡