本文仅做学习记录之用
TensorFlow官网链接。感觉写的很全面,打算按照这个学下去,后续的记录暂定按照它的目录来。
新手入门
1.1介绍
这段代码应该是最基本的了,比较少,不会的点就直接查,但是涉及tensorflow的会在后面逐渐记录。
np.float32()
是令内部元素的类型为float32
np.random.rand()
返回一组元素在[0,1)之间均匀分布的随机样本,如:
import numpy as np
print(np.random.rand(2,3)) # (2,3)表示维度
"""
输出:
[[ 0.77683057 0.13237516 0.50873495]
[ 0.39650787 0.52095996 0.05808078]]
"""
与之类似的,np.random.random()
的返回值同上,但输入参数不同,np.random.random()
的参数是tuple,而np.random.rand()
接受的是离散的参数,即np.random.random((2,3)) == np.random.rand(2,3)
还有,np.random.randn()
返回一个或一组服从标准正态分布(即N(0, 1))的随机样本值。
import numpy as np
print(np.random.randn(2,3)) # (2,3)表示维度
"""
输出:
[[ 0.46352983 0.01918194 -0.60883008]
[ 0.06863566 2.55242719 0.74146498]]
"""
np.dot()
表示矩阵相乘。如矩阵A
和B
相乘可以是np.dot(A, B)
或A.dot(B)
。官网说A @ B
也可以,自己跑的时候不知道为什么报错。
A = np.array( [[1,1], [0,1]] )
B = np.array( [[2,0], [3,4]] )
print("np.dot(A, B): ", np.dot(A, B))
print("A.dot(B): ", A.dot(B))
'''
输出
np.dot(A, B): array([[5, 4], [3, 4]])
A.dot(B): array([[5, 4], [3, 4]])
'''
xrange()
和range()
的区别:
这两者基本一致,区别在于range()
返回一个list,而xrange()
返回一个生成器对象。
print(range(5))
print(xrange(5))
print(list(xrange(5)))
'''
输出
[0, 1, 2, 3, 4]
xrange(5)
[0, 1, 2, 3, 4]
'''
相对而言,xrange()
性能更优,不需要一上来就开辟一个内存空间,在用作for
循环使用时,两者的是一致,所以直接使用xrange()
。
1.2 下载及安装
这个有很多博客记录,安装Anaconda再安装即可,这里不再赘述。
1.3 基本用法
TensorFlow的基本概念:
1.使用图 (graph
) 来表示计算任务,图中的节点被称之为 op
(operation 的缩写),一个 op
获得 0 个或多个 Tensor
, 执行计算, 产生 0 个或多个 Tensor
。
2.在被称之为 会话 (Session
) 的上下文 (context) 中执行图.
3.使用 tensor
表示数据.
4.通过 变量 (Variable
) 维护状态.
5.使用 feed
和 fetch
可以为任意的操作(arbitrary operation) 赋值或者从其中获取数据.
TensorFlow程序的运行过程:
TensorFlow 程序通常被组织成一个构建阶段和一个执行阶段. 在构建阶段, op
的执行步骤被描述成一个图. 在执行阶段, 使用会话执行执行图中的 op
.
例如, 通常在构建阶段创建一个图来表示和训练神经网络, 然后在执行阶段反复执行图中的训练 op
。
构建阶段
构建图的第一步, 是创建源op
(source op). 源op
不需要任何输入, 例如 常量 (Constant). 源op
的输出被传递给其它 op
做运算。例如:
import tensorflow as tf
# 创建一个常量 op, 产生一个 1x2 矩阵. 这个 op 被作为一个节点
# 加到默认图中.
# 构造器的返回值代表该常量 op 的返回值.
matrix1 = tf.constant([[3., 3.]])
# 创建另外一个常量 op, 产生一个 2x1 矩阵.
matrix2 = tf.constant([[2.],[2.]])
# 创建一个矩阵乘法 matmul op , 把 'matrix1' 和 'matrix2' 作为输入.
# 返回值 'product' 代表矩阵乘法的结果.
product = tf.matmul(matrix1, matrix2)
执行阶段
构建阶段完成后,才能启动图。首先创建一个Session
对象,若无参数,则为默认图。其run()
函数用来执行op
,如:
# 启动默认图.
sess = tf.Session()
result = sess.run(product)
print(result)
# 任务完成, 关闭会话.
sess.close()
其中,函数调用 ‘run(product)’ 触发了图中三个 op
(两个常量 op
和一个矩阵乘法 op
) 的执行。且op
通常是并发执行的。
为了避免忘记用close()
释放资源,可以用with
自动完成关闭动作。如:
with tf.Session() as sess:
result = sess.run([product])
print(result)
关于feed和fetch,暂不记录。
完整教程
2.1 总揽
这节就是个链接。。。
2.2 MNIST 数据下载
按照说的下载就完事了
2.3 MNIST入门
这部分直接上代码,整理在一起后又加了些备注
这里只使用基本的机器学习方法,不考虑像素之间的邻接关系,最后加个softmax就输出结果了。
import tensorflow as tf
import input_data
# 首先下载数据,然后转换数据格式,将图像拉成一维数据,训练集和测试集都放在mnist中
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# placeholder是占为符,None表示任意维数,即不限制训练集等的数量
x = tf.placeholder("float", [None, 784])
y_ = tf.placeholder("float", [None,10])
# 用变量存储参数(权重和偏移),初始值设为0
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
# 模型。即在w·x+b后加一个softmax,作为预测值
y = tf.nn.softmax(tf.matmul(x,W) + b)
# y_是真值数据,此处是ont_hot形式,如[0,0,0,0,0,0,1,0,0,0]表示“6”,y是预测值,也是ont_hot形式
# tf.log()是对y中的每一个元素求log
# tf.reduce_sum()是计算所有元素的总和
# 最终结果cross_entropy即是交叉熵
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
# GradientDescentOptimizer(0.01)表示使用梯度下降算法,学习率为0.01,也可以使用其他算法
# 目标是最小化交叉熵(cross_entropy)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
# 再运行前,应初始化创建的变量
init = tf.global_variables_initializer()
# 启动Session,并初始化变量
sess = tf.Session()
sess.run(init)
# 迭代优化
for i in range(1000):
# 随机抓去训练集中的100条数据
batch_xs, batch_ys = mnist.train.next_batch(100)
# train_step之前的op中包含占位符,需要使用feed_dict给出每一个占位符所用的值
# 用占位符的优势在于,即使迭代几百万次,也只需要构建一个op,不同于使用常量就需要几百万个op
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
# 在测试集上统计准确率
# tf.argmax(y, 1)是返回y中最大值的索引,如果y是一个矩阵,则返回一组索引,对应着每行最大值的位置
# tf.equal(v1, v2)返回v1和v2对应元素是否相等,如v1 = [1,0,0] v2 = [1,1,0],则返回[ True False True]
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
# tf.cast()是转变tensor类型,此处是将bool类型转为float
# tf.reduce_mean()是对tensor求均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print("正确率:", sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
2.4 MNIST进阶
同样通过代码+注释的方法记录
这里不在使用最基本的机器学习方法,而是加入了卷积的概念。
关于卷积核,查明白了一些定义,每个卷积核有长、宽、深三个长度单位,深也就是输入通道数。
"""
MNIST进阶
"""
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder("float", [None, 784])
y_ = tf.placeholder("float", [None,10])
# InteractiveSession类可以在运行图时插入一些计算图,相当于不再要求“构建->计算”这个顺序了
sess = tf.InteractiveSession()
# 后面的激活函数使用ReLU
# tf.truncated_normal(shape, mean, stddev) :shape表示生成张量的维度,mean是均值,stddev是标准差。与一般的正态分布区别在于,
# truncated_normal产生大于两倍的标准差时,会重新生成数据,所以所有的元素都在两倍标准差以内。
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
# 构建卷积函数
# tf.nn.conv2d()是卷积函数,x是输入的原图,x = [batch,in_height,in_width,in_channels],
# batch为训练过程中每迭代一次迭代的照片数,in_height,in_width分别为图片的高和宽,in_channels为图片的通道数
# W是卷积核,W = [filter_height,filter_width,in_channels,out_channels],分别为权重的高、宽、输入通道数和输出的通道数
# strides = [a,b,c,d],a、d固定为1,b、c分别是水平和垂直的滑动距离
# padding参数有两种模式:'SAME'和'VALID','SAME'模式在卷积的过程中会在原图的边缘“补0”,以匹配上卷积核,但'VALID'模式不会,
# 卷积过程中遇到无法匹配卷积核的情况,会直接舍弃那部分元素。
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
# 构建池化函数
# 池化有三种,分别是:
# 1.mean-pooling,即对邻域内特征点只求平均,对背景保留更好;
# 2.max-pooling,即对邻域内特征点取最大,对纹理提取更好;
# 3.Stochastic-pooling,介于两者之间,通过对像素点按照数值大小赋予概率,再按照概率进行亚采样
# tf.nn.max_pool()是在原特征基础上,做最大池化,x是输入的特征,与卷积相同:x = [batch, height, width, channels]
# ksize:池化窗口的大小,因为我们不想在batch和channels上做池化,所以一般是一般是[1, height, width, 1]
# strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
# padding:和卷积类似,可以取'VALID' 或者'SAME',用来决定是否‘补0’
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
# 将原本被拉成一条直线的图像,重新被转为28*28的图像,-1表示不需指定这一维的大小,会自动计算(这里是样本量),1为通道数,RGB图像为3
x_image = tf.reshape(x, [-1,28,28,1])
# 构建第一层卷积,W_conv1是第一个卷积核,b_conv1是第一个偏移
# [5, 5, 1, 32]表示卷积核为5*5,输入通道为1,输出的特征为32个
# 故而偏移量的也是32个
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
# 把x_image和权值向量进行卷积,加上偏置项,然后应用ReLU激活函数,就是让负数变为0
# 再对特征进行最大池化,feature map变为14*14*32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
# 构建第二层卷积,W_conv1是第二个卷积核,b_conv1是第二个偏移
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
# 同上,卷积->激活->池化
# feature map变为7*7*64
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
# 构建全连接层,将feature map转为一个1024维的特征
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
# tf.nn.dropout()放在输出层之前,用于减少过拟合,同时还会自动处理神经元输出值的scale
# 参数说明 tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None,name=None)
# x: 表示输入 keep_prob: 表示每个神经元输出不被屏蔽的概率
# 它能以不变的概率屏蔽神经元的输出,在某一次迭代中,某些权重就不会更新(当然,下一次迭代可能就更新了)
# 用占位符表示这个概率,训练时给一个0~1的概率,减少过拟合;测试时,给概率值为1,意味着不会屏蔽任何神经元的输出。
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# 输出层,从1024维特征转为10维的输出
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
# 同上,跟之前softmax一样
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 同上,还是使用交叉熵
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
# 使用更复杂的ADAM优化器来做梯度最速下降
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
# 同上,计算准确率
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
# 变量初始化
sess.run(tf.initialize_all_variables())
# 循环迭代参数
for i in range(20000):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={
x:batch[0], y_: batch[1], keep_prob: 1.0})
print "step %d, training accuracy %g"%(i, train_accuracy)
# 直接用train_step.run(),而不是sess.run(train_step),是不是两种都可以?
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
# sess.run(train_step, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
# 测试集准确率
print "test accuracy %g"%accuracy.eval(feed_dict={
x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0})