M1 MacBook运行Apple原生TensorFlow2.4的Numpy兼容性问题咨询
M1芯片环境TensorFlow 2.4添加LSTM层报错解决方案
问题现象
- 运行环境:M1 MacBook,使用苹果原生TensorFlow 2.4包,miniforge搭建的Python 3.8虚拟环境
- 代码运行背景:同一份Jupyter Notebook代码原本可在Intel架构设备、旧版TensorFlow环境下正常运行
- 已做排查:先后尝试匹配NumPy 1.20、1.18版本,完成降级操作后均未解决兼容性问题
- 触发场景:向Keras Sequential模型添加LSTM层时直接中断报错
核心报错信息
未实现错误:无法将符号张量(lstm_1/strided_slice:0)转换为numpy数组。该错误通常表示你正在尝试将张量传递给NumPy调用,而这种操作是不受支持的 --------------------------------------------------------------------------- 未实现错误 Traceback (most recent call last) <ipython-input-20-73358e637fe3> in <module> 4 model = Sequential() 5 model.add(Embedding(vocab_size+1, W2V_SIZE, weights=[embedding_matrix], input_length=MAX_SEQUENCE_LENGTH, trainable=False)) ----> 6 model.add(LSTM(500, dropout=0.2, recurrent_dropout=0.2)) 7 model.add(Dense(units = 10000, kernel_initializer = 'glorot_uniform', activation = 'relu')) 8 model.add(Dropout(0.35)) ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/training/tracking/base.py in _method_wrapper(self, *args, **kwargs) 515 self._self_setattr_tracking = False # pylint: disable=protected-access 516 try: --> 517 result = method(self, *args, **kwargs) 518 finally: 519 self._self_setattr_tracking = previous_value # pylint: disable=protected-access ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/engine/sequential.py in add(self, layer) 221 # 如果模型是在输入层上方连续构建的: 222 # 刷新其输出 --> 223 output_tensor = layer(self.outputs[0]) 224 if len(nest.flatten(output_tensor)) != 1: 225 raise ValueError(SINGLE_LAYER_OUTPUT_ERROR_MSG) ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in __call__(self, inputs, initial_state, constants, **kwargs) 658 659 if initial_state is None and constants is None: --> 660 return super(RNN, self).__call__(inputs, **kwargs) 661 662 # 如果指定了`initial_state`或`constants`中的任意参数,且这些参数是Keras ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, *args, **kwargs) 944 # >> model = tf.keras.Model(inputs, outputs) 945 if _in_functional_construction_mode(self, inputs, args, kwargs, input_list): --> 946 return self._functional_construction_call(inputs, args, kwargs, 947 input_list) 948 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in _functional_construction_call(self, inputs, args, kwargs, input_list) 1083 layer=self, inputs=inputs, build_graph=True, training=training_value): 1084 # 检查层构建后设置的输入假设,例如输入形状 -> 1085 outputs = self._keras_tensor_symbolic_call( 1086 inputs, input_masks, args, kwargs) 1087 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in _keras_tensor_symbolic_call(self, inputs, input_masks, args, kwargs) 815 return nest.map_structure(keras_tensor.KerasTensor, output_signature) 816 else: --> 817 return self._infer_output_signature(inputs, args, kwargs, input_masks) 818 819 def _infer_output_signature(self, inputs, args, kwargs, input_list): ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in _infer_output_signature(self, inputs, args, kwargs, input_masks) 856 # TODO(kaftan): 是否在此处执行maybe_build,还是已经完成构建? 857 self._maybe_build(inputs) --> 858 outputs = call_fn(inputs, *args, **kwargs) 859 860 self._handle_activity_regularization(inputs, outputs) ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent_v2.py in call(self, inputs, mask, training, initial_state) 1161 # LSTM不支持常量,处理过程中忽略该参数 1162 orig_initial_state = initial_state -> 1163 inputs, initial_state, _ = self._process_inputs(inputs, initial_state, None) 1164 1165 if isinstance(mask, list): ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in _process_inputs(self, inputs, initial_state, constants) 857 initial_state = self.states 858 elif initial_state is None: --> 859 initial_state = self.get_initial_state(inputs) 860 861 if len(initial_state) != len(self.states): ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in get_initial_state(self, inputs) 640 dtype = inputs.dtype 641 if get_initial_state_fn: --> 642 init_state = get_initial_state_fn( 643 inputs=None, batch_size=batch_size, dtype=dtype) 644 else: ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in get_initial_state(self, inputs, batch_size, dtype) 2504 2505 def get_initial_state(self, inputs=None, batch_size=None, dtype=None): -> 2506 return list(_generate_zero_filled_state_for_cell( 2507 self, inputs, batch_size, dtype)) 2508 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in _generate_zero_filled_state_for_cell(cell, inputs, batch_size, dtype) 2985 batch_size = array_ops.shape(inputs)[0] 2986 dtype = inputs.dtype -> 2987 return _generate_zero_filled_state(batch_size, cell.state_size, dtype) 2988 2989 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in _generate_zero_filled_state(batch_size_tensor, state_size, dtype) 3001 3002 if nest.is_nested(state_size): -> 3003 return nest.map_structure(create_zeros, state_size) 3004 else: 3005 return create_zeros(state_size) ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/util/nest.py in map_structure(func, *structure, **kwargs) 657 658 return pack_sequence_as( --> 659 structure[0], [func(*x) for x in entries], 660 expand_composites=expand_composites) 661 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/util/nest.py in <listcomp>(.0) 657 658 return pack_sequence_as( --> 659 structure[0], [func(*x) for x in entries], 660 expand_composites=expand_composites) 661 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/keras/layers/recurrent.py in create_zeros(unnested_state_size) 2998 flat_dims = tensor_shape.TensorShape(unnested_state_size).as_list() 2999 init_state_size = [batch_size_tensor] + flat_dims -> 3000 return array_ops.zeros(init_state_size, dtype=dtype) 3001 3002 if nest.is_nested(state_size): ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py in wrapper(*args, **kwargs) 199 """调用目标函数,若抛出TypeError则回退到分发器逻辑。""" 200 try: --> 201 return target(*args, **kwargs) 202 except (TypeError, ValueError): 203 # 注意:convert_to_eager_tensor当前抛出的是ValueError,而非 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py in wrapped(*args, **kwargs) 2818 def wrapped(*args, **kwargs): -> 2819 tensor = fun(*args, **kwargs) 2820 tensor._is_zeros_tensor = True 2821 return tensor ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py in zeros(shape, dtype, name) 2866 # 如果张量尺寸不大则创建常量,否则创建填充 2867 # 操作以避免序列化的GraphDef过大 -> 2868 output = _constant_if_small(zero, shape, dtype, name) 2869 if output is not None: -> 2870 return output ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py in _constant_if_small(value, shape, dtype, name) 2802 def _constant_if_small(value, shape, dtype, name): 2803 try: -> 2804 if np.prod(shape) < 1000: 2805 return constant(value, shape=shape, dtype=dtype, name=name) 2806 except TypeError: <__array_function__ internals> in prod(*args, **kwargs) ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/numpy/core/fromnumeric.py in prod(a, axis, dtype, out, keepdims, initial, where) 3028 10 3029 """ -> 3030 return _wrapreduction(a, np.multiply, 'prod', axis, dtype, out, 3031 keepdims=keepdims, initial=initial, where=where) 3032 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/numpy/core/fromnumeric.py in _wrapreduction(obj, ufunc, method, axis, dtype, out, **kwargs) 85 return reduction(axis=axis, out=out, **passkwargs) 86 ---> 87 return ufunc.reduce(obj, axis, dtype, out, **passkwargs) 88 89 ~/miniforge3/envs/tf2.4/lib/python3.8/site-packages/tensorflow/python/framework/ops.py in __array__(self) 850 851 def __array__(self): --> 852 raise NotImplementedError( 853 "无法将符号张量({})转换为numpy数组。" 854 "该错误通常表示你正在尝试将张量传递给"
问题根因
- 直接触发点位于TensorFlow 2.4内部的
_constant_if_small函数,该函数判断零张量是否为小尺寸时,直接调用np.prod(shape)计算形状元素总数。当LSTM层初始化时传入的batch size是动态符号张量,NumPy 1.20及以上版本会拒绝将符号张量传入计算接口,触发类型转换错误。 - 降级到NumPy 1.18仍报错,大概率是两种情况:一是降级后未重启Jupyter内核,NumPy版本未在当前会话生效;二是M1原生TensorFlow 2.4的早期构建包本身存在接口适配遗漏,未完美兼容低版本NumPy的输入要求。
解决方法
- 先确认当前会话的NumPy版本:在Jupyter单元格执行
import numpy; numpy.__version__,确认输出为1.19.2(TensorFlow 2.4官方验证兼容的版本),若不对则执行pip install numpy==1.19.2完成安装,安装后重启Jupyter内核再运行代码测试。 - 若降级后仍触发报错,可临时修改TF源码绕过冲突:找到虚拟环境路径下的
tensorflow/python/ops/array_ops.py文件,定位第2804行的if np.prod(shape) < 1000:代码,将np.prod(shape)替换为tensor_shape.num_elements(shape),保存文件后重启内核即可正常添加LSTM层。 - 长期优化建议:M1芯片适配的TensorFlow 2.4属于早期测试版本,对Keras循环层、自定义层的兼容存在较多遗留问题,可升级至适配M1的TensorFlow 2.10及以上版本,可覆盖绝大多数已知兼容问题。
内容的提问来源于stack exchange,提问作者Tom Xu
相关产品推荐
相关产品推荐

