2014-12-16 4 views
37

kurtararak değildir. Bellek kullanımını zamanla izledim ve birkaç gigabayt (~ 6 Gb) ile başladığını ve maks. Donanımın alabileceği 128 Gb. Çok sayıda metin belgesinin sınıflandırılması için rastgele ormanlar deniyordum. Basitlik için - neler olduğunu anlamaya - naif Bayes'e geri döndüm. Ben kullanıyorumscikit en GridSearch ve genel olarak Python benim GridSearches birkaç saat sonra başarısız tutmak bazı garip gözlemler yapmış ve ben başlangıçta neden çözemedim hafızayı

versiyonları Bu konuda GitHub'dan scikit-konu listesinde bazı ilgili tartışma bulundu 0.15.2

  • scikit-öğrenme Python 3.4.2

    • vardır Konu: https://github.com/scikit-learn/scikit-learn/issues/565 ve https://github.com/scikit-learn/scikit-learn/pull/770

      Ve zaten başarılı bir şekilde adreslenmiş gibi geliyor!

      Yani, kullanıyorum alakalı kod

      Sadece meraktan
      grid_search = GridSearchCV(pipeline, 
                parameters, 
                n_jobs=1, # 
                cv=5, 
                scoring='roc_auc', 
                verbose=2, 
                pre_dispatch='2*n_jobs', 
                refit=False) # tried both True and False 
      
      grid_search.fit(X_train, y_train) 
      print('Best score: {0}'.format(grid_search.best_score_)) 
      print('Best parameters set:') 
      

      , daha sonra ızgara döngü

      for p1 in parameterset1: 
          for p2 in parameterset2: 
           ... 
            pipeline = Pipeline([ 
               ('vec', CountVectorizer(
                  binary=True, 
                  tokenizer=params_dict[i][0][0], 
                  max_df=params_dict[i][0][1], 
                  max_features=params_dict[i][0][2], 
                  stop_words=params_dict[i][0][3], 
                  ngram_range=params_dict[i][0][4],)), 
               ('tfidf', TfidfTransformer(
                   norm=params_dict[i][0][5], 
                   use_idf=params_dict[i][0][6], 
                   sublinear_tf=params_dict[i][0][7],)), 
               ('clf', MultinomialNB())]) 
      
            scores = cross_validation.cross_val_score(
                   estimator=pipeline, 
                   X=X_train, 
                   y=y_train, 
                   cv=5, 
                   scoring='roc_auc', 
                   n_jobs=1) 
      
            params_dict[i][1] = '%s,%0.4f,%0.4f' % (params_dict[i][1], scores.mean(), scores.std()) 
            sys.stdout.write(params_dict[i][1] + '\n') 
      

      için iç içe aracılığıyla hızlı & kirli bir şekilde arama yapmaya karar verdi olduğunu Çok uzak çok iyi. Izgara arama, sonuçları çalışır ve stdout'a yazar. Ancak, bir süre sonra tekrar 128 Gb bellek kapağını aşıyor. Scikit'teki GridSearch ile aynı sorun. bazı denemeler sonra, sonunda döngü içinde

      gc.collect() 
      len(gc.get_objects()) # particularly this part! 
      

      sorunu çözer ve bellek kullanımı ~ 10 saat kullanım süresi boyunca 6.5 Gb de sürekli kalır öğrendim.

      Sonunda, yukarıdaki düzeltmeyle çalışmaya başladım, ancak bu sorunun neden olabileceği ve ipuçlarınızla ilgili fikirlerinizi duymak beni çok heyecanlandırıyor &! 0.15.2 yılında

  • +1

    Bu çok garip. Lütfen rastgele oluşturulmuş verileri (veya hatta sabit verileri kullanarak, örneğin np.ones (shape = (n_samples, n_features), dtype = np.float) ') kullanarak sorunları yeniden üreten bir betik dahil, github üzerine yeni bir sayı yazabilir misiniz? – ogrisel

    +7

    Elbette, sorun değil. Bu soruna neden olan bazı kodları https://github.com/rasbt/bugreport/tree/master/scikit-learn/gridsearch_memory adresine yükledim ve burada bir sorun açtı: https://github.com/scikit-learn/scikit-/3973/sorunları öğrenir. Teşekkürler! – Sebastian

    +0

    Geçmişte, sklearn (genellikle rastgele bir orman ile) bazı şeylerin çok fazla bellek tükettiğini de buldum. Soruna bağlı olarak, etrafta çalışmak zorunda kaldım. Bir yorum, tfidf/document problemleri için GradientBoostingClassifier'ın RandomForest'den daha iyi sonuçlar verebilmesidir.Ayrıca, tfidf transformatörün seyrek bir matris getireceğinden eminim (todo: versiyonunuz için emin olun) ... böylece sklearn'inizi güncellemeniz gerekir çünkü 0.15.2'deki RandomForest seyrek girişleri desteklemez. – user1269942

    cevap

    1

    RandomForest seyrek girdileri desteklemez.

    Yükseltme sklearn ve tekrar deneyin ... umarım bu yapılıyor sona birden fazla kopyası yolu daha az bellek tüketir sağlayacaktır. (Ve hız şeyler kadar)

    +0

    Bahşiş için teşekkürler. Evet, seyrek dizileri kesinlikle çok pahalı olan yoğun dizilere dönüştürmek için toarray() çağrısı kullanıyordum. Ancak, bu sorun "ucuz" naif Bayes veya lojistik regresyon sınıflandırıcı (Sgd) ile de meydana geldi. Her nasılsa çöp toplama ile ilgili bir sorun vardı. Python 3.4.3 ve scikit-learn sürüm 0.16.1 – Sebastian

    +0

    ile bir kez daha denemeliyim. NB ve LR'nin de seyrek girişleri desteklediğine inanıyorum. pre_dispatch = '2 * n_jobs' değerini sadece 1 – user1269942

    0

    Ben senin tam kodunu göremiyorum ama günümüzde benzer sorunla karşı karşıya. Denemeye değer. Benzer bir bellek patlaması kolaylıkla değiştirilebilir bir dizi veya liste benzeri bir nesneyi orijinal bir kopyanın bir kopyasını oluşturarak başka bir değişkene kopyaladığımız zaman kolayca olabilir ve ardından yeni diziyi veya listeyi ekleyerek veya benzer bir boyutu büyüterek değiştirebiliriz ve aynı zamanda orijinal nesneyi arka planda da arttırıyor.

    Yani bu üstel süreç olduğundan bir süre sonra biz bellek dışındadır. Yapabildim ve belki de deepcopy() orijinal nesneyi geçen bir değerde bu tür bir fenomenden sakınabilirsiniz.

    ben patladı yukarı hafızayı Benzer bir süreç ile, sonra% 10 hafıza yükte kalmayı başardı, benzer bir sorun vardı.

    GÜNCELLEME: Şimdi, panda DataFrame ile kodun pasajını görüyorum. Kolayca böyle bir değerleme sorunu olurdu.

    +0

    değerine dönüştürmeyi deneyebilirsin, scikit-learning codebase'e tekrar bakmam gerekiyor, ama eminim ki dahili olarak çok fazla kopya var (tahmin edicilerde) güvenlik nedenleriyle devam ediyor. Ancak, bir noktada "toplanan ve imha edilen çöpler" olmalı ve "gc.collect() " (gc.get_objects()) 'yi kullandığımda büyülü bir şekilde çalıştı. Mimariye ya da Python sürüm – Sebastian

    +0

    'a özgü olup olmadığını görmek için bir süre sonra tekrar denemeliyim, en azından pandalar df değerini geçmeye çalışacağım, ama yine de iyi şanslar. – Geeocode

    0

    GridSearch'a aşina değilim, ama bellek ve devasa listeler bir sorun olduğunda küçük bir özel jeneratör yazmanızı öneririm. Tüm öğeleriniz için yeniden kullanılabilir, sadece herhangi bir liste alır birini kullanın. Alt çözümün ötesini uygularsanız ilk önce bu makaleyi okuyun, en iyi jeneratörü makalesini buldum. for p1 in parameterset1:

    deneyin

    def listerator(this_list): 
        i = 0 
        while True: 
         yield this_list[i] 
         i += 1 
    

    : Ben bunu tüm daktilo ve parça parça gitti ve sahip olduğunuz diğer soruları da okuduktan sonra ben de

    https://www.jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/

    gerek yok deneyebilirsiniz 'Verim' sözcüğü (deklarasyonun herhangi bir yerinde) bunu bir jeneratör yapar, normal bir işlev değildir. Bu çalışır ve ben 0 eşittir, True bir şeyler yapmam gerekiyor, bu listeyi vermemi istiyorlar [0], işte giderseniz, i += 1'a tekrar ihtiyacın olursa bekleyeceğim. Bir dahaki sefere, i += 1'u alır ve yapar ve hala bir süre döngüsünde olduğunu fark eder ve bu listeyi [1] verir ve yerini kaydeder (i += 1 tekrar ... tekrar çağrılana kadar orada bekleyecektir). Listeyi bir kez beslediğimde ve bir jeneratör oluşturduğumda (burada x), listenizi tüketecektir.

    In [221]: for val in listerator([1,2,3,4]): 
        .....:  print val 
        .....:  
    1 
    2 
    3 
    4 
    --------------------------------------------------------------------------- 
    IndexError        Traceback (most recent call last) 
    <ipython-input-221-fa4f59138165> in <module>() 
    ----> 1 for val in listerator([1,2,3,4]): 
         2  print val 
         3 
    
    <ipython-input-220-263fba1d810b> in listerator(this_list, seed) 
         2   i = seed or 0 
         3   while True: 
    ----> 4    yield this_list[i] 
         5    i += 1 
    
    IndexError: list index out of range 
    

    Hayır:

    In [141]: x = listerator([1,2,3]) 
    
    In [142]: next(x) 
    Out[142]: 1 
    
    In [143]: next(x) 
    Out[143]: 2 
    
    In [144]: next(x) 
    Out[144]: 3 
    
    In [148]: next(x) 
    --------------------------------------------------------------------------- 
    IndexError        Traceback (most recent call last) 
    <ipython-input-148-5e4e57af3a97> in <module>() 
    ----> 1 next(x) 
    
    <ipython-input-139-ed3d6d61a17c> in listerator(this_list) 
         2  i = 0 
         3  while True: 
    ----> 4    yield this_list[i] 
         5    i += 1 
         6 
    
    IndexError: list index out of range 
    

    biz bir de kullanabilirsiniz Bakalım. Bunu yapalım:

    def listerator(this_list): 
        i = 0 
        while True: 
         try: 
          yield this_list[i] 
         except IndexError: 
          break 
         i += 1 
    
    In [223]: for val in listerator([1,2,3,4]): 
        print val 
        .....:  
    1 
    2 
    3 
    4 
    

    Çalışıyor. Şimdi, o olmasa bile bir liste öğesini geri göndermeye çalışmayın. Söylediklerinizi, neredeyse garanti edemez itibaren (belli bir yerden taze belli bir yerden alıp, veya başlangıç) tohum o edebilmek gerekir:

    def listerator(this_list, seed=None): 
        i = seed or 0 
        while True: 
         try: 
          yield this_list[i] 
         except IndexError: 
          break 
         i += 1 
    
    In [150]: l = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] 
    
    In [151]: x = listerator(l, 8) 
    
    In [152]: next(x) 
    Out[152]: 9 
    
    In [153]: next(x) 
    Out[153]: 10 
    
    In [154]: next(x) 
    Out[154]: 11 
    

    i = seed or 0 arayan bir şeydir tohumu, ancak tohum varsayılanları Yok, bu nedenle genellikle sadece mantıksal bir yerde başlar, 0, listenin başlangıcı

    Bu hayvanı herhangi bir belleği (neredeyse) kullanmadan nasıl kullanabilirsiniz?

    parameterset1 = [1,2,3,4] 
    parameterset2 = ['a','b','c','d'] 
    
    In [224]: for p1 in listerator(parameterset1): 
        for p2 in listerator(parameterset2): 
         print p1, p2 
        .....:   
    1 a 
    1 b 
    1 c 
    1 d 
    2 a 
    2 b 
    2 c 
    2 d 
    3 a 
    3 b 
    3 c 
    3 d 
    4 a 
    4 b 
    4 c 
    4 d 
    

    tanıdık geliyor mu? Artık trilyon değerlerini tek tek işleyebilir, diske yazmak için önemli olanları seçebilir ve sisteminizi asla şişiremezsiniz. Keyfini çıkarın!

    +0

    Merhaba, yorum için teşekkürler, jeneratörler kullanmayı biliyorum, ancak bu tartışmak istedim potansiyel bir platform belirli bir böcek hakkında daha fazla oldu. Elbette, akış verileri için bir HashingVectorizer ve SGD sınıflandırıcı kullanabilirsiniz; ama Tf-idfs'in doğru bir şekilde hesaplanması için, – Sebastian

    +0

    Tüm kelime dağarcığına erişebilmeniz gerekir. Ben bitirdikten sonra fark ettim, muhtemelen yardım edemezdim, soruyu daha yavaş okumalıydım, ama çözdüğünüze sevindim – codyc4321

    İlgili konular