25 KiB
25 KiB
In [ ]:
import autograd.numpy as np # We need to use this numpy wrapper to make automatic differentiation work later
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
# Defining some activation functions
def ReLU(z):
return np.where(z > 0, z, 0)
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def softmax(z):
"""Compute softmax values for each set of scores in the rows of the matrix z.
Used with batched input data."""
e_z = np.exp(z - np.max(z, axis=0))
return e_z / np.sum(e_z, axis=1)[:, np.newaxis]
def softmax_vec(z):
"""Compute softmax values for each set of scores in the vector z.
Use this function when you use the activation function on one vector at a time"""
e_z = np.exp(z - np.max(z))
return e_z / np.sum(e_z)In [ ]:
np.random.seed(2024)
x = np.random.randn(2) # network input. This is a single input with two features
W1 = np.random.randn(4, 2) # first layer weightsIn [ ]:
b1 = ...In [ ]:
z1 = ...In [ ]:
a1 = ...In [ ]:
sol1 = np.array([0.60610368, 4.0076268, 0.0, 0.56469864])
print(np.allclose(a1, sol1))In [ ]:
W2 = ...
b2 = ...In [ ]:
z2 = ...
a2 = ...In [ ]:
print(
np.allclose(np.exp(len(a2)), 2980.9579870417283)
) # This should evaluate to True if a2 has the correct shape :)In [ ]:
def create_layers(network_input_size, layer_output_sizes):
layers = []
i_size = network_input_size
for layer_output_size in layer_output_sizes:
W = ...
b = ...
layers.append((W, b))
i_size = layer_output_size
return layersIn [ ]:
def feed_forward_all_relu(layers, input):
a = input
for W, b in layers:
z = ...
a = ...
return aIn [ ]:
input_size = ...
layer_output_sizes = [...]
x = np.random.rand(input_size)
layers = ...
predict = ...
print(predict)In [ ]:
def feed_forward(input, layers, activation_funcs):
a = input
for (W, b), activation_func in zip(layers, activation_funcs):
z = ...
a = ...
return aIn [ ]:
network_input_size = ...
layer_output_sizes = [...]
activation_funcs = [ReLU, ReLU, sigmoid]
layers = ...
x = np.random.randn(network_input_size)
feed_forward(x, layers, activation_funcs)In [ ]:
def create_layers_batch(network_input_size, layer_output_sizes):
layers = []
i_size = network_input_size
for layer_output_size in layer_output_sizes:
W = ...
b = ...
layers.append((W, b))
i_size = layer_output_size
return layersIn [ ]:
inputs = np.random.rand(1000, 4)
def feed_forward_batch(inputs, layers, activation_funcs):
a = inputs
for (W, b), activation_func in zip(layers, activation_funcs):
z = ...
a = ...
return aIn [ ]:
network_input_size = ...
layer_output_sizes = [...]
activation_funcs = [...]
layers = create_layers_batch(network_input_size, layer_output_sizes)
x = np.random.randn(network_input_size)
feed_forward_batch(inputs, layers, activation_funcs)In [ ]:
iris = datasets.load_iris()
_, ax = plt.subplots()
scatter = ax.scatter(iris.data[:, 0], iris.data[:, 1], c=iris.target)
ax.set(xlabel=iris.feature_names[0], ylabel=iris.feature_names[1])
_ = ax.legend(
scatter.legend_elements()[0], iris.target_names, loc="lower right", title="Classes"
)In [ ]:
inputs = iris.data
# Since each prediction is a vector with a score for each of the three types of flowers,
# we need to make each target a vector with a 1 for the correct flower and a 0 for the others.
targets = np.zeros((len(iris.data), 3))
for i, t in enumerate(iris.target):
targets[i, t] = 1
def accuracy(predictions, targets):
one_hot_predictions = np.zeros(predictions.shape)
for i, prediction in enumerate(predictions):
one_hot_predictions[i, np.argmax(prediction)] = 1
return accuracy_score(one_hot_predictions, targets)In [ ]:
...
layers = ...In [ ]:
predictions = feed_forward_batch(inputs, layers, activation_funcs)In [ ]:
print(accuracy(predictions, targets))In [ ]:
def cross_entropy(predict, target):
return np.sum(-target * np.log(predict))
def cost(input, layers, activation_funcs, target):
predict = feed_forward_batch(input, layers, activation_funcs)
return cross_entropy(predict, target)In [ ]:
from autograd import grad
gradient_func = grad(
cost, 1
) # Taking the gradient wrt. the second input to the cost function, i.e. the layersIn [ ]:
layers_grad = gradient_func(
inputs, layers, activation_funcs, targets
) # Don't change thisIn [ ]:
def train_network(
inputs, layers, activation_funcs, targets, learning_rate=0.001, epochs=100
):
for i in range(epochs):
layers_grad = gradient_func(inputs, layers, activation_funcs, targets)
for (W, b), (W_g, b_g) in zip(layers, layers_grad):
W -= ...
b -= ...In [ ]:
...