1. 程式人生 > >keras學習筆記(三)

keras學習筆記(三)

資料歸一化

通過上次對cifar10資料集分類的任務,我的分類精度在0.79,但是當我對輸入的資料做了歸一化後,精度達到了0.99,實現的語句如下:

X_train = X_train.astype('float32')/255
X_test = X_test.astype('float32')/255
Y_train =Y_train.reshape(Y_train.shape[0])/10
Y_test = Y_test.reshape(Y_test.shape[0])/10

對輸入進行歸一化處理。對標籤也進行歸一化處理。是資料預處理的一種常見的手段。

資料歸一化與標準化存在一定區別,歸一化是資料標準化的一種典型做法,即將資料統一對映到[0,1]區間上. 資料的標準化是指將資料按照比例縮放,使之落入一個特定的區間.

歸一化最明顯的在神經網路中的影響有如下幾個方面:

1.有利於初始化的進行

2.避免給梯度數值的更新帶來數字的問題

3.有利於學習率的調整

4.加快尋找最優解的速度

上篇部落格說了上面那段是自己寫的,下面那段是網上別人寫的。我自己寫的進行了標準化前是0.79的精度,標準化後是0.99的精度,很顯然看出資料標準化對精度是有一定影響的。但是後面的那段我並沒有看到有資料歸一化,結果仍然能達到0.99.暫時還不清楚原因。可能是我選用了不同的損失函式的原因吧,可以自己進行更改驗證。

做了歸一化後可以使各個特徵都集中在固定的區間內,為什麼可以加快優化速度和學習率的調整呢?拿簡單的房價擬合問題來講,一個房子有很多個特徵,比如說面積,距離市中心的距離(km),臥室數量,樓層等等特徵。但是面積的數值較大(100-200),臥室數量一般為2-4,距離市中心距離(1-10),這麼多特徵,數值特別分散,如果使用統一的學習率,那麼每次如果距離減小一點點,可能相對於距離來說從3減到2.5變化很明顯,但是同樣的對於面積從200減到199.5變化速度太慢了。所以,將所有的正壓縮到同樣大小的空間中,這樣可以加快優化速度。

批量標準化(BatchNormalization)

下面是批量標準化的兩張圖,這兩張圖說明了為什麼要進行批量標準化(BatchNormalization)。批量標準化可以用於隱藏層中。進行了標準化後可以讓特徵集中分佈在中央。然後經過一個sigmoid或者tanh的處理,這樣可以得到一個很好的值,想象一下,如果一個特徵值為3,一個特徵為30,經過tanh處理後,得到的值分別為0.96和0.99,這就相當於我的神經網路對輸入得資料缺少了感知能力。但是如果標準化到一定的區間內,比如把這個範圍縮小10倍,得到了0.3和3兩個特徵值,在經過啟用函式處理,那麼處理過後的結果可能就是0.2和0.96,這樣有利於更深層次的前向和反向傳播。網路搭的越深,往往後面梯度就消失了,因為特徵值太大了,因此加入BN層可以使網路得到更加有效的資料。

用keras寫一個GAN網路:

import keras
from keras import layers
import numpy as np
import os
from keras.preprocessing import image

pre_data=32
height     = 32
width      = 32
channels   = 3
#獲取資料
(x_train,y_train),(x_test,y_test)=keras.datasets.cifar10.load_data()
x_train = x_train[y_train.flatten() == 5]
x_test  = x_test [y_test.flatten()  == 5]
#資料標準化
x_train=x_train.reshape((x_train.shape[0],)+(height,width,channels)).astype('float32')/255
x_test=x_test.reshape((x_test.shape[0],)+(height,width,channels)).astype('float32')/255
#構建生成器網路(從輸入到輸出的方式構建)generator_network
generator_input=keras.Input(shape=(pre_data,)) #generator_input.shape=(?, 32)
#用一個全連線層把相關特徵提出來,用16*16*128=32768個特徵。方便之後做卷積
x=layers.Dense(32768)(generator_input)#x.shape=(?, 32768)
x=layers.ReLU()(x)
x=layers.Reshape((16,16,128))(x)#x.shape=(?, 16, 16, 128)
#之後就可以做卷積了
x = layers.Conv2D(filters=128, kernel_size=3, padding='same')(x)
x = layers.ReLU()(x)

x = layers.Conv2D(filters=256, kernel_size=5, padding='same')(x)
x = layers.ReLU()(x)
#上取樣,用Conv2DTranspose,從16*16跨達到32*32
x = layers.Conv2DTranspose(filters=256, kernel_size=4, strides=2, padding='same')(x)
x = layers.ReLU()(x)

x = layers.Conv2D(filters=256, kernel_size=5, padding='same')(x)
x = layers.ReLU()(x)
#生成32*32*3的圖片
x = layers.Conv2D(filters = 3, kernel_size=7, padding='same')(x)
x = layers.Activation('tanh')(x)

generator = keras.models.Model(generator_input, x)
generator.summary()#列印生成網路

#構建判別器網路discriminator_network
discriminator_input = layers.Input(shape=(height, width, channels))#輸入的是32*32*3的圖片
x = layers.Conv2D(filters=128, kernel_size=3 ,padding='same')(discriminator_input)
x = layers.LeakyReLU()(x)

x = layers.Conv2D(filters=128, kernel_size=4 , strides=2,padding='same')(x)
x = layers.LeakyReLU()(x)

x = layers.Conv2D(filters=128, kernel_size=4 , strides=2,padding='same')(x)
x = layers.LeakyReLU()(x)

x = layers.Conv2D(filters=128, kernel_size=4 , strides=2,padding='same')(x)
x = layers.LeakyReLU()(x)

x = layers.Flatten()(x)
x = layers.Dropout(0.4)(x)#新增一個Dropout層
x = layers.Dense(1, activation = 'sigmoid')(x)#輸出一個一維的概率值

discriminator = keras.models.Model(discriminator_input, x)
discriminator.summary()#列印判別網路
#對判別器選用了優化器,損失函式
discriminator_optimizer = keras.optimizers.RMSprop(lr=0.0008, clipvalue=1.0, decay=1e-8)
discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy')
#固定辨別器的引數,這樣可以去訓練生成器
discriminator.trainable = False

gan_input=generator_input
gan_output=discriminator(generator(gan_input))
gan=keras.models.Model(gan_input,gan_output)
#對整個模型選用優化器和損失函式
optimizer=keras.optimizers.RMSprop(lr=0.001,rho=0.9,epsilon=1e-8,decay=0.0)
gan.compile(loss='binary_crossentropy',optimizer=optimizer)

iterations = 1000   #迭代1000次
batch_size = 32     #每批送入32張圖片
save_dir = 'E://Desktop//gan_image//'#為生成器生成的圖片找一個目錄儲存
start=0
for step in range(iterations):
    random_latent_vectors = np.random.normal(size=(batch_size, pre_data))
    generated_images=generator.predict(random_latent_vectors)#對於輸入得樣本預測輸出
    #每次放入一個batch_size的圖片,通過這種索引的方式放入
    stop=start+batch_size
    real_images=x_train[start:stop]
    #聯合生成圖片與真實圖片,生成圖片的標籤設定為1,真實圖片的標籤為0
    combined_images = np.concatenate([generated_images, real_images])
    labels = np.concatenate([np.ones((batch_size, 1)) , np.zeros((batch_size, 1))])
    #給標籤加一個很小的噪聲
    labels += 0.05 * np.random.random(labels.shape)
    #用正確的標籤去訓練判別器
    d_loss = discriminator.train_on_batch(combined_images, labels)
    #生成一組假的影象,然後將這組圖片的標籤設定為0(真),用於誤導判別器,讓判別器去判斷這個到底是不是真的。迭代訓練
    random_latent_vectors = np.random.normal(size=(batch_size, pre_data))
    mislead_targets = np.zeros((batch_size,1))
    #訓練整個網路
    a_loss = gan.train_on_batch(random_latent_vectors,mislead_targets)
    #計數器每次累加一個batch
    start += batch_size
    #確保送入的圖片能夠被索引到,如果圖片的索引不存在,則會報錯
    if start > len(x_train) - batch_size:
        start = 0
    #列印結果,總體損失和判別器損失
    if step%100==0:
        print('discriminator loss at step %s: %s' % (step, d_loss))
        print('adversarial   loss at step %s: %s' % (step, a_loss))

        # 儲存生成的圖片
        img = image.array_to_img(generated_images[0] * 255., scale=False)
        img.save(os.path.join(save_dir, 'generated_dog' + str(step) + '.png'))

        # 儲存訓練過程中輸入的真實的圖片,可以形成對比
        img = image.array_to_img(real_images[0] * 255., scale=False)
        img.save(os.path.join(save_dir, 'real_dog' + str(step) + '.png'))

之後打算用TensorFlow的框架寫一個GAN網路

資料歸一化參考部落格:https://blog.csdn.net/fontthrone/article/details/74067064

GAN網路參考了書籍:deep learning with python