2016-06-10 61 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