Int-Werte von Variablen verändern statt neu setzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Septias
User
Beiträge: 80
Registriert: Freitag 24. Juni 2016, 19:15

Hallo,
in meinem Projekte habe ich verschiedene Objekte, die als ihre eigenen Inputs die Outputs von anderen Objekten nehmen. Diese Outputs ändern sich jetzt aber mit jedem Durchgang, und da ich dafür nur Zuweisungen verwende, (self.output = irgendwas) bekommt die Outputvariable zwar einen neuen Wert, aber die Inputvariable des anderen Objekts wird nich automatisch mitgeändert.
Nun weis ich aber, dass wenn man Listen verändert die beiden Namen, (also Variablen) die auf die Liste "zeigen" (kann man das so sagen, weil es sind ja keine Zeiger wie in C++ ?) einen neuen Wert bekommen.
Nun also meine Frage, ob ich die Variablen auch so verändern kann, dass alle Variablen die auf das Objekt zeigen einen neuen Wert "bekomme" ?

PS: Eigentlich hätte ich es mit Listen mit nur einem Elemten gemacht, aber wenn ich diese Listen dann in eine neue Liste mache ([[Wert,],[Wert,],[Wert,]]) wird daraus (Wert, Wert, Wert, Wert) und ich habe den Verdacht, dass die Listen dann zu ganz normalen varibalen konvertiert werden und dann das Prolem mit der Zuweisung von Oben auftritt.
Für alle meine Codebeispiele gilt: Äußert bitte jegliche Art von Verbesserungsvorschlägen. Ich versuche immer meinen Stil zu verbessern und wenn man mir einfach sagt, was ich falsch machen, ist es um einiges einfacher, als wenn ich es mühselig selber herausfinden muss :-)
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Das ist sehr theoretisch.

Mein erster Gedanke war, dass ein oder mehr design patterns (https://github.com/faif/python-patterns) das leisten könnten, ich habe aber nichts finden können (am ehesten vom Prinzip her das observer-Pattern).

Grundsätzlich ist das viel Zeug, was du da noch zusätzlich rein packen musst. Persönlich denke ich, dass man dein Problem mit einfacheren Mitteln lösen kann, allerdings wäre es nett, wenn du mal etwas Quellcode zeigst, so dass mann abchecken kann, was du eigentlich willst. Wenn Daten sich ändern, dann muss man eigentlich im Programm auch etwas programmieren, dass alle anderen upgedatet werden. Mit etwas Zauber geht das m. E. nicht. Wenn du alternativ bestimmte Daten hast und je nach Bedarf davon ausgehend Ausgaben brauchst, dann könnte man diese Daten jeweils an die betreffende Funktion übergeben (einfache Lösung) oder direkt in einer Klasse halten und die Methoden dieser Klasse aufrufen (auch eine einfache Lösung), das hängt aber m. E. davon ab, was du genau willst und wie groß das ist, was du hast.

Deine Überlegung mit den Listen halte ich für nicht zielführend.

Hilft Dir das? (Würde ich aber so nicht machen, sondern - in so einem Fall - eine Funktion schreiben:

Code: Alles auswählen

data = [1,2,3]

class A(object):

    def __init__(self, name):
        self.name = name

    def tu_was(self, data):
        data[0] *= 4
        

a = A("Test")

print(a.name)

a.tu_was(data)

print(data)
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Observer pattern ist dein Freund. Alternativ dazu kannst du auch auf reaktive Programmierung setzen. Dazu sollte es in Python auch Bibliotheken oder Rahmenwerke geben.

Und zu guter letzt kannst du dein Problem unter Umständen auch mit property lösen. Denn dann stößt du immer eine unter Umständen kaskadierende Berechnung an, wenn du Objekte am Ende der Abhängigkeitskette nach ihren Werten fragst.
Septias
User
Beiträge: 80
Registriert: Freitag 24. Juni 2016, 19:15

Also ich bin dabei zu versuchen selber ein neuronales Netzwerk zu programmieren. Vielleicht könnte man das ganze einfacher mit Liste usw. machen, aber ich habe mich für eine objektorientierte Programmierweise entschieden. Die In- und Outputs, von denen ich oben geredet habe, sind dabei immer die In- und Outputs der verschiedenen Synapsen.

Das Neuranale Netzwerk besteht bei mir aus 3 Synapsen. Drei Synapsen in der 1. Schicht und eine in der Zweite. Die ersten beiden Snypasen bekommen ihren Input aus einer Inputliste, weshalb da kein Problem entsteht. Die zweite Schicht aber soll ihre Inputs aus Outputs der ersten Schicht bekommen. Dabei bekomme ich aber nur [1, None, None, None] raus, weil die Listen aus [None,] einfach zu ints werden und deshalb dann bei der Berechnung des Netzes nicht verändert werden. (es gibt ein Gewicht, das immer 1 haben muss und welches auch immer mit eins gefüttert werden muss (die Eins in der Liste)).

Aber guckt euch den Quellcode einfach mal an:

Code: Alles auswählen

import numpy as np
import math
lernrate, max_durchgaenge = 0.2, 1000


class SynapsenNetzClass:
    def __init__(self, input_liste, output_liste):
        self.input = input_liste
        self._input = input_liste[0]
        self.wunsch_output = output_liste
        self.synapsen = []

        synapsen_erste_schicht = len(input_liste[0])
        schichtenanzahl = synapsen_erste_schicht / 2 + 1
        for i in range(int(schichtenanzahl)):
            self.synapsen.append([])
            # neue Schicht mit Synapsen fuellen
            for o in range(int(synapsen_erste_schicht / (2 ** i))):
                if i:
                    liste = np.array([])
                    for x in self.synapsen[-2]:
                        liste = np.append(liste, x.output)
                    self.synapsen[-1].append(SynapseClass(liste))
                else:
                    self.synapsen[-1].append(SynapseClass(self._input[o]))

    def calculate_net(self):
        funktionierende_werte = 0
        durchgaenge = 0
        while funktionierende_werte != len(self.wunsch_output) and durchgaenge < max_durchgaenge:
            funktionierende_werte = 0
            durchgaenge += 1
            for index in range(len(self.input)):
                self._input[0] = self.input[index - 1]
                for synapsengruppe in self.synapsen:  # Schritt 1: Ausgabe des Netzes von links nach rechts berechnen
                    for synapse in synapsengruppe:
                        synapse.sigm()
                    print("Delta aller Synapsen: ",
                          [_.delta for synapsenschicht in self.synapsen for _ in synapsenschicht])
                    if not self.synapsen[-1][-1] == self.wunsch_output[index]:  # Geht von nur einer Outpusynapse aus
                        self.learn(index)
                        break
                    else:
                        funktionierende_werte += 1
        print("finished ! after %s durchgaengen" % str(durchgaenge))

    def learn(self, musternummer):
        # Schritt 2: Fehler der Ausgabeschicht berechnen
        for synapse in self.synapsen[-1]:
            synapse.delta = synapse.abl_sigm() * (synapse.output[0] - self.wunsch_output[musternummer])

        # Schritt 3 Delta ausrechnen:
        for schicht in range(len(self.synapsen)-2, -1, -1):
            for position, synapse in enumerate(self.synapsen[schicht]):
                schuld = 0
                for vorsynapse in self.synapsen[schicht + 1]:
                    schuld += synapse.delta * vorsynapse.delta
                synapse.delta = synapse.abl_sigm() * schuld

        # Schritt 4: wwb anpassen:
        for schicht in self.synapsen:
            for synapse in schicht:
                for index, weight in enumerate(synapse.weights):
                    weight -= synapse.delta * synapse.input[index] * lernrate


class SynapseClass:
    def __init__(self, werte):
        self.input = np.insert(werte, 0, 1)
        if type(werte) == np.ndarray:
            self.weights = np.insert(np.random.random(len(werte)), 0, 1)
        else:
            self.weights = np.insert(np.random.random(1), 0, 1)
        self.output = [None, ]
        self._abl_sigm_net = None
        self.delta = 1.0

    def net(self):
        # returns skalarprodukt from input * weight
        return np.dot(self.input, self.weights)

    @staticmethod
    def _sigm(x):
        return 1 / (1 + math.e ** (-x))

    def sigm(self):
        self.output[0] = self._sigm(self.net())

    def abl_sigm(self):
        return self._sigm(self.net()) * (1 - self._sigm(self.net()))
Ja, ist ein bisschen länger aber ich hoffe gut zu verstehen ^^. Wenn euch irgend etwas, was man anders schreiben sollte, oder was man besser lösen könnte auffält, schreibts mir gerne auch dazu. Bin immer noch nen Anfänger und freue mich über jeden Verbesserungsvorschlag ^^
Für alle meine Codebeispiele gilt: Äußert bitte jegliche Art von Verbesserungsvorschlägen. Ich versuche immer meinen Stil zu verbessern und wenn man mir einfach sagt, was ich falsch machen, ist es um einiges einfacher, als wenn ich es mühselig selber herausfinden muss :-)
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Naja, da ist dein Problem ja eher, das deine Grundarchitektur ungeschickt ist. Du hast schon viel gutes, aber Inputs in ein Neuron (das ist der richtige Name, Synapsen sind die Verbindungen, die modellierst du aber nicht) als Konstruktor-Argument ist eine Entwurfsfehler.

Stattdessen musst du die Berechnung in Schichten durchfuehren, und jedes Neuron bekommt dann eben den Input des Layers davor (bzw. der eigentlichen Eingabe, im Fall der ersten Schicht).

*Was* du bei der Konstruktion natuerlich reingeben musst ist die Anzahl der Gewichte, bzw. noch besser einen Vektor mit Gewichten. Der kann dann entweder randomisiert sein, oder von Platte geladen. Du willst dein wertvolles Training ja nicht verlieren.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hier mal eine Skizze:

Code: Alles auswählen

class InputNeuron:
    # this just declares it's output to be the
    # n-th element of the input. Generalises our
    # Network

    def __init__(self, index):
        self._index = index

    def compute(self, input):
        return input[self._index]

class Neuron:

    def __init__(self, weights):
        self._weights = weights

    def compute(self, input):
        return self.weights * input

class NeuralNetwork:


    def __init__(self, layers):
        self._layers = layers


    def compute(self, input):
        for layer in self._layers:
            input = [neuron.compute(input) for neuron in layer]
        return input


    @classmethod
    def create_fresh(cls, *layercount):
        assert len(layercount), "you need at least one layer"
        layers = [[InputNeuron(i) for i in layercount[0]]] # input layer
        for count in layercount:
            layers.append(
                [Neuron(create_random_weights(len(layers[-1])) for _ in range(count))]
            )
        return cls(layers)

Antworten