开工第一课 | 用 DocArray 搭建 fashion search 引擎

本文介绍如何使用 DocArray,一个由 Jina AI 推出的数据结构库,来搭建一个简单的服装搜索系统。通过这个教程,你可以学习到如何处理非结构化数据,进行图片上传、预处理、嵌入、搜索匹配,并使用 Jina 的 Finetuner 工具进行模型调优。

文章导读

DocArray 是由 Jina AI 近期发布的、适用于嵌套及非结构化数据传输的库,本文将演示如何利用 DocArray,搭建一个简单的服装搜索引擎。

开工第一天,各位同学大家好哇!

e8995e621600847505bf3fbd5bbccb07.png

节前我们发起了一个抽奖活动,送出了 5 份 Jina AI 周边大礼包,今天上午 10:00 已开奖,中奖的幸运粉丝记得及时填写个人信息领奖哦~

2ba77f6e9e9fa175f4ef04c7e5420571.png

此外,我们也为大家精心准备了一学就会的 Demo 以及开箱即用的工具,新的一年,让我们借助这个无敌 buff,解决非结构化数据传输这个让人头疼的障碍吧~

DocArray:深度学习工程师必备 library

 DocArray: The data structure for unstructured data. 

DocArray 是一种可扩展数据结构,完美适配深度学习任务,主要用于嵌套及非结构化数据的传输,支持的数据类型包括文本、图像、音频、视频、3D mesh 等。

与其他数据结构相比:

e8c9ce00feaecc0955c1c8dff2764aa8.png

✅ 表示完全支持,✔ 表示部分支持,❌ 表示不支持

利用 DocArray,深度学习工程师可以借助 Pythonic API,有效地处理、嵌入、搜索、推荐、存储和传输数据。

在后续教程示例中,你将了解:

* 借助 DocArray,搭建一个简单的服装搜索系统;

* 上传服装图片,并在数据集中找到相似匹配

注:本教程所有代码都可以在 GitHub 下载,下载地址见:

https://github.com/alexcg1/neural-search-notebooks

手把手教你搭建一个服装搜索系统

 准备工作:观看 DocArray 视频 

5min 买不了吃亏买不了上当,反而会扫除知识障碍,为后续步骤做好准备。

野生字幕君在线翻译中,预计本周发布中文字幕视频

如果你有志加入 Jina AI 字幕组,欢迎后台留言

来了,就是一家人

from IPython.display import YouTubeVideo
YouTubeVideo("Amo19S1SrhE", width=800, height=450)

 配置:设置基本变量,并依项目调整 

DATA_DIR = "./data"
DATA_PATH = f"{DATA_DIR}/*.jpg"
MAX_DOCS = 1000
QUERY_IMAGE = "./query.jpg" # image we'll use to search with
PLOT_EMBEDDINGS = False # Really useful but have to manually stop it to progress to next cell


# Toy data - If data dir doesn't exist, we'll get data of ~800 fashion images from here
TOY_DATA_URL = "https://github.com/alexcg1/neural-search-notebooks/raw/main/fashion-search/data.zip?raw=true"

 设置 

# We use "[full]" because we want to deal with more complex data like images (as opposed to text)
!pip install "docarray[full]==0.4.4"
from docarray import Document, DocumentArray

 加载图片 

# Download images if they don't exist
import os


if not os.path.isdir(DATA_DIR) and not os.path.islink(DATA_DIR):
    print(f"Can't find {DATA_DIR}. Downloading toy dataset")
    !wget "$TOY_DATA_URL" -O data.zip
    !unzip -q data.zip # Don't print out every darn filename
    !rm -f data.zip
else:
    print(f"Nothing to download. Using {DATA_DIR} for data")
# Use `.from_files` to quickly load them into a `DocumentArray`
docs = DocumentArray.from_files(DATA_PATH, size=MAX_DOCS)
print(f"{len(docs)} Documents in DocumentArray")
docs.plot_image_sprites() # Preview the images

 图片预处理 

from docarray import Document


# Convert to tensor, normalize so they're all similar enough
def preproc(d: Document):
    return (d.load_uri_to_image_tensor()  # load
             .set_image_tensor_shape((80, 60))  # ensure all images right size (dataset image size _should_ be (80, 60))
             .set_image_tensor_normalization()  # normalize color 
             .set_image_tensor_channel_axis(-1, 0))  # switch color axis for the PyTorch model later
# apply en masse
docs.apply(preproc)

 图片嵌入 

!pip install torchvision==0.11.2
# Use GPU if available
import torch
if torch.cuda.is_available():
    device = "cuda"
else:
    device = "cpu"
import torchvision
model = torchvision.models.resnet50(pretrained=True)  # load ResNet50
docs.embed(model, device=device)

 可视化嵌入向量 

if PLOT_EMBEDDINGS:
    docs.plot_embeddings(image_sprites=True, image_source="uri")

 创建 query Document 

此处使用的是数据集中的第一张图片

# Download query doc
!wget https://github.com/alexcg1/neural-search-notebooks/raw/main/fashion-search/1_build_basic_search/query.jpg -O query.jpg


query_doc = Document(uri=QUERY_IMAGE)
query_doc.display()
# Throw the one Document into a DocumentArray, since that's what we're matching against
query_docs = DocumentArray([query_doc])
# Apply same preprocessing
query_docs.apply(preproc)
# ...and create embedding just like we did with the dataset
query_docs.embed(model, device=device) # If running on non-gpu machine, change "cuda" to "cpu"

 匹配 

query_docs.match(docs, limit=9)

 查看结果 

模型会依据输入图片进行匹配,此处的匹配甚至会涉及到对模特的匹配。

我们只希望模型针对服装进行匹配,因此这里使用 Jina AI 的结果调优工具 Finetuner 进行调优。

详见:

https://finetuner.jina.ai/

(DocumentArray(query_doc.matches, copy=True)
    .apply(lambda d: d.set_image_tensor_channel_axis(0, -1)
                      .set_image_tensor_inv_normalization())).plot_image_sprites()
if PLOT_EMBEDDINGS:
    query_doc.matches.plot_embeddings(image_sprites=True, image_source="uri")

 进阶教程预告 

1、微调模型

后续 notebook 中,我们将展示如何借助 Jina Finetuner 提高模型的性能。

详见:https://finetuner.jina.ai/

2、创建应用

后续教程中,我们将演示如何利用 Jina 的神经搜索框架和 Jina Hub Executors,打造和扩展搜索引擎。

41fd69de7a930efcc4e7eb9791921f55.gif

查看高清动图,请访问:https://reurl.cc/RjLy5z

本文相关链接:

Jina Hub:https://hub.jina.ai/

Jina GitHub:https://github.com/jina-ai/jina/

Finetuner:https://finetuner.jina.ai/

加入 Slack:https://slack.jina.ai/

在 Colab 中查看以上全部代码:

https://reurl.cc/RjLy5z

460b4e46fc49a0a3a4ecb0205690c632.png

下一代开源神经搜索引擎

在 GitHub 找到我们

更多精彩内容(点击图片阅读)

145faeef4f619b97f99ee2d6ae2575c0.png

95f83c1540b86b995fca0e715ef81084.png

<think>我们正在处理关于Fashion-MNIST数据集访问方式的问题。用户的问题是:为什么需要使用`[0][0]`来查看第一张图像而不是直接使用`[0]`?根据引用[4]中提供的代码片段,我们可以看到:```pythonX,y=next(iter(data.DataLoader(mnist_train,batch_size=18)))show_images(X.reshape(18,28,28),2,9,titles=get_fashion_mnist_labels(y))```这里,`X`是从DataLoader中取出的一个批量的图像数据。DataLoader返回的每个批量通常是一个元组,包含图像数据和对应的标签。在这个例子中,`X`是图像数据,`y`是标签。但是,用户提到的`[0][0]`的访问方式并没有直接出现在引用中。不过,我们可以根据PyTorchDataLoader的一般使用方式来推断。在PyTorch中,DataLoader返回的数据结构取决于数据集如何定义。对于Fashion-MNIST,通常使用`torchvision.datasets.FashionMNIST`,它返回的是图像和标签组成的元组。当使用DataLoader加载时,每个迭代返回的是一个批量的数据,这个批量数据是一个包含两个元素的元组:-第一个元素是图像张量,形状为`(batch_size,1,28,28)`(如果使用通道在前)或`(batch_size,28,28,1)`(通道在后),但通常默认是`(batch_size,1,28,28)`。-第二个元素是标签张量,形状为`(batch_size,)`。因此,当我们从DataLoader中取出一个批量时,比如:```pythonbatch=next(iter(data_loader))```那么:-`batch[0]`是整个批量的图像,形状为`(batch_size,1,28,28)`-`batch[1]`是整个批量的标签,形状为`(batch_size,)`所以,要访问这个批量中的第一张图像,我们需要使用`batch[0][0]`:-`batch[0]`是图像张量,包含`batch_size`张图像。-`batch[0][0]`是图像张量中的第一张图像,形状为`(1,28,28)`(或者如果使用了`ToTensor`变换,则通道数在前)。而直接使用`batch[0]`得到的是整个批量的图像,是一个四维张量(如果batch_size>1),而不是单张图像。因此,用户提到的使用`[0][0]`是为了从批量数据中取出第一张图像。如果直接使用`[0]`,得到的是整个批量的图像数据(包括多张图像),而不是第一张图像。总结:-因为DataLoader返回的是一个元组(images,labels),所以第一个索引`[0]`选择的是图像部分(整个批量)。-第二个索引`[0]`选择的是这个批量中的第一张图像。所以,要获取第一张图像,需要两个索引:`[0][0]`。注意:如果用户使用的是单个样本(不使用批量,即batch_size=1),那么`batch[0]`的形状是`(1,1,28,28)`,此时`batch[0][0]`的形状是`(1,28,28)`,而`batch[0]`的形状是`(1,1,28,28)`。即使batch_size=1,我们通常也使用`[0][0]`来去除最外层的批量维度,得到单张图像。在引用[4]的代码中,他们使用`X.reshape(18,28,28)`,这里`X`是`batch[0]`,即18张图像(批量大小为18),形状为`(18,1,28,28)`,然后通过reshape去除了通道维度,变成了`(18,28,28)`。这是因为在显示图像时,灰度图通常不需要单独的通道维度(matplotlib期望的灰度图形状是`(H,W)`或`(H,W,1)`?实际上,对于`imshow`,如果是灰度图,可以用`(H,W)`,也可以用`(H,W,1)`)。他们这里直接reshape成`(18,28,28)`,然后`show_images`函数中遍历每个图像时,每个图像的形状就是`(28,28)`。因此,如果用户想查看单张图像,比如第一张,那么从批量中取出第一张图像后,还需要调整形状(去除通道维度)才能显示。例如:```pythonfirst_image=X[0][0]#形状为(1,28,28)#或者用squeeze去除通道维度first_image_squeezed=first_image.squeeze()#形状为(28,28)```或者也可以:```pythonfirst_image=X[0][0].numpy().reshape(28,28)```所以,关键在于理解DataLoader返回的数据结构。现在,我们来回答用户的问题,并生成相关问题。</think>### Fashion-MNIST数据集访问图像的方式解析 在Fashion-MNIST数据集中,使用`[0][0]`而非直接`[0]`访问第一张图像的根本原因在于**数据集的多层数据结构**。具体分析如下: #### 数据结构层次 1. **顶层结构**:数据集被组织为元组 `(data, target)` - `data`:包含所有图像的张量(形状为 `[样本数, 通道, 高, 宽]`) - `target`:包含所有标签的张量(形状为 `[样本数]`) ```python # 示例结构 dataset = (image_tensor, label_tensor) # 整体结构 ``` 2. **次级结构**:当使用DataLoader批量加载时: - 每个批次返回元组 `(batch_images, batch_labels)` - `batch_images` 形状为 `[batch_size, 1, 28, 28]`(灰度图) - `batch_labels` 形状为 `[batch_size]` #### 访问逻辑 - `[0]`:获取第一个元素(图像张量或标签张量) ```python batch = next(iter(dataloader)) # 返回 (images, labels) images = batch[0] # 整个批次的图像张量,形状 [batch_size, 1, 28, 28] ``` - `[0][0]`:先取图像张量,再取其中第一张图 ```python first_image = batch[0][0] # 形状 [1, 28, 28] ``` #### 直观对比 | 访问方式 | 返回内容 | 张量形状 | 是否可直接显示 | |---------|---------|---------|---------------| | `batch[0]` | 整个批次的图像 | `[batch_size, 1, 28, 28]` | 否(多图复合结构) | | `batch[0][0]` | 批次中第一张图 | `[1, 28, 28]` | 是(需`reshape(28,28)`) | 如引用[4]所示,可视化时需要先提取单张图像再调整形状: ```python X, y = next(iter(data.DataLoader(mnist_train, batch_size=18))) first_image = X[0][0].reshape(28, 28) # 关键步骤[^4] ``` #### 设计原因 1. **批量处理需求**:深度学习需批量训练,数据结构优先支持批量操作 2. **通道维度保留**:统一处理RGB/灰度图,即使单通道也保留维度 3. **与PyTorch/TensorFlow兼容**:符合主流框架的`(data, label)`元组规范 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值