安装featurewiz后TensorFlow Keras交叉验证报AttributeError错误
问题:安装featurewiz后Keras交叉验证报错
AttributeError: 'Adam' object has no attribute 'get_weights' 背景
我是TensorFlow Keras新手,执行conda install -c conda-forge featurewiz安装featurewiz前代码运行正常,安装后执行交叉验证代码时出现错误。
复现代码
from sklearn.model_selection import KFold, cross_validate, cross_val_score from scikeras.wrappers import KerasClassifier estimator = KerasClassifier(model, epochs=500, batch_size=10) kfold = KFold(n_splits=5, shuffle=True) results = cross_validate(estimator, X, y, cv=kfold, scoring=['accuracy', 'precision_weighted', 'recall_weighted', 'f1_weighted'], return_train_score=True) print(results)
核心错误
AttributeError: 'Adam' object has no attribute 'get_weights'
完整错误栈
WARNING:absl:Found untraced functions such as _update_step_xla while saving (showing 1 of 1). These functions will not be directly callable after loading. INFO:tensorflow:Assets written to: ram:///var/folders/c4/ywdtx99d1vl0ptsg1fy494_40000gn/T/tmpsuvxkjb9/assets INFO:tensorflow:Assets written to: ram:///var/folders/c4/ywdtx99d1vl0ptsg1fy494_40000gn/T/tmpsuvxkjb9/assets --------------------------------------------------------------------------- Empty Traceback (most recent call last) File ~/tensorflow-test/env/lib/python3.8/site-packages/joblib/parallel.py:862, in Parallel.dispatch_one_batch(self, iterator) 861 try: --> 862 tasks = self._ready_batches.get(block=False) 863 except queue.Empty: 864 # slice the iterator n_jobs * batchsize items at a time. If the 865 # slice returns less than that, then the current batchsize puts (...) 868 # accordingly to distribute evenly the last items between all 869 # workers. File ~/tensorflow-test/env/lib/python3.8/queue.py:167, in Queue.get(self, block, timeout) 166 if not self._qsize(): --> 167 raise Empty 168 elif timeout is None: Empty: During handling of the above exception, another exception occurred: AttributeError Traceback (most recent call last) Cell In[5], line 6 4 estimator = KerasClassifier(model, epochs=500, batch_size=10) #, verbose = 0 5 kfold = KFold(n_splits=5, shuffle=True) #seed, damit shuffle gleich bleibt , random_state=1337 ----> 6 results = cross_validate(estimator, X, y, cv=kfold, scoring=['accuracy', 'precision_weighted', 'recall_weighted', 'f1_weighted'], return_train_score=True) 8 print(results) File ~/tensorflow-test/env/lib/python3.8/site-packages/sklearn/model_selection/_validation.py:266, in cross_validate(estimator, X, y, groups, scoring, cv, n_jobs, verbose, fit_params, pre_dispatch, return_train_score, return_estimator, error_score) 263 # We clone the estimator to make sure that all the folds are 264 # independent, and that it is pickle-able. 265 parallel = Parallel(n_jobs=n_jobs, verbose=verbose, pre_dispatch=pre_dispatch) --> 266 results = parallel( 267 delayed(_fit_and_score)( 268 clone(estimator), 269 X, 270 y, 271 scorers, 272 train, 273 test, 274 verbose, 275 None, 276 fit_params, 277 return_train_score=return_train_score, 278 return_times=True, 279 return_estimator=return_estimator, 280 error_score=error_score, 281 ) 282 for train, test in cv.split(X, y, groups) 283 ) 285 _warn_or_raise_about_fit_failures(results, error_score) 287 # For callabe scoring, the return type is only know after calling. If the 288 # return type is a dictionary, the error scores can now be inserted with 289 # the correct key. File ~/tensorflow-test/env/lib/python3.8/site-packages/joblib/parallel.py:1085, in Parallel.__call__(self, iterable) 1076 try: 1077 # Only set self._iterating to True if at least a batch 1078 # was dispatched. In particular this covers the edge (...) 1082 # was very quick and its callback already dispatched all the 1083 # remaining jobs. 1084 self._iterating = False --> 1085 if self.dispatch_one_batch(iterator): 1086 self._iterating = self._original_iterator is not None 1088 while self.dispatch_one_batch(iterator): File ~/tensorflow-test/env/lib/python3.8/site-packages/joblib/parallel.py:873, in Parallel.dispatch_one_batch(self, iterator) 870 n_jobs = self._cached_effective_n_jobs 871 big_batch_size = batch_size * n_jobs --> 873 islice = list(itertools.islice(iterator, big_batch_size)) 874 if len(islice) == 0: 875 return False File ~/tensorflow-test/env/lib/python3.8/site-packages/sklearn/model_selection/_validation.py:268, in <genexpr>(.0) 263 # We clone the estimator to make sure that all the folds are 264 # independent, and that it is pickle-able. 265 parallel = Parallel(n_jobs=n_jobs, verbose=verbose, pre_dispatch=pre_dispatch) 266 results = parallel( 267 delayed(_fit_and_score)( --> 268 clone(estimator), 269 X, 270 y, 271 scorers, 272 train, 273 test, 274 verbose, 275 None, 276 fit_params, 277 return_train_score=return_train_score, 278 return_times=True, 279 return_estimator=return_estimator, 280 error_score=error_score, 281 ) 282 for train, test in cv.split(X, y, groups) 283 ) 285 _warn_or_raise_about_fit_failures(results, error_score) 287 # For callabe scoring, the return type is only know after calling. If the 288 # return type is a dictionary, the error scores can now be inserted with 289 # the correct key. File ~/tensorflow-test/env/lib/python3.8/site-packages/sklearn/base.py:89, in clone(estimator, safe) 87 new_object_params = estimator.get_params(deep=False) 88 for name, param in new_object_params.items(): --> 89 new_object_params[name] = clone(param, safe=False) 90 new_object = klass(**new_object_params) 91 params_set = new_object.get_params(deep=False) File ~/tensorflow-test/env/lib/python3.8/site-packages/sklearn/base.py:70, in clone(estimator, safe) 68 elif not hasattr(estimator, "get_params") or isinstance(estimator, type): 69 if not safe: --> 70 return copy.deepcopy(estimator) 71 else: 72 if isinstance(estimator, type): File ~/tensorflow-test/env/lib/python3.8/copy.py:153, in deepcopy(x, memo, _nil) 151 copier = getattr(x, "__deepcopy__", None) 152 if copier is not None: --> 153 y = copier(memo) 154 else: 155 reductor = dispatch_table.get(cls) File ~/tensorflow-test/env/lib/python3.8/site-packages/scikeras/_saving_utils.py:117, in deepcopy_model(model, memo) 116 def deepcopy_model(model: keras.Model, memo: Dict[Hashable, Any]) -> keras.Model: --> 117 _, (model_bytes, optimizer_weights) = pack_keras_model(model) 118 new_model = unpack_keras_model(model_bytes, optimizer_weights) 119 memo[model] = new_model File ~/tensorflow-test/env/lib/python3.8/site-packages/scikeras/_saving_utils.py:108, in pack_keras_model(model) 106 optimizer_weights = None 107 if model.optimizer is not None: --> 108 optimizer_weights = model.optimizer.get_weights() 109 model_bytes = np.asarray(memoryview(b.read())) 110 return ( 111 unpack_keras_model, 112 (model_bytes, optimizer_weights), 113 ) AttributeError: 'Adam' object has no attribute 'get_weights'
环境信息
- 设备:M1 Mac
- TensorFlow版本:2.11.0
- 可正常识别CPU和GPU设备
解决方案
1. 回退环境排查依赖冲突
安装featurewiz可能更新了TensorFlow/Keras相关依赖,导致版本不兼容:
- 查看环境修订记录并回退到安装前状态:
conda list --revisions conda install --revision <对应修订号> - 确认使用的是TensorFlow原生
tf.keras.optimizers.Adam,而非其他库的实现。
2. 修改Scikeras使用方式
问题出在克隆已编译模型时的优化器权重获取,改用模型构建函数规避:
def build_model(): # 定义你的模型结构 model = ... # 编译模型 model.compile(optimizer="adam", loss="你的损失函数", metrics=["accuracy"]) return model # 传入构建函数而非已编译模型 estimator = KerasClassifier(model=build_model, epochs=500, batch_size=10)
这样每个交叉验证fold会重新构建模型,避免克隆已编译模型的问题。
3. 初始化优化器权重
未训练的模型优化器可能未初始化,提前触发初始化:
# 传入一个和输入维度匹配的空数组,触发优化器初始化 model.predict(np.zeros((1, X.shape[1]))) estimator = KerasClassifier(model, epochs=500, batch_size=10)
4. 调整库版本
- 安装兼容TensorFlow 2.11的Scikeras版本,例如
scikeras==0.11.0 - 创建新conda环境,先安装TensorFlow和Scikeras验证代码,再逐步加入featurewiz,确认冲突来源
内容的提问来源于stack exchange,提问作者BlueBoy
相关产品推荐
相关产品推荐

