Skip to content

Commit 9b3fa90

Browse files
author
Valente Ramirez
committed
Implemented vectorization for total_cost computation.
The objective is to avoid looping through each individual example to compute the cost. In order to do this, we define a single matrix containing all the inputs for training/validation data. However, the ``accuracy`` function needs the non-vectorized results. Now, at the begining of ``SGD`` I save the data in both formats. Probably inefficient use of memory, but it should speed things up.
1 parent e8ae592 commit 9b3fa90

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

src/network2.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,26 @@ def SGD(self, training_data, epochs, mini_batch_size, eta,
144144
evaluation data at the end of each epoch. Note that the lists
145145
are empty if the corresponding flag is not set.
146146
"""
147-
training_data = list(training_data) # Check
147+
training_data = list(training_data)
148148
n = len(training_data)
149-
149+
training_inputs = np.column_stack([data[0] for data in training_data])
150+
training_results = np.column_stack([data[1] for data in training_data])
151+
150152
if evaluation_data:
151153
evaluation_data = list(evaluation_data)
152154
n_data = len(evaluation_data)
155+
evaluation_inputs = np.column_stack(
156+
[data[0] for data in evaluation_data])
157+
evaluation_results = np.column_stack(
158+
[vectorized_result(data[1]) for data in evaluation_data])
153159

154160
# early stopping functionality:
155161
best_accuracy = 0
156162
no_accuracy_change = 0
157163
if early_stopping_n > 0:
158164
monitor_evaluation_accuracy = True
159165

166+
# Main loop. Call to ``update_mini_batch``:
160167
evaluation_cost, evaluation_accuracy = [], []
161168
training_cost, training_accuracy = [], []
162169
for j in range(epochs): # Check: what if epochs doesn't divide n_test?
@@ -166,19 +173,20 @@ def SGD(self, training_data, epochs, mini_batch_size, eta,
166173
for k in range(0, n, mini_batch_size)]
167174
for mini_batch in mini_batches:
168175
self.update_mini_batch(
169-
mini_batch, eta, lmbda, len(training_data))
176+
mini_batch, eta, lmbda, n)
170177

178+
# End of epoch info:
171179
print("\nEpoch %s training complete" % j)
172180
if monitor_training_cost:
173-
cost = self.total_cost(training_data, lmbda)
181+
cost = self.total_cost(training_inputs, training_results, lmbda)
174182
training_cost.append(cost)
175183
print("Cost on training data: {0:.4f}".format(cost))
176184
if monitor_training_accuracy:
177185
accuracy = self.accuracy(training_data, convert=True)
178186
training_accuracy.append(accuracy)
179187
print("Accuracy on training data: {} / {}".format(accuracy, n))
180188
if monitor_evaluation_cost:
181-
cost = self.total_cost(evaluation_data, lmbda, convert=True)
189+
cost = self.total_cost(evaluation_inputs, evaluation_results, lmbda)
182190
evaluation_cost.append(cost)
183191
print("Cost on evaluation data: {0:.4f}".format(cost))
184192
if monitor_evaluation_accuracy:
@@ -201,38 +209,35 @@ def SGD(self, training_data, epochs, mini_batch_size, eta,
201209
"\nEarly-stopping: No accuracy change in last epochs: {}".format(early_stopping_n))
202210
# Always append accuracy and cost (values with no
203211
# regularization)
204-
cost = self.total_cost(training_data, 0)
212+
cost = self.total_cost(training_inputs, training_results, lmbda=0)
205213
training_cost.append(cost)
206-
print("Final cost on training data: {0:.4f}".format(cost))
214+
print("Final cost on training data: {0:.6f}".format(cost))
207215
accuracy = self.accuracy(training_data, convert=True)
208216
training_accuracy.append(accuracy)
209-
print(
210-
"Final accuracy on training data: {} / {}".format(accuracy, n))
211-
cost = self.total_cost(evaluation_data, 0, convert=True)
217+
print("Final accuracy on training data: {} / {}".format(accuracy, n))
218+
cost = self.total_cost(evaluation_inputs, evaluation_results, lmbda=0)
212219
evaluation_cost.append(cost)
213-
print(
214-
"Final cost on evaluation data: {0:.4f}".format(cost))
220+
print("Final cost on evaluation data: {0:.6f}".format(cost))
215221
accuracy = self.accuracy(evaluation_data)
216222
evaluation_accuracy.append(accuracy)
217-
print(
218-
"Accuracy on evaluation data: {} / {}".format(accuracy, n_data))
223+
print("Final accuracy on evaluation data: {} / {}".format(accuracy, n_data))
219224

220225
return evaluation_cost, evaluation_accuracy, \
221226
training_cost, training_accuracy
222227

223228
# Always append accuracy and cost (values with no regularization)
224-
cost = self.total_cost(training_data, 0)
229+
cost = self.total_cost(training_inputs, training_results, lmbda=0)
225230
training_cost.append(cost)
226-
print("\nFinal cost on training data: {0:.4f}".format(cost))
231+
print("\nFinal cost on training data: {0:.6f}".format(cost))
227232
accuracy = self.accuracy(training_data, convert=True)
228233
training_accuracy.append(accuracy)
229234
print("Final accuracy on training data: {} / {}".format(accuracy, n))
230-
cost = self.total_cost(evaluation_data, 0, convert=True)
235+
cost = self.total_cost(evaluation_inputs, evaluation_results, lmbda=0)
231236
evaluation_cost.append(cost)
232-
print("Final cost on evaluation data: {0:.4f}".format(cost))
237+
print("Final cost on evaluation data: {0:.6f}".format(cost))
233238
accuracy = self.accuracy(evaluation_data)
234239
evaluation_accuracy.append(accuracy)
235-
print("Accuracy on evaluation data: {} / {}".format(accuracy, n_data))
240+
print("Final accuracy on evaluation data: {} / {}".format(accuracy, n_data))
236241

237242
return evaluation_cost, evaluation_accuracy, \
238243
training_cost, training_accuracy
@@ -323,13 +328,14 @@ def accuracy(self, data, convert=False):
323328
for (x, y) in data]
324329
return sum(int(x == y) for (x, y) in results)
325330

326-
def total_cost(self, data, lmbda, convert=False):
331+
def total_cost(self, data_inputs, data_results, lmbda):
327332
"""Return the total cost for the data set ``data``. The flag
328333
``convert`` should be set to False if the data set is the
329334
training data (the usual case), and to True if the data set is
330335
the validation or test data. See comments on the similar (but
331336
reversed) convention for the ``accuracy`` method, above.
332337
"""
338+
"""
333339
cost = 0.0
334340
# Unregularized cost
335341
for x, y in data:
@@ -340,6 +346,15 @@ def total_cost(self, data, lmbda, convert=False):
340346
# Regularization cost
341347
cost += 0.5 * (lmbda / len(data)) * \
342348
sum(np.linalg.norm(w)**2 for w in self.weights)
349+
"""
350+
cost = 0.0
351+
N = len(data_inputs)
352+
a = self.feedforward(data_inputs)
353+
# Prediction cost
354+
cost += self.cost.fn(a, data_results) / N
355+
# Regularization cost
356+
cost += 0.5 * (lmbda / N) * sum(
357+
np.linalg.norm(w)**2 for w in self.weights)
343358
return cost
344359

345360
def save(self, filename):

0 commit comments

Comments
 (0)