@ -44,8 +44,15 @@ func devices() []*C.struct_ggml_backend_device {
}
type Backend struct {
// modelPath is the location of the model data
modelPath string
meta * fsggml . GGML
// tensorLoadTargets maps from the name of the tensor in the file
// to the name that is used by the model definition
tensorLoadTargets map [ string ] [ ] string
sched * C . struct_ggml_backend_sched
schedBackends [ ] * C . struct_ggml_backend
schedBufts [ ] * C . struct_ggml_backend_buffer_type
@ -64,8 +71,14 @@ type Backend struct {
maxGraphNodes int
}
func New ( ctx context . Context , r * os . File , params ml . BackendParams ) ( ml . Backend , error ) {
meta , n , err := fsggml . Decode ( r , - 1 )
func New ( modelPath string , params ml . BackendParams ) ( ml . Backend , error ) {
r , err := os . Open ( modelPath )
if err != nil {
return nil , err
}
defer r . Close ( )
meta , err := fsggml . Decode ( r , - 1 )
if err != nil {
return nil , err
}
@ -307,22 +320,77 @@ func New(ctx context.Context, r *os.File, params ml.BackendParams) (ml.Backend,
}
}
// map devices to backend buffer types so new tensors can be assigned to the correct device
deviceBufferTypes := make ( map [ * C . struct_ggml_backend_device ] * C . struct_ggml_backend_buffer_type )
// create backends and buffer types used for the compute graph scheduler
var schedBackends [ ] * C . struct_ggml_backend
var schedBufts [ ] * C . struct_ggml_backend_buffer_type
for _ , d := range append ( gpus , append ( accels , cpus ... ) ... ) {
b := C . ggml_backend_dev_init ( d , nil )
bt := C . ggml_backend_get_default_buffer_type ( b )
deviceBufferTypes [ d ] = bt
schedBackends = append ( schedBackends , b )
schedBufts = append ( schedBufts , bt )
if C . ggml_backend_is_cpu ( b ) {
// set number of threads for cpu backend
C . ggml_backend_cpu_set_n_threads ( b , C . int ( Threads ( params . NumThreads ) ) )
}
}
maxGraphNodes := max ( 8192 , len ( meta . Tensors ( ) . Items ( ) ) * 5 )
return & Backend {
modelPath : modelPath ,
flashAttention : params . FlashAttention ,
meta : meta ,
tensorLoadTargets : targets ,
tensors : tensors ,
sched : C . ggml_backend_sched_new (
( * C . ggml_backend_t ) ( unsafe . Pointer ( & schedBackends [ 0 ] ) ) ,
( * C . ggml_backend_buffer_type_t ) ( unsafe . Pointer ( & schedBufts [ 0 ] ) ) ,
C . int ( len ( schedBackends ) ) ,
C . size_t ( maxGraphNodes ) ,
C . _Bool ( len ( gpus ) > 1 && slices . Contains ( gpus , output . d ) ) ,
C . _Bool ( false ) ,
) ,
schedBackends : schedBackends ,
schedBufts : schedBufts ,
input : deviceBufferTypes [ input . d ] ,
layers : func ( ) map [ int ] * C . struct_ggml_backend_buffer_type {
m := make ( map [ int ] * C . struct_ggml_backend_buffer_type )
for i , layer := range layers {
m [ i ] = deviceBufferTypes [ layer . d ]
}
return m
} ( ) ,
maxGraphNodes : maxGraphNodes ,
} , nil
}
func init ( ) {
ml . RegisterBackend ( "ggml" , New )
}
func ( b * Backend ) Load ( ctx context . Context , progress func ( float32 ) ) error {
var doneBytes atomic . Uint64
totalBytes := uint64 ( n ) - meta . Tensors ( ) . Offset
totalBytes := uint64 ( b . meta . Length ) - b . meta . Tensors ( ) . Offset
g , ctx := errgroup . WithContext ( ctx )
g . SetLimit ( runtime . GOMAXPROCS ( 0 ) )
for _ , t := range meta . Tensors ( ) . Items ( ) {
for _ , t := range b . meta . Tensors ( ) . Items ( ) {
t := t
g . Go ( func ( ) error {
tts := make ( [ ] * C . struct_ggml_tensor , max ( 1 , len ( targets [ t . Name ] ) ) )
tts := make ( [ ] * C . struct_ggml_tensor , max ( 1 , len ( b . tensorLoadT argets [ t . Name ] ) ) )
for i := range tts {
target := targets [ t . Name ] [ i ]
target := b . tensorLoadT argets [ t . Name ] [ i ]
if target == "" {
target = t . Name
}
tt , ok := tensors [ target ]
tt , ok := b . tensors [ target ]
if ! ok {
return fmt . Errorf ( "unassigned tensor: %s" , t . Name )
}
@ -332,13 +400,13 @@ func New(ctx context.Context, r *os.File, params ml.BackendParams) (ml.Backend,
// Create a new FD for each goroutine so that each FD is read sequentially, rather than
// seeking around within an FD shared between all goroutines.
file , err := os . Open ( r . Name ( ) )
file , err := os . Open ( b . modelPath )
if err != nil {
slog . Warn ( "file open error" , "file" , r . Name ( ) , "error" , err )
slog . Warn ( "file open error" , "file" , b . modelPath , "error" , err )
return err
}
defer file . Close ( )
sr := io . NewSectionReader ( file , int64 ( meta . Tensors ( ) . Offset + t . Offset ) , int64 ( t . Size ( ) ) )
sr := io . NewSectionReader ( file , int64 ( b . meta . Tensors ( ) . Offset + t . Offset ) , int64 ( t . Size ( ) ) )
bts := make ( [ ] byte , 128 * format . KibiByte )
var s uint64
@ -350,7 +418,7 @@ func New(ctx context.Context, r *os.File, params ml.BackendParams) (ml.Backend,
n , err := io . ReadFull ( sr , bts [ : min ( len ( bts ) , int ( t . Size ( ) - s ) ) ] )
if err != nil {
slog . Warn ( "file read error" , "file" , r . Name ( ) , "error" , err )
slog . Warn ( "file read error" , "file" , b . modelPath , "error" , err )
return err
}
@ -360,9 +428,9 @@ func New(ctx context.Context, r *os.File, params ml.BackendParams) (ml.Backend,
s += uint64 ( n )
if params . P rogress != nil {
if progress != nil {
done := doneBytes . Add ( uint64 ( n ) )
params . P rogress( float32 ( done ) / float32 ( totalBytes ) )
p rogress( float32 ( done ) / float32 ( totalBytes ) )
}
}
@ -371,59 +439,10 @@ func New(ctx context.Context, r *os.File, params ml.BackendParams) (ml.Backend,
}
if err := g . Wait ( ) ; err != nil {
return nil , err
}
// map devices to backend buffer types so new tensors can be assigned to the correct device
deviceBufferTypes := make ( map [ * C . struct_ggml_backend_device ] * C . struct_ggml_backend_buffer_type )
// create backends and buffer types used for the compute graph scheduler
var schedBackends [ ] * C . struct_ggml_backend
var schedBufts [ ] * C . struct_ggml_backend_buffer_type
for _ , d := range append ( gpus , append ( accels , cpus ... ) ... ) {
b := C . ggml_backend_dev_init ( d , nil )
bt := C . ggml_backend_get_default_buffer_type ( b )
deviceBufferTypes [ d ] = bt
schedBackends = append ( schedBackends , b )
schedBufts = append ( schedBufts , bt )
if C . ggml_backend_is_cpu ( b ) {
// set number of threads for cpu backend
C . ggml_backend_cpu_set_n_threads ( b , C . int ( Threads ( params . NumThreads ) ) )
}
return err
}
maxGraphNodes := max ( 8192 , len ( meta . Tensors ( ) . Items ( ) ) * 5 )
return & Backend {
flashAttention : params . FlashAttention ,
meta : meta ,
tensors : tensors ,
sched : C . ggml_backend_sched_new (
( * C . ggml_backend_t ) ( unsafe . Pointer ( & schedBackends [ 0 ] ) ) ,
( * C . ggml_backend_buffer_type_t ) ( unsafe . Pointer ( & schedBufts [ 0 ] ) ) ,
C . int ( len ( schedBackends ) ) ,
C . size_t ( maxGraphNodes ) ,
C . _Bool ( len ( gpus ) > 1 && slices . Contains ( gpus , output . d ) ) ,
C . _Bool ( false ) ,
) ,
schedBackends : schedBackends ,
schedBufts : schedBufts ,
input : deviceBufferTypes [ input . d ] ,
layers : func ( ) map [ int ] * C . struct_ggml_backend_buffer_type {
m := make ( map [ int ] * C . struct_ggml_backend_buffer_type )
for i , layer := range layers {
m [ i ] = deviceBufferTypes [ layer . d ]
}
return m
} ( ) ,
maxGraphNodes : maxGraphNodes ,
} , nil
}
func init ( ) {
ml . RegisterBackend ( "ggml" , New )
return nil
}
func ( b * Backend ) Config ( ) fs . Config {