首页 > 解决方案 > 发布请求 tensorflow 服务:解包的值太多(预期 2)

问题描述

我使用我的模型设置了一个 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)

这是我的代码:

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

我的 data_sentence 是一个数组数组:

 [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]

标签: pythonapipython-requests

解决方案


您的代码中有两个单独的问题。一个与有效负载有关,另一个与您使用的方式有关requests.post

请求使用

requests.post,就像requests.request和其他类似的函数一样,返回类的单个实例Responsesource)。因此,要修复您的错误,您需要从

res, res2 = requests.post(...

res = requests.post(

现在,通常如果你尝试将一个东西解压成两个变量,你会得到一个更清晰的错误,指出没有足够的值可以解压:

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

你得到的错误实际上是相反的——你有太多的值需要解压。这就是为什么。

Response由返回的类requests.post定义了一个__iter__(self)方法(source),这将允许您以块的形式迭代响应,而不是一次读取所有响应。因此,当您这样做时res, res2 = response,Python 将尝试使用__iter__实现为您解包响应。如果您的响应中有超过 2 个块,您将没有足够的变量来处理其他块,因此您会收到错误“太多值无法解包”。

这种行为的简单演示:

>>> 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]

有效载荷

当您将data关键字参数传递给 时requests.post,它假定您要对其进行形式编码(docs)。您应该传递字典或元组列表,但是您拥有的是数组列表,它根本不是表单,因此您不想对其进行形式编码。

因此,当您传递 时(data=list_of_arrays),库期望第一个元素是具有两个元素的元组。相反,您有一个包含更多元素的数组,这再次导致相同的错误:unpack 的值太多

您想要做的是将其作为 JSON 或仅作为字符串发送。通常,您必须遵循文档并执行

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

不幸的是,您将遇到np.array不可序列化的问题,因此您必须先为序列化做好准备。根据这个答案,您只需调用.tolist()它将np.array为您将其序列化为整数列表。

因此最终的解决方案

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

推荐阅读