【问题标题】:ValueError: malformed node or string with ast.literal_eval() when adding a Keras layerValueError:添加 Keras 层时带有 ast.literal_eval() 的节点或字符串格式错误
【发布时间】:2019-01-13 15:40:17
【问题描述】:

我想构建一个评估字符串的 Keras 模型。如果我执行以下操作:

from keras.models import Sequential
from keras.layers import Dense

model = Sequential()
model.add(Dense(units=10, input_shape=(10,), activation='softmax'))

它工作正常。我可以看到model.summary()

但是,当我用ast.literal_eval()添加图层时

from keras.models import Sequential
from keras.layers import Dense
import ast

model = Sequential()
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
ast.literal_eval(code)

它让我下一个ValueError

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/ast.py", line 84, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python3.5/ast.py", line 83, in _convert
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x7efc40c90e10>

如果我使用 eval 而不是 ast.literal_eval 它也可以。

我正在使用python3.5。

【问题讨论】:

    标签: python keras valueerror


    【解决方案1】:

    一个大错误:literal_eval 仅适用于文字。在这种情况下,我有一个通话

    函数literal_eval首先解析字符串。

    来自 /usr/lib/python3.5/ast.py:第 38-46 行

    def literal_eval(node_or_string):
        """
        Safely evaluate an expression node or a string containing a Python
        expression.  The string or node provided may only consist of the following
        Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
        sets, booleans, and None.
        """
        if isinstance(node_or_string, str):
            node_or_string = parse(node_or_string, mode='eval')
    

    此时,node_or_stringExpression 的一个实例。然后,literal_eval 获取正文。

    来自 /usr/lib/python3.5/ast.py:第 47-48 行

        if isinstance(node_or_string, Expression):
            node_or_string = node_or_string.body
    

    最后,literal_eval 检查正文的类型 (node_or_string)。

    来自 /usr/lib/python3.5/ast.py:第 49-84 行

        def _convert(node):
            if isinstance(node, (Str, Bytes)):
                return node.s
            elif isinstance(node, Num):
                return node.n
            elif isinstance(node, Tuple):
                return tuple(map(_convert, node.elts))
            elif isinstance(node, List):
                return list(map(_convert, node.elts))
            elif isinstance(node, Set):
                return set(map(_convert, node.elts))
            elif isinstance(node, Dict):
                return dict((_convert(k), _convert(v)) for k, v
                            in zip(node.keys, node.values))
            elif isinstance(node, NameConstant):
                return node.value
            elif isinstance(node, UnaryOp) and \
                 isinstance(node.op, (UAdd, USub)) and \
                 isinstance(node.operand, (Num, UnaryOp, BinOp)):
                operand = _convert(node.operand)
                if isinstance(node.op, UAdd):
                    return + operand
                else:
                    return - operand
            elif isinstance(node, BinOp) and \
                 isinstance(node.op, (Add, Sub)) and \
                 isinstance(node.right, (Num, UnaryOp, BinOp)) and \
                 isinstance(node.left, (Num, UnaryOp, BinOp)):
                left = _convert(node.left)
                right = _convert(node.right)
                if isinstance(node.op, Add):
                    return left + right
                else:
                    return left - right
            raise ValueError('malformed node or string: ' + repr(node))
        return _convert(node_or_string)
    

    如果初始代码是ast.literal_eval('1+1')(例如),那么现在node_or_string 将是BinOp 的一个实例。但在以下情况下:

    code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
    ast.literal_eval(code)
    

    主体将是Call 的一个实例,它不会出现在函数的有效类型中。

    例如:

    import ast
    
    code_nocall = "1+1"
    node = ast.parse(code_nocall, mode='eval')
    body = node.body
    print(type(body)) # Returns <class '_ast.BinOp'>
    
    code_call = "print('hello')"
    node = ast.parse(code_call, mode='eval')
    body = node.body
    print(type(body)) # Returns <class '_ast.Call'>
    

    解决方案

    到目前为止,我发现的最好的解决方案是不直接使用eval,而是手动执行该过程。使用此功能:

    import ast
    
    def eval_code(code):
        parsed = ast.parse(code, mode='eval')
        fixed = ast.fix_missing_locations(parsed)
        compiled = compile(fixed, '<string>', 'eval')
        eval(compiled)
    

    现在可以了:

    eval_code("print('hello world')")
    
    from keras.models import Sequential
    from keras.layers import Dense
    model = Sequential()
    code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
    eval_code(code)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 2020-10-10
      • 1970-01-01
      • 2015-12-18
      • 2021-03-25
      • 1970-01-01
      相关资源
      最近更新 更多