ゼロから作るDeep Learning 3 ステップ5~ステップ10 まとめ
hirohirohirohiros.hatenablog.com
ステップ7
assert
assert文は,条件を書いて条件がFalseの時例外を出します.プログラムの条件をテストする目的で使われます.if文で書くよりスマートに書けます.実際にテストしてみます.
A = Square() B = Exp() C = Square() x = Variable(np.array(0.5)) a = A(x) b = B(a) y = C(b) assert y.creator == C assert y.creator.input == b assert y.creator.input.creator == A >> Traceback (most recent call last): >> File "step1.py", line 64, in <module> >> assert y.creator.input.creator == A >> AssertionError
わざと間違っているassert文を用意しましたが,ちゃんとAssertionErrorと表示されました.ただし,以下のコードでは,
assert y.creator == C assert y.creator.input == b assert y.creator.input.creator == A assert y.creator.input.creator.input == b >>Traceback (most recent call last): >> File "step1.py", line 64, in <module> >> assert y.creator.input.creator == A >>AssertionError
assertの3行目と4行目が間違っていますが,エラーが出るところは3行目のみです(当たり前ですが).assertで例外が発生したとき,それ以降のassertはまだ確認出来ていないことに注意する必要があります.
ステップ9
0次元のndarrayの挙動
x = np.array(1) y = x*2 print(type(x), x) print(type(y), y) >> <class 'numpy.ndarray'> 1 >> <class 'numpy.int32'> 2
0次元のndarrayに演算を行うと型がndarrayから変わってしまいます.(そもそもndarrayに0次元を取れるということを初めて知った気がします)
np.isscalar
引数がスカラーの時Trueを返す関数がnp.isscalarです.今回のようにndarrayしか取りたくない場合の判定に使えそうです.
print(np.isscalar(1)) print(np.isscalar(np.float(2.0))) print(np.isscalar(np.array(1))) print(np.isscalar(np.array([1]))) print(np.isscalar("a")) >>True >>True >>False >>False >>True
文字列のような関係ない型でもTrueとなるのでそこは注意が必要そうです.
ステップ10
np.allclose
二つの値が一致しているかを判別するには==が用いられますが,floatの時は計算誤差がつきまとうので注意が要ります.
0.3*3 == 0.9 >> False
完全に一致しているのでは無く,ある程度の誤差は許容して一致しているかを判定するのがnp.iscloseです.
np.isclose(a, b)とすると,|a-b| <= atol + rtol*|b| が成り立つときTrueを返します.デフォルトではatol=10^-8, rtol=10^-5です.
これを使うと
np.isclose(0.3*3, 0.9) >> True
となり,誤差を許容して一致している事が確認出来ます.許容する誤差の程度はatol, rtolで調整するということです.
テスト
unittestという標準ライブラリを使う事でソフトウェアのテストが簡単にできます.
import unittest class SquareTest(unittest.TestCase): def test_forward(self): x = Variable(np.array(2.0)) y = square(x) expected = np.array(4.0) self.assertEqual(y.data, expected)
unittest.TestCaseを継承したクラスを作成し,テストしたい内容を書きます.その時メゾットの名前はtestで始まらないとテスト内容と認識しないので注意が必要です.
実行時は-m unittestという引数を取ることでテストモードになります.成功すると
---------------------------------------------------------------------- Ran 1 test in 0.001s OK
となり,失敗すると
self.assertEqual(y.data, expected) AssertionError: array(4.) != array(5.) ---------------------------------------------------------------------- Ran 1 test in 0.005s FAILED (failures=1)
となります.分かりやすいですね.
複数個テストするメゾットを用意しても問題ありません.全て成功すると
... ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
2つ失敗すると
FF. ====================================================================== FAIL: test_backward (test.SquareTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\Users\***\Desktop\self-dev\dezero\test.py", line 16, in test_backward self.assertEqual(y.data, expected) AssertionError: array(4.) != array(6.) ====================================================================== FAIL: test_forward (test.SquareTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\Users\***\Desktop\self-dev\dezero\test.py", line 9, in test_forward self.assertEqual(y.data, expected) AssertionError: array(4.) != array(5.) ---------------------------------------------------------------------- Ran 3 tests in 0.002s FAILED (failures=2)
となります.どこのテストケースで失敗したのかも分かります.
また,引数に-vを入れ,python -m unittest -v test.py とすることで,どのテストケースで失敗したのか冗長的に表示されます.
test_backward (test.SquareTest) ... FAIL test_forward (test.SquareTest) ... FAIL test_gradient_check (test.SquareTest) ... ok ...