1

Pythonで遺伝的アルゴリズムのフレームワークを作成しようとしていますが、浅い/深いコピーで問題が発生しています。私のバックグラウンドは主にC/C ++であり、これらの接続がどのように持続しているかを理解するのに苦労しています。

私が見ているのは、サブクラス内の属性リストの長さが爆発的に増加していることです。私のコードは以下のとおりです...問題を指摘します。

これは単一の遺伝子のクラスです。基本的に、名前、値、およびブールフラグが必要です。私のクラスGene内のリストにデータを入力するインスタンス。Individual

# gene class
class Gene():
  # constructor
  def __init__(self, name, is_float):
    self.name_     = name
    self.is_float_ = is_float
    self.value_    = self.randomize_gene()


  # create a random gene
  def randomize_gene(self):
    return random.random()

これは私のIndividualクラスです。世代ごとに、これらの母集団が作成され(クラス宣言の後に作成コードを示します)、一般的な遺伝的アルゴリズム操作が適用されます。注目すべきは、print len(self.Genes_)このクラスがインスタンス化されるたびに大きくなる呼び出しです。

# individual class
class Individual():
  # genome definition
  Genes_      = []    # genes list
  evaluated_  = False # prevent re-evaluation
  fitness_    = 0.0   # fitness value (from evaluation)
  trace_      = ""    # path to trace file
  generation_ = 0     # generation to which this individual belonged
  indiv_      = 0     # identify this individual by number

  # constructor
  def __init__(self, gen, indv):
    # assign indices
    self.generation_ = gen
    self.indiv_      = indv
    self.fitness_    = random.random()

    # populate genome
    for lp in cfg.params_:
      g = Gene(lp[0], lp[1])
      self.Genes_.append(g)

    print len(self.Genes_)

> python ga.py
> 24
> 48
> 72
> 96
> 120
> 144
......

ご覧のとおり、各個体には24個の遺伝子が必要ですが、この集団は非常に急速に爆発します。私はこのような新しい個人の初期集団を作成します:

# create a randomized initial population
def createPopulation(self, gen):
  loc_population = []
  for i in range(0, cfg.population_size_):
    indv = Individual(gen, i)
    loc_population.append(indv)
  return loc_population

その後、メインループで(ダンプ全体についてお詫びしますが、必要だと感じました。セカンダリ呼び出し(ミューテーション/クロスオーバー)が必要な場合はお知らせください))

for i in range(0, cfg.generations_):
      # evaluate current population
      self.evaluate(i)

      # sort population on fitness
      loc_pop = sorted(self.population_, key=operator.attrgetter('fitness_'), reverse=True)

      # create next population & preserve elite individual
      next_population = []
      elitist = copy.deepcopy(loc_pop[0])
      elitist.generation_ = i
      next_population.append(elitist)

      # perform selection
      selection_pool = []
      selection_pool = self.selection(elitist)

      # perform crossover on selection
      new_children = []
      new_children = self.crossover(selection_pool, i)

      # perform mutation on selection
      muties = []
      muties = self.mutation(selection_pool, i)

      # add members to next population
      next_population = next_population + new_children + muties

      # fill out the rest with random
      for j in xrange(len(next_population)-1, cfg.population_size_ - 1):
        next_population.append(Individual(i, j))

      # copy next population over old population
      self.population_ = copy.deepcopy(next_population)

      # clear old lists
      selection_pool[:]  = []
      new_children[:]    = []
      muties[:]          = []
      next_population[:] = []
4

2 に答える 2

1

クラスを作成すると、実際には 1 つの「クラス オブジェクト」が作成されます。これらは、Python の他のオブジェクトと同様のオブジェクトです。Python ではすべてがオブジェクトであり、それらのオブジェクトが何をするかは、クラスではなくメソッドによって定義されます! それがダックタイピングの魔法です。Python では、新しいクラスをその場で動的に作成することもできます。

とにかく、唯一の「個人」クラスオブジェクトの「Genes_」属性に正確に1つのリストオブジェクトを追加しています。要するに、「個別」クラス オブジェクトのすべてのインスタンス オブジェクトが同じ「Genes_」リスト オブジェクトにアクセスしているということです。

このことを考慮

    # In 2.2 <= Python < 3.0 you should ALWAYS inherit from 'object'.
    class Foobar(object):
        doodah = []

    a = Foobar()
    b = Foobar()
    assert id(a.doodah) == id(b.doodah) # True

この場合、ご覧のとおり、「a.doodah」と「b.doodah」は同じオブジェクトです。

    class Foobar(object):
        def __init__(self):
            self.doodah = []

    a = Foobar()
    b = Foobar()
    assert id(a.doodah) != id(b.doodah) # True

この場合、それらは異なるオブジェクトです。

ケーキを持って食べることも可能です。このことを考慮

    class Foobar(object):
        doodah = []

    a = Foobar()
    b = Foobar()
    a.doodah = 'hlaghalgh'
    assert id(a.doodah) != id(b.doodah) # True

この場合、「doodah」属性が「a」オブジェクトに追加され、class 属性がオーバーライドされます。

お役に立てれば!

于 2012-11-03T05:06:04.193 に答える
1

私はあなたの質問を完全に理解しているとは言えませんが、あなたの問題は、あなたの Individual() クラスの Genes_ 変数がクラス名前空間で宣言されていることだと思います。この名前空間は、クラスのすべてのメンバーが利用できます。つまり、Individual() の各インスタンスは、同じ変数 Genes_ を共有します。

次の 2 つのスニペットを検討してください。

class Individual():
  # genome definition
  genes = []
  def __init__(self):
      for i in xrange(10):
              self.genes.append(i)

ind_1 = Individual()
print ind_1.genes
ind_2 = Individual()
print ind_1.genes
print ind_2.genes

class Individual():
  # genome definition
  def __init__(self):
      self.genes = []
      for i in xrange(10):
              self.genes.append(i)

ind_1 = Individual()
print ind_1.genes
ind_2 = Individual()
print ind_1.genes
print ind_2.genes

最初のスニペットの出力

>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

2番目のスニペットが出力されている間

>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

最初のシナリオでは、2 番目の Individual() がインスタンス化されると、遺伝子リスト変数が既に存在し、2 番目の個体からの遺伝子がこの既存のリストに追加されます。

このように Individual() クラスを作成するのではなく、

# individual class
class Individual():
  # genome definition
  Genes_      = []    # genes list

  # constructor
  def __init__(self, gen, indv):
    # assign indices
    self.generation_ = gen
    self.indiv_      = indv
    self.fitness_    = random.random()

Init で Genes_ 変数を宣言して、各 Individual() インスタンスが独自の遺伝子セットを取得することを検討する必要があります

# individual class
class Individual():

  # constructor
  def __init__(self, gen, indv):
    # genome definition
    self.Genes_      = []    # genes list
    # assign indices
    self.generation_ = gen
    self.indiv_      = indv
    self.fitness_    = random.random()
于 2012-11-03T01:39:31.720 に答える