GANs是在訓(xùn)練階段最需要計(jì)算的密集型模型之一,因?yàn)樗喈?dāng)于同時(shí)訓(xùn)練兩個(gè)神經(jīng)網(wǎng)絡(luò)。對(duì)于我的普通電腦來(lái)說(shuō),把gan訓(xùn)練到收斂是非常困難的。
遺傳算法是根據(jù)大自然中生物體進(jìn)化規(guī)律而設(shè)計(jì)提出的,是根據(jù)大自然中生物體進(jìn)化規(guī)律而設(shè)計(jì)提出的。是模擬達(dá)爾文生物進(jìn)化論的自然選擇和遺傳學(xué)機(jī)理的生物進(jìn)化過(guò)程的計(jì)算模型,是一種通過(guò)模擬自然進(jìn)化過(guò)程搜索最優(yōu)解的方法。
在本片文章中,我們嘗試使用遺傳算法來(lái)對(duì)訓(xùn)練GANs進(jìn)行優(yōu)化,我們的訓(xùn)練模型是生成手寫數(shù)字。
遺傳算法是一種學(xué)習(xí)算法,它利用交叉兩個(gè)好的神經(jīng)網(wǎng)絡(luò)的權(quán)值的思想,從而得到一個(gè)更好的神經(jīng)網(wǎng)絡(luò)。
遺傳算法如此有效的原因是沒(méi)有直接的優(yōu)化算法,所以允許有極端變化的結(jié)果的可能性。此外,他們通常會(huì)提出非常有趣的解決方案,這些方案通常會(huì)對(duì)問(wèn)題提供有價(jià)值的見解。
生成一組隨機(jī)權(quán)重。 這是第一個(gè)代理的神經(jīng)網(wǎng)絡(luò)。 在代理上執(zhí)行了一組測(cè)試。 代理會(huì)根據(jù)測(cè)試獲得分?jǐn)?shù)。 重復(fù)幾次以創(chuàng)建種群。選擇種群的前10%以進(jìn)行交叉。 從最高的10%中選擇兩個(gè)隨機(jī)的父母,他們的權(quán)重是交叉的。 每次發(fā)生交叉時(shí),發(fā)生突變的可能性都很小:這是一個(gè)隨機(jī)值,不會(huì)受到父母的影響。
這個(gè)過(guò)程會(huì)慢慢地優(yōu)化代理的性能,因?yàn)榇頃?huì)慢慢地適應(yīng)環(huán)境。
計(jì)算不密集:沒(méi)有線性代數(shù)計(jì)算要完成。唯一必要的機(jī)器學(xué)習(xí)計(jì)算是通過(guò)神經(jīng)網(wǎng)絡(luò)的正向傳遞。因此,與深度神經(jīng)網(wǎng)絡(luò)相比,系統(tǒng)要求非常廣泛。
適應(yīng)性強(qiáng):可以改編并插入許多不同的測(cè)試和方法來(lái)操縱遺傳算法的靈活性??梢酝ㄟ^(guò)使代理傳播生成器網(wǎng)絡(luò)并使用鑒別器作為測(cè)試,在遺傳算法內(nèi)創(chuàng)建GAN。這是一個(gè)至關(guān)重要的好處,這使我相信將來(lái)遺傳算法的使用將更加廣泛。
可解釋的:對(duì)于普通的神經(jīng)網(wǎng)絡(luò),該算法的學(xué)習(xí)模式是不可解釋的。對(duì)于遺傳算法,很容易理解為什么會(huì)發(fā)生某些事情:例如,當(dāng)給遺傳算法提供Tic-Tac-Toe環(huán)境時(shí),某些可識(shí)別的策略就會(huì)慢慢發(fā)展。這是一個(gè)很大的好處,因?yàn)槭褂脵C(jī)器學(xué)習(xí)就是使用技術(shù)來(lái)幫助我們了解重要事項(xiàng)。
可能需要很長(zhǎng)時(shí)間:某些的交叉和變異可能會(huì)對(duì)程序的準(zhǔn)確性造成負(fù)面影響,從而使程序收斂或達(dá)到某個(gè)損失閾值的速度變慢。。
在對(duì)遺傳算法有了一個(gè)一些的了解后,我現(xiàn)在可以向你展示這個(gè)程序:
import randomimport numpy as npfrom IPython.display import clear_outputfrom keras.layers import Reshapefrom keras.layers import Flattenfrom keras.layers import Conv2Dfrom keras.layers import Conv2DTransposefrom keras.layers import LeakyReLUfrom keras.layers import Dropout,Densefrom keras.optimizers import Adamfrom keras.models import Sequentialfrom keras.datasets.mnist import load_data(trainX, trainy), (testX, testy) = load_data()
這里我們使用Keras進(jìn)行鑒別器部分的構(gòu)建,但是遺傳算法中的神經(jīng)網(wǎng)絡(luò)是以numpy為基礎(chǔ)進(jìn)行構(gòu)建的。
class g enetic_algorithm: def execute(pop_size,generations,threshold,network): class Agent: def __init__(self,network):
這是' geneticalgorithm'類的創(chuàng)建,其中包含與遺傳算法有關(guān)的所有功能以及其應(yīng)如何發(fā)揮作用。 主要功能是它以popsize,generations,threshold,network作為參數(shù)。 pop_size是生成的種群的大小,generation是時(shí)代的術(shù)語(yǔ),threshold是損失值的閾值。 X和y用于標(biāo)記數(shù)據(jù)的遺傳算法。 對(duì)于沒(méi)有數(shù)據(jù)或未標(biāo)記數(shù)據(jù)的問(wèn)題,可以刪除X和y的所有實(shí)例。
class neural_network: def __init__(self,network): self.weights = [] self.activations = [] for layer in network: if layer[0] != None: input_size = layer[0] else: input_size = network[network.index(layer)-1][1] output_size = layer[1] activation = layer[2] self.weights.append(np.random.randn(input_size,output_size)) self.activations.append(activation) def propagate(self,data): input_data = data for i in range(len(self.weights)): z = np.dot(input_data,self.weights[i]) a = self.activations[i](z) input_data = a yhat = a return yhat self.neural_network = neural_network(network) self.fitness = 0
這個(gè)腳本描述了每個(gè)代理的神經(jīng)網(wǎng)絡(luò)的權(quán)值的初始化和網(wǎng)絡(luò)的傳播。
def generate_agents(population, network): return [Agent(network) for _ in range(population)]
此功能創(chuàng)建將要測(cè)試的第一批代理。
def fitness(agents): for agent in agents: dataset_len = 100 fake = [] real = [] y = [] for i in range(dataset_len//2): fake.append(agent.neural_network.propagate(np.random.randn(latent_size)).reshape(28,28)) y.append(0) real.append(random.choice(trainX)) y.append(1) X = fake+real X = np.array(X).astype('uint8').reshape(len(X),28,28,1) y = np.array(y).astype('uint8') model.fit(X,y,verbose = 0) fake = [] real = [] y = [] for i in range(dataset_len//2): fake.append(agent.neural_network.propagate(np.random.randn(latent_size)).reshape(28,28)) y.append(0) real.append(random.choice(trainX)) y.append(1) X = fake+real X = np.array(X).astype('uint8').reshape(len(X),28,28,1) y = np.array(y).astype('uint8') agent.fitness = model.evaluate(X,y,verbose = 0)[1]*100 return agents
適應(yīng)度函數(shù)是此遺傳算法的獨(dú)特部分:
def selection(agents): agents = sorted(agents, key=lambda agent: agent.fitness, reverse=False) print('\n'.join(map(str, agents))) agents = agents[:int(0.2 * len(agents))] return agents
(鑒別器的神經(jīng)網(wǎng)絡(luò)將在以后定義。 該模型將根據(jù)之前加載的MNIST數(shù)據(jù)集進(jìn)行訓(xùn)練。 該模型采用卷積網(wǎng)絡(luò)的形式,以返回二進(jìn)制結(jié)果)
此功能模仿了進(jìn)化中的選擇理論:最佳選擇生存,而其他選擇則死亡。 在這種情況下,它們的數(shù)據(jù)將被遺忘并且不再使用。
def unflatten(flattened,shapes): newarray = [] index = 0 for shape in shapes: size = np.product(shape) newarray.append(flattened[index : index + size].reshape(shape)) index += size return newarray
要執(zhí)行交叉和變異功能,需要將權(quán)重展平和展平成原始形狀。
def crossover(agents,network,pop_size): offspring = [] for _ in range((pop_size - len(agents)) // 2): parent1 = random.choice(agents) parent2 = random.choice(agents) child1 = Agent(network) child2 = Agent(network) shapes = [a.shape for a in parent1.neural_network.weights] genes1 = np.concatenate([a.flatten() for a in parent1.neural_network.weights]) genes2 = np.concatenate([a.flatten() for a in parent2.neural_network.weights]) split = random.ragendint(0,len(genes1)-1)child1_genes = np.asrray(genes1[0:split].tolist() + genes2[split:].tolist()) child2_genes = np.array(genes1[0:split].tolist() + genes2[split:].tolist()) child1.neural_network.weights = unflatten(child1_genes,shapes) child2.neural_network.weights = unflatten(child2_genes,shapes) offspring.append(child1) offspring.append(child2) agents.extend(offspring) return agents
交叉功能是程序中最復(fù)雜的功能之一。 它生成兩個(gè)新的'子代'代理,它們的權(quán)重被替換為兩個(gè)隨機(jī)生成的父代理的交叉。 這是創(chuàng)建權(quán)重的過(guò)程:
1. 壓平父母的權(quán)重
1. 產(chǎn)生兩個(gè)分裂點(diǎn)
1. 使用拆分點(diǎn)作為索引來(lái)設(shè)置兩個(gè)子代理的權(quán)重
def mutation(agents): for agent in agents: if random.uniform(0.0, 1.0) <= 0.1: weights = agent.neural_network.weights shapes = [a.shape for a in weights]flattened = np.concatenate([a.flatten() for a in weights]) randint = random.randint(0,len(flattened)-1) flattened[randint] = np.random.randn()newarray = [a ] indeweights = 0 for shape in shapes: size = np.product(shape) newarray.append(flattened[indeweights : indeweights + size].reshape(shape)) indeweights += size agent.neural_network.weights = newarray return agents
這是突變函數(shù)。扁平化與交叉函數(shù)相同。選擇一個(gè)隨機(jī)的點(diǎn),用一個(gè)隨機(jī)的值替換,而不是分割這些點(diǎn)。
for i in range(generations): print('Generation',str(i),':') agents = generate_agents(pop_size,network) agents = fitness(agents) agents = selection(agents) agents = crossover(agents,network,pop_size) agents = mutation(agents) agents = fitness(agents) if any(agent.fitness < threshold for agent in agents): print('Threshold met at generation '+str(i)+' !') if i % 100: clear_output() return agents[0]
這是execute函數(shù)的最后一部分,它執(zhí)行已定義的所有函數(shù)。
image_size = 28latent_size = 100model = Sequential()model.add(Conv2D(64, (3,3), strides=(2, 2), padding='same', input_shape=(image_size,image_size,1)))model.add(LeakyReLU(alpha=0.2))model.add(Dropout(0.4))model.add(Conv2D(64, (3,3), strides=(2, 2), padding='same'))model.add(LeakyReLU(alpha=0.2))model.add(Dropout(0.4))model.add(Flatten())model.add(Dense(1, activation='sigmoid'))opt = Adam(lr=0.0002, beta_1=0.5)model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])network = [[latent_size,100,sigmoid],[None,image_size**2,sigmoid]]ga = genetic_algorithmagent = ga.execute(1000,1000,90,network)(trainX, trainy), (testX, testy) = load_data()weights = agent.neural_network.weights
這就是卷積網(wǎng)絡(luò)實(shí)現(xiàn)的鑒別器。Imagesize是MNIST圖像的大小,latentsize用于確保
這將執(zhí)行整個(gè)遺傳算法。 對(duì)于網(wǎng)絡(luò)變量,每個(gè)嵌套列表都包含輸入神經(jīng)元編號(hào),輸出神經(jīng)元編號(hào)和激活函數(shù)。 execute函數(shù)返回最佳代理。
顯然,遺傳算法的收斂速度不會(huì)像基于梯度的算法那樣快,但計(jì)算工作在較長(zhǎng)一段時(shí)間內(nèi)分散,使它在計(jì)算機(jī)上不那么密集!
聯(lián)系客服