繁体   English   中英

每次调用时,Node js Child Process Spawn 都会运行整个 python 代码

[英]Node js Child Process Spawn runs whole python code every time I call

我有这段代码将 Nodejs 连接到 Python 脚本。 该脚本包含带有 Tensor 流后端等的 ML 模型,它基本上给出了一个字符串 output。 我将图像 URL 从节点 js via.child process spawn 发送到 python 并将其识别的表达式作为字符串返回。 基本上我正在做面部识别,编码在 python 但通过节点 js 调用并将字符串作为 JSON 数据(Rest API)发送到响应。

我面临的问题是,每当我调用 spawn 时,它都会运行 python 的整个代码,并且只要 python 脚本必须加载所有模块,如果我们从顶部开始并最终给出 Z78E6221F6393D1356681DB398F14C6D.

这是 python 代码

from gtts import gTTS
language = 'en'
#myobj = gTTS(text='Do you know the person? Yes or No', lang=language, slow=True)
#myobj.save("question1.mp3")
#myobj = gTTS(text='What is his or her name', lang=language, slow=True)
#myobj.save("question2.mp3")
import csv
import pandas as pd   
import numpy as np
#with open('database.csv','w') as f:
 # writer=csv.writer(f) 
 # writer.writerow(['Chinmay',embedded])
face_embeddings=np.array(pd.read_csv('database.csv',header=None))
face_names=np.array(pd.read_csv('database_names.csv',header=None))

from cv2 import cv2
import matplotlib.pyplot as plt
import matplotlib.patches as patches

from align import AlignDlib
import numpy as np 
import matplotlib.pyplot as plt
from PIL import Image
import torch
import torch.nn as nn
import torch.nn.functional as F
import os 
from torch.autograd import Variable  
from model import create_model

import transforms as transforms
from skimage import io
from skimage.transform import resize 
from models import *

import matplotlib.pyplot as plt
from keras.models import load_model
from keras.preprocessing.image import load_img, img_to_array
from util.model import CNNModel, generate_caption_beam_search
import os

from config import config
from pickle import load
import sys

cut_size = 44
transform_test = transforms.Compose([
    transforms.TenCrop(cut_size),
    transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])),
])
class_names = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral']
final_text=''
nn4_small2_pretrained = create_model()
nn4_small2_pretrained.load_weights('weights/nn4.small2.v1.h5')

def rgb2gray(rgb):
    return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])

def load_image(path): 
    img = cv2.imread(path, 1)
    # OpenCV loads images with color channels
    # in BGR order. So we need to reverse them
    return img[...,::-1]


def extract_features(filename, model, model_type):
    if model_type == 'inceptionv3':
        from keras.applications.inception_v3 import preprocess_input
        target_size = (299, 299)
    elif model_type == 'vgg16':
        from keras.applications.vgg16 import preprocess_input
        target_size = (224, 224)
      # Loading and resizing image
    image = load_img(filename, target_size=target_size)
    # Convert the image pixels to a numpy array
    image = img_to_array(image)
    # Reshape data for the model
    image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
    # Prepare the image for the CNN Model model
    image = preprocess_input(image)
    # Pass image into model to get encoded features
    features = model.predict(image, verbose=0)
    return features
def getrecogstr( imgurl ): 

    # Path of Image
    #image_file=imgurl

    image_file = sys.argv[1]

    # Initialize the OpenFace face alignment utility
    alignment = AlignDlib('models/landmarks.dat')

    # Load an image
    jc_orig = load_image(image_file)

    # Detect face and return bounding box -
    bb = alignment.getAllFaceBoundingBoxes(jc_orig)
    net = VGG('VGG19')
    checkpoint = torch.load(os.path.join('FER2013_VGG19', 'PrivateTest_model.t7'),map_location='cpu')
    net.load_state_dict(checkpoint['net'])

    # Load the tokenizer
    tokenizer_path = config['tokenizer_path']
    tokenizer = load(open(tokenizer_path, 'rb'))

    # Max sequence length (from training)
    max_length = config['max_length']
    caption_model = load_model('model.hdf5')
    image_model = CNNModel(config['model_type'])

    for i in bb:

        # Transform image using specified face landmark indices and crop image to 96x96
        jc_aligned = alignment.align(96, jc_orig, i, landmarkIndices=AlignDlib.OUTER_EYES_AND_NOSE)

        location=(i.height()+i.width())/(jc_orig.shape[0]+jc_orig.shape[1])

        #  Finding the emotion of cropped image
        gray = rgb2gray(jc_aligned)
        gray = resize(gray, (48,48), mode='symmetric').astype(np.uint8)
        img = gray[:, :, np.newaxis]

        img = np.concatenate((img, img, img), axis=2)
        img = Image.fromarray(img)
        inputs = transform_test(img)

        #net.cuda()
        net.eval()
        ncrops, c, h, w = np.shape(inputs)

        inputs = inputs.view(-1, c, h, w)
        #inputs = inputs.cuda()
        inputs = Variable(inputs, volatile=True)
        outputs = net(inputs)
        outputs_avg = outputs.view(ncrops, -1).mean(0)  # avg over crops
        score = F.softmax(outputs_avg)
        _, predicted = torch.max(outputs_avg.data, 0)
    # Find the name of the person in the image

        jc_aligned = (jc_aligned / 255.).astype(np.float32)
        embeddings = nn4_small2_pretrained.predict(np.expand_dims(jc_aligned, axis=0))[0]
        print("@@")
        print(embeddings)
        matched_embeddings=1000

        for j in range(len(face_embeddings)): 
            temp=np.sum(np.square(embeddings-face_embeddings[j]))
            if (temp<=0.56 and temp <matched_embeddings):
                matched_embeddings=np.sum(np.square(embeddings-face_embeddings[j]))
                face_index=j
        print(temp)
        print('above')
        if matched_embeddings!=1000:
            face_name=face_names[face_index][0]
            print("@@known")
        else:
            face_name='Unknown'
            print("@@unknown")
            #print("Unknown Person detected. Do you know this person yes or no ?")
            #Play welcome1.mp3

            #Play welcome2.mp3 if input is yes

        final_text+= face_name+' expression is '+class_names[int(predicted.cpu().numpy())] + "."
        print("@@"+final_text)
        sys.stdout.flush()
getrecogstr()


这是节点代码

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const port = 1000;
const spawn = require("child_process").spawn;
app.use(bodyParser.json()); // application/json

app.use((req, res, next) => {
 res.setHeader('Access-Control-Allow-Origin', '*');
 res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, PATCH, DELETE');
 res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
 next();
});
app.get('/test', (req, res, next) => {
 const imgurl = req.query.imgurl;
var process = spawn('python', ["./final.py",
   imgurl, 
 ]); 
 process.stdout.on('data', function (data) {
   const recog_str = data.toString().split('@@')[3];
   console.log(recog_str); 
 res.json(recog_str)

 })
})


server.listen(port, () => {

 console.log("Ok");
})

我只是想每次都跳过加载模块的那部分。 我知道我们必须运行模块才能使它们位于 memory 中,但这需要很长时间。 可以像 python 脚本一直在运行一样,我们可以在运行过程中从节点 js 发送 arguments 并调用可以返回该字符串的 function?

您可以在节点和衍生的 python 进程之间使用全局变量和消息通信。

我从教程中得到了关于消息队列的想法,但是在这里可以应用相同的方法。

应用程序.js

const app = require('express')();
const uuid = require('uuid');
const spawn = require("child_process").spawn;

var py = spawn('python', ["./face.py"]);
var globalobj = {}

//whenever any data arrives, it will be stored in globalobj.
py.stdout.on('data', function (data) {
    try {
        const { id, msg } = JSON.parse(data.toString());
        globalobj[id] = msg;
    } catch (err) {
        //If data chunk received is incomplete(child process sent large output) json parse fails.
    }
});

const delay = () => new Promise(resolve => {
    setTimeout(() => {
        resolve();
    }, 4000);
});

app.get('/test', async (req, res, next) => {
    const url = req.query.imgurl;
    const id = uuid.v4();

    py.stdin.write(JSON.stringify({ id, url }) + "\n");
    await delay();

    //If no response has arrived from the child process, globalobj wont have id key.
    if (globalobj[id] != undefined) {
        res.send(globalobj[id]);
        delete globalobj[id];
    } else {
        res.status(500).send('No response from child process');
    }
});

app.listen(3000, 'localhost', () => {
    console.log(`server started on port 3000`);
});

缺点是延迟后得到响应的消息将累积在全局 object 中。 此外py.stdout.on('data', function(data){})返回 stream 中的数据,因此如果消息较大,它将被 nodejs 分成块。 看到这个帖子

可以在此处找到在写入子标准输入时使用\n的原因。

主文件

import sys, json

while True:
    stdin = sys.stdin.readline().replace("\n", "")
    if stdin:
        data = json.loads(stdin)
        #do your computation here

        print(json.dumps({'id': data['id'], 'msg': 'your message'}), flush=True)
        stdin = None

当我快速测试时,它起作用了,但它可能不适用于所有情况。 在使用此方法之前对其进行测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM