Your comment about "naming" the cells suggests that you consider cells as separate files; however, Jupyter notebook cells are not separate files - they are part of the same file.
If you were writing a python script, you would declare your class, and then execute your class like so:
class Foo:
def __init__(self):
self.Bar = "win!"
foo = Foo()
print(foo.Bar)
Notebooks are the same, but you can choose to separate the code into different cells to organize your code:
# Cell 1
class Foo:
def __init__(self):
self.Bar = "win!"
and
# Cell 2
foo = Foo()
print(foo.Bar)
Breaking code into cells also allows you to execute the code in a different order than if it were in a regular script. So, if you haven't executed the code that declares the Perceptron class, you can't instantiate a Perceptron instance.
Another approach to debugging your problem is to merge the cells that seem to be misbehaving. There is nothing wrong with putting all of your code in the same cell. If your code won't work all together, something is wrong with your code. Once you get it working, then you can split the code into separate cells.