【问题标题】:call method in custom keras layers not covered in pytestpytest 未涵盖的自定义 keras 层中的调用方法
【发布时间】:2022-01-06 22:14:52
【问题描述】:

我正在尝试对使用自定义层的 keras 神经网络进行单元测试。当我尝试通过 pytest 和覆盖率运行它时,它指出 call 方法中的所有代码都没有被覆盖。

我不知道这是否是由于 pytest 将模型传递给单元测试的方式的特殊性,或者我的神经网络中确实没有使用 call 方法,因此出现了问题。

下面是一些示例代码:

示例神经网络

class Linear(keras.layers.Layer):
    def __init__(self, units=32, input_dim=32):
        super(Linear, self).__init__()
        self.w = self.add_weight(
            shape=(input_dim, units), initializer="random_normal", trainable=True
        )
        self.b = self.add_weight(shape=(units,), initializer="zeros", trainable=True)

def call(self, inputs):
    return tf.matmul(inputs, self.w) + self.b

def build_keras_model():
    
    inputs = keras.layers.Input(shape = (32,))
    x = Linear()(inputs)
    outputs = keras.layers.Dense(1)(x)
    
    model = keras.Model(inputs, outputs)
    return model

示例 PyTest 文件

from model import build_keras_model
import pytest
import numpy as np

def test_keras_model():
    model = build_keras_model()
    
    X = np.random.normal(size = (100, 32))
    y = np.random.normal(size = 100)[:, None]
    
    model.compile(loss = 'mae')
    
    model.fit(X, y, epochs = 1)
    
    assert model.predict(X).shape == (100, 1)

如果我在其自己的目录中使用coverage run -m pytest 和coverage report -m 测试此代码,则它显示call 方法内的行未被覆盖。

是 pytest、keras 还是我的设置方式有问题?

【问题讨论】:

  • 没有回答您的问题,但我注意到您在运行测试时正在训练模型。我已经完成了一些测试 ML 模型的工作,我建议 build_keras_model 应该保存模型。然后在您的测试中,您将加载保存的模型并测试输出形状是否正确。你目前的做法会导致你的测试很慢。

标签: python tensorflow keras pytest


【解决方案1】:

我认为如果你打算有 100% 的测试覆盖率,你必须显式调用 model 的 __call__() 方法。有趣的是,model.predict 似乎没有这样做(至少,不是在您需要的抽象级别。它在内部也使用相同的方法)。试试这个:

%%file test_keras.py
import pytest
import numpy as np
import tensorflow as tf

class Linear(tf.keras.layers.Layer):
    def __init__(self, units=32, input_dim=32):
        super(Linear, self).__init__()
        self.w = self.add_weight(
            shape=(input_dim, units), initializer="random_normal", trainable=True
        )
        self.b = self.add_weight(shape=(units,), initializer="zeros", trainable=True)

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

def build_keras_model():
    
    inputs = tf.keras.layers.Input(shape = (32,))
    x = Linear()(inputs)
    outputs = tf.keras.layers.Dense(1)(x)
    
    model = tf.keras.Model(inputs, outputs)
    return model

def test_keras_model():
    model = build_keras_model()
    
    X = np.random.normal(size = (100, 32))
    y = np.random.normal(size = 100)[:, None]
    
    model.compile(loss = 'mae')
    
    model.fit(X, y, epochs = 1)
    
    assert model(X).shape == (100, 1)
!coverage run -m pytest
============================= test session starts ==============================
platform linux -- Python 3.7.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /content
plugins: cov-3.0.0, typeguard-2.7.1
collected 1 item                                                               

test_keras.py .                                                          [100%]

============================== 1 passed in 6.46s ===============================
!coverage report -m /content/test_keras.py
Name            Stmts   Miss  Cover   Missing
---------------------------------------------
test_keras.py      23      0   100%
---------------------------------------------
TOTAL              23      0   100%

检查此postcall 方法与predict 方法与this 之间的区别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多