2015-10-27 113 views
0

我是一個新手,我正在創建一個框架,用進化算法演化C++中的對象。 演化算法演化對象並測試它們以獲得最佳解決方案(例如,演進權重神經網絡並對樣本數據進行測試,以便最終獲得具有良好準確性的網絡,而無需對其進行培訓) 。框架的用戶定義參數應該在哪裏?

我的問題是,有很多參數爲算法(選擇類型/交叉/突變,每個人的概率...),並且由於它是一個框架,用戶應該能夠輕鬆地訪問和修改它們。

當前的解決方案

現在,我創造了這個形式的頭文件parameters.h:

// DON'T CHANGE THESE PARAMETERS 
//mutation type 
#define FLIP 1 
#define ADD_CONNECTION 2 
#define RM_CONNECTION 3 

// USER DEFINED 
static const int TYPE_OF_MUTATION = FLIP; 

用戶修改靜態變量TYPE_OF_MUTATION然後我突變功能測試工作的價值TYPE_OF_MUTATION是並且調用正確的變異函數。

這種運作良好,但它有一些缺點:

  • 當我改變這個頭的參數,然後調用「作」,沒有變化考慮進去,我要叫「做清潔「然後」製造「。從我所看到的,這不是makefile中的問題,而是建築的工作原理。即使我在更改參數時重新構建,也意味着重新編譯整個項目,因爲這些參數在任何地方都可以使用;它絕對沒有效率。
  • ,如果你想運行遺傳算法數次使用不同的參數,你必須運行它第一次然後保存結果,更改參數,然後運行它第二次等

其他的可能性

我想過把這些參數作爲頂層函數的參數。問題是,函數然後需要20個參數左右,它似乎並不真正可讀...

我的意思是頂級函數是現在,進化算法只是通過做這樣的:

PopulationManager myPop; 
    myPop.evolveIt(); 

如果我定義的參數作爲參數,我們會碰到這樣的:

PopulationManager myPop; 
    myPop.evolveIt(20,10,5,FLIP,9,8,2,3,TOURNAMENT,0,23,4); 

你可以看到它可能如何地獄總是定義正確的順序參數!

結論

我知道讓你從預定義功能,建立自己的算法框架,但用戶不應該經歷的所有代碼更改參數一個接一個。

指出這個框架將在內部使用,用於一組確定的項目可能是有用的。

歡迎任何關於定義這些參數的最佳方式的輸入!

+0

如果你有很多參數,你可以將它們包裝在某種結構中並傳遞它們。 –

回答

0

如果選擇不改變我通常使用結構爲這樣:

enum class MutationType { 
    Flip, 
    AddConnection, 
    RemoveConnection 
}; 

struct Options { 
    // Documentation for mutation_type. 
    MutationType mutation_type = MutationType::Flip; 

    // Documentation for integer option. 
    int integer_option = 10; 
}; 

,然後提供一個構造函數這些選項。

Options options; 
options.mutation_type = MutationType::AddConnection; 
PopulationManager population(options); 

C++ 11使這很容易,因爲它允許指定的選項的缺省值,所以用戶只需要設置需要與默認不同的選項。

另請注意,我使用了enum作爲選項,這可確保用戶只能使用正確的值。

+0

謝謝你,這看起來是最好的選擇,與我使用的參數列表相比,enum和默認值的添加是很大的優勢。 – Dese

0

這是一個多態性的經典例子。在你提出的實現中,你正在做一個常量切換來決定選擇哪種多態變異算法來決定如何改變參數。在C++中,相應的機制是模板(靜態多態)或虛擬函數(動態多態)來選擇合適的變異算法應用於參數。

模板方式的優點是,在編譯時所有東西都可以解析,並且所得到的變異算法可以完全內聯,具體取決於實現。你放棄的是在運行時動態選擇參數變異算法的能力。

虛擬功能方式的優點是,您可以將變異算法的選擇推遲到運行時間,從而允許根據用戶輸入或什麼不同而變化。缺點是突變算法不能再被內聯,並且當你改變參數時你需要支付虛擬函數調用的代價(額外的間接級別)。

如果您想查看「算法變異」如何工作的真實示例,請在我的Iterated Dynamics存儲庫中的evolve.cpp上查看github。這是C代碼轉換爲C++,因此它既不使用模板也不使用虛擬功能。相反,它使用函數指針和開關常量來選擇適當的代碼。但是,這個想法是一樣的。

我的建議是看你是否可以先使用靜態多態(模板)。從最初的描述來看,無論如何你都是在編譯時修正突變的,所以你不會放棄任何東西。

如果這只是原型階段,並且您打算在運行時支持變換算法的切換,那麼請查看虛擬函數。作爲推薦的其他答案,請避開C風格編碼,如#define常數,而改爲使用適當的枚舉。

爲了解決「長參數列表氣味」,將所有參數打包到結構中的想法是一個好主意。除此之外,您可以通過使用builder pattern以更可讀的方式構建參數結構,而不僅僅是將一堆值分配到結構中,從而實現更高的可讀性。在此blog post中,我將構建器模式應用於Direct3D中的資源描述結構。這使我可以更直接地表達這些具有合理默認值的「數據包」,並直接顯示我的意圖,以在必要時覆蓋或替換具有特殊值的默認值。

+0

謝謝你的詳細答案,但我沒有尋找一種方法來實現突變和其他操作符,我已經有了一個基於模板的實現,因爲編碼類型本身可能會改變。我同意在這個階段開始改變參數定義是一種不好的做法,我會對代碼做出許多修改。 我會看看生成器模式,謝謝你的鏈接! – Dese

相關問題