简体   繁体   English

发布请求 tensorflow 服务:要解包的值太多(预期 2)

[英]Post request tensorflow serving: too many values to unpack (expected 2)

I set up a tensorflow running service with my model, but when I try to do a post request it returns me the following error (get request work):我用我的 model 设置了一个 tensorflow 运行服务,但是当我尝试进行发布请求时,它返回了以下错误(获取请求工作):

[nltk_data] Downloading package punkt to /home/viktor/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
HBox(children=(FloatProgress(value=1.0, bar_style='info', max=1.0), HTML(value='')))
Truncation was not explicitly activated but `max_length` is provided a specific value, please use `truncation=True` to explicitly truncate examples to max length. Defaulting to 'longest_first' truncation strategy. If you encode pairs of sequences (GLUE-style) with the tokenizer you can select this strategy more precisely by providing a specific strategy to `truncation`.

(3, 20)
Traceback (most recent call last):
  File "bert_api.py", line 99, in <module>
    res , res2= requests.post('http://3.143.108.46:8501/v1/models/colbert:predict', 
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/api.py", line 119, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/sessions.py", line 516, in request
    prep = self.prepare_request(req)
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/sessions.py", line 449, in prepare_request
    p.prepare(
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/models.py", line 317, in prepare
    self.prepare_body(data, files, json)
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/models.py", line 508, in prepare_body
    body = self._encode_params(data)
  File "/home/viktor/documents/miniconda3/lib/python3.8/site-packages/requests/models.py", line 97, in _encode_params
    for k, vs in to_key_val_list(data):
ValueError: too many values to unpack (expected 2)

This is my code:这是我的代码:

res, res2 = requests.post('http://url:port/v1/models/colbert:predict', 
    data=sentence_input)
print(res.status_code, res.reason)

my data_sentence is an array of arrays:我的 data_sentence 是一个 arrays 数组:

 [array([[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
       dtype=int32),
 array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32]

There are two separate issues in your code.您的代码中有两个单独的问题。 One pertains to the payload, the other to the way you are using requests.post .一个与有效负载有关,另一个与您使用requests.post的方式有关。

Requests usage请求使用

requests.post , just as requests.request and other similar functions, returns a single instance of Response class ( source ). requests.postrequests.request和其他类似函数一样,返回单个Response class 实例( 来源)。 For this reason, to fix your error you need to change from因此,要修复您的错误,您需要从

res, res2 = requests.post(...

to

res = requests.post(

Now, typically if you try to take one thing and unpack it into two variables, you would get a more clear error saying that there are not enough values to unpack:现在,通常如果你尝试将一个东西解压成两个变量,你会得到一个更清晰的错误,指出没有足够的值可以解压:

>>> a,b = [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 2, got 1)

The error you are getting actually says the opposite - that you have too many values to unpack.你得到的错误实际上是相反的——你有太多的值需要解压。 And here's why.这就是为什么。

The Response class returned by requests.post defines an __iter__(self) method ( source ), which will allow you to iterate over the response in chunks instead of reading it all at once. requests.post返回的Response class 定义了一个__iter__(self)方法( source ),这将允许您以块的形式迭代响应,而不是一次读取所有响应。 So when you do res, res2 = response , Python will try to unpack the response for you by using the __iter__ implementation.因此,当您执行res, res2 = response时,Python 将尝试使用__iter__实现为您解压响应。 If you have more than 2 chunks in your response, you won't have enough variables to handle the other chunks, so you get the error "too many values to unpack".如果您的响应中有超过 2 个块,您将没有足够的变量来处理其他块,因此您会收到错误“太多值无法解包”。

A simple demonstration of this behaviour:这种行为的简单演示:

>>> class X():
...     def __iter__(self):
...             for i in range(5):
...                     yield i
...
>>> x = X()
>>> a,b = x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> list(x)
[0, 1, 2, 3, 4]

Payload有效载荷

When you pass in the data keyword argument to requests.post , it assumes that you want to form-encode it ( docs ).当您将data关键字参数传递给requests.post时,它假定您想要对其进行形式编码( docs )。 You should either pass a dictionary or a list of tuples, but what you have is a list of arrays, which isn't a form at all, so you don't want to form-encode it.您应该传递字典或元组列表,但您拥有的是 arrays 列表,它根本不是表单,因此您不想对其进行形式编码。

So when you are passing (data=list_of_arrays) , the library expects the first element to be a tuple with two elements.因此,当您传递(data=list_of_arrays)时,库期望第一个元素是具有两个元素的元组。 Instead you have an array with much more elements, which again results in the same error: too many values to unpack .相反,您有一个包含更多元素的数组,这再次导致相同的错误: unpack 的值太多

What you want to do instead is to send it as JSON or just as a string.您要做的是将其作为 JSON 或仅作为字符串发送。 Typically, you would have to follow the docs and do通常,您必须遵循文档并执行

import json

payload = [np.random.randint(2, size=30).reshape(3,10), np.random.randint(2, size=30).reshape(3,10)]

res = requests.post('/', data=json.dumps(payload)) # pass it as a string

res = requests.post('/', json=payload) # or let the library serialize it

Unfortunately, you will then run into the issue where np.array isn't serializable, so you have to prepare it for serialization first.不幸的是,您将遇到np.array不可序列化的问题,因此您必须先为序列化做好准备。 As per this answer , you can just call .tolist() on np.array which will serialize it to a list of integers for you.根据这个答案,您可以在np.array上调用.tolist() ,它将为您将其序列化为整数列表。

Thus the final solution因此最终的解决方案

import json

payload = [np.random.randint(2, size=30).reshape(3,10), np.random.randint(2, size=30).reshape(3,10)]

# convert both np.arrays to list
payload = [payload[0].tolist(), payload[1].tolist()]
# or this way
payload = [arr.tolist() for arr in data]

# now the payload is serializable
res = requests.post('/', data=json.dumps(payload)) # pass it as a string

res = requests.post('/', json=payload) # or let the library serialize it

Looking at the error message i see that you are assigning two variables res, res2 to requests.post response that has more than 2 returning values查看错误消息,我看到您正在将两个变量 res、res2 分配给具有超过 2 个返回值的 requests.post 响应

#for example 
var1, var2 = [1, 2, 3]
#this will raise the same error as your's 

To solve this problem you need to index your response like this below要解决此问题,您需要像下面这样索引您的响应

res, res2 = requests.post('http://url:port/v1/models/colbert:predict', 
    data=sentence_input)[:2]
print(res.status_code, res.reason)

If response to your post request return a list, indexing will solve your problem如果对您的帖子请求的响应返回一个列表,索引将解决您的问题

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

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