Skip to content

Commit d3b06e3

Browse files
committed
Merge branch 'gguf-no-tempfile'
2 parents ab4e4ea + a535a08 commit d3b06e3

File tree

4 files changed

+55
-51
lines changed

4 files changed

+55
-51
lines changed

convert-llama-ggml-to-gguf.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,7 @@ def __init__(self, ggml_model, data, cfg, params_override = None, vocab_override
235235

236236
def save(self):
237237
print('* Preparing to save GGUF file')
238-
gguf_writer = gguf.GGUFWriter(
239-
self.cfg.output,
240-
gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA],
241-
use_temp_file = False )
238+
gguf_writer = gguf.GGUFWriter(self.cfg.output, gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA])
242239
self.add_params(gguf_writer)
243240
self.add_vocab(gguf_writer)
244241
if self.special_vocab is not None:

examples/finetune/convert-finetune-checkpoint-to-gguf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ def main():
475475
# we should have read all available data
476476
assert(offset == len(data))
477477

478-
gguf_writer = gguf.GGUFWriter(cfg.output, gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA], use_temp_file = False)
478+
gguf_writer = gguf.GGUFWriter(cfg.output, gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA])
479479
chk.save_gguf(gguf_writer)
480480
print(" gguf: write header")
481481
gguf_writer.write_header_to_file()

examples/train-text-from-scratch/convert-train-checkpoint-to-gguf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ def main():
485485
# we should have read all available data
486486
assert(offset == len(data))
487487

488-
gguf_writer = gguf.GGUFWriter(cfg.output, gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA], use_temp_file = False)
488+
gguf_writer = gguf.GGUFWriter(cfg.output, gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA])
489489
chk.save_gguf(gguf_writer)
490490
print(" gguf: write header")
491491
gguf_writer.write_header_to_file()

gguf-py/gguf/gguf.py

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -636,18 +636,16 @@ def get_type(val):
636636
sys.exit()
637637

638638

639+
class WriterState:
640+
EMPTY = auto()
641+
HEADER = auto()
642+
KV_DATA = auto()
643+
TI_DATA = auto()
644+
645+
639646
class GGUFWriter:
640647
fout: BufferedWriter
641-
arch: str
642-
offset_tensor = 0
643-
data_alignment = GGUF_DEFAULT_ALIGNMENT
644-
kv_data = b""
645-
kv_data_count = 0
646-
ti_data = b""
647-
ti_data_count = 0
648-
use_temp_file: bool
649-
temp_file: tempfile.SpooledTemporaryFile[bytes] | None = None
650-
tensors: list[tuple[np.ndarray[Any, Any], int]]
648+
tensors: list[np.ndarray[Any, Any]]
651649

652650
@property
653651
def pack_prefix(self):
@@ -656,9 +654,15 @@ def pack_prefix(self):
656654
else:
657655
return ">"
658656

659-
def __init__(self, path: os.PathLike[str] | str, arch: str, use_temp_file = True, endianess=GGUFEndian.LITTLE):
657+
def __init__(self, path: os.PathLike[str] | str, arch: str, endianess=GGUFEndian.LITTLE):
660658
self.fout = open(path, "wb")
661659
self.arch = arch
660+
self.offset_tensor = 0
661+
self.data_alignment = GGUF_DEFAULT_ALIGNMENT
662+
self.kv_data = b""
663+
self.kv_data_count = 0
664+
self.ti_data = b""
665+
self.ti_data_count = 0
662666
self.endianess = endianess
663667
self._simple_value_packing = {
664668
GGUFValueType.UINT8: f"{self.pack_prefix}B",
@@ -673,27 +677,41 @@ def __init__(self, path: os.PathLike[str] | str, arch: str, use_temp_file = True
673677
GGUFValueType.FLOAT64: f"{self.pack_prefix}d",
674678
GGUFValueType.BOOL: "?" ,
675679
}
676-
self.add_architecture()
677-
self.use_temp_file = use_temp_file
678680
self.tensors = []
681+
self.state = WriterState.EMPTY
682+
683+
self.add_architecture()
684+
679685
endianess_str = "Big Endian" if self.endianess == GGUFEndian.BIG else "Little Endian"
680686
print(f"This gguf file is for {endianess_str} only")
681687

682688
def write_header_to_file(self):
689+
if self.state is not WriterState.EMPTY:
690+
raise ValueError(f'Expected output file to be empty, got {self.state}')
691+
683692
self.fout.write(struct.pack("<I", GGUF_MAGIC))
684693
self.fout.write(struct.pack(f"{self.pack_prefix}I", GGUF_VERSION))
685694
self.fout.write(struct.pack(f"{self.pack_prefix}Q", self.ti_data_count))
686695
self.fout.write(struct.pack(f"{self.pack_prefix}Q", self.kv_data_count))
687696
self.flush()
688-
# print("tensors " + str(self.ti_data_count) + " kv " + str(self.kv_data_count))
697+
#print("tensors " + str(self.ti_data_count) + " kv " + str(self.kv_data_count))
698+
self.state = WriterState.HEADER
689699

690700
def write_kv_data_to_file(self):
701+
if self.state is not WriterState.HEADER:
702+
raise ValueError(f'Expected output file to contain the header, got {self.state}')
703+
691704
self.fout.write(self.kv_data)
692705
self.flush()
706+
self.state = WriterState.KV_DATA
693707

694708
def write_ti_data_to_file(self):
709+
if self.state is not WriterState.KV_DATA:
710+
raise ValueError(f'Expected output file to contain KV data, got {self.state}')
711+
695712
self.fout.write(self.ti_data)
696713
self.flush()
714+
self.state = WriterState.TI_DATA
697715

698716
def add_key(self, key: str):
699717
self.add_val(key, GGUFValueType.STRING, add_vtype=False)
@@ -807,33 +825,24 @@ def add_tensor_info(self, name: str, tensor_shape: Sequence[int], tensor_dtype:
807825
def add_tensor(self, name: str, tensor: np.ndarray[Any, Any], raw_shape: Sequence[int] | None = None, raw_dtype: GGMLQuantizationType | None = None):
808826
if self.endianess == GGUFEndian.BIG:
809827
tensor.byteswap(inplace=True)
810-
if self.use_temp_file and self.temp_file is None:
811-
fp = tempfile.SpooledTemporaryFile(mode="w+b", max_size=256*1024*1024)
812-
fp.seek(0)
813-
self.temp_file = fp
814828

815829
shape: Sequence[int] = raw_shape if raw_shape is not None else tensor.shape
816830
self.add_tensor_info(name, shape, tensor.dtype, tensor.nbytes, raw_dtype = raw_dtype)
817831

818-
pad = GGUFWriter.ggml_pad(tensor.nbytes, self.data_alignment) - tensor.nbytes
819-
820-
if self.temp_file is None:
821-
self.tensors.append((tensor, pad))
822-
return
823-
824-
tensor.tofile(self.temp_file)
825-
826-
if pad != 0:
827-
self.temp_file.write(bytes([0] * pad))
832+
self.tensors.append(tensor)
828833

829834
def write_padding(self, fp: BinaryIO, n: int, align: int | None = None):
830835
pad = GGUFWriter.ggml_pad(n, align if align is not None else self.data_alignment) - n
831836
if pad != 0:
832837
fp.write(bytes([0] * pad))
833838

834839
def write_tensor_data(self, tensor: np.ndarray[Any, Any]):
840+
if self.state is not WriterState.TI_DATA:
841+
raise ValueError(f'Expected output file to contain tensor info, got {self.state}')
842+
835843
if self.endianess==GGUFEndian.BIG:
836844
tensor.byteswap(inplace=True)
845+
837846
self.write_padding(self.fout, self.fout.tell())
838847
tensor.tofile(self.fout)
839848
self.write_padding(self.fout, tensor.nbytes)
@@ -843,18 +852,13 @@ def write_tensors_to_file(self):
843852

844853
self.write_padding(self.fout, self.fout.tell())
845854

846-
if self.temp_file is None:
847-
for (currtensor, currpad) in self.tensors:
848-
currtensor.tofile(self.fout)
849-
if currpad != 0:
850-
self.fout.write(bytes([0] * currpad))
851-
return
852-
853-
self.temp_file.seek(0)
854-
855-
shutil.copyfileobj(self.temp_file, self.fout)
856-
self.flush()
857-
self.temp_file.close()
855+
while True:
856+
try:
857+
tensor = self.tensors.pop(0)
858+
except IndexError:
859+
break
860+
tensor.tofile(self.fout)
861+
self.write_padding(self.fout, tensor.nbytes)
858862

859863
def flush(self):
860864
self.fout.flush()
@@ -983,11 +987,11 @@ def add_pad_token_id(self, id: int):
983987

984988

985989
class SpecialVocab:
986-
load_merges: bool = False
987-
merges: list[str] = []
988-
special_token_types: tuple[str, ...] = ('bos', 'eos', 'unk', 'sep', 'pad')
989-
special_token_ids: dict[str, int] = {}
990-
n_vocab: int | None = None
990+
load_merges: bool
991+
merges: list[str]
992+
special_token_types: tuple[str, ...]
993+
special_token_ids: dict[str, int]
994+
n_vocab: int | None
991995

992996
def __init__(
993997
self, path: str | os.PathLike[str], load_merges: bool = False,
@@ -997,8 +1001,11 @@ def __init__(
9971001
self.special_token_ids = {}
9981002
self.n_vocab = n_vocab
9991003
self.load_merges = load_merges
1004+
self.merges = []
10001005
if special_token_types is not None:
10011006
self.special_token_types = special_token_types
1007+
else:
1008+
self.special_token_types = ('bos', 'eos', 'unk', 'sep', 'pad')
10021009
self._load(Path(path))
10031010

10041011
def _load(self, path: Path) -> None:

0 commit comments

Comments
 (0)