@@ -23,8 +23,10 @@ import (
2323// - Contracted (contracting axes), where the output does multiply the values and reduce sum
2424// those dimensions.
2525//
26- // It follows that the resulting dimension number starts with the batch dimension, then the 'lhs'
27- // non-contracting/non-batch dimension, and finally the 'rhs' non-contracting/non-batch dimension.
26+ // The resulting shape is [batchIndices..., <lhs cross indices...>, <rhs cross indices...>], the
27+ // indices come in the order they were provided. The output dtype is by default the same as
28+ // the input, except if configured otherwise in config.OutputDType.
29+ //
2830// It provides the basic means of implementing Einsum.
2931//
3032// The XLA implementation only supports accumulation in F32 (if different than the input dtypes).
@@ -39,11 +41,14 @@ func (f *Function) DotGeneral(
3941 }
4042 lhsNode := nodes [0 ]
4143 rhsNode := nodes [1 ]
42- dtype := lhsNode .shape .DType
43- accumulationDType := dtype
44+ inputDType := lhsNode .shape .DType
45+ accumulationDType := inputDType
4446 if config .AccumulatorDType != dtypes .InvalidDType {
4547 accumulationDType = config .AccumulatorDType
4648 }
49+ if config .OutputDType == dtypes .InvalidDType {
50+ config .OutputDType = inputDType
51+ }
4752
4853 // Introduce a dependency to create a schedule barrier to prevent the compiler to try
4954 // to start processing weights too early (like converting them to the accumulationDType).
@@ -55,14 +60,14 @@ func (f *Function) DotGeneral(
5560 // The CUDA backend does not seem to need this (likely they do something like that internally).
5661 isCPU := f .builder .backend .plugin .IsCPU ()
5762 lhsReady , rhsReady := lhsNode , rhsNode
58- if accumulationDType != dtype && isCPU {
63+ if accumulationDType != inputDType && isCPU {
5964 lhsReady , rhsReady , err = dotGeneralAddDependency (f , lhsReady , rhsReady )
6065 if err != nil {
6166 return nil , err
6267 }
6368 }
6469
65- if accumulationDType != dtype {
70+ if accumulationDType != inputDType {
6671 if accumulationDType != dtypes .F32 {
6772 // XLA only supports accumulation in F32 (if different than the input dtypes).
6873 // For other accumulation dtypes, we convert the inputs to the type.
@@ -76,7 +81,7 @@ func (f *Function) DotGeneral(
7681 return nil , errors .WithMessagef (err , "failed to convert rhs to accumulation dtype" )
7782 }
7883 lhsReady , rhsReady = lhsReadyValue .(* Node ), rhsReadyValue .(* Node )
79- dtype = accumulationDType
84+ inputDType = accumulationDType
8085 }
8186 }
8287
@@ -89,7 +94,7 @@ func (f *Function) DotGeneral(
8994 //
9095 // So we make a simplification here: we only set the "dot_algorithm" is the plugin is not CUDA.
9196 useTF32 := accumulationDType == dtypes .F32 && f .builder .backend .DotGeneralUseTF32
92- if useTF32 || accumulationDType != dtype {
97+ if useTF32 || accumulationDType != inputDType {
9398 isCUDA := f .builder .backend .plugin .IsCUDA ()
9499 if isCUDA {
95100 // Set "precision_config"
0 commit comments