摘要:用MindSpore+Jina,基于Fashion-MNIST Dataset搭建的服装搜索系统。

引言

各位算法萌新们,是不是经常训练了模型却不知道如何部署和应用?或者只会调参但不会前端后端所以没法向老板们解释这个模型可以做啥?如果有一种非常简单的方式,让你在3分钟内就能建立一个以深度学习为支撑的搜索系统,并能在前端展示出来show给各位老板们看?想不想尝试呢?本文来自MindSpore社区技术治理委员会(TSC)的成员肖涵博士——Jina的创始人,用MindSpore+Jina,基于Fashion-MNIST Dataset搭建的服装搜索系统。

[本文目录]

  • 如何用Jina①步搞定?
  • Jina的hello-world是如何运行的?
  • 如何使用MindSpore+Jina来搭建搜索系统?
  • 创建一个MindSpore Executor
  • 修改MindSpore的Encoder和网络代码
  • 写一个单元测试
  • 准备Dockerfile
  • 最后一步:终于可以Build了!
  • 来看MindSpore的成品吧!
  • 总结

喜欢逛淘宝或者各大海淘网站的各位程序员(的女朋友们),你们在浏览服装的时候,是不是会经常看见模特们身上的衣服,全!都!想!要!但是,不知道从哪儿买,货号是什么?就算从各大穿搭博主那儿知道货号了,也懒得一一去搜索。现在,完全不需要这么麻烦,只要你花3分钟建立这个服装搜索系统,当你的女朋友再看到模特身上的衣服,就可以搜索出最相似的衣服,是不是很赞!

图1 Shop the look

在做之前,先了解一下我们今天需要使用的两个框架:MindSpore和Jina

  • MindSpore是2020年3月28日华为开源的深度学习框架,它能原生支持自家的昇腾芯片,极大的提升了运行性能!
  • Jina是一个由最先进的AI和深度学习驱动的云端神经搜索框架,可以在多个平台和架构上实现任何类型的大规模索引和查询。无论你搜索图片、视频片段还是音频片段,Jina都能处理。

这里使用的数据集是Fashion-MNIST dataset。它包含70,000张图片,其中60,000张为训练集,10,000张为测试集。每张图片都是28x28的灰度图像,一共10个类别。下面我们正式开始吧!

如何用Jina①步搞定?

首先你需要一台电脑,确认一下环境是否ok:

  • Mac OS or Linux
  • Python 3.7, 3.8
  • Docker

然后执行以下一行命令即可:

pip install jina && jina hello-world

或者直接用docker:

docker run -v "$(pwd)/j:/j" jinaai/jina hello-world --workdir /j && open j/hello-world.html  # replace "open" with "xdg-open" on Linux

现在开始运行程序,就可以看到运行结果了:

图3 Jina hello-world运行结果

是不是很神奇?那么Jina是如何实现的呢?可以先花1分钟时间了解Jina的十个基本组件,在本文中最重要的三个信息分别是:

  • YAML config:让用户可以自定义的描述对象的属性。
  • Executor:代表了Jina中的算法单元。譬如把图像编码成向量、对结果进行排序等算法等都可以用Executor来表述。我们可以用Crafter来把制作/分割和转化要搜索的内容,然后用 Encoder来将制作好的搜索对象表示为向量,再用Indexer 保存和检索搜索的向量和键值信息,最后用Ranker来对搜索出的结果排序。
  • Flow:表示一个高阶的任务, 譬如我们所说的索引(index)、搜索(search)、训练(train),都属于一个flow。

Jina的hello-world是如何运行的?

想知道hello-world运行的细节嘛?其实在很简单,在hello-world里,我们使用YAML文件来描述index和search的flow,可以导入YAML文件,并通过.plot() 命令来可视化:

from pkg_resources import resource_filename
from jina.flow import Flowf = Flow.load_config(resource_filename('jina', '/'.join(('resources', 'helloworld.flow.index.yml')))).plot()

图4 hello-world YAML文件流程图

YAML文件里的信息是如何表示成图的呢?下面可以看看直观的对比:

图5 YAML文件信息

其实,这个flow中包含了两步(在Jina中也可以叫两个Pod):第一步它将数据通过并行的方式喂给encoder,输出向量和meta信息分片存储在索引器中。查询flow也是以同样的方式运行,只不过在参数上有些小变化。

既然原理这么简单,如果我们自己训练的模型,是不是也可以替换呢?下面我们来手把手教大家如何只用4步,就可以用MindSpore+Jina来搭建服装搜索系统。

如何使用MindSpore+Jina来搭建搜索系统?

创建一个MindSpore Executor

MindSpore的ModelZoo里有很多深度学习模型,本文使用的是最经典的CV网络:LeNet。我们可以通过jina hub来创建一个新的MindSpore Executor,本文使用的Jina Hub版本是v0.7的,可以输入以下命令安装:

pip install "jina[hub]"

安装好后,如果你想创建一个新的executor,可以直接输入:

jina hub new

执行这个命令后会弹出一下指导命令,按照下面的要求输入即可,有些设置直接用默认的就行,直接按Enter键就可以啦。

比较重要的是这几个命令:

所有命令输入完成后,你会看到MindSporeLeNet这个文件夹已经创建成功了。然后下载MindSpore 的LeNet代码库和Fashion MNIST的训练数据,按照下面的方式把它们放到MindSporeLeNet模块下即可:

图7 MindSporeLeNet代码结构

修改MindSpore的Encoder和网络结构代码

  • 1.修改__init__.py

这是原始的__init__.py 代码,有一个基础类BaseEncoder ,我们要改变一下encode的方式,把它变成 BaseMindsporeEncoder。

from jina.executors.encoders import BaseEncoderclass MindsporeLeNet(BaseEncoder):""":class:`MindsporeLeNet` What does this executor do?."""def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)# your customized __init__ belowraise NotImplementedErrordef encode(self, data, *args, **kwargs):raise NotImplementedError

BaseMindsporeEncoder 是Jina中的抽象类,它在__init__构造函数中会导入MindSpore模型的checkpoint。此外,它还能通过self.model提供MindSpore模型的属性接口。下面这张表显示了MindSporeLeNet通过构造函数继承的类。

图8 MindSporeLeNet中继承的类

修改完以后如下所示:

from jina.executors.encoders.frameworks import BaseMindsporeEncoderclass MindsporeLeNet(BaseMindsporeEncoder):""":class:`MindsporeLeNet` Encoding image into vectors using mindspore."""def encode(self, data, *args, **kwargs):# do something with `self.model`raise NotImplementedErrordef get_cell(self):raise NotImplementedError
  • 2.执行 encode() 方法。

给定一堆batch size为B的图像数据(用的numpy 的ndarray来表示,shape为[B, H, W]),encode() 把图像数据转换成向量的embeddings(shape为[B, D])。通过self.model 导入MindSpore LeNet 模型后,我们可以通过self.model(Tensor(data)).asnumpy()来进行转换即可。

注意:self.model的输入shape很容易出错。原始的LeNet模型的输入是三通道的图片,shape是32x32,所以输入必须是[B, 3, 32, 32]。然而Fashion-MNIST是灰度图片,单通道,图像的shape是28x28,所以我们要么调整图片的尺寸,要么给图片补零。这里我们就用简单的补零操作了。最终的encode()函数如下所示:

def encode(self, data, *args, **kwargs):# LeNet only accepts BCHW format where H=W=32# hence we need to do some simple paddingdata = numpy.pad(data.reshape([-1, 1, 28, 28]),[(0, 0), (0, 0), (0, 4), (0, 4)]).astype('float32')return self.model(Tensor(data)).asnumpy()
  • 3.执行get_cell()方法。

在MindSpore中,我们通常把神经网络中的层叫做『cell』,它可以是一个单独的神经网络层(譬如conv2d, relu, batch_norm)。为了得到向量的embedding,我们只需要从LeNet中移除classification head 即可(譬如最后一个softmax层)。这个很好实现,只需要从原始的LeNet5类中继承,然后重写construct() 函数即可。

def get_cell(self):from .lenet.src.lenet import LeNet5class LeNet5Embed(LeNet5):def construct(self, x):x = self.conv1(x)x = self.relu(x)x = self.max_pool2d(x)x = self.conv2(x)x = self.relu(x)x = self.max_pool2d(x)x = self.flatten(x)x = self.fc1(x)x = self.relu(x)x = self.fc2(x)x = self.relu(x)return xreturn LeNet5Embed()

写一个单元测试

当你在创建一个Jina executor 的时候,一定不要忘了写单元测试,如果在executor里没有单元测试的话,是无法通过 Jina Hub API来创建的哦~

在这个样例中已经生成了一个测试模板,你可以在tests 文件夹里面找到test_mindsporelenet.py 文件。先检查下MindSpore是否运行,如果可以运行的话,看看输出的shape是否是我们所希望的。

import numpy as npfrom .. import MindsporeLeNetdef test_mindsporelenet():"""here is my test codehttps://docs.pytest.org/en/stable/getting-started.html#create-your-first-test"""mln = MindsporeLeNet(model_path='lenet/ckpt/checkpoint_lenet-1_1875.ckpt')tmp = np.random.random([4, 28 * 28])# The sixth layer is a fully connected layer (F6) with 84 units.# it is the last layer before the outputassert mln.encode(tmp).shape == (4, 84)

准备Dockerfile

python层面的准备工作已经完成了,下面我们准备Docker image。我们可以基于已有的Dockerfile来创建,只需要加一行运行train.py代码来生成checkpoint文件的代码即可。

FROM mindspore/mindspore-cpu:1.0.0# setup the workspace
COPY . /workspace
WORKDIR /workspace# install the third-party requirements
RUN pip install --user -r requirements.txt+ RUN cd lenet && \
+    python train.py --data_path data/fashion/ --ckpt_path ckpt --device_target="CPU" && \
+    cd -# for testing the image
RUN pip install --user pytest && pytest -sENTRYPOINT ["jina", "pod", "--uses", "config.yml"]

这一行使用了MindSpore LeNet代码库里的train.py来生成训练的checkpoint。我们在测试和部署的时候会用到这个checkpoint。在config.yml文件中,需要把checkpoint的文件地址放在model_path这个参数里。requests.on定义了MindSporeLeNet在index和search的request下应该如何执行。如果上面这些内容不理解也没关系,其实都是从helloworld.encoder.yml这个文件里复制和改动的。

!MindsporeLeNet
with:model_path: lenet/ckpt/checkpoint_lenet-1_1875.ckpt
metas:py_modules: - __init__.py# - You can put more dependencies here
requests:on:[IndexRequest, SearchRequest]:- !Blob2PngURI {}- !EncodeDriver {}- !ExcludeQLwith:fields:- buffer- chunks

最后一步:终于可以Build了!

终于可以把MindSporeLeNet build成Docker镜像了!!执行以下命令:

jina hub build MindsporeLeNet/ --pull --test-uses
  • --pull :当你的图片数据集不在本地时,这个命令会告诉 Hub builder 来下载数据集
  • --test-uses :增加一个额外的测试来检查创建的镜像是否可以通过 Jina Flow API试运行成功。

现在终端已经开始打印日志了,如果时间太久的话,可以在MindsporeLeNet/lenet/src/config.py 中将epoch_size调小。

最后成功的信息:

HubIO@51772[I]:Successfully built cfa38dcfc1f9
HubIO@51772[I]:Successfully tagged jinahub/pod.encoder.mindsporelenet:0.0.1
HubIO@51772[I]:building MindsporeLeNet/ takes 57 seconds (57.86s)
HubIO@51772[S]: built jinahub/pod.encoder.mindsporelenet:0.0.1 (sha256:cfa38dcfc1) uncompressed size: 1.1 GB

现在你可以通过下面的命令将它作为一个Pod来使用了:

jina pod --uses jinahub/pod.encoder.mindsporelenet:0.0.1

对比jina pod --uses abc.yml, 我们会发现jinahub/pod.encoder.mindsporelenet:0.0.1的日志信息的开头处有一个docker容器。这些log日志是从Docker的container传输到host端的,下面描述了两者具体的差异。

图9 差异对比

当然,你也可以上传这个镜像到Docker仓库里:

jina hub build MindsporeLeNet/ --pull --test-uses --repository YOUR_NAMESPACE --push

来看MindSpore的成品吧!

最后,直接在index和search的flow中来使用新创建的MindSpore Executor吧,很简单,只需要替换pods.encode.uses这行代码就行:

图10 index与query的YAML文件差异

jina hello-world 的参数可以自定义,只要指定我们刚刚编写好的index和query的YAML文件,输入以下命令即可:

jina hello-world --uses-index helloworld.flow.index.yml --uses-query helloworld.flow.query.yml

哈哈,完成了!几分钟之内你就可以看到开头动图显示的查询结果了!

图11 最终输出结果

总结

本文中使用了MindSpore+Jina来共同搭建一个服装搜索系统,代码非常简单,其实只要学会修改encode的代码,根据需要构建网络层,然后打包成docker的image,修改YAML文件就可以用Jina来实现最终的展示效果了,这样大家只要可以根据自己的需求,修改少量的代码,即可自行搭建一个基于MindSpore的搜索系统,是不是非常简单呢~感兴趣的同学可以直接点击以下链接,就可以直接运行:https://gitee.com/mindspore/community/tree/master/mindspore-jina

本文分享自华为云社区《3分钟教你用MindSpore和Jina搭建一个服装搜索系统!》,原文作者:chengxiaoli 。

点击关注,第一时间了解华为云新鲜技术~

所见即搜,3分钟教你搭建一个服装搜索系统!相关推荐

  1. 10分钟教你搭建一个可公网访问的私人网盘,和付费网盘彻底say goodbye~

    今天偶然间看一个私人网盘的搭建,给大家一起分享一下.我这边是在windows环境下运行的. 检查配置 首先我们需要检查一下配置,需要本地安装有JDK,没有的话自行下载安装.如下所示则表示已经安装. 运 ...

  2. 10分钟教你搭建一个好玩的Python全文搜索引擎

    有一个群友在群里问个如何快速搭建一个搜索引擎,在搜索之后我看到了这个 代码所在 Git:https://github.com/asciimoo/searx 官方很贴心,很方便的是已经提供了docker ...

  3. 十分钟教你搭建一个漂亮的博客(二--主题的修改)

    总体效果 框架的选择(butterfly) 前面我们搭建的博客,可以看见非常的单调,那如果我们想要让他变得漂亮,自然我们是不会自己去写代码的,我们通过网上比较成熟的框架,通过修改配置文件便可以得到漂亮 ...

  4. 教你搭建一个花卉识别系统(超级简单)

    目录 一.开源神经网络(AlexNet) 1.获取数据集 2.神经网络模型 3.训练神经网络 4.对模型进行预测 二.花卉识别系统搭建(flask) 1.构建页面: 2.调用神经网络模型 3.系统识别 ...

  5. 零基础教你搭建一个自己的靶场!

    零基础教你搭建一个自己的靶场! 目录 零基础教你搭建一个自己的靶场! 前言 部署 准备工作 安装环境 docker 的安装 docker-compose的安装 配置环境 安装 下载 配置 总结 前言 ...

  6. 手把手教你搭建一个属于自己的Ghost博客

    介绍 Ghost 是基于 Node.js 的开源博客平台,由前 WordPress UI 部门主管 John O'Nolan 和 WordPress 高级工程师(女) Hannah Wolfe 创立, ...

  7. 手把手教你搭建一个中式菜谱知识图谱可视化系统

    手把手教你搭建一个中式菜谱知识图谱可视化系统 中式菜谱知识图谱 1.系统功能 2.先来看看效果 实体间关联关系及实体信息显示 不同类型实体开关显示 搜索功能展示 3.系统实现流程 3.1 数据爬取 3 ...

  8. 教大家搭建一个手机app软件导航网

    今天教大家搭建一个手机app软件导航网 1.服务器基础环境 服务器宝塔界面安装Nginx 1.20.1 + php 5.6 +mysql 5.6.50 ​2.上传手机app软件导航网源码,源码上传后解 ...

  9. 十分钟教你打造一个微信语音点歌系统

    最近在做一个微信项目,接触到了微信公众平台.通过公众平台可以很方便的搭建一个功能完善的移动应用.昨天发现:开发者可使用手机号来申请接口测试帐号,体验高级接口. 这篇文章的应用将使用到高级接口中的语音识 ...

最新文章

  1. 重读TCP协议(3)
  2. 微信小应用,又一大神,音乐播放器
  3. task ':app:compileDebugJavaWithJavac'.错误
  4. 能熟练掌握和应用计算机基础知识,浙江省大学生计算机基础知识与应用能力等级考试二级(V......
  5. python 端口扫描
  6. 微软私有云分享(R2)22 计算机配置文件与基础设置
  7. 作者:窦志成,男,中国人民大学信息学院研究员、硕士生导师。
  8. python利用什么写模块_python模块是什么?写法及作用分析
  9. 手把手教你做iOS的soap应用(webservice)
  10. 合肥科学岛安光所计算机应用,国家大气污染防治攻关联合中心成立 合肥科学岛安光所承担重任...
  11. 深度学习之LSTM完全图解
  12. mysql中日期相减_一篇文章,搞定Excel表格中日期计算,内含公式详解!
  13. 电脑重装系统蓝屏是什么原因
  14. c fread 快读 详解_热量计算公式及例题详解
  15. 金蝶专业版服务器提示系统错误,金蝶专业版连接云服务器异常
  16. Latex中求和符号的使用
  17. Django: OperationalError no such table
  18. shell中设置IFS,使用自定义分割符
  19. 原生小程序 申请小程序 - 发布流程
  20. ZCU104开发板:开发板介绍1

热门文章

  1. CSS 参考资料/学习资料
  2. java 中的scanner_java 中的Scanner
  3. vgp虚拟路面_长安大学工程机械国家虚拟仿真实验教学中心|公路路面摊铺施工虚拟仿真实验|...
  4. c++ 初始化列表和构造函数初始化区别
  5. webstorm 设置js或者html文件自动缩进为4个空格不生效
  6. 「Luogu」[JSOI2007]字符加密 解题报告
  7. 04号团队-团队任务3:每日立会(2018-12-04)
  8. 在线预览(pptx、ppt、pps、docx、doc、xlsx、xls)
  9. spring事务源码解析
  10. win7升级到win10不能上网解决方法