Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file owl_algodiff_generic.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209# 1 "src/base/algodiff/owl_algodiff_generic.ml"(*
* OWL - OCaml Scientific Computing
* Copyright (c) 2016-2022 Liang Wang <liang@ocaml.xyz>
* Core nested automatic differentiation algorithm and differentiation API
* ported from DiffSharp (http://diffsharp.github.io), copyright (c) 2014-2016
* National University of Ireland Maynooth (Atilim Gunes Baydin), 2014-2018
* National University of Ireland Maynooth (Barak A. Pearlmutter
* <barak@pearlmutter.net>), 2016-2018 University of Oxford (Atilim Gunes
* Baydin <gunes@robots.ox.ac.uk>), 2017-2018 Microsoft Research Cambridge
* (Don Syme <dsyme@microsoft.com>
*)(* Functor of making AD module of different precisions *)moduleMake(A:Owl_types_ndarray_algodiff.Sig)=struct(* include functions in the Core module *)moduleCore=Owl_algodiff_core.Make(A)includeCore(* include graph conversion functions *)includeOwl_algodiff_graph_convert.Make(Core)(* instantiate operations *)moduleOps=Owl_algodiff_ops.Make(Core)includeOps(* include core reverse mode functions *)moduleReverse=Owl_algodiff_reverse.Make(structincludeCoreletreverse_add=Maths.addend)(* convenient wrappers *)letmake_forwardpti=DF(p,t,i)letmake_reversepi=letadjoint_cp_cat=tinletregistert=tinletlabel="Noop",[]inDR(p,ref(zerop),(adjoint,register,label),ref0,i,ref0)(* expose reverse prop: propagate gradients *)letreverse_prop=Reverse.reverse_prop(* derivative of f (scalar -> scalar) at x, forward ad *)letdiff'fx=ifnot(is_floatx)thenfailwith"input of `diff` must be a scalar";letx=make_forwardx(pack_flt1.)(tag())inlety=fxinprimaly,tangenty(* derivative of f (scalar -> scalar) at x, forward ad *)letdifffx=diff'fx|>snd(* gradient of f (vector -> scalar) at x, reverse ad *)letgrad'fx=letx=make_reversex(tag())inlety=fxinifnot(is_floaty)thenfailwith"output of `grad` must be a scalar";Reverse.reverse_resety;Reverse.reverse_push(pack_flt1.)y;primaly,x|>adjval(* gradient of f (vector -> scalar) at x, reverse ad *)letgradfx=grad'fx|>snd(* jacobian vector product of f (vector -> vector) at x along v, forward ad *)letjacobianv'fxv=ifshapex<>shapevthenfailwith"jacobianv': vector not the same dimension as input";letx=make_forwardxv(tag())inlety=fxinprimaly,tangenty(* jacobian vector product of f (vector -> vector) at x along v, forward ad *)letjacobianvfxv=jacobianv'fxv|>snd(* transposed jacobian vector product of f (vector -> vector) at x along v, backward ad *)letjacobianTv'fxv=letx=make_reversex(tag())inlety=fxinifshapey<>shapevthenfailwith"jacobianTv': vector not the same dimension as output";Reverse.reverse_resety;Reverse.reverse_pushvy;primaly,x|>adjval(* transposed jacobian vector product of f (vector -> vector) at x along v, backward ad *)letjacobianTvfxv=jacobianTv'fxv|>snd(* jacobian of f (vector -> vector) at x, both x and y are row vectors, also return the
original value. The jacobian J satisfies dx = J df *)letjacobian'=letdim_typx=matchprimal'xwith|F_->`float|Arrx->lets=A.shapexinletd=Array.lengthsinifd>2then`arrelseifs.(0)=1then`rows.(1)elseifs.(1)=1then`cols.(0)else`mat|_->assertfalseinfunfx->lety=fxinletm,n=matchdim_typy,dim_typxwith|`rowa,`row1->a,1|`rowa,`rowb->a,b|_->failwith"jacobian: input and output must both be row vectors"inletz=letjvps=ifm>nthenArray.initn(funi->letv=A.zeros[|1;n|]inA.(setv[|0;i|](float_to_elt1.));jacobianvfx(Arrv))elseArray.initm(funi->letv=A.zeros[|1;m|]inA.(setv[|0;i|](float_to_elt1.));jacobianTvfx(Arrv))inmatchywith|F_->failwith"input to jacobian must be a row vector not a float"|Arr_->letz=A.zeros[|n;m|]injvps|>Array.iteri(funiv->matchvwith|Arrv->ifm>nthenA.copy_row_tovzielseA.copy_col_to(A.transposev)zi|_->failwith"error: jacobian");Arrz|DF_|DR_->ifm>nthenOps.Maths.concatenate~axis:0jvpselseOps.Maths.concatenate~axis:0jvps|>Ops.Maths.transposeinprimaly,z(* jacobian of f *)letjacobianfx=jacobian'fx|>snd(* gradient, hessian of f (vector -> scalar) at [x] *)letgradhessianfx=jacobian'(gradf)x(* original value, gradient, and hessian *)letgradhessian'fx=letg,h=gradhessianfxinfx,g,h(* hessian of f *)lethessianfx=(f|>grad|>jacobian)x(* original value and hessian of f *)lethessian'fx=fx,hessianfx(* original value, gradient-vector product, hessian-vector product *)letgradhessianv'fxv=letgv,hv=grad'(funy->jacobianvfyv)xinfx,gv,hv(* gradient-vector product and hessian-vector product *)letgradhessianvfxv=let_,gv,hv=gradhessianv'fxvingv,hv(* original value and hessian-vector product *)lethessianv'fxv=letfv,_,hv=gradhessianv'fxvinfv,hv(* hessian-vector *)lethessianvfxv=let_,_,hv=gradhessianv'fxvinhv(* laplacian of f *)letlaplacianfx=F(hessianfx|>unpack_arr|>A.trace)letlaplacian'fx=fx,laplacianfxend(* ends here *)