• java web应用调用python深度学习训练的模型


      之前参见了中国软件杯大赛,在大赛中用到了深度学习的相关算法,也训练了一些简单的模型。项目线上平台是用java编写的web应用程序,而深度学习使用的是python语言,这就涉及到了在java代码中调用python语言的方法。

      为了能在java应用中使用python语言训练的算法模型,我在网上找了很久。我大概找到了三种方法

      1. java代码可以直接调用python代码,只需要下载相应的jar包就行。这种方式我没有尝试,只是觉得这样做使得java应用太过于依赖python的环境了。还有网上也有将python代码打包成jar的方法,然后可以让java代码调用,但是很多第三方库不能打包成jar包。

      2. 将python训练的模型参数保存到文本中,用java代码重现模型的预测算法。我之前就这样做过。这么做显然工作量太大,而且出现的bug几率大大增加。最重要的是很多深度学习的框架就没办法用了。

      3. 使用python进程运行深度学习中训练的模型,在java应用程序中调用python进程提供的服务。这种方法我认为是最好的。python语言写得程序毕竟还是在python环境中执行最有效率。而且python应用和java应用可以运行在不同的服务器上,通过进程的远程访问调用。

      以下是我实现java应用程序访问python进程的python代码部分。进程之间只能是通过socket进行通信。我本来想过用python编写一个web应用,对java提供HTTP服务,后来觉得这样还需要web服务器,对环境依赖太大,而且两个进程间的通信也很简单,所以干脆直接用socket进行调用得了

    import socket
    import sys
    import threading
    import json
    import numpy as np
    from tag import train2
    # nn=network.getNetWork()
    # cnn = conv.main(False)
    # 深度学习训练的神经网络,使用TensorFlow训练的神经网络模型,保存在文件中
    nnservice = train2.NNService(model='model/20180731.ckpt-1000')
    def main():
        # 创建服务器套接字
        serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        # 获取本地主机名称
        host = socket.gethostname()
        # 设置一个端口
        port = 12345
        # 将套接字与本地主机和端口绑定
        serversocket.bind((host,port))
        # 设置监听最大连接数
        serversocket.listen(5)
        # 获取本地服务器的连接信息
        myaddr = serversocket.getsockname()
        print("服务器地址:%s"%str(myaddr))
        # 循环等待接受客户端信息
        while True:
            # 获取一个客户端连接
            clientsocket,addr = serversocket.accept()
            print("连接地址:%s" % str(addr))
            try:
                t = ServerThreading(clientsocket)#为每一个请求开启一个处理线程
                t.start()
                pass
            except Exception as identifier:
                print(identifier)
                pass
            pass
        serversocket.close()
        pass
    
    
    
    class ServerThreading(threading.Thread):
        # words = text2vec.load_lexicon()
        def __init__(self,clientsocket,recvsize=1024*1024,encoding="utf-8"):
            threading.Thread.__init__(self)
            self._socket = clientsocket
            self._recvsize = recvsize
            self._encoding = encoding
            pass
    
        def run(self):
            print("开启线程.....")
            try:
                #接受数据
                msg = ''
                while True:
                    # 读取recvsize个字节
                    rec = self._socket.recv(self._recvsize)
                    # 解码
                    msg += rec.decode(self._encoding)
                    # 文本接受是否完毕,因为python socket不能自己判断接收数据是否完毕,
                    # 所以需要自定义协议标志数据接受完毕
                    if msg.strip().endswith('over'):
                        msg=msg[:-4]
                        break
                # 解析json格式的数据
                re = json.loads(msg)
                # 调用神经网络模型处理请求
                res = nnservice.hand(re['content'])
                sendmsg = json.dumps(res)
                # 发送数据
                self._socket.send(("%s"%sendmsg).encode(self._encoding))
                pass
            except Exception as identifier:
                self._socket.send("500".encode(self._encoding))
                print(identifier)
                pass
            finally:
                self._socket.close() 
            print("任务结束.....")
            
            pass
    
        def __del__(self):
            
            pass
    if __name__ == "__main__":
        main()

    在java代码中访问python进程的代码:

        private Object remoteCall(String content){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("content", content);
            String str = jsonObject.toJSONString();
            // 访问服务进程的套接字
            Socket socket = null;
            List<Question> questions = new ArrayList<>();
            log.info("调用远程接口:host=>"+HOST+",port=>"+PORT);
            try {
                // 初始化套接字,设置访问服务的主机和进程端口号,HOST是访问python进程的主机名称,可以是IP地址或者域名,PORT是python进程绑定的端口号
                socket = new Socket(HOST,PORT);
                // 获取输出流对象
                OutputStream os = socket.getOutputStream();
                PrintStream out = new PrintStream(os);
                // 发送内容
                out.print(str);
                // 告诉服务进程,内容发送完毕,可以开始处理
                out.print("over");
                // 获取服务进程的输入流
                InputStream is = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
                String tmp = null;
                StringBuilder sb = new StringBuilder();
                // 读取内容
                while((tmp=br.readLine())!=null)
                    sb.append(tmp).append('
    ');
                // 解析结果
                JSONArray res = JSON.parseArray(sb.toString());
                
                return res;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {if(socket!=null) socket.close();} catch (IOException e) {}
                log.info("远程接口调用结束.");
            }
            return null;
        }
  • 相关阅读:
    AngularJS:实现动态添加输入控件功能
    Openfire:XMPP的几种消息类型
    Openfire:重新配置openfire
    Clojure:日期操作方法
    Openfire:通过Servlet群发消息
    Openfire:访问Servlet时绕开Openfire的身份验证
    Clojure:解决selmer模板不刷新的问题
    Intellij Idea 13:运行Clojure的repl环境
    MVC.Net 5:允许保存和输出Html内容
    BAE Flask UEditor 使用七牛云
  • 原文地址:https://www.cnblogs.com/maosonglin/p/9397257.html
Copyright © 2020-2023  润新知