• Deep Java Library(四)使用DJL Serving部署JAVA模型 For Windows


    1.下载Windows版DJL Serving

    Windows版DJL Serving下载地址:
    https://publish.djl.ai/djl-serving/serving-0.23.0.zip
    下载下来是一个zip压缩包,大约50M左右,目前最新版本为0.23.0

    2.安装DJL Serving

    解压serving-0.23.0.zip后目录如下
    在这里插入图片描述
    (1)bin目录是DJL Serving的主目录,里面serving.bat是启动脚本
    (2)conf目录是DJL Serving的配置目录,里面我们主要看一下config.properties
    这是初始化的config.properties配置

    # debug=false
    # inference_address=http://127.0.0.1:8080
    # management_address=http://127.0.0.1:8080
    # management_address=unix:/tmp/management.sock
    model_store=models
    load_models=ALL
    # model_url_pattern=.*
    # number_of_netty_threads=0
    # job_queue_size=1000
    # cors_allowed_origin=*
    # cors_allowed_methods=*
    # cors_allowed_headers=*
    # keystore=conf/keystore.p12
    # keystore_pass=changeit
    # keystore_type=PKCS12
    # private_key_file=conf/key.pem
    # certificate_file=conf/certs.pem
    # max_request_size=2000485760
    # batch_size=1
    # max_batch_delay=100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    debug=false : 配置debug模式是否开启
    inference_address:配置服务API接口访问地址
    management_address:配置服务UI界面的访问地址
    model_store:配置模型加载位置
    load_models:配置模型具体加载路径,具体格式为如下:

    [EndpointData]=modelUrl
    其中[EndpointData]格式支持四种
    1,[modelName]只配置一个模型名称
    2,[modelName:version]配置模型名称,模型版本
    3,[modelName:version:engine]配置模型名称,模型版本,模型引擎
    4,[modelName:version:engine:deviceNames]配置模型名称,模型版本,模型引擎,模型驱动GPU或者CPU
    例如:
    load_models=[person:v1:MXNet:*]=file:///D:/LIHAOWORK/serving-0.23.0/person.zip
    多个模型之间用逗号隔开
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    本次demo只应用的上述几个配置,剩余的配置说明可以具体查看官网:
    https://docs.djl.ai/docs/serving/serving/docs/configuration.html
    (3)lib目录是DJL Serving的类包目录
    (4)plugins目录是DJL Serving是插件目录
    由于DJL Serving默认启动加载插件的位置为bin目录下的plugins目录里面的插件文件,我们可以直接将plugins目录以及里面的插件直接复制到bin目录下
    在这里插入图片描述plugins目录里面
    在这里插入图片描述

    3.启动DJL Serving

    Windows下打开cmd
    在这里插入图片描述
    切换到DJL Serving的bin目录下
    在这里插入图片描述
    使用serving 启动DJL Serving
    在这里插入图片描述
    启动日志里面会显示所有的插件已经加载,并且API和UI的地址都是
    http://127.0.0.1:8080

    4.访问DJL Serving

    打开浏览器访问http://127.0.0.1:8080
    在这里插入图片描述

    5.添加模型引擎依赖jar包

    点击系统—>依赖
    在这里插入图片描述
    点击添加依赖
    在这里插入图片描述
    选择类型为JAR,方式是file或者maven
    在这里插入图片描述
    由于本次测试的模型为OnnxRuntime引擎,需要两个依赖包
    onnxruntime-1.15.0.jar
    onnxruntime-engine-0.23.0.jar
    maven的具体依赖为

    >
        >ai.djl.onnxruntime>
        >onnxruntime-engine>
        >0.23.0>
        >runtime>
    >
    >
        >com.microsoft.onnxruntime>
        >onnxruntime>
        >1.15.1>
    >
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    由于公司的网络非常的烂,并且好像这个UI插件的上传对于较大点的jar包有问题,可以直接将需要的jar包拷贝到bin目录下的deps目录,如果没有deps目录就新建一个。
    在这里插入图片描述
    刷新查看
    在这里插入图片描述

    6.添加模型包zip文件

    在这里插入图片描述
    synset文件是模型的ArtifactName文件具体内容如下

    person
    
    • 1

    person.onnx是训练好的模型文件
    libs目录里面是包含classes目录最里面是自定义的translator和translatorFactory
    在这里插入图片描述

    PersonTranslatorFactory类代码如下

    import ai.djl.modality.Input;
    import ai.djl.modality.Output;
    import ai.djl.translate.TranslatorFactory;
    import ai.djl.Model;
    import ai.djl.translate.Translator;
    import ai.djl.util.Pair;
    import java.io.Serializable;
    import java.lang.reflect.Type;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    public class PersonTranslatorFactory implements TranslatorFactory, Serializable {
        private static final long serialVersionUID = 1L;
    
        private static final Set<Pair<Type, Type>> SUPPORTED_TYPES = new HashSet<>();
    
        static {
            SUPPORTED_TYPES.add(new Pair<>(Input.class, Output.class));
        }
    
    
        /** {@inheritDoc} */
        @Override
        public Set<Pair<Type, Type>> getSupportedTypes() {
            return SUPPORTED_TYPES;
        }
    
        /** {@inheritDoc} */
        @Override
        @SuppressWarnings("unchecked")
        public <I, O> Translator<I, O> newInstance(
                Class<I> input, Class<O> output, Model model, Map<String, ?> arguments) {
            if (isSupported(input, output)) {
                System.out.println("1");
                return (Translator<I, O>) new PersonTranslator();
            }
            throw new IllegalArgumentException("Unsupported input/output types.");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    PersonTranslator类代码如下

    import ai.djl.modality.Input;
    import ai.djl.modality.Output;
    import ai.djl.modality.cv.Image;
    import ai.djl.modality.cv.ImageFactory;
    import ai.djl.modality.cv.output.BoundingBox;
    import ai.djl.modality.cv.output.DetectedObjects;
    import ai.djl.modality.cv.output.Rectangle;
    import ai.djl.modality.cv.transform.CenterCrop;
    import ai.djl.modality.cv.transform.Resize;
    import ai.djl.modality.cv.transform.ToTensor;
    import ai.djl.modality.cv.translator.YoloV5Translator;
    import ai.djl.ndarray.NDArray;
    import ai.djl.ndarray.NDList;
    import ai.djl.translate.*;
    import java.io.ByteArrayInputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    public class PersonTranslator implements ServingTranslator {
    
            private final Integer width = 640;
            private final Integer height = 640;
            private  final float threshold = 0.2f;
            //初始化转换器
            private Translator<Image, DetectedObjects> translator = YoloV5Translator
                    .builder()
                    .optThreshold(threshold)
                    .optSynsetArtifactName("synset.txt")
                    .build();
    
            @Override
            public NDList processInput(TranslatorContext ctx, Input input) throws Exception {
                byte[] data = input.getAsBytes(0);
                ImageFactory factory = ImageFactory.getInstance();
                Image image = factory.fromInputStream(new ByteArrayInputStream(data));
    
                NDArray array = image.toNDArray(ctx.getNDManager());
                Pipeline pipeline = new Pipeline();
                pipeline.add(new CenterCrop());
                pipeline.add(new Resize(width, height));
                pipeline.add(new ToTensor());
                return pipeline.transform(new NDList(array));
            }
    
            @Override
            public Output processOutput(TranslatorContext ctx, NDList list) throws Exception {
                DetectedObjects output = translator.processOutput(ctx, list);
                List<String> classList = new ArrayList<>();
                List<Double> probList = new ArrayList<>();
                List<BoundingBox> rectList = new ArrayList<>();
                final List<DetectedObjects.DetectedObject> items = output.items();
                items.forEach(item -> {
                    classList.add(item.getClassName());
                    probList.add(item.getProbability());
    
                    Rectangle b = item.getBoundingBox().getBounds();
                    Rectangle newBox = new Rectangle(b.getX() / width, b.getY() / height, b.getWidth() / width, b.getHeight() / height);
                    rectList.add(newBox);
                });
                Output out = new Output(200, "OK");
                out.add(new DetectedObjects(classList, probList, rectList).toJson());
                return out;
            }
    
    
    
            @Override
            public void prepare(TranslatorContext ctx) throws Exception {
                translator.prepare(ctx);
            }
    
            @Override
            public Batchifier getBatchifier() {
                return translator.getBatchifier();
            }
    
            @Override
            public void setArguments(Map<String, ?> arguments) {}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    在PersonTranslator中主要是实现ServingTranslator接口,里面我们重写了
    processInput和processOutput,其中processInput我们将image处理为NDList,processOutput中我们将结果转为DetectedObjects。
    后面我们会专门总结写一下自定义模型上传的形式和种类以及注意事项。
    最后将person文件打包成zip包

    7.指定自定义模型启动

    具体命令如下:
    serving -m “person::OnnxRuntime=file:///D:/LIHAOWORK/serving-0.23.0/person.zip”
    在这里插入图片描述
    在这里插入图片描述
    其中标红的地方显示使用我们自定义的工厂。

    8.模型测试

    点击model
    在这里插入图片描述
    我们自定义的模型已经READY就绪,点击READY下面三角图标测试,
    Data type选择raw,点击上传图片,点击推理
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    测试图片如下:
    在这里插入图片描述

  • 相关阅读:
    Redis分布式锁解锁案例讲解
    leetcode:21. 合并两个有序链表
    2024年GPLT团体程序设计比赛L2-D吉利矩阵题解
    安全协议之-TLS握手过程详解
    18——Swing程序设计
    ChatGPT充值,银行卡被拒绝
    工龄10年的测试员从大厂“裸辞”后...
    数据库的数据类型
    云信产业集团受邀出席2022大健康论坛暨人民康养大会
    九八投洽会,图扑为你再现工业元宇宙
  • 原文地址:https://blog.csdn.net/qq_39879126/article/details/132729418