1、課程項目目標前端
搭建一個完整的web系統,功能上能識別上傳血常規檢驗報告圖片中的年齡、性別及檢驗的各項數據,並能經過神經網絡等機器學習算法根據血常規檢驗的各項數據預測年齡和性別。python
2、學習心得總結git
孟寧老師的這門網絡程序設計課程素材並無沿用一些固有的成型的更多有練手性質的項目,而是很創新地選擇當前熱門潮流的機器學習方向,着手方向是很新的。更可貴的是,面對日益重要的醫療行業,看準了當前輔助診斷系統還要更加完善智能的契機和需求,這個項目不只是一次嘗試,也是很具備實際意義的。web
做爲一個項目小白我在該課程中經歷了一個項目從無到有的過程,充分體會到了這種開放資源、協做互動的模式,還有清晰的文檔說明、嚴謹的代碼複審等重要性,這種模式推動的項目完善遠沒有想象的簡單,卻實際來的高效。算法
我對這門課程的收穫從原來對機器學習就簡單想到聚類算法的片面認識,到如今認識了許多機器學習庫,尤爲對Spark中的mlib庫進行了認真學習和運用,還學習了經常使用的算法:決策樹、貝葉斯、隨機森林、svm等。以及經過ocr識別學習瞭解了一些視覺庫。總之經過圖像、預測、web三個模塊我學習了一個項目雛形的大概構造,也對機器學習再也不感到很神祕,對另一些如opencv庫等也提起了興趣。mongodb
學習流程A1神經網絡實現手寫字符識別系統,這個demo主要對深度學習有一個具象的認識,這個過程主要是配置環境,而後我開始學習一些python的基礎語法;A2血常規檢驗報告的圖像OCR識別,這一步對我而言跨的比較大,只是fetch最新版本後從有經驗同窗代碼中瞭解了圖像識別中根據圖像自己特色及幾何學作特徵提取、識別、預處理的這種思路;A3根據血常規檢驗的各項數據預測年齡和性別,由於鼓勵你們嘗試不一樣的學習庫看預測準確度的優劣,來自工程實踐同窗的推薦這一部分我投入不少精力學習了Spark的mlib庫,並嘗試了它提供的貝葉斯、決策樹、二分類、隨機深林等不一樣算法,雖然每種算法間核心代碼改動不超過10行,但只有動手嘗試過之後才能更好理解一些參數的意義和它們之間的區別。只有這一部分原本是我以爲有但願pr的,但由於可能Spark平臺提供的封裝確實簡便,我對項目託管平臺相關操做各類不熟,很快就已經有大神把各類spark下算法都上傳了並有詳盡的結果分析,再次感受和別人的巨大差距。整個項目是以python爲基礎的,做爲一個剛開始接觸python的小白沒有作出什麼貢獻,但從一開始接到任務的手足無措,到慢慢知道該從何下手,我從各路大神代碼中偷偷學到了許多,興趣是最好老師,但願從一次次蹣跚前進中逐漸鍛鍊成一個優秀的碼農。apache
3、Spark下隨機森林算法json
隨機森林算法是機器學習、計算機視覺等領域內應用極爲普遍的一個算法,它不只能夠用來作分類,也可用來作迴歸即預測,隨機森林機由多個決策樹構成,相比於單個決策樹算法,它分類、預測效果更好,不容易出現過分擬合的狀況。bootstrap
由多個決策樹構成的森林,算法分類結果由這些決策樹投票獲得,決策樹在生成的過程中分別在行方向和列方向上添加隨機過程,行方向上構建決策樹時採用放回抽樣(bootstraping)獲得訓練數據,列方向上採用無放回隨機抽樣獲得特徵子集,並據此獲得其最優切分點,這即是隨機森林算法的基本原理,以下圖:api
簡言之隨機森林算法可以很好地避免決策樹的過分擬合問題,由於隨機森林經過若干決策樹進行投票來決定最終的預測或分類結果。同時爲解決隨機森林分佈環境下的效率問題,隨機森林在分佈式環境下進行了優化。Spark 中的隨機森林算法主要實現了三個優化策略:一、切分點抽樣統計二、特徵裝箱(Binning)三、逐層訓練(level-wise training)。
關於Spark下隨機森林算法接口調用核心代碼以下:
1 from __future__ import print_function 2 import json 3 import sys 4 import math 5 from pyspark import SparkContext 6 from pyspark.mllib.classification import NaiveBayes, NaiveBayesModel 7 from pyspark.mllib.util import MLUtils 8 #隨機森林中關鍵的類是 org.apache.spark.mllib.tree.RandomForest、org.apache.spark.mllib.tree.model.RandomForestModel 這兩個類,它們提供了隨機森林具體的 trainClassifier 和 predict 函數。 9 10 class BloodTestReportbyNB: 11 12 def __init__(self, sc): 13 self.sc = sc 14 # 讀取數據 15 print('Begin Load Data File!') 16 self.sexData = MLUtils.loadLabeledPoints(self.sc, "LabeledPointsdata_sex.txt") 17 self.ageData = MLUtils.loadLabeledPoints(self.sc, "LabeledPointsdata_age.txt") 18 print('Data File has been Loaded!') 19 self.predict_gender = "" 20 self.predict_age = "" 21 22 def predict(self): 23 sexTraining = self.sexData 24 ageTraining = self.ageData 25 #訓練隨機森林分類器,trainClassifier返回的是RandomForestModel對象 26 #分類數;categoricalFeaturesInfo爲空,意味着全部的特徵爲連續型變量;樹的個數;特徵子集採樣策略,auto 表示算法自主選取;純度計算;樹的最大層次;特徵最大裝箱數。具體我設置的是樹=3,最大深度=4,最大葉子數=32,純度計算方式:基尼係數;性別分類=2,年齡分類=1000(取值與純度計算方式有關)。 27 sexModel = RandomForest.trainClassifier(sexTraining,numClasses=2, categoricalFeaturesInfo={}, 28 numTrees=3, featureSubsetStrategy="auto", 29 impurity='gini', maxDepth=4, maxBins=32) 30 ageModel = RandomForest.trainClassifier(ageTraining,numClasses=1000, categoricalFeaturesInfo={}, 31 numTrees=3, featureSubsetStrategy="auto", 32 impurity='gini', maxDepth=4, maxBins=32) 33 #讀取預測數據 34 sexPredict = MLUtils.loadLabeledPoints(self.sc, "LabeledPointsdata_predict_gender.txt") 35 agePredict = MLUtils.loadLabeledPoints(self.sc, "LabeledPointsdata_predict_age.txt") 36 # 對數據進行預測 37 predict_genderCollect = sexPredict.map(lambda p: p.label).zip(sexModel.predict(sexTest.map(lambda x: x.features)))#導入rdd數據集,組成鍵值對 38 predict_ageCollect = agePredict.map(lambda p: p.label).zip(ageModel.predict(ageTest.map(lambda x: x.features))) 39 self.predict_gender = predict_genderCollect[0] 40 self.predict_age = predict_ageCollect[0] 41 if 0 == self.predict_gender: 42 self.predict_gender = "男" 43 if 1 == self.predict_gender: 44 self.predict_gender = "女" 45 print ('Predict Gender:', self.predict_gender) 46 print ('Predict Age:', self.predict_age) 47 predict_data = { 48 "age": self.predict_age, 49 "gender": self.predict_gender 50 } 51 json_data = json.dumps(predict_data, ensure_ascii=False) 52 print ('JSON data of predict_data:', json_data) 53 return json_data 54 if __name__ == "__main__": 55 sc = SparkContext(appName="BloodTestReportPythonNaiveBayesExample") 56 BloodTestReportbyNB = BloodTestReportbyNB(sc) 57 BloodTestReportbyNB.predict()
其中隨機森林中關鍵的類是org.apache.spark.mllib.tree.RandomForest、org.apache.spark.mllib.tree.model.RandomForestModel這兩個類,它們提供了隨機森林具體的trainClassifier和predict函數。
另外隨機森林模型函數的參數分別表明分類數;categoricalFeaturesInfo爲空,意味着全部的特徵爲連續型變量;樹的個數;特徵子集採樣策略,auto 表示算法自主選取;純度計算;樹的最大層次;特徵最大裝箱數。具體我設置的是樹=3,最大深度=4,最大葉子數=32,純度計算方式:基尼係數;性別分類=2,年齡分類=1000(取值與純度計算方式有關)。
利用隨機森林算法對性別預測的準確度能夠達到71%,中途輸出結果如圖:
同時爲了生成Spark能過識別的labeled point數據(格式如圖,每行第一位爲標籤位,後面以空格隔開的爲特徵因子),與前端整合過程當中要分別處理深度學習數據集data_all.csv,將數據集中的數據項與BloodTestReportOCR中血常規報告單的數據項保持一致,以及將JSON格式的預測數據轉換爲Spark可識別的LabeledPoint數據並分別存放於LabeledPointsdata_predict_age.txt和LabeledPointsdata_predict_gender.txt。實現代碼分別以下:
1 #將JSON格式的血常規數據轉換爲Saprk可識別的LabeledPoint數據 2 def predict_dataFormat(report_data): 3 output1 = open('LabeledPointsdata_predict_age.txt', 'w') 4 output2 = open('LabeledPointsdata_predict_gender.txt', 'w') 5 outputline1 = str(report_data["profile"]["age"]) + "," 6 if report_data["profile"]["gender"] == "Man": 7 outputline2 = "0," 8 if report_data["profile"]["gender"] == "Woman": 9 outputline2 = "1," 10 for item in report_data["bloodtest"]: 11 if item["alias"] == "GRA" or item["alias"] == "EO" or item["alias"] == "GRA%" or item["alias"] == "EO%": 12 continue 13 else: 14 outputline1 += item["value"] + " " 15 outputline2 += item["value"] + " " 16 output1.write(outputline1) 17 output2.write(outputline2)
1 #生成LabeledPoints類型數據,格式以下: 2 #label,factor1 factor2 .... factorn 3 #第一列爲類別標籤,後面以空格隔開的爲特徵(因子) 4 import csv 5 reader = csv.reader(file('./data_set.csv', 'rb')) 6 output1 = open('LabeledPointsdata_age.txt', 'w') 7 output2 = open('LabeledPointsdata_sex.txt', 'w') 8 9 flag = 0 10 row = 0 11 12 for line in reader: 13 row = row + 1 14 if 1 == row: 15 continue 16 17 column = 0 18 for c in line: 19 column = column + 1 20 if 1 == column: 21 continue 22 if 2 == column: 23 if "男" == c: 24 outputline2 = "0," 25 else: 26 outputline2 = "1," 27 continue 28 if 3 == column: 29 outputline1 = c + "," 30 else: 31 if "--.--"==c: 32 flag = 1 33 break 34 else: 35 outputline1 += (c + " ") 36 outputline2 += (c + " ") 37 if 0 == flag: 38 outputline1 += '\n' 39 outputline2 += '\n' 40 else: 41 flag = 0 42 continue 43 print(column) 44 output1.write(outputline1) 45 output2.write(outputline2) 46 output1.close() 47 output2.close() 48 print('Format Successful!')
4、項目Demo
一、環境配置:
#安裝numpy sudo apt-get install python-numpy # http://www.numpy.org/ #安裝opencv sudo apt-get install python-opencv # http://opencv.org/ #安裝OCR和預處理相關依賴 sudo apt-get install tesseract-ocr sudo pip install pytesseract sudo apt-get install python-tk sudo pip install pillow #安裝Flask框架 sudo pip install Flask #安裝MongoDB sudo apt-get install mongodb # 若是提示no module name mongodb, 先執行sudo apt-get update sudo service mongodb started sudo pip install pymongo #安裝JDK、Scala、Spark(略),並配置JDK和Spark相關的環境變量(sudo gedit /etc/profile,在文件最後添加以下配置) export JAVA_HOME=/opt/jdk1.8.0_45 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:$PATH export SCALA_HOME=/opt/scala-2.11.6 export PATH=${SCALA_HOME}/bin:$PATH export SPARK_HOME=/opt/spark-hadoop/ export PYTHONPATH=/opt/spark-hadoop/python
二、運行效果:
python dataformat.py
python view.py
瀏覽器訪問 http://0.0.0.0:8080/
主界面:
上傳圖片:
生成報告(注:此處可對數據進行修改調整):
進行預測:
附:版本庫地址
學號:SA16225281
姓名:王陳航