#๐ Help with Backward Propagation of MLP
12 messages ยท Page 1 of 1 (latest)
@wintry shuttle
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
I ran into the following error while implementing my code for backward propagation of a multilayer perceptron
Error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 126
122 return y
124 if __name__ == '__main__':
125 # create an MLP
--> 126 mlp = MLP(2, [5], 1)
128 # create some inputs (dummy data)
129 inputs = np.array([0.1, 0.2])
Cell In[9], line 56, in MLP.__init__(self, num_inputs, num_hidden, num_outputs)
54 derivatives = []
55 for i in range(len(layers)-1): # number of derivatives are same as the weight matrices
---> 56 d = np.zeros(layers[i], layers[i+1])
57 derivatives.append(d)
58 self.derivatives = derivatives
TypeError: Cannot interpret '5' as a data type
Code:
import numpy as np
# Steps:
# save activations and derivatives
# implement backpropagartion
# implement gradient descent
# implement train
# train our network with some dummy dataset
# make some predictions
# ........ Code below ............
# create a class
class MLP():
"""A Multilayer Perceptron class.
"""
# representation of a simple multilayer perceptron
def __init__(self, num_inputs=3, num_hidden=[3, 5], num_outputs=2):
"""Constructor for the MLP. akes the number of inputs,
a variable number of hidden layers, and number of outputs.
Args:
num_inputs (int): Number of inputs
num_hidden (list): A list of ints for the hidden layers
num_outputs (int): Number of outputs
"""
self.num_inputs = num_inputs
self.num_hidden = num_hidden
self.num_outputs = num_outputs
# create a generic representation of the layers
layers = [self.num_inputs] + self.num_hidden + [self.num_outputs] # this gets a list where each item in a list represents the number of neurons in a layer
# initiate random connection weights of the layers
self.weights = []
for i in range(len(layers)-1): # weights are in between layer, so they'll be one less than te number of layers
w = np.random.rand(layers[i], layers[i + 1])
self.weights.append(w)
# alternate method for weights
#weights = []
#for i in range(len(layers)-1):
#w = np.random.rand(layers[i], layers[i + 1])
#weights.append(w)
#self.weights = weights
# create data representation for activation and derivatives
activations = []
for i in range(len(layers)):
a = np.zeros(layers[i]) # we want an amount of zeros in list equal to the number of neurons we have in each layer
activations.append(a)
self.activations = activations # store value in an instance variable
derivatives = []
for i in range(len(layers)-1): # number of derivatives are same as the weight matrices
d = np.zeros(layers[i], layers[i+1])
derivatives.append(d)
self.derivatives = derivatives
def forward_propagate(self, inputs):
"""Computes forward propagation of the network based on input signals.
Args:
inputs (ndarray): Input signals
Resturns:
activations (ndarray): Output values
"""
# the input layer activation is just the input itself
activations = inputs
self.activations[0] = inputs # save activation instance for first layer as inputs
# iterate through the network layers
for i, w in enumerate(self.weights):
# calculate the net inputs (matrix multiplication between previus activation and weight matrix)
net_inputs = np.dot(activations, w)
# apply sigmoid activation function
activations = self._sigmoid(net_inputs)
self.activations [i+1] = activations # save activations as i+1 because activatins are 1 moe than the weights. to make sure you are using corresponding values in your calculation for h, you have to increase a's i value by 1. e.g w1 corresponds with a2, w2 corresponds with a3, etc
# return output layer activation
return activations
def back_propagate(self, error, verbose=False):
# 3. dE/dW_i = {(y - a_[i+1]) x s'(h_[i+1])} matmul {a_i}
# 2. s'(h_[i+1]) = s(h_[i+1]) x (1 - s(h_[i+1]))
# 1. s(h_[i+1])) = a_[i+1]
# 3. dE/dW_[i-1] = {(y - a_[i+1]) x s'(h_[i+1])} W_i s'(h_i) a_[i+1]
for i in reversed(range(len(self.derivatives))):
# 1.
activations = self.activations[i+1]
# Part of 3.
delta = error * self._sigmoid_derivative(activations) # ndarray([0.1, 0.2]) --> ndarray([[0.1, 0.2]]) - changed to 2d array with a single row
delta_reshaped = delta.reshape(delta.shape[0], -1).T # transposes the array
current_activations = self.activations[i] # ndarray([0.1, 0.2]) --> ndarray([[0.1], [0.2]]) - changed to 2d array with 2 rows
current_activations_reshaped = current_activations.reshape(current_activations.shape[0], -1) # restructure array as shown in above comment
self.derivatives[i] = np.dot(current_activations, delta)
error = np.dot(delts, self.weights[i].T)
if verbose:
print("Derivatives for W{}: {}".format(i, self.derivatives(i)))
return error
def _sigmoid_derivative(self, x):
return x * (1.0 - x)
def _sigmoid(self, x):
"""Sigmoid activation function
Args:
x (float): Value to be processed
Returns:
y (float): Output
"""
y = 1.0 / (1 + np.exp(-x))
return y
if __name__ == '__main__':
# create an MLP
mlp = MLP(2, [5], 1)
# create some inputs (dummy data)
inputs = np.array([0.1, 0.2])
target = np.array([0.3])
# perform forward propagation
output = mlp.forward_propagate(inputs)
# calculate the error
error = target - output
# back propagation
mlp.back_propagate(error)
# print the results
print("The network input is {}".format(inputs))
print("The network output is {}".format(output))
print("The network error is {}".format(error))
Sorry about the messed up indentations for the def
They're like that because I had to break up the code to send in here
@wintry shuttle did you solve this yet?
because you probably want something like this
d = np.zeros([layers[i],layers[i+1]])
if your goal with that line was making a matrix of zeroes with dimensions [layer n, layer n+1]
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.