深度学习-10-测试

深度学习-10-测试

本文是《深度学习入门2-自製框架》 的学习笔记,记录自己学习心得,以及对重点知识的理解。如果内容对你有帮助,请支持正版,去购买正版书籍,支持正版书籍不仅是尊重作者的辛勤劳动,也是鼓励更多优秀作品问世。

当前笔记内容主要为:步骤 10  测试 章节的相关理解。

书籍总共分为5个阶段,每个阶段分很多步骤,最终是一步一步实现一个深度学习框架。例如前两个阶段为:

第 1 阶段共包括 10 个步骤 。 在这个阶段,将创建自动微分的机制
第 2 阶段,从步骤11-24,该阶段的主要目标是扩展当前的 DeZero ,使它能够执行更复杂的计算 ,使它能 够处理接收多个输入的函数和返回多个输出的函数

1.Python 的单元测试

软件开发中测试必不可少,有时候测试都会占用项目流程中很大一段时间。为了保证项目质量,更是要求测试进行相关自动化,以便加速。而且分为sit uat 测试不同阶段,来保证投产质量。

不同的变成语言,有不同测试框架,例如java 里面有junit 框架支持。python 语言里面有 unittest 库来支持。 这里我们以unittest 库来说明。

编写代码

class SquareTest(unittest.TestCase):
    def test_forward(self):
        x = Variable(np.array(2.0))
        y = square(x)
        expected = np.array(4.0)
        self.assertEquals(y.data, expected)

执行命令运行测试:

python -m unittest step10.py


注意如果你用的是创建了虚拟venv ,则需要先激活此环境,然后再执行命令

查看输出结果:

(venv) PS C:\pyworkspace\Dezero> python -m unittest step10.py  
C:\pyworkspace\Dezero\step10.py:97: DeprecationWarning: Please use assertEqual instead.        
  self.assertEquals(y.data, expected)
.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK


我们可以看到测试通过了,并且有汇总信息。这个测试案例是测试-平方函数,我们知道 2的平方等于4 ,结果确实等于4。


2.square 函数反向传播的测试

对square 函数进行反向传播测试, 增加一下代码:

class SquareTest(unittest.TestCase):
    def test_forward(self):
        x = Variable(np.array(2.0))
        y = square(x)
        expected = np.array(4.0)
        self.assertEquals(y.data, expected)

    def test_backward(self):
        x = Variable(np.array(3.0))
        y = square(x)
        y.backward()
        expected = np.array(6.0)
        self.assertEquals(x.grad, expected)
        

其中 test_backward 函数是本次新加的代码        


查看测试结果:

(venv) PS C:\pyworkspace\Dezero>
(venv) PS C:\pyworkspace\Dezero> python -m unittest step10.py
C:\pyworkspace\Dezero\step10.py:104: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(x.grad, expected)                                                           
..                                                                    
----------------------------------------------------------------------
Ran 2 tests in 0.002s                                                 
                                                                      
OK                                                                    
(venv) PS C:\pyworkspace\Dezero> 

结果正向传播,反向传播的两个测试案例都通过了。y=x^2 的导函数是 y=2x 在x = 3.0 的时候,导函数的值为 2*3.0 = 6.0 正确。


3.通过梯度检验来自动测试

在上面的第二步骤中,我们是手动定义x = 3.0  并且我们手动求导发现导函数是 2x ,并且求得值是  6.0 ,这一步骤是否可以自动化呢?

这里引入一个方法:梯度检验 ,代替手动计算的测试方法。达到高效测试的目的。

# 求导公式计算任意函数倒数
def numberical_diff(f, x, eps= 13-4) :
    x0= Variable(x.data -eps)
    x1 = Variable(x.data + eps)
    y0 = f(x0)
    y1 = f(x1)

    return (y1.data -y0.data) /(2*eps)

class SquareTest(unittest.TestCase):
    def test_forward(self):
        x = Variable(np.array(2.0))
        y = square(x)
        expected = np.array(4.0)
        self.assertEquals(y.data, expected)

    def test_backward(self):
        x = Variable(np.array(3.0))
        y = square(x)
        y.backward()
        expected = np.array(6.0)
        self.assertEquals(x.grad, expected)

    def test_gradient(self):
        x = Variable(np.random.random(1))   # 随机生成x 值
        y = square(x)
        y.backward()
        num_grad = numberical_diff(square, x)
        flg = np.allclose(x.grad, num_grad)   #判断 ndarray 实例的a,b 值是否接近
                                            #如果 a 和 b 的所有元素满足以 下条件,则返回 True
        self.assertTrue(flg)


再次执行测试案例:

python -m unittest step10.py 

查看执行结果:

(venv) PS C:\pyworkspace\Dezero> python -m unittest step10.py
C:\pyworkspace\Dezero\step10.py:111: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(x.grad, expected)                                                           
...                                                                   
----------------------------------------------------------------------
Ran 3 tests in 0.002s                                                 
                                                                      
OK                                                                    
(venv) PS C:\pyworkspace\Dezero> 
4.本节所有代码
'''
step10.py
测试,使用unittest 库自动进行测试
'''

import numpy as np
import unittest

class Variable:
    def __init__(self, data):
        if data is not None:  # 新增
            if not isinstance(data, np.ndarray):
                raise TypeError('{} is not supported'.format(type(data)))
        self.data = data
        self.grad = None
        self.creator = None

    def set_creator(self, func):
        self.creator = func

    def backward(self):
        if self.grad is None:
            self.grad = np.ones_like(self.data)

        funcs = [self.creator]
        while funcs:
            f = funcs.pop()
            x, y = f.input, f.output
            x.grad = f.backward(y.grad)

            if x.creator is not None:
                funcs.append(x.creator)


class Function:
    def __call__(self, input):
        x = input.data
        y = self.forward(x)  # 新增
        output = Variable(as_array(y))  # 转成 ndarray 类型
        output.set_creator(self)  # 输出者保存创造者对象
        self.input = input
        self.output = output  # 保存输出者。我是创造者的信息,这是动态建立 "连接"这 一 机制的核心
        return output

    def forward(self, x):
        raise NotImplementedError()  # 使用Function  这个方法forward 方法的人 , 这个方法应该通过继承采实现

    def backward(self, gy):
        raise NotImplementedError()


class Square(Function):
    def forward(self, x):
        y = x ** 2
        return y

    def backward(self, gy):
        x = self.input.data
        gx = 2 * x * gy  # 方法的参数 gy 是 一个 ndarray 实例 , 它是从输出传播而来的导数 。
        return gx


class Exp(Function):
    def forward(self, x):
        y = np.exp(x)
        return y

    def backward(self, gy):
        x = self.input.data
        gx = np.exp(x) * gy
        return gx


def square(x):
    f = Square()
    return f(x)


def exp(x):
    f = Exp()
    return f(x)


def as_array(x):  # 新增
    if np.isscalar(x):  # 使用 np.isscalar 函数来检查 numpy.float64 等属于标量
        return np.array(x)
    return x


# 求导公式计算任意函数倒数
def numberical_diff(f, x, eps= 13-4) :
    x0= Variable(x.data -eps)
    x1 = Variable(x.data + eps)
    y0 = f(x0)
    y1 = f(x1)

    return (y1.data -y0.data) /(2*eps)

class SquareTest(unittest.TestCase):
    def test_forward(self):
        x = Variable(np.array(2.0))
        y = square(x)
        expected = np.array(4.0)
        self.assertEquals(y.data, expected)

    def test_backward(self):
        x = Variable(np.array(3.0))
        y = square(x)
        y.backward()
        expected = np.array(6.0)
        self.assertEquals(x.grad, expected)

    def test_gradient(self):
        x = Variable(np.random.random(1))
        y = square(x)
        y.backward()
        num_grad = numberical_diff(square, x)
        flg = np.allclose(x.grad, num_grad)   #判断 ndarray 实例的a,b 值是否接近
                                            #如果 a 和 b 的所有元素满足以 下条件,则返回 True
        self.assertTrue(flg)

if __name__ == '__main__':
    x = Variable(np.array(0.5))
    a = square(x)
    b = exp(a)
    y = square(b)

    y.grad = np.array(1.0)
    y.backward()
    print(x.grad)

    # 优化ones_like 初始化后
    # 不需要定义 y.grad = np.array(1.0) 这个了
    x = Variable(np.array(0.5))
    y = square(exp(square(x)))
    y.backward()
    print(x.grad)

    # 错误使用

    x = Variable(np.array(1.0))
    x = Variable(None)
    # x = Variable(1.0)  # 错误使用

    # Numpy 特性问题
    x = np.array([1.0])
    y = x ** 2
    print(type(x), x.ndim)

    print(type(y))

    x = np.array(1.0)
    y = x ** 2
    print(type(x), x.ndim)
    print(type(y))
5.测试小结

通过本节,可以学习如果使用 unittest 这个库进行代码测试。

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值