QuizGenerator 0.4.2__py3-none-any.whl → 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- QuizGenerator/contentast.py +809 -117
- QuizGenerator/generate.py +219 -11
- QuizGenerator/misc.py +0 -556
- QuizGenerator/mixins.py +50 -29
- QuizGenerator/premade_questions/basic.py +3 -3
- QuizGenerator/premade_questions/cst334/languages.py +183 -175
- QuizGenerator/premade_questions/cst334/math_questions.py +81 -70
- QuizGenerator/premade_questions/cst334/memory_questions.py +262 -165
- QuizGenerator/premade_questions/cst334/persistence_questions.py +83 -60
- QuizGenerator/premade_questions/cst334/process.py +558 -79
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_calculation.py +39 -13
- QuizGenerator/premade_questions/cst463/gradient_descent/gradient_descent_questions.py +61 -36
- QuizGenerator/premade_questions/cst463/gradient_descent/loss_calculations.py +29 -10
- QuizGenerator/premade_questions/cst463/gradient_descent/misc.py +2 -2
- QuizGenerator/premade_questions/cst463/math_and_data/matrix_questions.py +60 -43
- QuizGenerator/premade_questions/cst463/math_and_data/vector_questions.py +173 -326
- QuizGenerator/premade_questions/cst463/models/attention.py +29 -14
- QuizGenerator/premade_questions/cst463/models/cnns.py +32 -20
- QuizGenerator/premade_questions/cst463/models/rnns.py +28 -15
- QuizGenerator/premade_questions/cst463/models/text.py +29 -15
- QuizGenerator/premade_questions/cst463/models/weight_counting.py +38 -30
- QuizGenerator/premade_questions/cst463/neural-network-basics/neural_network_questions.py +91 -111
- QuizGenerator/premade_questions/cst463/tensorflow-intro/tensorflow_questions.py +128 -55
- QuizGenerator/question.py +114 -20
- QuizGenerator/quiz.py +81 -24
- QuizGenerator/regenerate.py +98 -29
- {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/METADATA +1 -1
- {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/RECORD +31 -33
- QuizGenerator/README.md +0 -5
- QuizGenerator/logging.yaml +0 -55
- {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/WHEEL +0 -0
- {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/entry_points.txt +0 -0
- {quizgenerator-0.4.2.dist-info → quizgenerator-0.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,10 +3,10 @@ import logging
|
|
|
3
3
|
import math
|
|
4
4
|
import keras
|
|
5
5
|
import numpy as np
|
|
6
|
+
from typing import List, Tuple
|
|
6
7
|
|
|
7
|
-
from QuizGenerator.
|
|
8
|
-
from QuizGenerator.
|
|
9
|
-
from QuizGenerator.contentast import ContentAST
|
|
8
|
+
from QuizGenerator.question import Question, QuestionRegistry
|
|
9
|
+
from QuizGenerator.contentast import ContentAST, AnswerTypes
|
|
10
10
|
from QuizGenerator.constants import MathRanges
|
|
11
11
|
from QuizGenerator.mixins import TableQuestionMixin
|
|
12
12
|
|
|
@@ -60,15 +60,17 @@ class AttentionForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
60
60
|
|
|
61
61
|
## Answers:
|
|
62
62
|
# Q, K, V, output, weights
|
|
63
|
-
|
|
64
|
-
self.answers["weights"] =
|
|
65
|
-
self.answers["output"] =
|
|
63
|
+
|
|
64
|
+
self.answers["weights"] = AnswerTypes.Matrix(self.weights, label="Weights")
|
|
65
|
+
self.answers["output"] = AnswerTypes.Matrix(self.output, label="Output")
|
|
66
66
|
|
|
67
67
|
return True
|
|
68
68
|
|
|
69
|
-
def
|
|
69
|
+
def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
70
|
+
"""Build question body and collect answers."""
|
|
70
71
|
body = ContentAST.Section()
|
|
71
|
-
|
|
72
|
+
answers = []
|
|
73
|
+
|
|
72
74
|
body.add_element(
|
|
73
75
|
ContentAST.Text("Given the below information about a self attention layer, please calculate the output sequence.")
|
|
74
76
|
)
|
|
@@ -81,19 +83,27 @@ class AttentionForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
81
83
|
}
|
|
82
84
|
)
|
|
83
85
|
)
|
|
84
|
-
|
|
86
|
+
|
|
87
|
+
answers.append(self.answers["weights"])
|
|
88
|
+
answers.append(self.answers["output"])
|
|
85
89
|
body.add_elements([
|
|
86
90
|
ContentAST.LineBreak(),
|
|
87
|
-
self.answers["weights"]
|
|
91
|
+
self.answers["weights"],
|
|
88
92
|
ContentAST.LineBreak(),
|
|
89
|
-
self.answers["output"]
|
|
93
|
+
self.answers["output"],
|
|
90
94
|
])
|
|
91
|
-
|
|
95
|
+
|
|
96
|
+
return body, answers
|
|
97
|
+
|
|
98
|
+
def get_body(self, **kwargs) -> ContentAST.Section:
|
|
99
|
+
"""Build question body (backward compatible interface)."""
|
|
100
|
+
body, _ = self._get_body(**kwargs)
|
|
92
101
|
return body
|
|
93
102
|
|
|
94
|
-
def
|
|
103
|
+
def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
104
|
+
"""Build question explanation."""
|
|
95
105
|
explanation = ContentAST.Section()
|
|
96
|
-
digits = Answer.DEFAULT_ROUNDING_DIGITS
|
|
106
|
+
digits = ContentAST.Answer.DEFAULT_ROUNDING_DIGITS
|
|
97
107
|
|
|
98
108
|
explanation.add_element(
|
|
99
109
|
ContentAST.Paragraph([
|
|
@@ -188,5 +198,10 @@ class AttentionForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
188
198
|
)
|
|
189
199
|
explanation.add_element(ContentAST.Matrix(np.round(self.output, digits)))
|
|
190
200
|
|
|
201
|
+
return explanation, []
|
|
202
|
+
|
|
203
|
+
def get_explanation(self, **kwargs) -> ContentAST.Section:
|
|
204
|
+
"""Build question explanation (backward compatible interface)."""
|
|
205
|
+
explanation, _ = self._get_explanation(**kwargs)
|
|
191
206
|
return explanation
|
|
192
207
|
|
|
@@ -3,10 +3,10 @@ import logging
|
|
|
3
3
|
import math
|
|
4
4
|
import keras
|
|
5
5
|
import numpy as np
|
|
6
|
+
from typing import List, Tuple
|
|
6
7
|
|
|
7
8
|
from QuizGenerator.question import Question, QuestionRegistry
|
|
8
|
-
from QuizGenerator.
|
|
9
|
-
from QuizGenerator.contentast import ContentAST
|
|
9
|
+
from QuizGenerator.contentast import ContentAST, AnswerTypes
|
|
10
10
|
from QuizGenerator.constants import MathRanges
|
|
11
11
|
from .matrices import MatrixQuestion
|
|
12
12
|
|
|
@@ -65,22 +65,24 @@ class ConvolutionCalculation(MatrixQuestion):
|
|
|
65
65
|
self.result = self.conv2d_multi_channel(self.image, self.kernel, stride=self.stride, padding=self.padding)
|
|
66
66
|
|
|
67
67
|
self.answers = {
|
|
68
|
-
f"result_{i}" :
|
|
68
|
+
f"result_{i}" : AnswerTypes.Matrix(self.result[:,:,i], label=f"Result of filter {i}")
|
|
69
69
|
for i in range(self.result.shape[-1])
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
return True
|
|
73
73
|
|
|
74
|
-
def
|
|
74
|
+
def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
75
|
+
"""Build question body and collect answers."""
|
|
75
76
|
body = ContentAST.Section()
|
|
76
|
-
|
|
77
|
+
answers = []
|
|
78
|
+
|
|
77
79
|
body.add_elements(
|
|
78
80
|
[
|
|
79
81
|
ContentAST.Text("Given image represented as matrix: "),
|
|
80
82
|
ContentAST.Matrix(self.image, name="image")
|
|
81
83
|
]
|
|
82
84
|
)
|
|
83
|
-
|
|
85
|
+
|
|
84
86
|
body.add_elements(
|
|
85
87
|
[
|
|
86
88
|
ContentAST.Text("And convolution filters: "),
|
|
@@ -89,7 +91,7 @@ class ConvolutionCalculation(MatrixQuestion):
|
|
|
89
91
|
for i in range(self.kernel.shape[-1])
|
|
90
92
|
]
|
|
91
93
|
)
|
|
92
|
-
|
|
94
|
+
|
|
93
95
|
body.add_element(
|
|
94
96
|
ContentAST.Paragraph(
|
|
95
97
|
[
|
|
@@ -97,24 +99,29 @@ class ConvolutionCalculation(MatrixQuestion):
|
|
|
97
99
|
]
|
|
98
100
|
)
|
|
99
101
|
)
|
|
100
|
-
|
|
102
|
+
|
|
101
103
|
body.add_element(ContentAST.LineBreak())
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
ContentAST.
|
|
104
|
+
|
|
105
|
+
for i in range(self.result.shape[-1]):
|
|
106
|
+
answers.append(self.answers[f"result_{i}"])
|
|
107
|
+
body.add_elements([
|
|
108
|
+
ContentAST.Container([
|
|
109
|
+
self.answers[f"result_{i}"],
|
|
110
|
+
ContentAST.LineBreak()
|
|
111
|
+
])
|
|
107
112
|
])
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
|
|
114
|
+
return body, answers
|
|
115
|
+
|
|
116
|
+
def get_body(self, **kwargs) -> ContentAST.Section:
|
|
117
|
+
"""Build question body (backward compatible interface)."""
|
|
118
|
+
body, _ = self._get_body(**kwargs)
|
|
113
119
|
return body
|
|
114
120
|
|
|
115
|
-
def
|
|
121
|
+
def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
122
|
+
"""Build question explanation."""
|
|
116
123
|
explanation = ContentAST.Section()
|
|
117
|
-
digits = Answer.DEFAULT_ROUNDING_DIGITS
|
|
124
|
+
digits = ContentAST.Answer.DEFAULT_ROUNDING_DIGITS
|
|
118
125
|
|
|
119
126
|
explanation.add_element(
|
|
120
127
|
ContentAST.Paragraph([
|
|
@@ -183,4 +190,9 @@ class ConvolutionCalculation(MatrixQuestion):
|
|
|
183
190
|
ContentAST.Matrix(np.round(self.result[:, :, f_idx], digits))
|
|
184
191
|
)
|
|
185
192
|
|
|
193
|
+
return explanation, []
|
|
194
|
+
|
|
195
|
+
def get_explanation(self, **kwargs) -> ContentAST.Section:
|
|
196
|
+
"""Build question explanation (backward compatible interface)."""
|
|
197
|
+
explanation, _ = self._get_explanation(**kwargs)
|
|
186
198
|
return explanation
|
|
@@ -3,10 +3,11 @@ import logging
|
|
|
3
3
|
import math
|
|
4
4
|
import keras
|
|
5
5
|
import numpy as np
|
|
6
|
+
from typing import List, Tuple
|
|
6
7
|
|
|
7
8
|
from .matrices import MatrixQuestion
|
|
8
|
-
from QuizGenerator.question import Question, QuestionRegistry
|
|
9
|
-
from QuizGenerator.contentast import ContentAST
|
|
9
|
+
from QuizGenerator.question import Question, QuestionRegistry
|
|
10
|
+
from QuizGenerator.contentast import ContentAST, AnswerTypes
|
|
10
11
|
from QuizGenerator.constants import MathRanges
|
|
11
12
|
from QuizGenerator.mixins import TableQuestionMixin
|
|
12
13
|
|
|
@@ -63,13 +64,15 @@ class RNNForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
63
64
|
## Answers:
|
|
64
65
|
# x_seq, W_xh, W_hh, b_h, h_0, h_states
|
|
65
66
|
|
|
66
|
-
self.answers["output_sequence"] =
|
|
67
|
+
self.answers["output_sequence"] = AnswerTypes.Matrix(value=self.h_states, label="Hidden states")
|
|
67
68
|
|
|
68
69
|
return True
|
|
69
70
|
|
|
70
|
-
def
|
|
71
|
+
def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
72
|
+
"""Build question body and collect answers."""
|
|
71
73
|
body = ContentAST.Section()
|
|
72
|
-
|
|
74
|
+
answers = []
|
|
75
|
+
|
|
73
76
|
body.add_element(
|
|
74
77
|
ContentAST.Paragraph([
|
|
75
78
|
ContentAST.Text("Given the below information about an RNN, please calculate the output sequence."),
|
|
@@ -87,22 +90,27 @@ class RNNForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
87
90
|
}
|
|
88
91
|
)
|
|
89
92
|
)
|
|
90
|
-
|
|
93
|
+
|
|
91
94
|
body.add_element(ContentAST.LineBreak())
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
|
|
96
|
+
answers.append(self.answers["output_sequence"])
|
|
97
|
+
body.add_element(self.answers["output_sequence"])
|
|
98
|
+
|
|
99
|
+
return body, answers
|
|
100
|
+
|
|
101
|
+
def get_body(self, **kwargs) -> ContentAST.Section:
|
|
102
|
+
"""Build question body (backward compatible interface)."""
|
|
103
|
+
body, _ = self._get_body(**kwargs)
|
|
97
104
|
return body
|
|
98
105
|
|
|
99
|
-
def
|
|
106
|
+
def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
107
|
+
"""Build question explanation."""
|
|
100
108
|
explanation = ContentAST.Section()
|
|
101
|
-
digits = Answer.DEFAULT_ROUNDING_DIGITS
|
|
109
|
+
digits = ContentAST.Answer.DEFAULT_ROUNDING_DIGITS
|
|
102
110
|
|
|
103
111
|
explanation.add_element(
|
|
104
112
|
ContentAST.Paragraph([
|
|
105
|
-
|
|
113
|
+
"For an RNN forward pass, we compute the hidden state at each time step using:"
|
|
106
114
|
])
|
|
107
115
|
)
|
|
108
116
|
|
|
@@ -128,7 +136,7 @@ class RNNForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
128
136
|
# Show detailed examples for first 2 timesteps (or just 1 if seq_len == 1)
|
|
129
137
|
seq_len = len(self.x_seq)
|
|
130
138
|
num_examples = min(2, seq_len)
|
|
131
|
-
|
|
139
|
+
|
|
132
140
|
explanation.add_element(ContentAST.Paragraph([""]))
|
|
133
141
|
|
|
134
142
|
for t in range(num_examples):
|
|
@@ -198,5 +206,10 @@ class RNNForwardPass(MatrixQuestion, TableQuestionMixin):
|
|
|
198
206
|
ContentAST.Matrix(np.round(self.h_states, digits))
|
|
199
207
|
)
|
|
200
208
|
|
|
209
|
+
return explanation, []
|
|
210
|
+
|
|
211
|
+
def get_explanation(self, **kwargs) -> ContentAST.Section:
|
|
212
|
+
"""Build question explanation (backward compatible interface)."""
|
|
213
|
+
explanation, _ = self._get_explanation(**kwargs)
|
|
201
214
|
return explanation
|
|
202
215
|
|
|
@@ -3,11 +3,11 @@ import logging
|
|
|
3
3
|
import math
|
|
4
4
|
import keras
|
|
5
5
|
import numpy as np
|
|
6
|
+
from typing import List, Tuple
|
|
6
7
|
|
|
7
|
-
from QuizGenerator.misc import MatrixAnswer
|
|
8
8
|
from QuizGenerator.premade_questions.cst463.models.matrices import MatrixQuestion
|
|
9
|
-
from QuizGenerator.question import Question, QuestionRegistry
|
|
10
|
-
from QuizGenerator.contentast import ContentAST
|
|
9
|
+
from QuizGenerator.question import Question, QuestionRegistry
|
|
10
|
+
from QuizGenerator.contentast import ContentAST, AnswerTypes
|
|
11
11
|
from QuizGenerator.constants import MathRanges
|
|
12
12
|
from QuizGenerator.mixins import TableQuestionMixin
|
|
13
13
|
|
|
@@ -59,17 +59,19 @@ class word2vec__skipgram(MatrixQuestion, TableQuestionMixin):
|
|
|
59
59
|
|
|
60
60
|
## Answers:
|
|
61
61
|
# center_word, center_emb, context_words, context_embs, logits, probs
|
|
62
|
-
self.answers["logits"] =
|
|
62
|
+
self.answers["logits"] = AnswerTypes.Vector(self.logits, label="Logits")
|
|
63
63
|
most_likely_idx = np.argmax(self.probs)
|
|
64
64
|
most_likely_word = self.context_words[most_likely_idx]
|
|
65
|
-
self.answers["center_word"] =
|
|
65
|
+
self.answers["center_word"] = AnswerTypes.String(most_likely_word, label="Most likely context word")
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
return True
|
|
69
69
|
|
|
70
|
-
def
|
|
70
|
+
def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
71
|
+
"""Build question body and collect answers."""
|
|
71
72
|
body = ContentAST.Section()
|
|
72
|
-
|
|
73
|
+
answers = []
|
|
74
|
+
|
|
73
75
|
body.add_element(
|
|
74
76
|
ContentAST.Paragraph([
|
|
75
77
|
f"Given center word: `{self.center_word}` with embedding {self.center_emb}, compute the skip-gram probabilities for each context word and identify the most likely one."
|
|
@@ -78,23 +80,30 @@ class word2vec__skipgram(MatrixQuestion, TableQuestionMixin):
|
|
|
78
80
|
body.add_elements([
|
|
79
81
|
ContentAST.Paragraph([ContentAST.Text(f"`{w}` : "), str(e)]) for w, e in zip(self.context_words, self.context_embs)
|
|
80
82
|
])
|
|
81
|
-
|
|
83
|
+
|
|
84
|
+
answers.append(self.answers["logits"])
|
|
85
|
+
answers.append(self.answers["center_word"])
|
|
82
86
|
body.add_elements([
|
|
83
87
|
ContentAST.LineBreak(),
|
|
84
|
-
self.answers["logits"]
|
|
88
|
+
self.answers["logits"],
|
|
85
89
|
ContentAST.LineBreak(),
|
|
86
|
-
self.answers["center_word"]
|
|
90
|
+
self.answers["center_word"]
|
|
87
91
|
])
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
|
|
90
93
|
log.debug(f"output: {self.logits}")
|
|
91
94
|
log.debug(f"weights: {self.probs}")
|
|
92
|
-
|
|
95
|
+
|
|
96
|
+
return body, answers
|
|
97
|
+
|
|
98
|
+
def get_body(self, **kwargs) -> ContentAST.Section:
|
|
99
|
+
"""Build question body (backward compatible interface)."""
|
|
100
|
+
body, _ = self._get_body(**kwargs)
|
|
93
101
|
return body
|
|
94
102
|
|
|
95
|
-
def
|
|
103
|
+
def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
104
|
+
"""Build question explanation."""
|
|
96
105
|
explanation = ContentAST.Section()
|
|
97
|
-
digits = Answer.DEFAULT_ROUNDING_DIGITS
|
|
106
|
+
digits = ContentAST.Answer.DEFAULT_ROUNDING_DIGITS
|
|
98
107
|
|
|
99
108
|
explanation.add_element(
|
|
100
109
|
ContentAST.Paragraph([
|
|
@@ -199,5 +208,10 @@ class word2vec__skipgram(MatrixQuestion, TableQuestionMixin):
|
|
|
199
208
|
])
|
|
200
209
|
)
|
|
201
210
|
|
|
211
|
+
return explanation, []
|
|
212
|
+
|
|
213
|
+
def get_explanation(self, **kwargs) -> ContentAST.Section:
|
|
214
|
+
"""Build question explanation (backward compatible interface)."""
|
|
215
|
+
explanation, _ = self._get_explanation(**kwargs)
|
|
202
216
|
return explanation
|
|
203
217
|
|
|
@@ -3,9 +3,10 @@ import logging
|
|
|
3
3
|
import math
|
|
4
4
|
import keras
|
|
5
5
|
import numpy as np
|
|
6
|
+
from typing import List, Tuple
|
|
6
7
|
|
|
7
|
-
from QuizGenerator.question import Question, QuestionRegistry
|
|
8
|
-
from QuizGenerator.contentast import ContentAST
|
|
8
|
+
from QuizGenerator.question import Question, QuestionRegistry
|
|
9
|
+
from QuizGenerator.contentast import ContentAST, AnswerTypes
|
|
9
10
|
from QuizGenerator.constants import MathRanges
|
|
10
11
|
|
|
11
12
|
log = logging.getLogger(__name__)
|
|
@@ -84,16 +85,15 @@ class WeightCounting(Question, abc.ABC):
|
|
|
84
85
|
continue
|
|
85
86
|
|
|
86
87
|
self.num_parameters = self.model.count_params()
|
|
87
|
-
self.answers["num_parameters"] =
|
|
88
|
-
"num_parameters",
|
|
89
|
-
self.num_parameters
|
|
90
|
-
)
|
|
88
|
+
self.answers["num_parameters"] = AnswerTypes.Int(self.num_parameters, label="Number of Parameters")
|
|
91
89
|
|
|
92
90
|
return True
|
|
93
91
|
|
|
94
|
-
def
|
|
92
|
+
def _get_body(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
93
|
+
"""Build question body and collect answers."""
|
|
95
94
|
body = ContentAST.Section()
|
|
96
|
-
|
|
95
|
+
answers = []
|
|
96
|
+
|
|
97
97
|
body.add_element(
|
|
98
98
|
ContentAST.Paragraph(
|
|
99
99
|
[
|
|
@@ -101,7 +101,7 @@ class WeightCounting(Question, abc.ABC):
|
|
|
101
101
|
]
|
|
102
102
|
)
|
|
103
103
|
)
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
body.add_element(
|
|
106
106
|
ContentAST.Code(
|
|
107
107
|
self.model_to_python(
|
|
@@ -110,18 +110,23 @@ class WeightCounting(Question, abc.ABC):
|
|
|
110
110
|
)
|
|
111
111
|
)
|
|
112
112
|
)
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
body.add_element(ContentAST.LineBreak())
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
|
|
116
|
+
answers.append(self.answers["num_parameters"])
|
|
117
|
+
body.add_element(self.answers["num_parameters"])
|
|
118
|
+
|
|
119
|
+
return body, answers
|
|
120
|
+
|
|
121
|
+
def get_body(self, **kwargs) -> ContentAST.Section:
|
|
122
|
+
"""Build question body (backward compatible interface)."""
|
|
123
|
+
body, _ = self._get_body(**kwargs)
|
|
120
124
|
return body
|
|
121
125
|
|
|
122
|
-
def
|
|
126
|
+
def _get_explanation(self, **kwargs) -> Tuple[ContentAST.Section, List[ContentAST.Answer]]:
|
|
127
|
+
"""Build question explanation."""
|
|
123
128
|
explanation = ContentAST.Section()
|
|
124
|
-
|
|
129
|
+
|
|
125
130
|
def markdown_summary(model) -> ContentAST.Table:
|
|
126
131
|
# Ensure the model is built by running build() or calling it once
|
|
127
132
|
if not model.built:
|
|
@@ -129,37 +134,42 @@ class WeightCounting(Question, abc.ABC):
|
|
|
129
134
|
model.build(model.input_shape)
|
|
130
135
|
except:
|
|
131
136
|
pass # Some subclassed models need real data to build
|
|
132
|
-
|
|
137
|
+
|
|
133
138
|
data = []
|
|
134
|
-
|
|
139
|
+
|
|
135
140
|
total_params = 0
|
|
136
|
-
|
|
141
|
+
|
|
137
142
|
for layer in model.layers:
|
|
138
143
|
name = layer.name
|
|
139
144
|
ltype = layer.__class__.__name__
|
|
140
|
-
|
|
145
|
+
|
|
141
146
|
# Try to extract output shape
|
|
142
147
|
try:
|
|
143
148
|
outshape = tuple(layer.output.shape)
|
|
144
149
|
except:
|
|
145
150
|
outshape = "?"
|
|
146
|
-
|
|
151
|
+
|
|
147
152
|
params = layer.count_params()
|
|
148
153
|
total_params += params
|
|
149
|
-
|
|
154
|
+
|
|
150
155
|
data.append([name, ltype, outshape, params])
|
|
151
|
-
|
|
156
|
+
|
|
152
157
|
data.append(["**Total**", "", "", f"**{total_params}**"])
|
|
153
158
|
return ContentAST.Table(data=data, headers=["Layer", "Type", "Output Shape", "Params"])
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
|
|
160
|
+
|
|
156
161
|
summary_lines = []
|
|
157
162
|
self.model.summary(print_fn=lambda x: summary_lines.append(x))
|
|
158
163
|
explanation.add_element(
|
|
159
164
|
# ContentAST.Text('\n'.join(summary_lines))
|
|
160
165
|
markdown_summary(self.model)
|
|
161
166
|
)
|
|
162
|
-
|
|
167
|
+
|
|
168
|
+
return explanation, []
|
|
169
|
+
|
|
170
|
+
def get_explanation(self, **kwargs) -> ContentAST.Section:
|
|
171
|
+
"""Build question explanation (backward compatible interface)."""
|
|
172
|
+
explanation, _ = self._get_explanation(**kwargs)
|
|
163
173
|
return explanation
|
|
164
174
|
|
|
165
175
|
|
|
@@ -222,6 +232,4 @@ class WeightCounting_RNN(WeightCounting):
|
|
|
222
232
|
return model, ["units", "return_sequences"]
|
|
223
233
|
|
|
224
234
|
|
|
225
|
-
|
|
226
|
-
class ConvolutionCalculation(Question):
|
|
227
|
-
pass
|
|
235
|
+
# ConvolutionCalculation is implemented in cnns.py
|