2016-06-10 39 views
3

我具有以下功能基於輸入的F#Pick功能?

let private sigmoid (z:float) = 
    1.0/(1.0 + exp(-z)) 
let private sigmoidM (z : Matrix<float>) : Matrix<float> = 
    z.Map (fun x -> sigmoid(x)) 
let private sigmoidV (z:Vector<float>) = 
    z.Map(fun x -> sigmoid(x)) 

我想只具有S形,並將其執行對標量,矢量或矩陣取決於輸入。

也就是說,這個函數需要非常高效,因爲它在循環的最關鍵部分。有關如何做到這一點的任何見解?隨意張貼如何謹慎,如果它會很慢,它會很慢。

+0

感興趣:[從一個函數返回不同維度的數組;是否有可能在F#?](http://stackoverflow.com/questions/34599909/returning-arrays-of-different-dimensions-from-one-function-is-it-possible-in-f) –

+0

出於好奇爲什麼你需要'Vector'結果。當我做我的神經網絡時,我只需要'矩陣'。矩陣只使用'sigmoid'和矩陣使用'Map'函數,就像你做的那樣,我在另一個答案中做了。 –

+0

做神經網絡時還要注意。使用CPU和GPU之間的速度差異如此之大,以至於我只使用CPU來學習和測試代碼,而任何認真的工作只會使用GPU,甚至只能使用預先寫好的測試庫,例如, [TensorFlow](https://www.tensorflow.org/),我還沒有使用[CNTK](https://github.com/Microsoft/CNTK)。簡而言之,如果您正在學習神經網絡如何工作並在一個小時內獲得結果,我不會擔心它;當你開始做大型項目時,擔心後者。 –

回答

5

您可以使用標準的.NET重載:

open MathNet.Numerics.LinearAlgebra 

type Sigmoid() = class end with 
    static member sigmoid (z:float) = 1.0/(1.0 + exp(-z)) 
    static member sigmoid (z:Matrix<float>) = z.Map (fun x -> Sigmoid.sigmoid(x)) 
    static member sigmoid (z:Vector<float>) = z.Map (fun x -> Sigmoid.sigmoid(x)) 

// Usage 
let x = Sigmoid.sigmoid 4.3 
let y = Sigmoid.sigmoid (matrix [[1.0; 2.0]; [3.0; 4.0]]) 
let z = Sigmoid.sigmoid (vector [1.0; 2.0]) 

// Results 
val x : float = 0.9866130822 
val y : Matrix<float> = 
      DenseMatrix 2x2-Double 
      0.731059 0.880797 
      0.952574 0.982014 
val z : Vector<float> = seq [0.7310585786; 0.880797078] 

由於重載決策在編譯時做這不會影響性能。

標準.NET重載不滿意嗎?不想將該函數編碼爲成員?你想讓它更通用(也接受float32)並可擴展到其他類型?

使用靜態類型的限制:

type Sigmoid() = class end with 
    static member Sigmoid (_:Sigmoid, z:float ) = 1.0/(1.0 + exp(-z)) 
    static member Sigmoid (_:Sigmoid, z:float32) = 1.0f/(1.0f + exp(-z)) 

let inline _sigmoid (s:'Sigmoid) (x:'T) :'T = 
    ((^T or ^Sigmoid) : (static member Sigmoid : 'Sigmoid * 'T -> 'T) (s, x)) 

let inline sigmoid x = _sigmoid (Sigmoid()) x 

type Sigmoid with 
    static member inline Sigmoid (_:Sigmoid, z:Matrix<'T>) = z.Map (fun x -> sigmoid x) 
    static member inline Sigmoid (_:Sigmoid, z:Vector<'T>) = z.Map (fun x -> sigmoid x) 

// Usage 
let x = sigmoid 4.3 
let y = sigmoid (matrix [[ 1.0; 2.0 ];[ 3.0; 4.0 ]]) 
let z = sigmoid (vector [ 1.0; 2.0 ]) 

let x' = sigmoid 4.3f 
let y' = sigmoid (matrix [[1.0f; 2.0f];[ 3.0f; 4.0f]]) 
let z' = sigmoid (vector [ 1.0f; 2.0f]) 

UPDATE

注意@TheInnerLight指出在評論認爲,爲您的特定sigmoid功能,您還可以這樣寫:

let inline sigmoid z = 
    LanguagePrimitives.GenericOne/(LanguagePrimitives.GenericOne + exp(-z)) 

這將工作於floatfloat32

這最終還可以用於矢量和矩陣,具體取決於它們的實現。

如果所有操作都否定,divide和exp在這些類型上已經是泛型並且它們都支持GenericOne,那麼對於您的特定情況,這將是一個更好的解決方案。

不幸的是截至今天,MathNet並未以這種方式爲Matrix和Vector實現GenericOneexp

+1

在創建採用各種數字類型的'Sigmoid'函數時,您不需要額外的基礎結構。你可以直接寫'let inline sigmoid z = LanguagePrimitives.GenericOne /(LanguagePrimitives.GenericOne + exp(-z))' – TheInnerLight

+0

@TheInnerLight事實上,對於這個「sigmoid」函數的特定情況應該是正確的方法,因爲''1''和''exp''已經是所需類型的泛型。所以對於這種情況就夠了。您應該添加它作爲答案。 – Gustavo

+0

不,這只是對您答案的一個小修改,使用不同的數字類型只是您添加的一些額外信息,而不是原始問題的一部分。我只是在暗示它,所以如果你願意,你可以把它放在你的答案中。 – TheInnerLight