总体而言: 我尝试使用 Cloudbuild 和 Cloudrun 构建 BERT 模型。我将模型(参数)和元数据(标签)保存在 GCP Cloud Storage 中。但是,我遇到了通过 joblib.load() 加载metadata.bin 文件的错误。 我的metadata.bin 文件包含UTF-8 字符,但joblib.load 需要ASCII 字符。在我的版本中默认协议是4,但错误消息表明协议是0。
相关依赖项: python 3.8.0,joblib 1.1.1(我已经尝试升级最新版本),google -api-core==2.19.1,google-auth==2.32.0,google-cloud-core==2.4.1,google-cloud-storage==2.18.0
我的努力: 我已经尝试过两种情况。
- 尝试过 本地 在这种情况下, 在 GCP Cloud Storage 下载 model.bin 和metadata.bin 文件都有效
- 尝试过 docker 在这种情况下, 在docker化容器中加载metadata.bin文件和model.bin文件也可以
错误详细信息
:
`
File "./src_review/model_server.py", line 70, in load_bert_model
metadata = joblib.load(metadata_path)
File "/usr/local/lib/python3.8/site-packages/joblib/numpy_pickle.py", line 658, in load
obj = _unpickle(fobj, filename, mmap_mode)
File "/usr/local/lib/python3.8/site-packages/joblib/numpy_pickle.py", line 577, in _unpickle
obj = unpickler.load()
File "/usr/local/lib/python3.8/pickle.py", line 1210, in load
dispatch[key[0]](self)
File "/usr/local/lib/python3.8/pickle.py", line 1244, in load_persid
raise UnpicklingError(
_pickle.UnpicklingError: persistent IDs in protocol 0 must be ASCII strings`
我的代码: `| ||来自 GCP 官方文档
def load_bert_model(config: argparse.Namespace):
bucket = storage_client.bucket(bucket_name)
model_blob = bucket.blob(model_file)
metadata_blob = bucket.blob(metadata_file)
local_model_path = '/tmp/pytorch_model.bin'
metadata_path = '/tmp/meta.bin'
print(f"Downloading model to {local_model_path}")
model_blob.download_to_filename(local_model_path)
log.info(f"Model downloaded to {local_model_path}")
metadata_blob.download_to_filename(metadata_path)
log.info(f"Metadata (label) downloaded to {metadata_path}")
metadata = joblib.load(metadata_path)
...`
`||`
预期原因:
def upload_directory_with_transfer_manager(bucket_name, source_directory, workers=1):
bucket = create_bucket_if_not_exists(bucket_name)
directory_as_path_obj = Path(source_directory)
paths = directory_as_path_obj.rglob("*.bin")
file_paths = [path for path in paths if path.is_file()]
relative_paths = [path.relative_to(source_directory) for path in file_paths]
string_paths = [str(path) for path in relative_paths]
print("Found {} files.".format(len(string_paths)))
results = transfer_manager.upload_many_from_filenames(
bucket, string_paths, source_directory=source_directory, max_workers=workers, skip_if_exists=False
)
for name, result in zip(string_paths, results):
if isinstance(result, Exception):
print("Failed to upload {} due to exception: {}".format(name, result))
else:
print("Uploaded {} to {}.".format(name, bucket.name))
我认为云运行配置与我的测试环境有很大不同。但我没想到主要原因。
感谢您的努力! I think cloud run config is quite different from my test environments. But I could not expected the main causes.
Thanks for your efforts!
遇到的错误“协议 0 中的持久 ID 必须是 ASCII 字符串”表明正尝试使用旧版本的
pickle
协议加载使用较新版本的
pickle
协议保存的
joblib
文件。这可能发生在在本地环境中使用更高版本的 Python 或
joblib
创建文件时。
尽管已将
joblib
升级到最新版本,但存储在 Cloud Storage 中的文件可能仍然使用旧版本的协议进行序列化。
可以尝试以下解决方案:
1. 重新保存
metadata.bin
文件:
-
确保在本地环境中使用与 Cloud Run 环境相同的 Python 和
joblib
版本。 -
使用
joblib.dump()
函数重新保存metadata.bin
文件。这将使用当前环境的pickle
协议对文件进行序列化。 -
将更新后的
metadata.bin
文件上传到 Cloud Storage。
2. 指定
pickle
协议版本:
-
在加载
metadata.bin
文件时,使用joblib.load()
函数的protocol
参数指定pickle
协议版本。尝试使用较低的协议版本,例如:
metadata = joblib.load(metadata_path, protocol=2)
- 可以尝试不同的协议版本,直到找到能够成功加载文件的版本。
3. 确保编码一致性:
-
在保存和加载
metadata.bin
文件时,请确保使用的编码一致。可以尝试在joblib.dump()
和joblib.load()
函数中指定encoding='utf-8'
参数。
4. 检查 Cloud Run 环境:
-
仔细检查的 Cloud Run 环境的 Python 和
joblib
版本。确保它们与在本地环境中使用的版本兼容。
其他建议:
-
为了便于调试,可以尝试在 Cloud Run 实例中打印
joblib
和pickle
的版本信息:
import joblib
import pickle
print(f"Joblib version: {joblib.__version__}")
print(f"Pickle version: {pickle.format_version}")
-
如果仍然遇到问题,请考虑在 Cloud Storage 中创建新的存储桶,并将所有文件(包括
model.bin
和metadata.bin
)上传到该存储桶。这将有助于排除与现有文件相关的任何潜在问题。
通过遵循这些步骤,应该能够解决
joblib.load()
错误并成功加载
metadata.bin
文件。