Last active
November 2, 2019 20:31
-
-
Save postspectacular/3dccbfed1b753edadf1b6fee8add4808 to your computer and use it in GitHub Desktop.
Sigmoid versions (AssemblyScript)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// uses Math.exp() approximation from: | |
// https://www.musicdsp.org/en/latest/Other/222-fast-exp-approximations.html | |
// @ts-ignore: decorator | |
@inline | |
function fastexp9(x: f64): f64 { | |
// prettier-ignore | |
return (362880+x*(362880+x*(181440+x*(60480+x*(15120+x*(3024+x*(504+x*(72+x*(9+x)))))))))*2.75573192e-6; | |
} | |
// @ts-ignore: decorator | |
@inline | |
function sigmoidApprox(x: f64): f64 { | |
return 1.0 / (1.0 + fastexp9(-x)); | |
} | |
// @ts-ignore: decorator | |
@inline | |
function sigmoidDerivApprox(x: f64): f64 { | |
x = fastexp9(-x); | |
const y = 1.0 + x; | |
return x / (y * y); | |
} | |
export function sigmoidApproxPtr(out: usize, src: usize, n: usize): usize { | |
const res = out; | |
while (n-- > 0) { | |
f64.store(out, sigmoidApprox(f64.load(src))); | |
out += sizeof<f64>(); // 8 | |
src += sizeof<f64>(); // 8 | |
} | |
return res; | |
} | |
export function sigmoidDerivApproxPtr(out: usize, src: usize, n: usize): usize { | |
const res = out; | |
while (n-- > 0) { | |
f64.store(out, sigmoidDerivApprox(f64.load(src))); | |
out += sizeof<f64>(); // 8 | |
src += sizeof<f64>(); // 8 | |
} | |
return res; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; disassembled WASM of the above fn | |
; only math ops in the loop, no fn calls... | |
(func $assembly/index/sigmoidApproxPtr (; 3 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) | |
(local $3 f64) | |
(local $4 i32) | |
(local $5 i32) | |
local.get $0 | |
loop $continue|0 | |
local.get $2 | |
local.tee $5 | |
i32.const 1 | |
i32.sub | |
local.set $2 | |
local.get $5 | |
i32.const 0 | |
i32.lt_u | |
i32.eqz | |
if | |
local.get $0 | |
f64.const 1 | |
f64.const 1 | |
f64.const 362880 | |
local.get $1 | |
f64.load | |
f64.neg | |
local.tee $3 | |
f64.const 362880 | |
local.get $3 | |
f64.const 181440 | |
local.get $3 | |
f64.const 60480 | |
local.get $3 | |
f64.const 15120 | |
local.get $3 | |
f64.const 3024 | |
local.get $3 | |
f64.const 504 | |
local.get $3 | |
f64.const 72 | |
local.get $3 | |
f64.const 9 | |
local.get $3 | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.mul | |
f64.add | |
f64.const 2.75573192e-06 | |
f64.mul | |
f64.add | |
f64.div | |
f64.store | |
local.get $0 | |
i32.const 8 | |
i32.add | |
local.set $0 | |
local.get $1 | |
i32.const 8 | |
i32.add | |
local.set $1 | |
br $continue|0 | |
end | |
end | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Chem's original impl (only renamed) & using "native" math | |
// see: https://docs.assemblyscript.org/standard-library/math#variants | |
// @ts-ignore: decorator | |
@inline | |
function sigmoidNat(x: f64): f64 { | |
return 1.0 / (1.0 + Math.exp(-x)); | |
} | |
// updated to avoid double eval of exp(): | |
// @ts-ignore: decorator | |
@inline | |
function sigmoidDerivNat(x: f64): f64 { | |
x = Math.exp(-x); | |
const y = 1.0 + x; | |
return x / (y * y); | |
} | |
export function sigmoidNatPtr(out: usize, src: usize, n: usize): usize { | |
const res = out; | |
while (n-- > 0) { | |
f64.store(out, sigmoidNat(f64.load(src))); | |
out += sizeof<f64>(); // 8 | |
src += sizeof<f64>(); // 8 | |
} | |
return res; | |
} | |
export function sigmoidDerivNatPtr(out: usize, src: usize, n: usize): usize { | |
const res = out; | |
while (n-- > 0) { | |
f64.store(out, sigmoidDerivNat(f64.load(src))); | |
out += sizeof<f64>(); // 8 | |
src += sizeof<f64>(); // 8 | |
} | |
return res; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NOT YET SUPPORTED DUE TO MISSING SIMD OP CODE IMPLS in v8: | |
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/ImplementationStatus.md | |
// @ts-ignore: decorator | |
@inline | |
function addm_64x2(x: v128, y: v128, n: f64): v128 { | |
return f64x2.mul(x, f64x2.add(y, f64x2.splat(n))); | |
} | |
// @ts-ignore: decorator | |
@inline | |
function fastexp9_64x2(ptr: usize): v128 { | |
let x = v128.load(ptr); | |
let y = addm_64x2(x, x, 9.0); | |
y = addm_64x2(x, y, 72.0); | |
y = addm_64x2(x, y, 504.0); | |
y = addm_64x2(x, y, 3024.0); | |
y = addm_64x2(x, y, 15120.0); | |
y = addm_64x2(x, y, 60480.0); | |
y = addm_64x2(x, y, 181440.0); | |
y = addm_64x2(x, y, 362880.0); | |
y = addm_64x2(x, y, 362880.0); | |
return f64x2.mul(y, f64x2.splat(2.75573192e-6)); | |
} | |
// @ts-ignore: decorator | |
@inline | |
function sigmoid_64x2(x: usize): v128 { | |
const one = f64x2.splat(1.0); | |
return f64x2.div(one, f64x2.add(one, fastexp9_64x2(-x))); | |
} | |
export function sigmoid_64x2_ptr(out: usize, src: usize, n: usize): usize { | |
const res = out; | |
n >>= 1; | |
while (n-- > 0) { | |
v128.store(out, sigmoid_64x2(src)); | |
out += sizeof<v128>(); | |
src += sizeof<v128>(); | |
} | |
return res; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Chem's original loop | |
export function sigmoidNatArray(x: Array<f64>, derivate: boolean): Array<f64> { | |
let results: Array<f64> = []; | |
for (let i = x.length; --i >= 0; ) { | |
results[i] = derivate ? sigmoidDerivNat(x[i]) : sigmoidNat(x[i]); | |
} | |
return results; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Chem's original loop WASM | |
; uses AssemblyScript's runtime, Array accessor indirection, bounds checks etc. | |
(func $assembly/index/sigmoidNatArray (; 40 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32) | |
(local $2 i32) | |
(local $3 i32) | |
(local $4 i32) | |
(local $5 f64) | |
local.get $0 | |
call $~lib/rt/pure/__retain | |
drop | |
call $~lib/rt/__allocArray | |
call $~lib/rt/pure/__retain | |
local.tee $4 | |
call $~lib/rt/pure/__retain | |
local.set $3 | |
local.get $0 | |
i32.load offset=12 | |
local.set $2 | |
loop $loop|0 | |
local.get $2 | |
i32.const 1 | |
i32.sub | |
local.tee $2 | |
i32.const 0 | |
i32.ge_s | |
if | |
local.get $3 | |
local.get $2 | |
local.get $1 | |
if (result f64) | |
local.get $0 | |
local.get $2 | |
call $~lib/array/Array<f64>#__get | |
local.tee $5 | |
f64.neg | |
call $~lib/math/NativeMath.exp | |
f64.const 1 | |
local.get $5 | |
f64.neg | |
call $~lib/math/NativeMath.exp | |
f64.add | |
call $~lib/math/NativeMath.pow | |
f64.div | |
else | |
f64.const 1 | |
f64.const 1 | |
local.get $0 | |
local.get $2 | |
call $~lib/array/Array<f64>#__get | |
f64.neg | |
call $~lib/math/NativeMath.exp | |
f64.add | |
f64.div | |
end | |
call $~lib/array/Array<f64>#__set | |
br $loop|0 | |
end | |
end | |
local.get $4 | |
call $~lib/rt/pure/__release | |
local.get $0 | |
call $~lib/rt/pure/__release | |
local.get $3 | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment