Ejemplo n.º 1
0
    def _read_array_header(file: BinaryIO) -> Tuple[int, int]:
        """
        Helper method to read the header of an NdArray chunk.

        The method reads the shape tuple, verifies the TypeId and seeks the file to the start
        of the array. The shape tuple is returned.

        Parameters
        ----------
        file : BinaryIO
            finalfusion file with a storage at the start of a NdArray chunk.

        Returns
        -------
        shape : Tuple[int, int]
            Shape of the storage.

        Raises
        ------
        FinalfusionFormatError
            If the TypeId does not match TypeId.f32
        """
        rows, cols = _read_required_binary(file, "<QI")
        type_id = TypeId(_read_required_binary(file, "<I")[0])
        if TypeId.f32 != type_id:
            raise FinalfusionFormatError(
                f"Invalid Type, expected {TypeId.f32}, got {type_id}")
        file.seek(_pad_float32(file.tell()), 1)
        return rows, cols
Ejemplo n.º 2
0
 def write_chunk(self, file: BinaryIO):
     _write_binary(file, "<I", int(self.chunk_identifier()))
     padding = _pad_float32(file.tell())
     chunk_len = struct.calcsize("QI") + padding + struct.calcsize(
         f"<{self.size}f")
     _write_binary(file, f"<QQI{padding}x", chunk_len, self.size,
                   int(TypeId.f32))
     _serialize_array_as_le(file, self)
Ejemplo n.º 3
0
 def write_chunk(self, file: BinaryIO):
     _write_binary(file, "<I", int(self.chunk_identifier()))
     padding = _pad_float32(file.tell())
     chunk_len = struct.calcsize("<QII") + padding + struct.calcsize(
         f'<{self.size}f')
     # pylint: disable=unpacking-non-sequence
     rows, cols = self.shape
     _write_binary(file, "<QQII", chunk_len, rows, cols, int(TypeId.f32))
     _write_binary(file, f"{padding}x")
     _serialize_array_as_le(file, self)
Ejemplo n.º 4
0
 def read_chunk(file: BinaryIO) -> 'Norms':
     n_norms, dtype = _read_required_binary(file, "<QI")
     type_id = TypeId(dtype)
     if TypeId.f32 != type_id:
         raise FinalfusionFormatError(
             f"Invalid Type, expected {TypeId.f32}, got {str(type_id)}")
     padding = _pad_float32(file.tell())
     file.seek(padding, 1)
     array = np.fromfile(file=file, count=n_norms, dtype=np.float32)
     if sys.byteorder == "big":
         array.byteswap(inplace=True)
     return Norms(array)
Ejemplo n.º 5
0
 def _read_quantized_header(
         file: BinaryIO
 ) -> Tuple[PQ, Tuple[int, int], Optional[np.ndarray]]:
     """
     Helper method to read the header of a quantized array chunk.
     Returns a tuple containing PQ, quantized_shape and optional norms.
     """
     projection = _read_required_binary(file, '<I')[0] != 0
     read_norms = _read_required_binary(file, '<I')[0] != 0
     quantized_len = _read_required_binary(file, '<I')[0]
     reconstructed_len = _read_required_binary(file, '<I')[0]
     n_centroids = _read_required_binary(file, '<I')[0]
     n_embeddings = _read_required_binary(file, '<Q')[0]
     assert reconstructed_len % quantized_len == 0
     type_id = _read_required_binary(file, '<I')[0]
     if int(TypeId.u8) != type_id:
         raise FinalfusionFormatError(
             f"Invalid Type, expected {str(TypeId.u8)}, got {type_id}")
     type_id = _read_required_binary(file, '<I')[0]
     if int(TypeId.f32) != type_id:
         raise FinalfusionFormatError(
             f"Invalid Type, expected {str(TypeId.f32)}, got {type_id}")
     file.seek(_pad_float32(file.tell()), 1)
     if projection:
         projection = _read_array_as_native(file, np.float32,
                                            reconstructed_len**2)
         projection_shape = (reconstructed_len, reconstructed_len)
         projection = projection.reshape(projection_shape)
     else:
         projection = None
     quantizer_shape = (quantized_len, n_centroids,
                        reconstructed_len // quantized_len)
     quantizers_size = quantized_len * n_centroids * (reconstructed_len //
                                                      quantized_len)
     quantizers = _read_array_as_native(file, np.float32, quantizers_size)
     quantizers = quantizers.reshape(quantizer_shape)
     if read_norms:
         norms = _read_array_as_native(file, np.float32, n_embeddings)
     else:
         norms = None
     quantizer = PQ(quantizers, projection)
     return quantizer, (n_embeddings, quantized_len), norms
Ejemplo n.º 6
0
 def write_chunk(self, file: BinaryIO):
     _write_binary(file, "<I", int(self.chunk_identifier()))
     padding = _pad_float32(file.tell())
     chunk_len = struct.calcsize("<IIIIIQII") + padding
     proj = self._quantizer.projection is not None
     if proj:
         chunk_len += struct.calcsize(
             f"<{pow(self._quantizer.reconstructed_len, 2)}f")
     chunk_len += struct.calcsize(f"<{self._quantizer.subquantizers.size}f")
     norms = self._norms is not None
     if self._norms is not None:
         chunk_len += struct.calcsize(f"<{self._norms.size}f")
     chunk_len += self._quantized_embeddings.size
     chunk_header = (chunk_len, proj, norms, self.quantized_len,
                     self.shape[1], self.quantizer.n_centroids,
                     self.shape[0], int(TypeId.u8), int(TypeId.f32))
     _write_binary(file, "<QIIIIIQII", *chunk_header)
     file.write(struct.pack(f"{padding}x"))
     if proj:
         _serialize_array_as_le(file, self.quantizer.projection)
     _serialize_array_as_le(file, self.quantizer.subquantizers)
     if norms:
         _serialize_array_as_le(file, self._norms)
     self._quantized_embeddings.tofile(file)