连体网络MINIST识别 作业过程记录
1.minist 数据
tensorsflow中文社区提供python源码自动下载和安装,加到自己代码文件里:
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
训练集:60000行的训练数据集(mnist.train)
测试数据:10000行的测试数据集(mnist.test)
每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签。
图片:“xs”
标签:“ys”
训练数据集和测试数据集都包含xs和ys,
比如训练数据集的图片是 mnist.train.images ,
训练数据集的标签是 mnist.train.labels。
每张图片28*28=784(可展成向量)
在MNIST训练数据集中,mnist.train.images 是一个形状为 [60000, 784]
mnist.train.labels 是一个 [60000, 10] 的数字矩阵。
1. tesnsorflow minist入门
1.1 Softmax回归介绍
softmax模型可以用来给不同的对象分配概率。即使在之后,我们训练更加精细的模型时,最后一步也需要用softmax来分配概率。比如说,我们的模型可能推测一张包含9的图片代表数字9的概率是80%但是判断它是8的概率是5%(因为8和9都有上半部分的小圆),然后给予它代表其他数字的概率更小的值。
softmax回归(softmax regression)分两步:
第一步:为了得到一张给定图片属于某个特定数字类的证据(evidence),我们对图片像素值进行加权求和。
我们也需要加入一个额外的偏置量(bias),因为输入往往会带有一些无关的干扰量。因此对于给定的输入图片 x 它代表的是数字 i 的证据可以表示为:
其中 Wi W i 代表权重, bi b i 代表数字 i 类的偏置量,j 代表给定图片 x 的像素索引用于像素求和。
第二步:
然后用softmax函数可以把这些证据转换成概率 y:
这里的softmax可以看成是一个激励(activation)函数或者链接(link)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布。因此,给定一张图片,它对于每一个数字的吻合度可以被softmax函数转换成为一个概率值。softmax函数可以定义为:
展开等式右边的子式,可以得到:
softmax可以理解为下:
![这里写图片描述](https://i-blog.csdnimg.cn/blog_migrate/46d66a9ff4d0cd23ee82e8d428e3e99d.png)
1.2 softmax回归模型实现
import tensorflow as tf
x = tf.placeholder("float", [None, 784]) #None表示此张量的第一个维度可以是任何长度的
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x,W) + b)
1.3 训练模型
loss损失函数
之一:“交叉熵”(cross-entropy),定义如下
y 是我们预测的概率分布, y’ 是实际的分布(我们输入的one-hot vector)。
y_ = tf.placeholder("float", [None,10]) #新的占位符用于输入正确值:
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
#tf.log 计算 y 的每个元素的对数, y_ 的每一个元素和 tf.log(y_) 的对应元素相乘,用 tf.reduce_sum 计算张量的所有元素的总和
#注意,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和。
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
2.作业要求
连体网络MINIST识别:
构建如下图所示识别模型:该模型由两个相同的网络G(x)组成。两个网络共享相同的参数W.
该模型实现如下的功能,输入两个MINIST图片,判断是不是同一个数字。
例如,输入 负样本对:X1=6的图片 , X2=9的图片 输出:1
输入 正样本对:X1=3的图片 , X2=3的图片 输出:0
G(x)是一个一般的全连接网络(两边的网络结构是一样的!共享参数W、b等),由结构可以自己设计。比如建议两层网络:hidden1:784(28x28)->500; hidden2: 500->10,使用relu。也可以尝试其他节点数组合,和其他非线性变换函数。
强调:G(X)的功能定义为提取一张minist图像的特征。
该模型的训练采用如下损失函数:
注意:使用此loss需要定 y=0 (两个数字相同)y=1 (两个数字不同)!!!!!!!!!!
要求:合理设计网络,及训练数据采样方法,提升网络的正负样本对的预测精度:用ACC衡量。
提交训练、测试代码。及训练、测试截图。
提示:
1. minist读取可以用tensorflow里写好的工具
from tensorflow.examples.tutorials.mnist import input_data
...
mnist = input_data.read_data_sets('./data/mnist',one_hot=False)
print(mnist.validation.num_examples)
print(mnist.train.num_examples)
print(mnist.test.num_examples)
...
- 正负样本对的合理采样设计会影响训练效果:
例如如下的方式:
for itera in range(iter):
x_1, y_1 = mnist.train.next_batch(batch_size)
x_2, y_2 = mnist.train.next_batch(batch_size)
y_s = np.array(y_1!=y_2,dtype=np.float32)
这样只能碰运气碰到几对正样本,但大多数都可能是负样本。两个类型的样本数不平衡。
3. 损失函数中构建需要都用tf函数,否则无法构建计算图:
常数需要用tf.constant
其他函数例如:E_w = tf.sqrt(tf.reduce_sum(tf.square(o1-o2),1)), tf.exp()等请自查
4. 两个网络结构是一样的!共享参数。怎样共享参数?考虑我们之前的参数复用练习。
5. 建议用AdamOptimizer优化器,其他参数建议
lr = 0.01
iter = 20000
batch_size = 64
3.github代码解析
3.1 Python类中的init() 和 self 的解析
此处的self,是个对象(Object),是当前类的实例。应的self.valueName 和 self.function()中的valueName:表示self对象,即实例的变量。与其他的,Class的变量,全局的变量,局部的变量,是相对应的。function:表示是调用的是self对象,即实例的函数。与其他的全局的函数,是相对应的。
3.2 tf.bias_add(vaue,bias,name=None)和tf.add(x,y,name=None)
tf.bias_add(vaue,bias,name=None)
输入:
value: Tensor
bias:一维的tensor,数据维度和value的最后一维相同。数据类型和value相同
输出:tensor
import tensorflow as tf
a=tf.constant([[1,1],[2,2],[3,3]],dtype=tf.float32)
b=tf.constant([1,-1],dtype=tf.float32)
c=tf.constant([1],dtype=tf.float32)
with tf.Session() as sess:
print('bias_add:')
print(sess.run(tf.nn.bias_add(a, b)))
#执行下面语句错误
#print(sess.run(tf.nn.bias_add(a, c)))
print('add:')
print(sess.run(tf.add(a, c)))
#输出:
#bias_add:
#[[ 2. 0.]
#[ 3. 1.]
#[ 4. 2.]]
#add:
#[[ 2. 2.]
#[ 3. 3.]
#[ 4. 4.]]
tf.add(x,y,name=None)
tf.nn.bias_add()是 tf.add 的一个特例,也即 tf.add 支持的操作比 tf.nn.bias_add 更多。二者均支持 broadcasting(广播机制),也即两个操作数最后一个维度保持一致。除了支持最后一个维度保持一致的两个操作数相加外,tf.add 还支持第二个操作数是一维的情况,例。
Weights = tf.get_variable(name = 'Weights', initializer = tf.zeros([2,1])) #reuse
biases = tf.get_variable(name = 'biases',initializer = tf.zeros([1,1])) #reuse
y = tf.add()tf.matmul(traininput,Weights),biase)
#traininput(30,2)
#得到的y(30,1)
3.3 tf.Session() 和tf.InteractiveSession()
sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
# We can just use 'c.eval()' without passing 'sess'
print(c.eval())
sess.close()
#输出 30
老师上课说的是 没有Session()启动,就不能tensorflow。
tf.InteractiveSession ()需要的代码少,原因就是它允许变量不需要使用session就可以产生结构。它能让你在运行图的时候,插入一些计算图,这些计算图是由某些操作(operations)构成的。这对于工作在交互式环境中的人们来说非常便利,比如使用IPython。
tf.Session():需要在启动session之前构建整个计算图,然后启动该计算图。
使用tf.InteractiveSession()来构建会话的时候,我们可以先构建一个session然后再定义操作(operation),如果我们使用tf.Session()来构建会话我们需要在会话构建之前定义好全部的操作(operation)然后再构建会话。
3.4 tf.reduce_sum():
作用:我的理解是计算tensor某个维度的和,可以给数据降维啊
参数:
input_tensor,
axis=None,
keep_dims=False,
name=None,
reduction_indices=None
看例子:
x = tf.constant([[1, 1, 1], [1, 1, 1]]) #2*3维数据
tf.reduce_sum(x) # 6,在所有维度加起来
tf.reduce_sum(x, 0) # [2, 2, 2],在列方向
tf.reduce_sum(x, 1) # [3, 3],在行方向
tf.reduce_sum(x, 1, keep_dims=True) # [[3], [3]],keep_dims=True 减少的维度限制在1的长度
tf.reduce_sum(x, [0, 1]) #