使用Python函数将模型保存至AWS S3时遇Pickle参数验证错误求助
问题排查与解决方案
错误原因
pickle.dump()函数没有返回值(返回None),你把它的赋值结果pickle_data传给了save_feature_matrix的dataset参数,导致S3的put()方法收到的Body是None,不符合参数要求(需要字节、字节数组或类文件对象),这就是报错的核心原因。
修复方案
方案1:内存中直接序列化(推荐,无需本地文件)
使用BytesIO在内存中完成模型的序列化,直接传递字节流给S3:
import pickle from io import BytesIO import boto3 # 训练代码保持不变 TS = TimeSeriesSplit(n_splits = 5) dt = DecisionTreeClassifier() grid = {'max_depth': [5,7,9,11,15], 'min_samples_leaf': [5,7,9,11,13],'criterion': ['gini','entropy']} gs = GridSearchCV(dt, param_grid=grid, cv=TS) gs.fit(X_train, y_train) # 修改保存函数与调用逻辑 def save_model_to_s3(bucket, bucket_path, model): session = boto3.Session(aws_access_key_id, aws_secret_access_key, aws_session_token) s3 = session.resource('s3') # 内存中序列化模型 buffer = BytesIO() pickle.dump(model, buffer) buffer.seek(0) # 重置文件指针到开头 s3.Object(bucket, bucket_path).put(Body=buffer) # 调用函数 bucket = "aplicaciones-cd-12" key = "modelos/arboles_gridsearch.pkl" save_model_to_s3(bucket, key, gs)
方案2:读取本地文件的字节内容
如果需要先保存到本地文件,需重新读取文件的字节数据再传给S3:
import pickle import boto3 # 训练代码保持不变 TS = TimeSeriesSplit(n_splits = 5) dt = DecisionTreeClassifier() grid = {'max_depth': [5,7,9,11,15], 'min_samples_leaf': [5,7,9,11,13],'criterion': ['gini','entropy']} gs = GridSearchCV(dt, param_grid=grid, cv=TS) gs.fit(X_train, y_train) # 保存函数保持不变,修改调用逻辑 def save_feature_matrix(bucket, bucket_path,dataset): session = boto3.Session(aws_access_key_id,aws_secret_access_key,aws_session_token) s3 = session.resource('s3') s3.Object(bucket, bucket_path).put(Body=dataset) # 调用函数 bucket = "aplicaciones-cd-12" key = "modelos/arboles_gridsearch.pkl" # 先保存模型到本地文件 pickle.dump(gs, open('model.pkl','wb')) # 读取本地文件的字节内容 with open('model.pkl', 'rb') as f: pickle_data = f.read() save_feature_matrix(bucket, key, pickle_data)
额外注意事项
- 确保AWS凭证(
aws_access_key_id、aws_secret_access_key、aws_session_token)配置正确,且拥有目标S3桶的写入权限。 - 方案1避免了本地文件IO操作,在生产环境或大模型场景下效率更高。
内容的提问来源于stack exchange,提问作者Erick Toscano S.
相关产品推荐
相关产品推荐

