Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file operation.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322(** Computational primitives for neural networks, integrating [Tensor] with [Assignments]. *)openBasemoduleAsgns=Arrayjit.AssignmentsmoduleIdx=Arrayjit.IndexingmoduleAt=struct(** Get the value at the given indices. *)let(.@{})=Tensor.get_valuelet(.@%{})=Tensor.get_grad(** Set the value at the given indices. *)let(.@{}<-)=Tensor.set_valuelet(.@%{}<-)=Tensor.set_grad(** Get the value at the given index from a single-axis shape tensor. *)let(.@[])tindx=Tensor.get_valuet[|indx|]let(.@%[])tindx=Tensor.get_gradt[|indx|](** Set the value at the given index for a single-axis shape tensor. *)let(.@[]<-)tindx=Tensor.set_valuet[|indx|]let(.@%[]<-)tindx=Tensor.set_gradt[|indx|]endmoduleInitial_NTDSL=structletterm=Tensor.term~grad_spec:Prohibit_gradletnumber=Tensor.number~grad_spec:Prohibit_gradletndarray=Tensor.ndarray~grad_spec:Prohibit_gradmoduleO=structendendmoduleInitial_TDSL=structletterm=Tensor.term~grad_spec:If_neededletnumber=Tensor.number~grad_spec:If_neededletndarray=Tensor.ndarray~grad_spec:If_neededletparam=Tensor.parammoduleO=structendendletadd?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:v1+v2inlet%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g;g2=+ginTensor.binop~label:("+"::label)~compose_op:Pointwise_bin~op_asn~grad_asnletsub?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:v1-v2inlet%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g;g2=-ginTensor.binop~label:("-"::label)~compose_op:Pointwise_bin~op_asn~grad_asnletmulcompose_op~op_asn=letmoduleNTDSL=Initial_NTDSLinlet%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g*v2;g2=+v1*ginTensor.binop~compose_op~op_asn~grad_asnletpointmul?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:v1*v2inmulPointwise_bin~op_asn~label:("*."::label)(* N1: AxB, N2 BxC, v: AxC, A: output of N1, B: input/output of N1/N2, C: input of N2. Although the
matrix algebra would require that we insert additional transposes in gradient multiplies: AxB =
AxC * CxB = AxC * (BxC)^T -> N1g += Ng * N2v^T, BxC = BxA * AxC = (AxB)^T * AxC -> N2g += N1v^T *
Ng, in our setup there is no transposing to do, since the projections produce correct indices for
their corresponding matrices. *)letmatmul?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:+v1*v2inmulCompose~op_asn~label:("*"::label)(** Similar to the explicit mode of [numpy.einsum], the binary variant. Can compute various forms of
matrix multiplication, inner and outer products, etc.
Note that ["a,b->c"] from [numpy] is ["a;b=>c"] in OCANNL, since ["->"] is used to separate the
input and the output axes. *)leteinsum?(label=[])spec=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:+v1*v2inlet%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g*v2;g2=+v1*ginTensor.binop~label:(";=>"::label)~compose_op:(Einsumspec)~op_asn~grad_asn(** Like [einsum], but adds instead than multiplying the resulting values. *)letouter_sum?(label=[])spec=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~t2~projections=v=:+v1+v2inlet%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g;g2=+ginTensor.binop~label:(";=>+"::label)~compose_op:(Einsumspec)~op_asn~grad_asn(** Similar to the explicit mode of [numpy.einsum], the unary variant. Can permute axes, extract
diagonals, compute traces etc.
Note that ["a->c"] from [numpy] is ["a=>c"] in OCANNL, since ["->"] is used to separate the
input and the output axes. *)leteinsum1?(label=[])spec=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~projections=v=:+v1inlet%cdgrad_asn~v:_~g~t1~projections=g1=+ginTensor.unop~label:("=>"::label)~transpose_op:(Shape.Permutespec)~op_asn~grad_asnletrelu?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~projections=v=:?/v1~projectionsinlet%cdgrad_asn~v~g~t1~projections=g1=+v-?/ginTensor.unop~label:("?/"::label)~transpose_op:Pointwise_un~op_asn~grad_asnmoduleNDO_without_pow=structlet(*)=matmul~grad_spec:Prohibit_gradlet(*.)=pointmul~grad_spec:Prohibit_gradlet(+)=add~grad_spec:Prohibit_gradlet(?/)=relu~grad_spec:Prohibit_gradlet(!.)=Tensor.number~grad_spec:Prohibit_gradlet(!..)?labeli=Tensor.number?label~grad_spec:Prohibit_grad@@Float.of_intilet(-)=sub~grad_spec:Prohibit_gradlet(~-)?labelt=(*.)?label!.(-1.)tendletrecpointpow?(label:stringlist=[])~grad_specpt1:Tensor.t=letmoduleNTDSL=structincludeInitial_NTDSLmoduleO=structincludeNDO_without_powlet(**.)?labelbaseexp=pointpow?label~grad_spec:Tensor.Prohibit_gradexpbaseendendinletp_t=NTDSL.numberpinlet%cdop_asn~v~t1~t2~projections=v=:v1**v2~projectionsinlet%cdgrad_asn=ifTensor.is_prohibit_gradgrad_specthenfun~v:_~g:_~t1:_~t2:_~projections:_->Asgns.NoopelseifFloat.equalp2.0thenfun~v:_~g~t1~t2:_~projections->g1=+p_t*.t1*gelseifFloat.equalp1.0thenfun~v:_~g~t1~t2:_~projections->g1=+gelsefun~v:_~g~t1~t2:_~projections->g1=+p_t*.(t1**.(p-.1.))*ginTensor.binop~label:("**."::label)~compose_op:Pointwise_bin~op_asn~grad_asn~grad_spect1p_tmoduleNDO_without_div=structincludeNDO_without_powlet(**.)?labelbaseexp=pointpow?label~grad_spec:Tensor.Prohibit_gradexpbaseendletrecpointdiv?(label:stringlist=[])~grad_spect1t2=letmoduleNTDSL=structincludeInitial_NTDSLmoduleO=structincludeNDO_without_divlet(/.)=pointdiv~grad_spec:Tensor.Prohibit_gradendendinlet%cdop_asn~v~t1~t2~projections=v=:v1/v2in(* We cannot use g in a tensor expression since it's an array, so we keep it to the left
(RHS1). *)let%cdgrad_asn~v:_~g~t1~t2~projections=g1=+g/v2;g2=+g*(-1*.t1/.(t2**.2))inTensor.binop~label:("/."::label)~compose_op:Pointwise_bin~op_asn~grad_asn~grad_spect1t2letrange?(label=[])?(grad_spec=Tensor.Prohibit_grad)?axis_labelupto=letresult=Tensor.term~label:(("0"^"..."^Int.to_stringupto)::label)~grad_spec~batch_dims:[]~input_dims:[]~init_op:Range_over_offsetsinmatchaxis_labelwith|None->result~output_dims:[upto+1]()|Somel->result~output_axes:[(l,upto+1)]()letrange_of_shape?(label=[])?(grad_spec=Tensor.Prohibit_grad)?batch_dims?input_dims?output_dims?batch_axes?input_axes?output_axes()=letf(dims,axes)=Array.of_list@@Option.value~default:[]@@Option.first_somedims@@Option.mapaxes~f:(List.map~f:snd)inletdims=Array.concat_map~f[|(batch_dims,batch_axes);(output_dims,output_axes);(input_dims,input_axes)|]inletbatch_dims=Option.first_somebatch_dims@@Option.some_if(Option.is_nonebatch_axes)[]inletinput_dims=Option.first_someinput_dims@@Option.some_if(Option.is_noneinput_axes)[]inletoutput_dims=Option.first_someoutput_dims@@Option.some_if(Option.is_noneoutput_axes)[]inTensor.term~label:(("r"^Idx.dims_to_stringdims)::label)~grad_spec?batch_dims?input_dims?output_dims?batch_axes?input_axes?output_axes~init_op:Range_over_offsets()(** A [stop_gradient] is an identity in the forward pass and a no-op in the backprop pass. *)letstop_gradient?(label=[])=letmoduleNTDSL=Initial_NTDSLinletgrad_asn~v:_~g:_~t1:_~projections:_=Asgns.Noopinlet%cdop_asn~v~t1~projections=v=:v1inTensor.unop~label:("stop_grad"::label)~transpose_op:Pointwise_un~op_asn~grad_asn~grad_spec:Prohibit_gradletslice?(label=[])~grad_spec(batch_idx:Idx.static_symbol)t1:Tensor.t=letmoduleNTDSL=Initial_NTDSLinletop_asn~v~t1~projections=Asgns.Fetch{array=v;fetch_op=Slice{batch_idx;sliced=t1.Tensor.value};dims=lazy(Lazy.forceprojections).Idx.lhs_dims;}inlet%cdgrad_asn~v:_~g~t1~projections=g1=+ginTensor.unop~label:("@|"::label)~transpose_op:(Batch_slicebatch_idx)~op_asn~grad_asn~grad_spect1letembed_symbol?(label=[])static_sym:Tensor.t=letmoduleNTDSL=Initial_NTDSLinletop_asn~v~projections=Asgns.Fetch{array=v;fetch_op=Embed_symbolstatic_sym;dims=lazy(Lazy.forceprojections).Idx.lhs_dims;}inletgrad_asn~v:_~g:_~projections:_=Asgns.NoopinTensor.op~label:("!@"::label)~op_asn~grad_asn~grad_spec:Prohibit_grad(Shape.make~batch_dims:[]~input_dims:[]~output_dims:[1]())[]moduleDO=structlet(*)=matmul~grad_spec:If_neededlet(*.)=pointmul~grad_spec:If_neededlet(+)=add~grad_spec:If_neededlet(**.)?labelbaseexp=pointpow?labelexpbase~grad_spec:If_neededlet(?/)=relu~grad_spec:If_neededlet(!~)label=Tensor.paramlabellet(!.)=Tensor.number~grad_spec:If_neededlet(!..)?labeli=Tensor.number?label~grad_spec:If_needed@@Float.of_intilet(!@)=embed_symbollet(-)=sub~grad_spec:If_neededlet(~-)?labelt=(*.)?label!.(-1.)tlet(/.)=pointdiv~grad_spec:If_neededlet(@|)?labelt1idx=slice?label~grad_spec:If_neededidxt1endmoduleNDO=structincludeNDO_without_divlet(/.)=pointdiv~grad_spec:Prohibit_gradlet(@|)?labelt1idx=slice?label~grad_spec:Prohibit_gradidxt1endmoduleTDSL=structincludeInitial_TDSLmoduleO=DOleteinsum=einsum~grad_spec:If_neededletouter_sum=outer_sum~grad_spec:If_neededleteinsum1=einsum1~grad_spec:If_neededletrange=range~grad_spec:If_neededletrange_of_shape=range_of_shape~grad_spec:If_neededletstop_gradient=stop_gradient(** The input [i] dimensions default to empty. The batch dimensions will be inferred if omitted.
[strict] controls whether [Constant_fill] will try to fit the given values in the tensor and
contribute to shape inference. If it is not provided explicitly, it will be [true] if [b] is
omitted, and [false] otherwise. *)letinit_const~l?strict?b?(i=[])~ovalues=letstrict=match(strict,b)withSomes,_->s|None,Some_->false|None,None->trueinTensor.term~label:[l]~grad_spec:Prohibit_grad?batch_dims:b~input_dims:i~output_dims:o~init_op:(Constant_fill{values;strict})()(** It's like `Tensor.param` but without shape inference. *)letinit_param~l?(b=[])?(i=[])?(o=[])values=Tensor.term~label:[l]~grad_spec:Require_grad~batch_dims:b~input_dims:i~output_dims:o~init_op:(Constant_fill{values;strict=false})()endmoduleNTDSL=structincludeInitial_NTDSLmoduleO=NDOleteinsum=einsum~grad_spec:Prohibit_gradletouter_sum=outer_sum~grad_spec:Prohibit_gradleteinsum1=einsum1~grad_spec:Prohibit_gradletterm=Tensor.term~grad_spec:Prohibit_gradletrange=range~grad_spec:Prohibit_gradletrange_of_shape=range_of_shape~grad_spec:Prohibit_gradletcounter?(label=[])=letmoduleNTDSL=Initial_NTDSLinlet%cdop_asn~v~t1~projections=v=+t1~projectionsinletgrad_asn~v:_~g:_~t1:_~projections:_=Asgns.NoopinTensor.unop~label:("counter"::label)~transpose_op:Pointwise_un~op_asn~grad_asn~grad_spec:Prohibit_gradend