跳到内容

扩展数组

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 扩展数组 (lance._arrow.PandasBFloat16Type)。这些与 ml_dtypes bfloat16 NumPy 扩展数组兼容。

如果您正在使用 Pandas,可以使用 lance.bfloat16 dtype 字符串创建数组

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 dtype。

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...']

EncodedImage

lance.arrow.EncodedImageArray 是一个以其编码和压缩表示形式存储 jpeg 和 png 图像的数组,就像它们写入磁盘时一样。当您想要以压缩格式操作图像时,例如从磁盘读取或将其嵌入 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...'