前言:有监督学习和无监督学习
有监督学习就是通过已有的训练样本去训练得到一个最优模型,再利用这个模型将所有的输入映射为相应的输出,对输出进行简单的判断从而实现预测和分类的目的,也就具有了对未知数据进行预测和分类的能力。
在有监督学习有两类任务,可分为回归和分类。
回归:即给出一堆自变量X和因变量Y,让你来拟合出一个函数,来进行预测。
分类:也是由特征向量X和它们的标签Y组成,当你利用数据训练出模型后,给你一个自变量,让你求它的因变量是什么?例如logistics、SVM、KNN等。
无监督学习:在无监督学习中,事先没有任何训练样本,也就是事先对输入没有一个明确的函数映射关系,神经网络需要直接对数据进行建模,让它进行学习。无监督学习主要任务是聚类,所谓聚类就是通过计算样本间和群体间距离,把类似的群体聚集在一起。主要算法包括Kmeans、EM算法。
自编码器
在神经网络中分为有监督学习和无监督学习,而自编码器就是通过无监督学习的神经网络。对输入数据的进行处理得过程表示称为编码,编码后的维度一般远小于输入数据,使得自编码器可用于降维。更重要的是,自编码器可作为强大的特征检测器,应用于深度神经网络的预训练。
此外,自编码器还可以随机生成与训练数据类似的数据,这被称作生成模型。比如,可以用人脸图片训练一个自编码器,它可以生成新的图片。
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=False)
learning_rate = 0.01
training_epochs = 5
batch_size = 256
display_step = 1
examples_to_show = 10
n_input = 784
X = tf.placeholder("float", [None, n_input])
n_hidden_1 = 256
n_hidden_2 = 128
weights = {
'encoder_h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
'encoder_h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
'decoder_h1': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_1])),
'decoder_h2': tf.Variable(tf.random_normal([n_hidden_1, n_input])),
}
biases = {
'encoder_b1': tf.Variable(tf.random_normal([n_hidden_1])),
'encoder_b2': tf.Variable(tf.random_normal([n_hidden_2])),
'decoder_b1': tf.Variable(tf.random_normal([n_hidden_1])),
'decoder_b2': tf.Variable(tf.random_normal([n_input])),
}
def encoder(x):
layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']),biases['encoder_b1']))
layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['encoder_h2']), biases['encoder_b2']))
return layer_2
def decoder(x):
layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['decoder_h1']),biases['decoder_b1']))
layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['decoder_h2']), biases['decoder_b2']))
return layer_2
encoder_op = encoder(X)
decoder_op = decoder(encoder_op)
y_pred = decoder_op
y_true = X
cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2))
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
with tf.Session() as sess:
if int((tf.__version__).split('.')[1]) < 12 and int((tf.__version__).split('.')[0]) < 1:
init = tf.initialize_all_variables()
else:
init = tf.global_variables_initializer()
sess.run(init)
total_batch = int(mnist.train.num_examples/batch_size)
for epoch in range(training_epochs):
for i in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
_, c = sess.run([optimizer, cost], feed_dict={X: batch_xs})
if epoch % display_step == 0:
print("Epoch:", '%04d' % (epoch+1),
"cost=", "{:.9f}".format(c))
print("Optimization Finished!")
encode_decode = sess.run(
y_pred, feed_dict={X: mnist.test.images[:examples_to_show]})
f, a = plt.subplots(2, 10, figsize=(10, 2))
for i in range(examples_to_show):
a[0][i].imshow(np.reshape(mnist.test.images[i], (28, 28)))
a[1][i].imshow(np.reshape(encode_decode[i], (28, 28)))
plt.show()
从本质上说,自编码器就是一种数据压缩的算法。它通过编码器和解码器分别进行对输入的压缩,和对压缩后的数据进行重构。一个好的自编码器可以高效还原压缩过的数据。
自编码器的特点
- 数据相关性:自编码器只能够压缩和自身分布类似的数据,倘若用猫狗数据集训练出来的自编码器去压缩人脸,肯定是不行的。
- 数据有损性:在进行编码和解码的过程中,肯定会造成数据的损失。
- 自动学习性:因为自编码器是从数据样本中自动学习的,所以在输入输出的过程中,不需要进行任何新的工作。
GAN是什么,又是为什么而生?
GAN是在学习从随机变量到训练样本的映射关系。其中随机变量可以选择服从正态分布,那么就能得到一个由多层感知机组成的生成网络,网络的输入是一个一维的随机变量,而输出则是一张图片。生成网络的作用就是如何让输出的伪造图片看起来像训练样本;在生成网络后面接上一个多层感知机组成的判别网络,这个网络的输入是随机选择一张真实样本或者生成网络的输出,输出是输入图片来自于真实样本或者生成网络的概率;当判别网络能够很好地分辨出输入不是真实样本时,也能通过梯度的方式说明什么样的输入才更加像真实样本,从而通过这个信息来调整生成网络。从而需要尽可能的让自己的输出像真实样本,而则尽可能的将不是真实样本的情况分辨出来。
在GAN网络中,有两个模型:
生成模型:比作是一个样本生成器,输入一个噪声/样本,然后把它包装成一个逼真的样本,也就是输出。简单来说,生成网络是制造样本的,它的目的就是使得自己造样本的能力尽可能强,强到判别网络没法判断是真样本还是假样本。
判别模型:判别模型就比作一个二分类器,来判断输入的样本是真是假,也就是能判别出来属于的一张图它是来自真实样本集还是假样本集。假如输入的是真样本,网络输出就接近1,输入的是假样本,网络输出接近0。这样就可以很完美地达到了很好判别的目的。
在GAN中,有一个很重要的思想就是博弈思想。
和上面所说的一样,一个生成逼真的数据,让你无法分清是真是假,而另一个则要尽力去分辨出哪一个是真,哪一个是假。
在GAN的训练过程中,在同一轮梯度传递的过程中可以细分为2步:先训练判别器,再训练生成器。(注意不是等所有的判别器训练好以后,才开始训练生成器,因为判别器的训练也需要上一轮梯度反传中生成器的输出值作为输入)
当训练判别器的时候,上一轮生成器产生的图片会和真实图片直接拼接在一起,作为x输入。然后按顺序摆放0和1,假图对应0,真图对应1。然后就可以通过,x输入生成一个score(从0到1之间的数),通过score和y组成的损失函数,就可以进行梯度传递了。
当训练生成器的时候, 需要把生成器和判别器当作一个整体。输入一组随机向量,就可以在生成器生成一张图,通过判别器对生成的这张图进行打分。这里的目标是使score=1,score和y=1之间的差异可以组成损失函数,然后可以作为反向传播梯度。注意,这里的判别器的参数是不可训练的,因为此时判别器不能改变,保证生成器符合当下判别器的标准进行打分。
from __future__ import print_function, division
from keras.datasets import mnist
from keras.layers import Input, Dense, Reshape, Flatten, Dropout
from keras.layers import BatchNormalization, Activation, ZeroPadding2D
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D, Conv2D
from keras.models import Sequential, Model
from keras.optimizers import Adam
import matplotlib.pyplot as plt
import sys
import numpy as np
class GAN():
def __init__(self):
self.img_rows = 28
self.img_cols = 28
self.channels = 1
self.img_shape = (self.img_rows, self.img_cols, self.channels)
self.latent_dim = 100
optimizer = Adam(0.0002, 0.5)
self.discriminator = self.build_discriminator()
self.discriminator.compile(loss='binary_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
self.generator = self.build_generator()
z = Input(shape=(self.latent_dim,))
img = self.generator(z)
self.discriminator.trainable = False
validity = self.discriminator(img)
self.combined = Model(z, validity)
self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)
def build_generator(self):
model = Sequential()
model.add(Dense(256, input_dim=self.latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(1024))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(np.prod(self.img_shape), activation='tanh'))
model.add(Reshape(self.img_shape))
model.summary()
noise = Input(shape=(self.latent_dim,))
img = model(noise)
return Model(noise, img)
def build_discriminator(self):
model = Sequential()
model.add(Flatten(input_shape=self.img_shape))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(256))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(1, activation='sigmoid'))
model.summary()
img = Input(shape=self.img_shape)
validity = model(img)
return Model(img, validity)
def train(self, epochs, batch_size=128, sample_interval=50):
(X_train, _), (_, _) = mnist.load_data()
X_train = X_train / 127.5 - 1.
X_train = np.expand_dims(X_train, axis=3)
valid = np.ones((batch_size, 1))
fake = np.zeros((batch_size, 1))
for epoch in range(epochs):
idx = np.random.randint(0, X_train.shape[0], batch_size)
imgs = X_train[idx]
noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
gen_imgs = self.generator.predict(noise)
d_loss_real = self.discriminator.train_on_batch(imgs, valid)
d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake)
d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
g_loss = self.combined.train_on_batch(noise, valid)
print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss))
if epoch % sample_interval == 0:
self.sample_images(epoch)
def sample_images(self, epoch):
r, c = 5, 5
noise = np.random.normal(0, 1, (r * c, self.latent_dim))
gen_imgs = self.generator.predict(noise)
gen_imgs = 0.5 * gen_imgs + 0.5
fig, axs = plt.subplots(r, c)
cnt = 0
for i in range(r):
for j in range(c):
axs[i,j].imshow(gen_imgs[cnt, :,:,0], cmap='gray')
axs[i,j].axis('off')
cnt += 1
fig.savefig("images/%d.png" % epoch)
plt.close()
if __name__ == '__main__':
gan = GAN()
gan.train(epochs = 30000,
batch_size = 16,
sample_interval = 200)