컴파일되지 않습니다 :최소한의 Numeric.AD 예 내가 Numeric.AD에서 다음과 같은 최소한의 예를 컴파일하려고
import Numeric.AD
timeAndGrad f l = grad f l
main = putStrLn "hi"
을하고이 오류로 실행 :
test.hs:3:24:
Couldn't match expected type ‘f (Numeric.AD.Internal.Reverse.Reverse
s a)
-> Numeric.AD.Internal.Reverse.Reverse s a’
with actual type ‘t’
because type variable ‘s’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context:
Data.Reflection.Reifies s Numeric.AD.Internal.Reverse.Tape =>
f (Numeric.AD.Internal.Reverse.Reverse s a)
-> Numeric.AD.Internal.Reverse.Reverse s a
at test.hs:3:19-26
Relevant bindings include
l :: f a (bound at test.hs:3:15)
f :: t (bound at test.hs:3:13)
timeAndGrad :: t -> f a -> f a (bound at test.hs:3:1)
In the first argument of ‘grad’, namely ‘f’
In the expression: grad f l
단서로 왜 이런 일이 일어나는가?
grad :: (Traversable f, Num a) => (forall s. Reifies s Tape => f (Reverse s a) -> Reverse s a) -> f a -> f a
을하지만 실제로 내 코드에서 같은 것을 할 필요가 : 앞의 예에서보고에서 나는이 grad
의 유형을 "병합"것을 수집합니다. 사실, 이것은 컴파일하지 않는 가장 최소의 예입니다. 내가 원하는 더 복잡한 일은 다음과 같습니다.
example :: SomeType
example f x args = (do stuff with the gradient and gradient "function")
where gradient = grad f x
gradientFn = grad f
(other where clauses involving gradient and gradient "function")
여기에는 컴파일하는 형식 시그니처가있는 약간 더 복잡한 버전이 있습니다.
{-# LANGUAGE RankNTypes #-}
import Numeric.AD
import Numeric.AD.Internal.Reverse
-- compiles but I can't figure out how to use it in code
grad2 :: (Show a, Num a, Floating a) => (forall s.[Reverse s a] -> Reverse s a) -> [a] -> [a]
grad2 f l = grad f l
-- compiles with the right type, but the resulting gradient is all 0s...
grad2' :: (Show a, Num a, Floating a) => ([a] -> a) -> [a] -> [a]
grad2' f l = grad f' l
where f' = Lift . f . extractAll
-- i've tried using the Reverse constructor with Reverse 0 _, Reverse 1 _, and Reverse 2 _, but those don't yield the correct gradient. Not sure how the modes work
extractAll :: [Reverse t a] -> [a]
extractAll xs = map extract xs
where extract (Lift x) = x -- non-exhaustive pattern match
dist :: (Show a, Num a, Floating a) => [a] -> a
dist [x, y] = sqrt(x^2 + y^2)
-- incorrect output: [0.0, 0.0]
main = putStrLn $ show $ grad2' dist [1,2]
그러나, 나는 Reverse s a
처리하는 방법을 모르기 때문에 코드에서 첫 번째 버전, grad2
을 사용하는 방법을 알아낼 수 없습니다. 두 번째 버전 인 grad2'
은 내부 생성자 Lift
을 사용하여 Reverse s a
을 만들었으므로 올바른 유형을 가지고 있지만 출력 그래디언트가 모두 0이기 때문에 내부 (특히 매개 변수 s
)의 작동 방식을 이해하면 안됩니다. 다른 생성자 Reverse
(여기에 표시되지 않음)을 사용하면 잘못된 그래디언트가 생성됩니다.
다른 방법으로 사람들이 ad
코드를 사용한 라이브러리/코드의 예가 있습니까? 내 유스 케이스는 매우 일반적인 것 같아요.
timeAndGrad에 유형 서명을 제공하면 어떻게됩니까? 랭크 1 방식에 더 많은 행운이있을 수 있습니다. – ocharles
형식 서명과 다른 접근 방식을 추가하기 위해 제 질문을 편집했습니다 (또한 작동하지 않음). – kye