扩展数组

Lance为Arrow数组和Pandas Series提供了扩展,用于表示机器学习应用中的数据类型。

BFloat16

BFloat16是一种16位浮点数,专为机器学习应用场景设计。直观来看,它仅具有2-3位数字的精度,但其数值范围与32位浮点数相同:约1e-38到1e38。相比之下,16位浮点数的数值范围约为5.96e-8到65504。

Lance提供了针对BFloat16的Arrow扩展数组(lance.arrow.BFloat16Array) 和Pandas扩展数组(PandasBFloat16Type)。 这些与ml_dtypes的bfloat16 NumPy扩展数组兼容。

如果您正在使用Pandas,可以使用lance.bfloat16数据类型字符串来创建数组:

>>> import lance.arrow

>>> pd.Series([1.1, 2.1, 3.4], dtype="lance.bfloat16")
0    1.1015625
1      2.09375
2      3.40625
dtype: lance.bfloat16

要创建一个Arrow数组,请使用lance.arrow.bfloat16_array()函数:

>>> from lance.arrow import bfloat16_array

>>> bfloat16_array([1.1, 2.1, 3.4])
<lance.arrow.BFloat16Array object at 0x000000016feb94e0>
[
  1.1015625,
  2.09375,
  3.40625
]

最后,如果您已有现成的NumPy数组,您可以将其转换为以下任一形式:

>>> import numpy as np
>>> from ml_dtypes import bfloat16
>>> from lance.arrow import PandasBFloat16Array, BFloat16Array

>>> np_array = np.array([1.1, 2.1, 3.4], dtype=bfloat16)
>>> PandasBFloat16Array.from_numpy(np_array)
<PandasBFloat16Array>
[1.1015625, 2.09375, 3.40625]
Length: 3, dtype: lance.bfloat16
>>> BFloat16Array.from_numpy(np_array)
<lance.arrow.BFloat16Array object at 0x...>
[
  1.1015625,
  2.09375,
  3.40625
]

读取时,可以使用每个数组类的to_numpy方法将其转换回NumPy的bfloat16数据类型。

ImageURI

lance.arrow.ImageURIArray 是一个用于存储图像URI位置的数组,这些图像位于其他存储系统中。例如,本地文件系统中的 file:///path/to/image.png 或 AWS S3 上的 s3://bucket/path/image.jpeg。当您希望从现有存储介质中延迟加载图像时,可以使用此数组类型。

可以通过调用lance.arrow.ImageURIArray.from_uris() 来创建,传入由pyarrow.StringArray表示的URI列表或 可迭代生成字符串的对象。请注意,URI不会进行严格验证,且 图像不会自动读入内存。

>>> from lance.arrow import ImageURIArray

>>> ImageURIArray.from_uris([
...    "/tmp/image1.jpg",
...    "file:///tmp/image2.jpg",
...    "s3://example/image3.jpg"
... ])
<lance.arrow.ImageURIArray object at 0x...>
['/tmp/image1.jpg', 'file:///tmp/image2.jpg', 's3://example/image3.jpg']

lance.arrow.ImageURIArray.read_uris() 会将图像读取到内存中,并返回一个新的 lance.arrow.EncodedImageArray 对象。

from lance.arrow import ImageURIArray

relative_path = "images/1.png"
uris = [os.path.join(os.path.dirname(__file__), relative_path)]
ImageURIArray.from_uris(uris).read_uris()
<lance.arrow.EncodedImageArray object at 0x...>
[b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00...']

编码图像

lance.arrow.EncodedImageArray is an array that stores jpeg and png images in their encoded and compressed representation as they would appear written on disk. Use this array when you want to manipulate images in their compressed format such as when you’re reading them from disk or embedding them into HTML.

可以通过在现有的lance.arrow.ImageURIArray上调用lance.arrow.ImageURIArray.read_uris()来创建。这将把引用的图像读入内存。 也可以通过调用lance.arrow.ImageArray.from_array()并传入已读入pyarrow.BinaryArray的编码图像数组来创建,或者通过调用lance.arrow.ImageTensorArray.to_encoded()来创建。

提供了一个lance.arrow.EncodedImageArray.to_tensor()方法用于解码编码图像,并将其返回为lance.arrow.FixedShapeImageTensorArray,从中可以转换为numpy数组或TensorFlow张量。 对于图像解码,它将首先尝试使用通过可选函数参数提供的解码器。如果未提供解码器,它将依次尝试使用Pillowtensorflow。如果既没有可用库也没有自定义解码器,则会引发异常。

from lance.arrow import ImageURIArray

uris = [os.path.join(os.path.dirname(__file__), "images/1.png")]
encoded_images = ImageURIArray.from_uris(uris).read_uris()
print(encoded_images.to_tensor())

def tensorflow_decoder(images):
    import tensorflow as tf
    import numpy as np

    return np.stack(tf.io.decode_png(img.as_py(), channels=3) for img in images.storage)

print(encoded_images.to_tensor(tensorflow_decoder))
<lance.arrow.FixedShapeImageTensorArray object at 0x...>
[[42, 42, 42, 255]]
<lance.arrow.FixedShapeImageTensorArray object at 0x...>
[[42, 42, 42, 255]]

FixedShapeImageTensor

lance.arrow.FixedShapeImageTensorArray 是一个将图像存储为张量的数组,其中每个像素点都用数值表示。通常图像以三维张量的形式存储,形状为(高度,宽度,通道数)。在彩色图像中,根据RGB色彩模型,每个像素由三个值(通道)表示。 该数组中的图像可以单独读取为numpy数组,也可以堆叠成一个四维numpy数组,形状为(批次大小,高度,宽度,通道数)。

可以通过对已有的lance.arrow.EncodedImageArray调用lance.arrow.EncodedImageArray.to_tensor()来创建。这将解码编码图像并返回为lance.arrow.FixedShapeImageTensorArray。也可以通过调用lance.arrow.ImageArray.from_array()并传入一个pyarrow.FixedShapeTensorArray来创建。

可以通过调用lance.arrow.FixedShapeImageTensorArray.to_encoded()并传入自定义编码器,将其编码为lance.arrow.EncodedImageArray。如果未提供编码器,系统将依次尝试使用tensorflowPillow。默认编码器会将其编码为PNG格式。如果这两个库都不可用,则会抛出异常。

>>> from lance.arrow import ImageURIArray

>>> uris = [image_uri]
>>> tensor_images = ImageURIArray.from_uris(uris).read_uris().to_tensor()
>>> tensor_images.to_encoded()
<lance.arrow.EncodedImageArray object at 0x...>
[...
b'\x89PNG\r\n\x1a...'