1. 程式人生 > >scala 下 sigmoid 與breeze.numeric.sigmoid差異對比

scala 下 sigmoid 與breeze.numeric.sigmoid差異對比

scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => 1.0 / (1.0 + Math.exp(-x)));val cost = System.nanoTime - beforeInit;
beforeInit: Long = 35022621366051878
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.6666755488429456, 0.6787806786393414, 0.6529507380367386, 0.6808414264302959, 0.5888748381101, 0.6206479525547044, 0.5472020814143724, 0.5753974761545867, 0.5587867292203849, 0.5063225260538604, 0.6904543881882752, 0.5606615580952308, 0.6879474616785335, 0.6145848916214701, 0.5044123510408592, 0.5960397224312342, 0.7101654507649577, 0.6918354450622388, 0.5142539384969489, 0.6753761634399785, 0.5981233179292798, 0.5789215904180679, 0.7023174432239545, 0.5710123819509948, 0.5088592463935145, 0.682943856507884, 0.7109637098283254, 0.639949076321439, 0.5695993566470937, 0.5109011361739307, 0.5053771358846573, 0.6872196495199817, 0.62922618014367, 0.6113402049344542, 0.6518850736815989, 0.5...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => 1.0 / (1.0 + Math.exp(-x)));println(System.nanoTime - beforeInit);
1771465
beforeInit: Long = 35022633234799178
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.6666755488429456, 0.6787806786393414, 0.6529507380367386, 0.6808414264302959, 0.5888748381101, 0.6206479525547044, 0.5472020814143724, 0.5753974761545867, 0.5587867292203849, 0.5063225260538604, 0.6904543881882752, 0.5606615580952308, 0.6879474616785335, 0.6145848916214701, 0.5044123510408592, 0.5960397224312342, 0.7101654507649577, 0.6918354450622388, 0.5142539384969489, 0.6753761634399785, 0.5981233179292798, 0.5789215904180679, 0.7023174432239545, 0.5710123819509948, 0.5088592463935145, 0.682943856507884, 0.7109637098283254, 0.639949076321439, 0.5695993566470937, 0.5109011361739307, 0.5053771358846573, 0.6872196495199817, 0.62922618014367, 0.6113402049344542, 0.6518850736815989, 0.5...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => breeze.numerics.sigmoid(x));println(System.nanoTime - beforeInit);
1912128
beforeInit: Long = 35022662283025264
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.6666755488429456, 0.6787806786393414, 0.6529507380367386, 0.6808414264302959, 0.5888748381101, 0.6206479525547044, 0.5472020814143724, 0.5753974761545867, 0.5587867292203849, 0.5063225260538604, 0.6904543881882752, 0.5606615580952308, 0.6879474616785335, 0.6145848916214701, 0.5044123510408592, 0.5960397224312342, 0.7101654507649577, 0.6918354450622388, 0.5142539384969489, 0.6753761634399785, 0.5981233179292798, 0.5789215904180679, 0.7023174432239545, 0.5710123819509948, 0.5088592463935145, 0.682943856507884, 0.7109637098283254, 0.639949076321439, 0.5695993566470937, 0.5109011361739307, 0.5053771358846573, 0.6872196495199817, 0.62922618014367, 0.6113402049344542, 0.6518850736815989, 0.5...
scala> Display all 675 possibilities? (y or n)xtDouble)
scala> val rd = (0 until 20000).map(i => rand.nextDouble)
rd: scala.collection.immutable.IndexedSeq[Double] = Vector(0.12850502397540942, 0.3800041327418344, 0.8536607295833647, 0.9821419704320834, 0.9938382163394424, 0.7708907441645584, 0.4612756601796696, 0.9371991197262541, 0.5184642043060644, 0.3427131854754534, 0.6524428612208136, 0.3653548619699837, 0.2500488616933274, 0.3845525940247323, 0.7905273172914156, 0.6233163882696882, 0.372006158200208, 0.8347691893470309, 0.5578402978215722, 0.03409879025840201, 0.6124513832158451, 0.3294679930932689, 0.3043858000267232, 0.9841288626829339, 0.21286344025656612, 0.37437105411110394, 0.2746904891571903, 0.11215396563509472, 0.5582924876697188, 0.5361226069230965, 0.623635777327592, 0.18959661621427737, 0.5094273476465386, 0.08909292800046442, 0.33631329890983075, 0.2226581701432716, 0.6965624230...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => 1.0 / (1.0 + Math.exp(-x)));println(System.nanoTime - beforeInit);
5988031
beforeInit: Long = 35023297370957812
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.5320821190238922, 0.5938740997008346, 0.7013344997792978, 0.7275330232805813, 0.729845374992795, 0.6837135480806683, 0.6133167545291345, 0.7185335456160364, 0.6267885758448689, 0.5848494372094519, 0.6575607445298361, 0.590336074284138, 0.5621885273773267, 0.5949706623004747, 0.687944544614549, 0.6509724330457866, 0.5919436478913106, 0.6973624044695454, 0.635952679757521, 0.508523871668941, 0.6484997927293775, 0.5816299257386118, 0.5755143104336967, 0.7279267042885952, 0.5530158284135527, 0.5925147554574627, 0.5682440488414993, 0.5280091381218828, 0.6360573628979685, 0.6309099771887011, 0.6510449970795169, 0.5472576749753335, 0.6246722217973547, 0.5222585107776622, 0.5832947021280129, 0...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => breeze.numerics.sigmoid(x));println(System.nanoTime - beforeInit);
7606556
beforeInit: Long = 35023300754974325
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.5320821190238922, 0.5938740997008346, 0.7013344997792978, 0.7275330232805813, 0.729845374992795, 0.6837135480806683, 0.6133167545291345, 0.7185335456160364, 0.6267885758448689, 0.5848494372094519, 0.6575607445298361, 0.590336074284138, 0.5621885273773267, 0.5949706623004747, 0.687944544614549, 0.6509724330457866, 0.5919436478913106, 0.6973624044695454, 0.635952679757521, 0.508523871668941, 0.6484997927293775, 0.5816299257386118, 0.5755143104336967, 0.7279267042885952, 0.5530158284135527, 0.5925147554574627, 0.5682440488414993, 0.5280091381218828, 0.6360573628979685, 0.6309099771887011, 0.6510449970795169, 0.5472576749753335, 0.6246722217973547, 0.5222585107776622, 0.5832947021280129, 0...

綜上試驗,直接編寫公式,速度相比呼叫breeze庫,時間更短,開銷更小。

scala> def sig(x: Double): Double = 1.0 / (1.0 + Math.exp(-x))
sig: (x: Double)Double

scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => sig(x));println(System.nanoTime - beforeInit);
9380656
beforeInit: Long = 35023440728477327
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.5320821190238922, 0.5938740997008346, 0.7013344997792978, 0.7275330232805813, 0.729845374992795, 0.6837135480806683, 0.6133167545291345, 0.7185335456160364, 0.6267885758448689, 0.5848494372094519, 0.6575607445298361, 0.590336074284138, 0.5621885273773267, 0.5949706623004747, 0.687944544614549, 0.6509724330457866, 0.5919436478913106, 0.6973624044695454, 0.635952679757521, 0.508523871668941, 0.6484997927293775, 0.5816299257386118, 0.5755143104336967, 0.7279267042885952, 0.5530158284135527, 0.5925147554574627, 0.5682440488414993, 0.5280091381218828, 0.6360573628979685, 0.6309099771887011, 0.6510449970795169, 0.5472576749753335, 0.6246722217973547, 0.5222585107776622, 0.5832947021280129, 0...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => breeze.numerics.sigmoid(x));println(System.nanoTime - beforeInit);
7435700
beforeInit: Long = 35023447719287935
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.5320821190238922, 0.5938740997008346, 0.7013344997792978, 0.7275330232805813, 0.729845374992795, 0.6837135480806683, 0.6133167545291345, 0.7185335456160364, 0.6267885758448689, 0.5848494372094519, 0.6575607445298361, 0.590336074284138, 0.5621885273773267, 0.5949706623004747, 0.687944544614549, 0.6509724330457866, 0.5919436478913106, 0.6973624044695454, 0.635952679757521, 0.508523871668941, 0.6484997927293775, 0.5816299257386118, 0.5755143104336967, 0.7279267042885952, 0.5530158284135527, 0.5925147554574627, 0.5682440488414993, 0.5280091381218828, 0.6360573628979685, 0.6309099771887011, 0.6510449970795169, 0.5472576749753335, 0.6246722217973547, 0.5222585107776622, 0.5832947021280129, 0...
scala>     val beforeInit = System.nanoTime;val handsgn = rd.map(x => 1.0 / (1.0 + Math.exp(-x)));println(System.nanoTime - beforeInit);
6011454
beforeInit: Long = 35023455808772793
handsgn: scala.collection.immutable.IndexedSeq[Double] = Vector(0.5320821190238922, 0.5938740997008346, 0.7013344997792978, 0.7275330232805813, 0.729845374992795, 0.6837135480806683, 0.6133167545291345, 0.7185335456160364, 0.6267885758448689, 0.5848494372094519, 0.6575607445298361, 0.590336074284138, 0.5621885273773267, 0.5949706623004747, 0.687944544614549, 0.6509724330457866, 0.5919436478913106, 0.6973624044695454, 0.635952679757521, 0.508523871668941, 0.6484997927293775, 0.5816299257386118, 0.5755143104336967, 0.7279267042885952, 0.5530158284135527, 0.5925147554574627, 0.5682440488414993, 0.5280091381218828, 0.6360573628979685, 0.6309099771887011, 0.6510449970795169, 0.5472576749753335, 0.6246722217973547, 0.5222585107776622, 0.5832947021280129, 0...

scala> new breeze.linalg.DenseVector(rd.toArray)
res21: breeze.linalg.DenseVector[Double] = DenseVector(0.12850502397540942, 0.3800041327418344, 0.8536607295833647, 0.9821419704320834, 0.9938382163394424, 0.7708907441645584, 0.4612756601796696, 0.9371991197262541, 0.5184642043060644, 0.3427131854754534, 0.6524428612208136, 0.3653548619699837, 0.2500488616933274, 0.3845525940247323, 0.7905273172914156, 0.6233163882696882, 0.372006158200208, 0.8347691893470309, 0.5578402978215722, 0.03409879025840201, 0.6124513832158451, 0.3294679930932689, 0.3043858000267232, 0.9841288626829339, 0.21286344025656612, 0.37437105411110394, 0.2746904891571903, 0.11215396563509472, 0.5582924876697188, 0.5361226069230965, 0.623635777327592, 0.18959661621427737, 0.5094273476465386, 0.08909292800046442, 0.33631329890983075, 0.2226581701432716, 0.69656242309717...
scala>     val beforeInit = System.nanoTime;breeze.numerics.sigmoid(res21);println(System.nanoTime - beforeInit);
3372600
beforeInit: Long = 35024279429434608


scala>     val beforeInit = System.nanoTime;breeze.numerics.sigmoid(new breeze.linalg.DenseVector(rd.toArray));println(System.nanoTime - beforeInit);
4293909
beforeInit: Long = 35024437699054802

本次試驗,證明在有函式呼叫的情況下,開銷有較大上升。
時間開銷分別:handFomula < breeze.numeric < funcDef。
值得注意的是,當將20000個實陣列織成Vector形式進行計算時,breeze有了極大的效能提升。基本可以將時間開銷降低到先前一半的水平。即便是包含Vector組織的時間開銷,依然在計算時間上有較大優勢。
並且在20、200、2000、20000條樣本的測試下,breeze有著幾乎等比例提升。

綜上:當計算資料為數字或者數值變數,在不影響邏輯和可讀性的情況下,儘量將公式操作以程式碼形式寫入邏輯。
但當出現對向量、矩陣進行操作,抑或者對大量數值同時計算,建議通過線性庫適當調整形式,進而借用線性庫的加速特性,提高程式執行效率。