Coverage Report

Created: 2019-07-03 22:50

/home/liu/buildslave/linux-x64-runtests/build/test/unit/nnc/while.backward.tests.c
Line
Count
Source
1
#include "case.h"
2
#include "ccv_case.h"
3
#include "ccv_nnc_case.h"
4
#include <ccv.h>
5
#include <nnc/ccv_nnc.h>
6
#include <nnc/ccv_nnc_easy.h>
7
#include <nnc/_ccv_nnc_graph.h>
8
#include <3rdparty/dsfmt/dSFMT.h>
9
10
TEST_SETUP()
11
{
12
  ccv_nnc_init();
13
}
14
15
static int while_4(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data)
16
15
{
17
15
  return inputs[0]->data.i64[0] < 4;
18
15
}
19
20
TEST_CASE("graph with a while loop to compute back propagation 0.34 * 1.11 ^ 5")
21
1
{
22
1
  ccv_nnc_graph_t* graph = ccv_nnc_graph_new();
23
1
  ccv_nnc_tensor_t* y = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
24
1
  ccv_nnc_tensor_t* x0 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
25
1
  ccv_nnc_tensor_t* x = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
26
1
  x->type |= CCV_TAPE_ALLOC;
27
1
  ccv_nnc_tensor_t* z = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
28
1
  z->type |= CCV_TAPE_ALLOC;
29
1
  ccv_nnc_tensor_t* g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
30
1
  ccv_nnc_graph_t* while_graph = ccv_nnc_graph_new();
31
1
  ccv_nnc_graph_exec_t loop = ccv_nnc_graph_while(graph, CCV_NNC_GRAPH_FORWARD, while_graph);
32
1
  ccv_nnc_tensor_multiview_t xx;
33
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
34
1
      x0, z, x
35
1
  }, CCV_NNC_MULTIVIEW_K1N, 2, while_graph, &xx);
36
1
  xx.type |= CCV_TAPE_ALLOC;
37
1
  ccv_nnc_tensor_multiview_t zz;
38
1
  ccv_nnc_tensor_multiview((ccv_nnc_tensor_t*[]){
39
1
      z, x
40
1
  }, CCV_NNC_MULTIVIEW_K0N, 2, while_graph, &zz);
41
1
  zz.type |= CCV_TAPE_ALLOC;
42
1
  ccv_nnc_graph_exec_t prod0 = ccv_nnc_graph_exec_new(while_graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, TENSOR_LIST(y, (ccv_nnc_tensor_t*)&xx), TENSOR_LIST((ccv_nnc_tensor_t*)&zz));
43
1
  ccv_nnc_graph_exec_t noop = ccv_nnc_graph_exec_new(while_graph, CMD_NOOP(), ccv_nnc_no_hint, 0, 0, 0, 0);
44
1
  ccv_nnc_graph_exec_concat(while_graph, prod0, noop);
45
1
  ccv_nnc_graph_set_sources(while_graph, GRAPH_EXEC_LIST(prod0));
46
1
  ccv_nnc_graph_set_destinations(while_graph, GRAPH_EXEC_LIST(noop));
47
1
  ccv_nnc_tensor_t count_tensor = ccv_nnc_tensor_for_while_count(while_graph);
48
1
  ccv_nnc_graph_set_while_expr(while_graph, while_4, 0, TENSOR_LIST(&count_tensor), GRAPH_EXEC_LIST(noop));
49
1
  ccv_nnc_graph_t* while_back_graph = ccv_nnc_graph_new();
50
1
  while_back_graph->peer = while_graph;
51
1
  ccv_nnc_graph_exec_t back_loop = ccv_nnc_graph_while(graph, CCV_NNC_GRAPH_BACKWARD, while_back_graph);
52
1
  ccv_nnc_tensor_t* dx = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
53
1
  ccv_nnc_graph_exec_t back_prod0 = ccv_nnc_graph_exec_new(while_back_graph, CMD_EWPROD_BACKWARD(), ccv_nnc_no_hint, TENSOR_LIST(g, y, (ccv_nnc_tensor_t*)&xx, (ccv_nnc_tensor_t*)&zz), TENSOR_LIST(dx, g));
54
1
  ccv_nnc_graph_exec_t back_noop = ccv_nnc_graph_exec_new(while_back_graph, CMD_NOOP(), ccv_nnc_no_hint, 0, 0, 0, 0);
55
1
  ccv_nnc_graph_exec_concat(while_back_graph, back_noop, back_prod0);
56
1
  ccv_nnc_graph_set_sources(while_back_graph, GRAPH_EXEC_LIST(back_noop));
57
1
  ccv_nnc_graph_set_destinations(while_back_graph, GRAPH_EXEC_LIST(back_prod0));
58
1
  ccv_nnc_graph_set_while_expr(while_back_graph, while_4, 0, 0, 0, GRAPH_EXEC_LIST(back_noop));
59
1
  ccv_nnc_graph_exec_concat(graph, loop, back_loop);
60
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
61
1
  x0->data.f32[0] = 0.34;
62
1
  y->data.f32[0] = 1.11;
63
1
  g->data.f32[0] = 1;
64
1
  ccv_nnc_tensor_tape_t* tape = ccv_nnc_tensor_tape_new();
65
1
  ccv_nnc_graph_run(graph, tape, 0, 0, GRAPH_EXEC_LIST(loop), GRAPH_EXEC_LIST(back_loop));
66
1
  ccv_nnc_graph_free(graph);
67
1
  REQUIRE_EQ_WITH_TOLERANCE(g->data.f32[0], 1.11 * 1.11 * 1.11 * 1.11 * 1.11, 1e-6, "back propagation of 0.34 * 1.11 ^ 5 should be 1.11 ^ 5");
68
1
  ccv_nnc_tensor_tape_free(tape);
69
1
  ccv_nnc_tensor_multiview_free(xx);
70
1
  ccv_nnc_tensor_multiview_free(zz);
71
1
  ccv_nnc_tensor_free(x0);
72
1
  ccv_nnc_tensor_free(dx);
73
1
  ccv_nnc_tensor_free(x);
74
1
  ccv_nnc_tensor_free(y);
75
1
  ccv_nnc_tensor_free(z);
76
1
  ccv_nnc_tensor_free(g);
77
1
}
78
79
TEST_CASE("symbolic graph with a while loop z = log(x * y) (x <- z) 5 times, then u = v * z, compute y'")
80
1
{
81
1
  ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
82
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
83
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
84
1
  ccv_nnc_symbolic_graph_t* while_graph = ccv_nnc_symbolic_graph_new();
85
1
  ccv_nnc_tensor_symbol_t xy = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "xy");
86
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z");
87
1
  ccv_nnc_tensor_symbol_t u = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "u");
88
1
  ccv_nnc_tensor_symbol_t v = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "v");
89
1
  ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while0");
90
1
  ccv_nnc_graph_exec_symbol_t prod0 = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(xy), "prod0");
91
1
  ccv_nnc_graph_exec_symbol_t log0 = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWLOG_FORWARD(), TENSOR_SYMBOL_LIST(xy), TENSOR_SYMBOL_LIST(z), "log0");
92
1
  ccv_nnc_graph_exec_symbol_autogen(while_graph, GRAPH_EXEC_SYMBOL_LIST(prod0, log0), 0);
93
1
  ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
94
1
  ccv_nnc_graph_exec_symbol_concat(while_graph, log0, noop);
95
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z, v), TENSOR_SYMBOL_LIST(u), "prod1");
96
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
97
1
  ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_4, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(noop));
98
1
  ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z, x)));
99
1
  ccv_nnc_symbolic_graph_set_sources(while_graph, GRAPH_EXEC_SYMBOL_LIST(prod0));
100
1
  ccv_nnc_symbolic_graph_set_destinations(while_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
101
1
  ccv_nnc_graph_t* graph = 0;
102
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
103
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
104
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, 0, 0, 0, 0, ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), ccv_nnc_symbolic_graph_destinations(symbolic_graph), ccv_nnc_symbolic_graph_destination_size(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
105
1
  ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
106
1
  ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
107
1
  ccv_nnc_tensor_t* v_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, v);
108
1
  x_tensor->data.f32[0] = 1;
109
1
  y_tensor->data.f32[0] = 3.2;
110
1
  v_tensor->data.f32[0] = 0.22;
111
1
  ccv_nnc_graph_run(graph, 0, 0, 0, TRAVERSE_FULL);
112
1
  ccv_nnc_tensor_t* u_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, u);
113
1
  float z0 = 1, y0 = 3.2;
114
1
  int i;
115
6
  for (i = 0; i < 5; 
i++5
)
116
5
    z0 = log(z0 * y0);
117
1
  z0 = 0.22 * z0;
118
1
  REQUIRE_EQ_WITH_TOLERANCE(u_tensor->data.f32[0], z0, 1e-6, "u should match the for loop result");
119
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
120
1
  ccv_nnc_tensor_arena_free(tensor_arena);
121
1
  ccv_nnc_graph_free(graph);
122
1
  ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(u), TENSOR_SYMBOL_LIST(y), ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), ccv_nnc_symbolic_graph_destinations(symbolic_graph), ccv_nnc_symbolic_graph_destination_size(symbolic_graph));
123
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
124
1
  ccv_nnc_tensor_symbol_t dy = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, y);
125
1
  ccv_nnc_graph_exec_symbol_t dyx = ccv_nnc_graph_exec_symbol_for_backward(symbolic_graph, dy);
126
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, 0, 0, 0, 0, ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), &dyx, 1, &graph, &tensor_arena, &graph_exec_arena);
127
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
128
1
  x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
129
1
  y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y);
130
1
  v_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, v);
131
1
  x_tensor->data.f32[0] = 1;
132
1
  y_tensor->data.f32[0] = 3.2;
133
1
  v_tensor->data.f32[0] = 0.22;
134
1
  ccv_nnc_tensor_t* du_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, ccv_nnc_tensor_symbol_for_backward(symbolic_graph, u));
135
1
  du_tensor->data.f32[0] = 1;
136
1
  ccv_nnc_tensor_tape_t* tape = ccv_nnc_tensor_tape_new();
137
1
  ccv_nnc_graph_run(graph, tape, 0, 0, TRAVERSE_FULL);
138
1
  ccv_nnc_tensor_t* dy_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, dy);
139
1
  // Effectively, we are computing:
140
1
  // D[Log[Log[Log[Log[Log[x * y] * y] * y] * y] * y] * v, y]
141
1
  // From WolframAlpha: http://www.wolframalpha.com/input/?i=D%5BLog%5BLog%5BLog%5BLog%5BLog%5Bx+*+y%5D+*+y%5D+*+y%5D+*+y%5D+*+y%5D+*+v,+y%5D 
142
1
  const float dya = 0.22 * (((1 / log(1 * 3.2) + 1) / (log(3.2 * log(1 * 3.2)) * log(3.2 * log(3.2 * log(1 * 3.2)))) + 1 / log(3.2 * log(3.2 * log(1 * 3.2))) + 1) / (3.2 * log(3.2 * log(3.2 * log(3.2 * log(1 * 3.2))))) + 1 / 3.2);
143
1
  REQUIRE_EQ_WITH_TOLERANCE(dy_tensor->data.f32[0], dya, 1e-6, "back propagation of this while loop should match WolframAlpha result");
144
1
  ccv_nnc_tensor_tape_free(tape);
145
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
146
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
147
1
  ccv_nnc_tensor_arena_free(tensor_arena);
148
1
  ccv_nnc_graph_free(graph);
149
1
}
150
151
#include "case_main.h"