0. 简介
在曩昔,我写的首要都是“传统类”的机器学习文章,如朴素贝叶斯分类、逻辑回归和Perceptron算法。在曩昔的一年中,我一直在研讨深度学习技能,因而,我想和咱们共享一下怎么运用Tensorflow从头开端构建和练习卷积神经网络。这样,咱们今后就能够将这个常识作为一个构建块来发明风趣的深度学习运用程序了。
为此,你需求装置Tensorflow(请参阅装置阐明),你还应该对Python编程和卷积神经网络背面的理论有一个根本的了解。装置完Tensorflow之后,你能够在不依赖GPU的情况下运转一个较小的神经网络,但关于更深层次的神经网络,就需求用到GPU的核算才能了。
在互联网上有许多解说卷积神经网络作业原理方面的网站和课程,其间有一些仍是很不错的,图文并茂、易于了解[点击此处获取更多信息]。我在这儿就不再解说相同的东西,所以在开端阅览下文之前,请提早了解卷积神经网络的作业原理。例如:
什么是卷积层,卷积层的过滤器是什么?
什么是激活层(ReLu层(运用最广泛的)、S型激活或tanh)?
什么是池层(最大池/均匀池),什么是dropout?
随机梯度下降的作业原理是什么?
本文内容如下:
Tensorflow根底
1.1 常数和变量
1.2 Tensorflow中的图和会话
1.3 占位符和feed_dicts
Tensorflow中的神经网络
2.1 介绍
2.2 数据加载
2.3 创立一个简略的一层神经网络
2.4 Tensorflow的多个方面
2.5 创立LeNet5卷积神经网络
2.6 影响层输出巨细的参数
2.7 调整LeNet5架构
2.8 学习速率和优化器的影响
Tensorflow中的深度神经网络
3.1 AlexNet
3.2 VGG Net-16
3.3 AlexNet功能
结语
1. Tensorflow 根底
在这儿,我将向曾经从未运用过Tensorflow的人做一个简略的介绍。假如你想要当即开端构建神经网络,或许现已了解Tensorflow,能够直接跳到第2节。假如你想了解更多有关Tensorflow的信息,你还能够检查这个代码库,或许阅览斯坦福大学CS20SI课程的讲义1和讲义2。
1.1 常量与变量
Tensorflow中最根本的单元是常量、变量和占位符。
tf.constant()和tf.Variable()之间的差异很清楚;一个常量有着稳定不变的值,一旦设置了它,它的值不能被改动。而变量的值能够在设置完成后改动,但变量的数据类型和形状无法改动。
#We can create constants and variables of different types.
#However, the different types do not mix well together.
a = tf.constant(2, tf.int16)
b = tf.constant(4, tf.float32)
c = tf.constant(8, tf.float32)
d = tf.Variable(2, tf.int16)
e = tf.Variable(4, tf.float32)
f = tf.Variable(8, tf.float32)
#we can perform computations on variable of the same type: e + f
#but the following can not be done: d + e
#everything in Tensorflow is a tensor, these can have different dimensions:
#0D, 1D, 2D, 3D, 4D, or nD-tensors
g = tf.constant(np.zeros(shape=(2,2), dtype=np.float32)) #does work
h = tf.zeros([11], tf.int16)
i = tf.ones([2,2], tf.float32)
j = tf.zeros([1000,4,3], tf.float64)
k = tf.Variable(tf.zeros([2,2], tf.float32))
l = tf.Variable(tf.zeros([5,6,5], tf.float32))
除了tf.zeros()和tf.ones()能够创立一个初始值为0或1的张量(见这儿)之外,还有一个tf.random_normal()函数,它能够创立一个包括多个随机值的张量,这些随机值是从正态散布中随机抽取的(默许的散布均值为0.0,标准差为1.0)。
别的还有一个tf.truncated_normal()函数,它创立了一个包括从切断的正态散布中随机抽取的值的张量,其间下上限是标准误差的两倍。
有了这些常识,咱们就能够创立用于神经网络的权重矩阵和误差向量了。
weights = tf.Variable(tf.truncated_normal([256 * 256, 10]))
biases = tf.Variable(tf.zeros([10]))
print(weights.get_shape().as_list())
print(biases.get_shape().as_list())
>>>[65536, 10]
>>>[10]
1.2 Tensorflow 中的图与会话
在Tensorflow中,一切不同的变量以及对这些变量的操作都保存在图(Graph)中。在构建了一个包括针对模型的一切核算过程的图之后,就能够在会话(Session)中运转这个图了。会话能够跨CPU和GPU分配一切的核算。
graph = tf.Graph()
with graph.as_default():
a = tf.Variable(8, tf.float32)
b = tf.Variable(tf.zeros([2,2], tf.float32))
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
print(f)
print(session.run(f))
print(session.run(k))
>>>
>>> 8
>>> [[ 0. 0.]
>>> [ 0. 0.]]
1.3 占位符 与 feed_dicts
咱们现已看到了用于创立常量和变量的各种形式。Tensorflow中也有占位符,它不需求初始值,仅用于分配必要的内存空间。 在一个会话中,这些占位符能够经过feed_dict填入(外部)数据。
以下是占位符的运用示例。
list_of_points1_ = [[1,2], [3,4], [5,6], [7,8]]
list_of_points2_ = [[15,16], [13,14], [11,12], [9,10]]
list_of_points1 = np.array([np.array(elem).reshape(1,2) for elem in list_of_points1_])
list_of_points2 = np.array([np.array(elem).reshape(1,2) for elem in list_of_points2_])
graph = tf.Graph()
with graph.as_default():
#we should use a tf.placeholder() to create a variable whose value you will fill in later (during session.run()).
#this can be done by 'feeding' the data into the placeholder.
#below we see an example of a method which uses two placeholder arrays of size [2,1] to calculate the eucledian distance
point1 = tf.placeholder(tf.float32, shape=(1, 2))
point2 = tf.placeholder(tf.float32, shape=(1, 2))
def calculate_eucledian_distance(point1, point2):
difference = tf.subtract(point1, point2)
power2 = tf.pow(difference, tf.constant(2.0, shape=(1,2)))
add = tf.reduce_sum(power2)
eucledian_distance = tf.sqrt(add)
return eucledian_distance
dist = calculate_eucledian_distance(point1, point2)
with tf.Session(graph=graph) as session:
tf.global_variables_initializer().run()
for ii in range(len(list_of_points1)):
point1_ = list_of_points1[ii]
point2_ = list_of_points2[ii]
feed_dict = {point1 : point1_, point2 : point2_}
distance = session.run([dist], feed_dict=feed_dict)
print("the distance between {} and {} -> {}".format(point1_, point2_, distance))
>>> the distance between [[1 2]] and [[15 16]] -> [19.79899]
>>> the distance between [[3 4]] and [[13 14]] -> [14.142136]
>>> the distance between [[5 6]] and [[11 12]] -> [8.485281]
>>> the distance between [[7 8]] and [[ 9 10]] -> [2.8284271]
2. Tensorflow 中的神经网络
2.1 简介
包括神经网络的图(如上图所示)应包括以下过程:
1. 输入数据集:练习数据集和标签、测验数据集和标签(以及验证数据集和标签)。 测验和验证数据集能够放在tf.constant()中。而练习数据集被放在tf.placeholder()中,这样它能够在练习期间分批输入(随机梯度下降)。
2. 神经网络**模型**及其一切的层。这能够是一个简略的彻底衔接的神经网络,仅由一层组成,或许由5、9、16层组成的更杂乱的神经网络。
3. 权重矩阵和**误差矢量**以恰当的形状进行界说和初始化。(每层一个权重矩阵和误差矢量)
4. 丢失值:模型能够输出分对数矢量(估量的练习标签),并经过将分对数与实践标签进行比较,核算出丢失值(具有穿插熵函数的softmax)。丢失值表明估量练习标签与实践练习标签的挨近程度,并用于更新权重值。
5. 优化器:它用于将核算得到的丢失值来更新反向传达算法中的权重和误差。
2.2 数据加载
下面咱们来加载用于练习和测验神经网络的数据集。为此,咱们要下载MNIST和CIFAR-10数据集。 MNIST数据集包括了6万个手写数字图画,其间每个图画巨细为28 x 28 x 1(灰度)。 CIFAR-10数据集也包括了6万个图画(3个通道),巨细为32 x 32 x 3,包括10个不同的物体(飞机、轿车、鸟、猫、鹿、狗、青蛙、马、船、货车)。 由于两个数据会集都有10个不同的目标,所以这两个数据集都包括10个标签。
首要,咱们来界说一些便利载入数据和格式化数据的办法。
def randomize(dataset, labels):
permutation = np.random.permutation(labels.shape[0])
shuffled_dataset = dataset[permutation, :, :]
shuffled_labels = labels[permutation]
return shuffled_dataset, shuffled_labels
def one_hot_encode(np_array):
return (np.arange(10) == np_array[:,None]).astype(np.float32)
def reformat_data(dataset, labels, image_width, image_height, image_depth):
np_dataset_ = np.array([np.array(image_data).reshape(image_width, image_height, image_depth) for image_data in dataset])
np_labels_ = one_hot_encode(np.array(labels, dtype=np.float32))
np_dataset, np_labels = randomize(np_dataset_, np_labels_)
return np_dataset, np_labels
def flatten_tf_array(array):
shape = array.get_shape().as_list()
return tf.reshape(array, [shape[0], shape[1] shape[2] shape[3]])
def accuracy(predictions, labels):
return (100.0 * np.sum(np.argmax(predictions, 1) == np.argmax(labels, 1)) / predictions.shape[0])
这些办法可用于对标签进行独热码编码、将数据加载到随机数组中、扁平化矩阵(由于彻底衔接的网络需求一个扁平矩阵作为输入):
在咱们界说了这些必要的函数之后,咱们就能够这样加载MNIST和CIFAR-10数据集了:
mnist_folder = './data/mnist/'
mnist_image_width = 28
mnist_image_height = 28
mnist_image_depth = 1
mnist_num_labels = 10
mndata = MNIST(mnist_folder)
mnist_train_dataset_, mnist_train_labels_ = mndata.load_training()
mnist_test_dataset_, mnist_test_labels_ = mndata.load_testing()
mnist_train_dataset, mnist_train_labels = reformat_data(mnist_train_dataset_, mnist_train_labels_, mnist_image_size, mnist_image_size, mnist_image_depth)
mnist_test_dataset, mnist_test_labels = reformat_data(mnist_test_dataset_, mnist_test_labels_, mnist_image_size, mnist_image_size, mnist_image_depth)
print("There are {} images, each of size {}".format(len(mnist_train_dataset), len(mnist_train_dataset[0])))
print("Meaning each image has the size of 28281 = {}".format(mnist_image_sizemnist_image_size1))
print("The training set contains the following {} labels: {}".format(len(np.unique(mnist_train_labels_)), np.unique(mnist_train_labels_)))
print('Training set shape', mnist_train_dataset.shape, mnist_train_labels.shape)
print('Test set shape', mnist_test_dataset.shape, mnist_test_labels.shape)
train_dataset_mnist, train_labels_mnist = mnist_train_dataset, mnist_train_labels
test_dataset_mnist, test_labels_mnist = mnist_test_dataset, mnist_test_labels
######################################################################################
cifar10_folder = './data/cifar10/'
train_datasets = ['data_batch_1', 'data_batch_2', 'data_batch_3', 'data_batch_4', 'data_batch_5', ]
test_dataset = ['test_batch']
c10_image_height = 32
c10_image_width = 32
c10_image_depth = 3
c10_num_labels = 10
with open(cifar10_folder + test_dataset[0], 'rb') as f0:
c10_test_dict = pickle.load(f0, encoding='bytes')
c10_test_dataset, c10_test_labels = c10_test_dict[b'data'], c10_test_dict[b'labels']
test_dataset_cifar10, test_labels_cifar10 = reformat_data(c10_test_dataset, c10_test_labels, c10_image_size, c10_image_size, c10_image_depth)
c10_train_dataset, c10_train_labels = [], []
for train_dataset in train_datasets:
with open(cifar10_folder + train_dataset, 'rb') as f0:
c10_train_dict = pickle.load(f0, encoding='bytes')
c10_train_dataset_, c10_train_labels_ = c10_train_dict[b'data'], c10_train_dict[b'labels']
c10_train_dataset.append(c10_train_dataset_)
c10_train_labels += c10_train_labels_
c10_train_dataset = np.concatenate(c10_train_dataset, axis=0)
train_dataset_cifar10, train_labels_cifar10 = reformat_data(c10_train_dataset, c10_train_labels, c10_image_size, c10_image_size, c10_image_depth)
del c10_train_dataset
del c10_train_labels
print("The training set contains the following labels: {}".format(np.unique(c10_train_dict[b'labels'])))
print('Training set shape', train_dataset_cifar10.shape, train_labels_cifar10.shape)
print('Test set shape', test_dataset_cifar10.shape, test_labels_cifar10.shape)
你能够从Yann LeCun的网站下载MNIST数据集。下载并解压缩之后,能够运用python-mnist 东西来加载数据。 CIFAR-10数据集能够从这儿下载。