我在尝试通过HTTP Rest调用请求部署的在线预测时遇到问题 在Google AI平台上进行建模。无论如何打包数据,都会出现以下错误。错误是:
print(input_encoded_m)
print(questions_encoded)
(<tf.Tensor 'dropout_41/Identity:0' shape=(None, 552, 64) dtype=float32>,
<tf.Tensor 'dropout_42/Identity:0' shape=(None, 5, 64) dtype=float32>)
我已经确认了Google凭据的工作,并且可以从我的Android应用程序执行查询以获取有关该模型的信息,并且成功。
我认为问题在于数据的格式。我已按照https://cloud.google.com/ml-engine/docs/online-predict和https://cloud.google.com/ml-engine/docs/v1/predict-request的说明进行操作。我尝试发送各种版本,例如
Expected float32, got *******
应该将3D数组作为输入-基本上,模型的输入是150x150x3数组,其中每个像素的值都在0到1.0(浮点)之间。因为模型需要浮点输入,所以我无法将原始的150x150x3像素值转换为base64。因此,我在上面的链接中使用解释来发送3D数组。我尝试了许多不同的方法,但目前还不知道该怎么办。 这是显示3D字符串数组的图像,该数组表示模型需要的缩放输入
注意:我正在从JSON file中读取数据-我在下面的命令行成功gcloud调用中使用了相同的数据来执行预测。这是说明内容的图像。
注意:我可以使用{"instances": [xxx]} where have formatted xxx in many different ways.
在命令行上执行此操作,如下所示
答案 0 :(得分:0)
这是一个常见问题:
gcloud所需的格式与发送到该服务的HTTP请求的正文之间存在细微差异。我们知道这很令人困惑,将来我们将努力解决这一困惑。这是一个简短的说明,可以帮助您入门。
发送到API的请求的正文具有以下形式:
/*
We have to #define _GNU_SOURCE to get access to `char **environ`
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sendfile.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <errno.h>
#include <string.h>
struct child
{
pid_t pid;
int fd_in;
int fd_out;
int fd_err;
};
static void
close_if_valid(int fd)
{
if (fd != -1) close(fd);
}
/*
Closes all file-descriptors for child communication
and waits for child to exit
returns status value from waitpid().
see `man waitpid` on how to interpret that value
*/
int child_wait(struct child *c)
{
close_if_valid(c->fd_in);
close_if_valid(c->fd_out);
close_if_valid(c->fd_err);
int status;
pid_t p = waitpid(c->pid, &status, 0);
if (p == 0)
error(1, errno, "waitpid() failed");
return status;
}
int
dup_if_valid(int fd1, int fd2)
{
if (fd1 != -1 && fd1 != fd2)
return dup2(fd1, fd2);
return fd2;
}
pid_t
child_spawn_fd(const char *const argv[], const char *const env[],
int in, int out, int err)
{
fflush(stdout);
pid_t p = fork();
if (p)
return p;
/***********************
We are now in child
***********************/
/*
Set file descriptors to expected values,
-1 means inherit from parent
*/
if (dup_if_valid(in, 0) == -1)
goto CHILD_ERR;
if (dup_if_valid(out, 1) == -1)
goto CHILD_ERR;
if (dup_if_valid(err, 2) == -1)
goto CHILD_ERR;
/*
close all unneeded file descriptors
This will free resources and keep files and sockets belonging to
the parent from beeing open longer than needed
On *BSD we may call `closefrom(3);`, but this may not exits
on Linux. So we loop over all possible file descriptor numbers.
A better solution, is to look in `/proc/self/fs`
*/
int max_fd = sysconf(_SC_OPEN_MAX);
for (int fd = 3; fd <= max_fd; fd++)
close(fd);
if (env)
environ = (char **)env;
/* Change to execvp if command should be looked up in $PATH */
execv(argv[0], (char * const *)argv);
CHILD_ERR:
_exit(1);
}
#define CHILD_PIPE_STDIN (1 << 0)
#define CHILD_PIPE_STDOUT (1 << 1)
#define CHILD_PIPE_STDERR (1 << 2)
#define READ_END 0
#define WRITE_END 1
struct child
child_spawn(const char * const argv[], const char * const env[], int flags)
{
int in_pipe[2] = {-1, -1};
int out_pipe[2] = {-1, -1};
int err_pipe[2] = {-1, -1};
if (flags & CHILD_PIPE_STDIN)
if (pipe(in_pipe))
error(EXIT_FAILURE, errno, "pipe(in_pipe) failed");
if (flags & CHILD_PIPE_STDOUT)
if (pipe(out_pipe))
error(EXIT_FAILURE, errno, "pipe(out_pipe) failed");
if (flags & CHILD_PIPE_STDERR)
if (pipe(err_pipe))
error(EXIT_FAILURE, errno, "pipe(err_pipe) failed");
pid_t p = child_spawn_fd(argv, env,
in_pipe[READ_END],
out_pipe[WRITE_END],
err_pipe[WRITE_END]);
if (p == -1)
error(EXIT_FAILURE, errno, "fork() failed");
close_if_valid(in_pipe[READ_END]);
close_if_valid(out_pipe[WRITE_END]);
close_if_valid(err_pipe[WRITE_END]);
struct child c =
{
.pid = p,
.fd_in = in_pipe[WRITE_END],
.fd_out = out_pipe[READ_END],
.fd_err = err_pipe[READ_END],
};
return c;
}
/*
Safer implementation of `system()`. It does not invoke shell, and takes
command as NULL terminated list of execuatable and parameters
*/
int
my_system(const char * const argv[])
{
struct child c = child_spawn(argv, NULL, 0);
int status = child_wait(&c);
if (WIFEXITED(status))
return WEXITSTATUS(status);
else
return -1;
}
int
main (int argc, char **argv)
{
printf("Running 'ls -l' using my_system()\n");
printf("---------------------------------\n");
fflush(stdout);
const char * ls_argv[] =
{
"/bin/ls",
"-l",
NULL
};
int e = my_system(ls_argv);
printf("---------\n");
printf("\exit code ---> %d\n", e);
printf("\nRunning 'ls -l' using child_spawn() and reading from stdout\n");
printf("-----------------------------------------------------------\n");
fflush(stdout);
struct child c = child_spawn(ls_argv, NULL, CHILD_PIPE_STDOUT);
/*
Read from the childs stdout and write to current stdout
*/
size_t copied = 0;
while (1)
{
char buff[4096];
ssize_t rlen = read(c.fd_out, buff, 4096);
if (rlen == -1)
error(EXIT_FAILURE, errno, "read() failed");
if (rlen == 0)
break;
size_t written = 0;
while (written < rlen)
{
ssize_t wlen = write(1, buff + written, rlen - written);
if (wlen == -1)
error(EXIT_FAILURE, errno, "write() failed");
written += wlen;
}
copied += written;
}
/* Wait for child to end */
int status = child_wait(&c);
printf("---------\n");
if (WIFEXITED(status))
{
printf(" ---> child exited normally with exit code %d and with %ld bytes copied\n",
WEXITSTATUS(status),
copied);
}
else
printf(" ---> child exited by som other reason than _exit()");
printf("\nWriting to Elmer Fudd filter\n");
const char *quote = "Be very very quiet, I'm hunting rabbits!\n";
printf("Original text: %s", quote);
printf("-----------------------------------------------------------\n");
fflush(stdout);
const char *fudd_filter[] =
{"/bin/sed", "-e" "s/r/w/g", NULL};
struct child c2 = child_spawn(fudd_filter, NULL, CHILD_PIPE_STDIN);
size_t qlen = strlen(quote);
const char *q = quote;
while (qlen)
{
ssize_t wlen = write(c2.fd_in, q, qlen);
if (wlen == -1)
error(EXIT_FAILURE, errno, "write() failed");
q += wlen;
qlen -= wlen;
}
child_wait(&c2);
}
gcloud中使用的文件只是用换行符分隔的实例列表:
{"instances": [<instance 1>, <instance 2>, ...]}
我查看了您的文件,有2条建议:
a)因为使用gcloud命令可以正常工作,所以我将使用AI Platform UI来测试您的JSON输入,就像API会使用的那样。
注意:复制并粘贴输入后,请使用测试
根据文档中的说明,我们需要以下内容:
<instance 1>
<instance 2>
在这种情况下,您有
{
"instances": [
<object>
...
]
}
b)您需要将{
"conv2d_input": [
<object>
...
]
}
替换为conv2d_input
并添加额外的[]:
我用自己的模型测试了您的input,并且工作正常。
instances
我通常使用此代码:
{
"instances":
[
[[[0.23137255012989044, 0.27450981736183167, 0.250980406999588],
...
,[0.2980392277240753, 0.43529412150382996, 0.2078431397676468]]]
]
}