【mushroom】TF学习笔记总结记录

机器学习

#1

week1 实际操作1 Win7 64bit + anaconda(python 2.7) 安装TensorFlow步骤

  1. 以管理员身份打开命令提示符,并运行此命令,设置 Anaconda 仓库镜像 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --set show_channel_urls yes
  2. conda create -n python3 python=3.5.2 anaconda
  3. activate python3
  4. activate tensorflow
  5. 安装 CPU 版本:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ https ://mirrors.tuna.tsinghua.edu.cn/tensorflow/windows/cpu/tensorflow-1.1.0-cp35-cp35m-win_amd64.whl 也可以打开 https ://mirrors.tuna.tsinghua.edu.cn/tensorflow/ 选择合适的 whl 文件地址进行安装。

TensorFlow基本介绍

  1. TensorFlow采用计算图的形式来表示数值计算,在计算图中,每一个节点表示一次数学计算,每一条边表示计算之间的依赖关系。
  2. 张量(Tensor)是计算图的基本数据结构,可以理解为多维数据。
  3. 流(flow)表达了张量之间通过计算相互转化的过程。
  4. TensorFlow的架构: 1)前段系统:多种编程环境,通过session的形式,连接后端的运行时,启动计算图的执行过程 2)后端系统:提供运行时环境,负责执行计算图。
  5. TensorFlow基本使用: 1)使用tensor表示数据 2)通过变量variable输入训练数据,维护状态 3)使用计算图computational graph来表示计算任务 4)在会话session的上下文context中执行计算图

实际操作2 :x=2,y=3,z=7,求x*y + z

import tensorflow as tf
x = tf.Variable (0, name = "x-var")
y = tf.Variable (0, name = "y-var")
z = tf.Variable (0, name = "z-var")
multi_op = tf.multiply(x, y, name="multi_op")
add_op = tf.add (multi_op, z, name="add_op")
sess = tf.Session()
result1 = sess.run (multi_op, feed_dict={x: 2, y: 3})
result2 = sess.run (add_op, feed_dict= {multi_op:result1, z: 7})
print ("result2:", result2,"type:",type(result2))
sess.close ()

实际操作3:矩阵乘法:A:[[3.,3.]],B:[[2.],[2.]]

import tensorflow as tf
a = tf.constant([[3.,3.]]) #1行 2列
b = tf.constant([[2.],[2.]]) #2行 1列
matmul_op = tf.matmul (a, b)
sess = tf.Session ()
result = sess.run (matmul_op)
print (result)

#2

思考问题: 1.有效的计算参数很多的梯度下降算法。 梯度下降法中:θ_i=θ_(i-1)- η∇L(θ_(i-1)) 根据交叉熵:L(θ)= ∑_(n=1)^N▒c^n (θ) ∂L(θ)/∂w= ∑_(n=1)^N▒(∂c^n (θ))/∂w ∂c/∂w= ∂z/∂w* ∂c/∂z 使用forward pass来计算∂z/∂w,每个wi之前的input。 使用backward pass来计算∂c/∂z,首先计算输出层的∂c/(∂z_i )= ∂c/(∂y_i )* (∂y_i)/(∂z_i ),再回溯计算∂c/∂z

3.softmax和cross_entropy原理理解释? Softmax:在多分类的逻辑回归中,label i对应着权重向量wi和偏差bi,对于收集到的数据x, 分类i的zi=wi*x + bi, zi取值为任意实数,softmax需要对这些zi换成以e为底的zi次方ezi,这样可以将负值转化成为正数,同时可以拉大数值之间的 差距。最后将ezi加总,每个ezi除以这个总和,得到yi。yi为数据x被分为label i的概率,总和为1。 Cross_entropy:交叉熵为两种以熵来计量的东西之间的关系,熵在信息论里面衡量的是数据的混乱程度,本质是香农信息量(plog21/p,0<p≤1)的期望。交叉熵表示预测结果与真实结果之间的差异程度,为0表示没有差异。对于两个0-1分布X∼B(1,p),X∼B(1,q),p为真实分布,q非真实分布,如果使用错误分布q来表示来自真实分布p的平均编码长度,则应该是:H(p,q)= -∑▒〖p(x)logq(x)〗。因为用q来编码的样本来自分布p,所以期望H(p,q)中概率是p(i)。H(p,q)称之为“交叉熵”。

4.tf.Variable:主要在于一些可训练变量(trainable variables),比如模型的权重(weights,W)或者偏差(bias);在声明时,必须提供初始值;在真实训练时,其值是会改变的,自然事先需要指定初始值。tf.placeholder:用于得到传递进来的真实的训练样本:不必指定初始值,可在运行时,通过 Session.run 的函数的 feed_dict 参数指定;这也是其命名的原因所在,仅仅作为一种占位符。tf.constant():创造一个常量tensor。

5.TensorFlow中使用tf.Grap类表示可计算的图。图是由操作Operation和张量Tensor来构成,其中Operation表示图的节点(即计算单元),而Tensor则表示图的边(即Operation之间流动的数据单元)。在TensorFlow中,始终存在一个默认的Graph。如果要将Operation添加到默认Graph中,只需要调用定义Operation的函数(例如tf.add())。如果我们需要定义多个Graph,则需要在with语句中调用Graph.as_default()方法将某个graph设置成默认Graph,于是with语句块中调用的Operation或Tensor将会添加到该Graph中。

6.tf.name_scope() 主要是用来管理命名空间的,这样子让我们的整个模型更加有条理。而 tf.variable_scope() 的作用是为了实现变量共享,它和 tf.get_variable() 来完成变量共享的功能。 在tf.name_scope()和tf.variable_scope()中可以用tf.Variable()创造变量名相同的变量。 import tensorflow as tf config = tf.ConfigProto() config.gpu_options.allow_growth = True sess = tf.Session(config=config) with tf.name_scope(‘nsc1’): v1 = tf.Variable([1], name=‘v1’) with tf.variable_scope(‘vsc1’): v2 = tf.Variable([1], name=‘v2’) v3 = tf.get_variable(name=‘v3’, shape=[]) print ('v1.name: ', v1.name) print ('v2.name: ', v2.name) print ('v3.name: ', v3.name) with tf.name_scope(‘nsc1’): v4 = tf.Variable([1], name=‘v4’) print ('v4.name: ', v4.name) 输出:

7.tf.variable_scope() 和tf.get_variable()的理解 在tensorflow中提供了tf.get_variable函数来创建或者获取变量。当tf.get_variable用于创建变量时,则与tf.Variable的功能基本相同。两函数指定变量名称的参数不同,对于tf.Variable函数,变量名称是一个可选的参数,通过name="v"的形式给出。而tf.get_variable函数,变量名称是一个必填的参数,它会根据变量名称去创建或者获取变量。先通过tf.variable_scope生成一个上下文管理器,并指明需求的变量在这个上下文管理器中,就可以直接通过tf.get_variable获取已经生成的变量。 在上下文管理器中已经生成一个v的变量,若想通过tf.get_variable函数获取其变量,则可以通过reuse参数的设定为True来获取(可以将reuse按照字面意思理解,重用) 并且tf.variable_scope只能获取已经创建过的变量。 如果tf.variable_scope函数使用参数reuse=None或者reuse=False创建上下文管理器,则tf.get_variable函数可以创建新的变量。但不可以创建已经存在的变量即为同名的变量。

8.tf.global_variables_initializer()函数初始化所有可变张量的状态。 init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) 训练神经网络的目的是修改权重和偏差以最好地预测标签。为了使用权重和偏差,需要一个可以修改的Tensor,即不能使用tf.placeholder()和tf.constant(),因为那些Tensors不能被修改。所以这里应该使用tf.Variable。使用tf.Variable类允许我们改变权重和偏差,但是需要选择一个初始值。如上所示,使用session(会话)调用tf.global_variables_initializer()操作。tf.global_variables_initializer()会返回一个操作,从计算图中初始化所有TensorFlow变量。

实践任务a:用tensorflow实现逻辑回归


#3

总结的非常好,使用markdown做一下排版,更清晰,:joy:


#4

好的,我来学习学习markdown,昨天上传的时候也是觉得这个排版不太友好:joy:


#5

学习python可以直接在命令行调用:jupyter notebok 。编写完毕后,另存为markdown,解压后把文件里的内容直接考过来,如果有图片可以在适当的位置粘贴就可以了。


#6

正在百度上查markdown呢就看到了您的回复~谢谢啦,我去试一试:blush:


#7
  1. 有效的计算参数很多的梯度下降算法。 梯度下降法中:$θ_i=θ_(i-1)- η∇L(θ_(i-1)) $ 根据交叉熵:$L(θ)= ∑_(n=1)^N▒c^n (θ)$ $∂L(θ)/∂w= ∑_(n=1)^N▒(∂c^n (θ))/∂w $ $∂c/∂w= ∂z/∂w * ∂c/∂z $ 使用forward pass来计算 $∂z/∂w$ ,每个 $w$ 之前的input。 使用backward pass来计算$∂c/∂z$,首先计算输出层的$∂c/(∂z_i )= ∂c/(∂y_i )* (∂y_i)/(∂z_i )$,再回溯计算$∂c/∂z$

  2. softmax和cross_entropy原理理解释? Softmax:在多分类的逻辑回归中,label i对应着权重向量wi和偏差bi,对于收集到的数据x, 分类i的$zi=wi*x + bi$, zi取值为任意实数,softmax需要对这些 zi换成以e为底的zi次方ezi,这样可以将负值转化成为正数,同时可以拉大数值之间的差距。最后将ezi加总,每个ezi除以这个总和,得到yi。yi为数据x被分 为label i的概率,总和为1。 Cross_entropy:交叉熵为两种以熵来计量的东西之间的关系,熵在信息论里面衡量的是数据的混乱程度,本质是香农信息量$(plog21/p,0<p≤1)$的期望。交叉 熵表示预测结果与真实结果之间的差异程度,为0表示没有差异。对于两个0-1分布$X∼B(1,p)$,$X∼B(1,q)$,p为真实分布,q非真实分布,如果使用错误分布q来 表示来自真实分布p的平均编码长度,则应该是:$H(p,q)= -∑▒〖p(x)logq(x)〗$。因为用q来编码的样本来自分布p,所以期望H(p,q)中概率是p(i)。H(p,q) 称之为“交叉熵”。

  3. tf.Variable:主要在于一些可训练变量(trainable variables),比如模型的权重(weights,W)或者偏差(bias);在声明时,必须提供初始值;在 真实训练时,其值是会改变的,自然事先需要指定初始值。tf.placeholder:用于得到传递进来的真实的训练样本:不必指定初始值,可在运行时,通过 Session.run 的函数的 feed_dict 参数指定;这也是其命名的原因所在,仅仅作为一种占位符。tf.constant():创造一个常量tensor。

  4. TensorFlow中使用tf.Grap类表示可计算的图。图是由操作Operation和张量Tensor来构成,其中Operation表示图的节点(即计算单元),而Tensor则表示 图的边(即Operation之间流动的数据单元)。在TensorFlow中,始终存在一个默认的Graph。如果要将Operation添加到默认Graph中,只需要调用定义Operation 的函数(例如tf.add())。如果我们需要定义多个Graph,则需要在with语句中调用Graph.as_default()方法将某个graph设置成默认Graph,于是with语句块中 调用的Operation或Tensor将会添加到该Graph中。

  5. tf.name_scope() 主要是用来管理命名空间的,这样子让我们的整个模型更加有条理。而 tf.variable_scope() 的作用是为了实现变量共享,它和 tf.get_variable() 来完成变量共享的功能。在tf.name_scope()和tf.variable_scope()中可以用tf.Variable()创造变量名相同的变量

import tensorflow as tf
# 设置GPU按需增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
with tf.name_scope('nsc1'):
    v1 = tf.Variable([1], name='v1')
    with tf.variable_scope('vsc1'):
        v2 = tf.Variable([1], name='v2')
        v3 = tf.get_variable(name='v3', shape=[])
print ('v1.name: ', v1.name)
print ('v2.name: ', v2.name)
print ('v3.name: ', v3.name)
with tf.name_scope('nsc1'):
    v4 = tf.Variable([1], name='v4')
print ('v4.name: ', v4.name)

  1. tf.variable_scope() 和tf.get_variable()的理解 在tensorflow中提供了tf.get_variable函数来创建或者获取变量。当tf.get_variable用于创建变量时,则与tf.Variable的功能基本相同。 两函数指定变量名称的参数不同,对于tf.Variable函数,变量名称是一个可选的参数,通过name="v"的形式给出。而tf.get_variable函数,变量名称是一个必填的参数,它会根据变量名称去创建或者获取变量。 先通过tf.variable_scope生成一个上下文管理器,并指明需求的变量在这个上下文管理器中,就可以直接通过tf.get_variable获取已经生成的变量。

在上下文管理器中已经生成一个v的变量,若想通过tf.get_variable函数获取其变量,则可以通过reuse参数的设定为True来获取(可以将reuse按照字面意思理解,重用)

并且tf.variable_scope只能获取已经创建过的变量。 如果tf.variable_scope函数使用参数reuse=None或者reuse=False创建上下文管理器,则tf.get_variable函数可以创建新的变量。但不可以创建已经存在的变量即为同名的变量。

8.	tf.global_variables_initializer()函数初始化所有可变张量的状态。
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)

训练神经网络的目的是修改权重和偏差以最好地预测标签。为了使用权重和偏差,需要一个可以修改的Tensor,即不能使用tf.placeholder()和tf.constant(), 因为那些Tensors不能被修改。所以这里应该使用tf.Variable。使用tf.Variable类允许我们改变权重和偏差,但是需要选择一个初始值。如上所示,使用 session(会话)调用tf.global_variables_initializer()操作。tf.global_variables_initializer()会返回一个操作,从计算图中初始化所有TensorFlow变量。

动手实操:tensorflow实现逻辑模型

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 13 19:11:59 2017

@author: Mac
"""
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True) #一个脚本自动下载和导入MNIST数据集。
                                                              #它会自动创建一个'MNIST_data'的目录来存储数据。
sess = tf.InteractiveSession()  #在构建图的过程中运行某个组件
#构建softmax回归模型
x = tf.placeholder(tf.float32, shape=[None, 784]) #n*784,放置样本的特征输入x,none说明不确定有多少个训练样本,784=28*28,将图片转化成一个向量
y_ = tf.placeholder(tf.float32, shape=[None, 10])  #放置样本的类别标签y
W = tf.Variable(tf.zeros([784, 10])) #初始化权值,784 * 10的矩阵
b = tf.Variable(tf.zeros([10])) #初始化偏置量
#变量初始化,变量需要通过seesion初始化后,才能在session中使用
sess.run(tf.initialize_all_variables())
#预测函数,计算每个分类的softmax概率值
y = tf.nn.softmax(tf.matmul(x,W) + b)
#损失函数,交叉熵,tf.reduce_sum把每张图片的交叉熵值都加起来了
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
#训练模型,梯度下降算法,学习率为0.01
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
#计算损失函数的偏导数,计算待更新的参数的更新量,更新参数。 
for i in range(3000):  #迭代3000次
  batch = mnist.train.next_batch(50) #每一次迭代加载50个训练样本
  train_step.run(feed_dict={x: batch[0], y_: batch[1]}) #执行一次train_step,并通过feed_dict将x 和 y_张量占位符用训练训练数据替代
#评估分类
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#映射成浮点数,计算平均值
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print (accuracy.eval(feed_dict = {x: mnist.test.images, y_: mnist.test.labels}))

#8

谢谢fishexpert和xshengjie两位大佬的帮助,我又用makedown编辑了一下,看起来更友好了~不过为啥我把图片粘贴进去,显示的都是代码捏


#9

你上传一下图片看可以么?


#10

解决啦,谢谢~之前出错是因为我把图片粘贴到错误的位置了:joy:


#11

之前是用的内置数据集mnist来进行的逻辑回归,然后我又学习了下如何自己导入数据集进行逻辑回归并且输出逻辑回归中的参数w,b


import pandas as pd                # 用于读取数据文件
import tensorflow as tf
sess = tf.InteractiveSession() 
#读取数据文件
df = pd.read_csv("C:/Users/Mac/Desktop/iris.txt", header=None)
train_data = df.values
# 分离特征和标签,并获取数据维数
train_X = train_data[:, :4] #取前四列作为特征值X
print(train_X)
train_y = train_data[:, 4:] #后三列为标签
print(train_y)
# 构建softmax回归模型
X = tf.placeholder(tf.float32, shape=[None, 4]) #4为特征个数
y_ = tf.placeholder(tf.float32, shape=[None, 3]) #用一个3维向量表示分类
# 训练目标,权重和偏置值
W = tf.Variable(tf.zeros([4, 3]))
b = tf.Variable(tf.zeros([3]))
sess.run(tf.initialize_all_variables())
#预测函数,计算每个分类的softmax概率值
y = tf.nn.softmax(tf.matmul(X,W) + b)
#损失函数,交叉熵
cross_entropy = -tf.reduce_sum(y_*tf.log(y),axis=0)
#训练模型,梯度下降算法,学习率为0.01
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

for step in range(1000):
    train_step.run(feed_dict = {X: train_X, y_: train_y})
    if step % 100 == 0:
        print(step, sess.run(W),sess.run(b))

sess.close()

数据文件长这样:

部分输出结果:


#12

哈哈,大佬,为什么我用你的代码,精确度只有0.098哇,是不是我这出啥问题了?


#13

把学习率调低一点,之前我写的是0.5,调成0.01准确率会提高很多。


#14
1.	Batch Normalization 原理解释&benefit(优点)?
BN的基本思想:随着网络深度的加深或者在训练过程中,非线性变化前的激活输入值X(X = WU + B)
的分布会逐渐发生偏移或者变动。举一个例子:对于sigmoid函数来说,如果激活输入值X是大的正值或
者负值,那么经过激活函数sigmoid后,下一层的输入值σ(X)就逐渐往sigmoid函数的取值区间的上下
限两端靠近,所以这导致后向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的
本质原因。BN就是通过一定的规范化方法,把每层神经网络的任意神经元的激活输入值(X)分布变为标
准正态分布(均值为0,方差为1),落在非线性函数(如sigmoid)对输入比较敏感的区域。若X服从均
值为0,方差为1的正态标准分布,则 64%的概率在[-1,1]之间,95%的概率在[-2,2]之间,说明σ(Z)
有95%的概率其导数值变化很大。

同时BN为了保证非线性的获得,对变换后的X又进行了scale加上shift操作(y=scale*x + shift),
每个神经元增加了两个参数scale和shift参数,意思是通过scale和shift把这个值从标准正态分布左
移或者由移一点并长胖一点或者变瘦一点。BN操作的位置如下图,位于Z这个激活值获得之后,非线性
函数变化之前。

BN的具体操作过程。首先是对mini-batch中的激活输入值求平均。然后求mini-batch激活输入值的方
差,然后对于激活输入值进行标准正态处理,对标准化的激活输入值进行scale和shift操作,得到新
的激活输入值。

BN的优点:将非线性变换函数的输入值落入对输入比较敏感的区域,以此避免了梯度消失问题。
由于梯度一直都能保持比较大的状态,所以很明显对神经网络的参数调整效率比较高,也就是说
收敛地快。
2.	如何理解卷积?
卷积就是加权叠加,表示为y[n]=x[n]∗h[n]=∑_k^n▒〖x[k]h[n-k]〗。若用一维离散信号来理解,
x为输入信号,x[0]为0时刻的输入信号,x[1]为1时刻的输入信号,h为响应函数,h[0]为对当前输
入信号的响应,h[1]为对上一次输入信号的响应。由于每个时刻的输入信号不仅影响当前的输出信
号,还会对下几次的输出信号有残余的影响。因此,0时刻只有x[0]一个输入信号,之前没有输入,
所以输出信号为y[0]=x[0]h[0];1时刻受到0,1两个时刻输入信号的影响y[1]=x[1]h[0]+x[0]h[1];
2时刻受到0,1,2三个输入信号的影响y[2]=x[2]h[0]+x[1]h[1]+ x[0]h[2];…….。在这里h表示的
就是权重,对于当前的输出来说,它受到之前输入信号的影响,但是每一期的影响都是不同的,因
此要乘上权重。同理在连续信号中,加权叠加就变为一个积分表示了。
3.	如何理解卷积神经网络(CNN)中的卷积(Convolution Kernel)和池化(Pooling)&有哪些Pooling?
对于CNN中卷积的理解:在CNN的一个卷积层中,是对图片进行处理,如果仅考虑黑白图片,即为二维信号。卷积的计算公式为:  

其中x是输入的图片数据(像素),h是卷积核。相当于对两个矩阵做乘法,然后将乘法之后的矩阵中的每一个值相加,得到y值。
一个卷积核代表对于原图中一个特征进行提取。比如有一个卷积核是为了寻找圆形,卷积操作会在原图上滑动这个卷积核,最终
得到的层称为feature map(表示原图中的圆形信息)。对于CNN中池化的理解:池化的本质就是采样,对于输入的feature map,
选择某种方式进行压缩。具体有Max-Pooling, Mean-Pooling,Stochastic-Pooling。
池化的作用有两点:
第一个是减少参数,第二个是增加了鲁棒性,即对于 Input,当其中像素在邻域发生微小位移时,池化层的输出是不变的。
4.	Learning Rate 如何选取,它过大/过小会产生什什么影响?
下图展示了选取不同的学习率的影响。如果学习率太小,如蓝色的线显示,cost function的值会下降
的很慢,需要的学习时间会很长。如果学习率比较大。如绿色的线显示。在之前的迭代中,
Cost function的值会下降,但是下降到一定程度之后,再迭代就不会发生太大的变化。如果学习率
非常大,如黄色线显示,cost function的值会下降一点后转而增大。

5.	机器学习中,有哪些正则化的方法?目的是什么?Dropout的好处是?
1)	正则化的方法
损失函数后面添加一个额外项,常用的额外项一般有两种L1正则化和L2正则化,这个额外项可以看做损失函数的惩罚项,即对损失函数中的某一些参数做一些限制。
①L1正则化是指权值向量w中各个元素的绝对值之和,通常表示为||w||1. 
L1正则化的损失函数为: J=J_0+а∑_W▒〖|W〗|。相当于对J_0做了一个约束,令L=а∑_W▒〖|W〗|,则J =J_0+L,即在L约束下求出J_0取最小值的解。
②L2正则化是指权值向量w中各个元素的平方和然后再求平方根,通常表示为||w||2。L2正则化的损失函数为: J=J_0+а∑_W▒W^2 
2)	正则化的目的:防止过拟合,提高泛化能力。
当正则化后的损失函数对于W求偏导后,求导结果中W前的系数会小于1,发生了权重衰减。更小的权值W,表示网络的复杂度更低,可以防止过拟合。
3)	Dropout通过修改神经网络本身来防止过拟合。在训练开始时,随机地临时(sample)“删除”一些的input层和隐藏层的神经元,不会删减output层的神经元。
然后按照BP算法更新神经网络中的权值(删除的单元不更新),这就是一次迭代的过程,在第二次迭代中,也用同样的方法,随机 “删除”一些神经元(resample。
第三次、第四次……都是这样,直至训练结束。运用了dropout的训练过程,相当于训练了很多个细长的神经网络,每一个这样的网络,都可以给出一个分类结果,
这些结果有的是正确的,有的是错误的,再对结果做一个平均作为最终的结果,从而减少了模型的variance。

6.	Covariate Shift 和 Internal Covariate Shift 如何理解?
Covariate shift:训练集和测试集中X的概率密度不一样。假设q1(x)是测试集中一个样本点的概率
密度,q0(x)是训练集中一个样本点的概率密度。最终我们估计一个条件概率密度p(y|x,θ),它由
x和一组参数θ={θ1,θ2......θm}所决定。对于一组参数来说,对应loss(θ)函数评估其性能的
好坏。综上,当我们找出在q0(x)分布上最优的一组θ'时,能否保证q1(x)上测试时也最好呢?传
统机器学习假设训练集和测试集是独立同分布的,即q0(x)=q1(x),所以可以推出最优θ'依然可
以保证q1(x)最优。但现实当中这个假设往往不成立,伴随新数据产生,老数据会过时,当q0(x)
不再等于q1(x)时,就被称作covariate shift。

Internal Covariate Shift:在训练过程中,每一层的激活值的分布随着网络训练时参数的变化而变
化,当输入值为一个很大的正数或者负数时,会导致激活值的分布趋于非线性饱和区,如 sigmoid函
数两头梯度几乎为0,这就会导致梯度消失。可以用Batch Normalization的方式来解决。
7.	如何理解Momentum ?weight decay?它们在神经网络训练中的作用是什什么?
Momentum:翻译过来就是动量。当在利用梯度下降算法寻找loss function的最小值的时候,程序会因
为遇到比较平稳的点(plateau),鞍点(saddle)以及局部最优点(local minima)而停止,因为在这
些点的偏导数都趋近于零或者等于零。为了避免程序卡在这些点上,引入了动量的概念,即下一步的移
动方向由当前点的偏导数以及上一步的移动方向共同决定,举个例子,在遇到鞍点的时候,偏导数虽然
为零,但是θ会因为受到上一步移动方向的影响继续沿着之前的方向移动。

weight decay:权重衰减。在进行L2正则化的时候,由于给loss function加入了一个惩罚项,L对W的
偏导数会发生变化。因为ηλ都是大于零的数,所以1-η*λ会小于1,这个就叫权重衰减。好处是由
于W 变小,可以减少过拟合的现象。

8.	如何理解“过拟合 overfitting”? 神经网络训练,如何避免overfitting?
过拟合:模型在训练集上能够得到很好的结果,但是这个模型在测试集上的表现很差,说明发生了过拟合现象。
如何避免:
1)	Early stopping:将训练集的正确率与测试集的正确率进行对比,由于随着训练加深,训练集的loss 值会不断提高,但是会发生过拟合现象,导致测试集的loss值先下降再上升。一般的做法是分出一个validation set,将训练的模型在这个数据集上进行预测,找到在validation set中loss值最低模型,而不是训练集中loss值最低的模型。
2)	正则化
3)	Dropout
9.	各种优化方法(SGD/Momentum/Adagrad/Adam等),对比优缺点?
1)	SDG:随机梯度下降。对于训练数据集,我们首先将其分成n个batch,每个batch包含m个样本。
我们每次更新都利用一个batch的数据,而非整个训练集。好处:减少训练时间,收敛更快(以一个
极端情况为例,若训练集前一半和后一半梯度相同。那么如果前一半作为一个batch,后一半作为另
一个batch,那么在一次遍历训练集时,batch的方法向最优解前进两个step,而整体的方法只前进一
个step。)缺点:其更新方向完全依赖于当前的batch,因而其更新十分不稳定。

2)	Momentum:解决SDG的缺点,更新的时候在一定程度上保留之前更新的方向,同时利用当前
batch的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,
并且还有一定摆脱局部最优的能力。

3)	Adagrad:以上两种方法所有的参数都是一个学习率,但是同一个更新速率不一定适合所有
的参数,比如有的参数可能已经到了仅需要微调的阶段,但又有些参数由于对应样本少等原因,
还需要较大幅度的调动。Adagrad算法能够在训练中自动的对learning rate进行调整,对于出现
频率较低参数采用较大的η更新;相反,对于出现频率较高的参数采用较小的η更新。Adagra在
每轮训练中对每个参数Wi的学习率进行更新,参数更新公式如下:σt是g0,g1,g2,…,gt的均方根。

4)	Adam:另一种自适应学习率的方法。它利用梯度的一阶矩估计和二阶矩估计动态调整每个
参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得
参数比较平稳


#15
10.	经典的卷积神经网络(CNN)之一,LeNet5模型详细解释?
LeNet-5共有7层(不包括输入层),每层都包含不同数量的训练参数,主要有卷积层、下抽样层、全连接层3种连接方式。
输入图像为32*32的灰度值图像,后面有三个卷积层,一个全连接层和一个高斯连接层。他的第一个卷积层C1包含6个卷积
核,卷积核的尺寸为5*5,即总共有(5*5+1)*6=个参数,1代表是的偏置值,后面是一个2*2的平均池化层S2用来进行降
采样,再之后是一个Sigmoid激活函数用来进行非线性处理。而后是第二个卷积层C3,同样卷积核是5*5,这里使用了16个
卷积核,对应16个feature map。下面的第二个池化层S4和第一个池化层S2一致,都是2*2的降采样。接下来的是第三个卷
积层C5有120个卷积核,卷积大小同样为5*5,因为输入图像的大小刚好也是。5*5,因此构成了全链接。F6曾是一个全连
接层,拥有84个隐含节点,激活函数为Sigmoid。最后一层由欧式径向基函数单元组成,他输出最后的分类结果。
TensorFlow实现简单的卷积网络
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('MNIST_data', one_hot=True)
sess=tf.Session()
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])#labels y_
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
#权重初始化。加入少量的噪声来打破对称性以及避免零梯度,这里采用的是截断的正态分布噪声
def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1) #均值为0,标准差为0.1的正态分布
  return tf.Variable(initial)
#偏置值初始化,由于使用ReLU这个激活函数,给偏置增加一些小的正值(0.1)用来避免死亡节点
def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)
#定义卷积和池化,x是输入,W是卷积的参数,如[5,5,1,32],前面两个数字代表卷积核的尺寸,第三个数字代表channel(黑白图片为1,彩色图片为3),最后一个代表卷积核的数量
def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') #strides代表卷积模板移动的步长,SAME代表给边界加上Padding让卷积的输出和输入保持同样的尺寸
#最大池化函数。使用2*2的最大池化,将一个2*2的像素块降低为1*1的像素,最大池化会保持原始像素快中灰度值最高的那一个像素
def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],  
                        strides=[1, 2, 2, 1], padding='SAME') #以横竖两个方向以2为步长,如果步长还是1,那么我们会得到一个尺寸不变的图片
#因为卷积神经网络会利用空间结构信息,因此需要将1D的输入向量转为2D的图片结构,-1代表样本数量不固定,每个样本是748=28x28x1的数据,分别对应图片数据的长宽高
x_image = tf.reshape(x, [-1,28,28,1])
#产生32个feature去卷积,其中的1是因为我们的数据第三个维度高度为1.
#W_conv1是按照fliter格式为[filter_height, filter_width, in_channels, out_channels]`,最后32是我们自己设定的数字
W_conv1 = weight_variable([5, 5, 1, 32]) #卷积核尺寸为5*5,1个颜色通道,32个不同的卷积核
b_conv1 = bias_variable([32])
#第一次卷积和池化,Relu激活
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
#第二次卷积和池化,Relu激活
#因为上次输出了32个通道,所以这次的输入通道变成32,卷积核的数量为64,说明这一层的卷积会提取64种特征
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
#池化后样本的形状从[-1,28,28,1]变为[-1,7,7,64]
W_fc1 = weight_variable([7 * 7 * 64, 1024]) #说明全脸接种隐含节点有1024个
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) #转化成1D的向量
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#减轻过拟合,定义一个dropout层
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#dropout层的输出连接一个softmax层,得到最后的概率输出
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
#损失函数使用cross entropy,并且使用Adam优化器,学习率为1e-4
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
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"))
#开始训练,dropout的keep_prob比率为0.5,使用大小为50的minibatch
sess.run(tf.global_variables_initializer())
for i in range(500):
  batch = mnist.train.next_batch(50)
  if i%100 == 0:  #每训练100次,对准确率进行一次测评,实时监测模型的性能
    train_accuracy = accuracy.eval(feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0},session=sess)
    print("step %d, training accuracy %g"%(i, train_accuracy))
  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},session=sess))

#16
1. LSTM/GRU 原理解释 
RNN 是循环神经网络,hidden layer会连向下一时间的hidden layer。在RNN中,会出现vanishing gradient的问题,即total loss在学习过程中崎岖不平,
因此在学习过程中很难调整学习率learning rate.在RNN中每一个时间步骤用到的参数都是一样的,这跟卷积神经网络中共用部分参数的思想一致。
为了解决RNN中的vanishing gradient问题,提出了LSTM。主要就是把上面的神经元(网络中的小圆圈)换成LSTM block。LSTM block包含三个gate,分别是
input gate, forget gate, output gate。Xt是t时刻的输入,为一个vector。将Xt与四个参数矩阵相乘,得到四个新的vector:z0,z,zi,zf.

把z输入到LSTM中,经过激活函数,得到g(z);zi是input gate的输入,经过激活函数得到f(zi),input gate主要控制LSTM是否能够得到输入,原理在于将
g(z)与f(zi)相乘,如果f(zi)为0,相乘之后也只能得到0,表明input gate关闭;
zf作为forget gate的输入,也要经过激活函数得到f(zf),取出之前目前memory cell中的值c,两者相乘,新的memory cell中的值为c= g(z)* f(zi)+c*f(zf),
如果f(zf)为0,表明forget gate关闭,舍弃之前的记忆值。然后将新的记忆值c经过激活函数得到h(c)。
z0是output gate的输入,经过激活函数得到f(z0),输出值是a= h(c)* f(z0)。output gate主要控制是否输出,如果f(z0)为0,说明不能输出(输出为0)。
激活函数一般为sigmoid函数,因为这个函数的输出在0-1之间,像一个概率值。

GRU相比于LSTM,结构更加简单,比LSTM减少一个gate,说明参数可以减少1/3左右,因此计算效率更高。同时占用的内存也比较少。在实际使用中,LSTM与
GRU的差异不大,一般最后得到的准确率指标等都想进,但是相对来说,GRU达到收敛状态时所需要的迭代次数更少,训练速度更快。
2. word2vec 和GloVe 原理
word2vec是将语言中的字词转化为计算机可以理解的稠密向量,进而可以做其他自然语言处理的任务,如:文本分类、词性标注、机器翻译等等。word2vec
主要分为CBOW和Skip-Gram两种模式。其中w(t)代表当前词语位于句子的位置t,同理定义其他记号。在窗口内(上图为窗口大小为5),除了当前词语之外的
其他词语共同构成上下文。

CBOW 是 Continuous Bag-of-Words Model 的缩写,是一种根据上下文的词语预测当前词语的出现概率的模型。其学习目标是最大化对数似然函数:

其中,w表示语料库C中任意一个词。输入层是上下文的词语的词向量(训练开始的时候,词向量是个随机值,随着训练的进行不断被更新)。投影层对其求和.
所谓求和,就是简单的向量加法。输出层输出最可能的w。由于语料库中词汇量是固定的|C|个,所以上述过程其实可以看做一个多分类问题。给定特征,从|C|个
分类中挑一个。
Skip-gram只是逆转了CBOW的因果关系而已,即已知当前词语,预测上下文。输入层不再是多个词向量,而是一个词向量,投影层直接将输入层的词向量传递给
输出层。语言模型的概率函数可以写作:

GloVe是综合基于奇异值分解的LSA算法和word2vec算法,即使用了语料库的全局统计(overall statistics)特征,也使用了局部的上下文特征(即滑动窗口)。
为了做到这一点GloVe模型引入了Co-occurrence Probabilities Matrix。首先引入word-word的共现矩阵X,
X的元素Xij是语料库中出现在word i上下文中的word j的次数;
Xi=∑kXik,是出现在word i上下文中的所有word的总次数;
Pij=P(j|i)=Xij/Xi,是word j出现在word i 上下文的概率。
由Co-occurrence Probabilities Matrix可以看出Ratio=Pik/Pjk的取值是有一定的规律的。Ratio值能够反映word之间的相关性,而GloVe模型就是利用了这个Ratio值。

GloVe模型的目标就是获取每一个word的向量表示v。不妨假设现在已经得到了word i,j,k 的词向量wi,wj,wk。GloVe认为,这三个向量通过某种函数的作用后所呈
现出来的规律和Ratio=Pik/Pjk具有一致性(即相等),也就可以认为词向量中包含了共现概率矩阵中的信息。
假设这个未知的函数是F,则:
    F(wi,wj,wk)=PikPjk
此处可以类比word2vec的基本思想(以基于哈弗曼树的CBOW为例),假设word i和其context words的词向量已知,通过一层神经网络作用于context words的向量
得到的结果与word i在哈夫曼树中的位置具有一致性。
3. word2vec工业界有哪些应用场景?
1)在社交网络中的推荐:在个性化推荐的场景中,会给当前用户推荐他可能关注的大V,基本上是通过推荐与该用户已经关注过大v相似的大v,来实现这种推荐。
重点在于如何计算两个大v的相似度,将大v看做一个词,每个用户关注大v的顺序看做一个文档,通过word2vec将这个大v训练为一个向量。
2)计算商品的相似度:在商品推荐的场景中,竞品推荐和搭配推荐的时候都有可能需要计算任何两个商品的相似度,根据浏览/收藏/下单/App下载等行为,可以
将商品看做词,将每一个用户的一类行为序看做一个文档,通过word2vec将这个商品训练为一个向量。
4. Resnet、GoogleNet 、VGG16 网络结构原理解释?
VGG 16: 13个卷积层,3个全连接层,一共有16层,由此得名。
1)输入224*224*3的图片,经过第一段卷积层Conv1(包含两个子卷积层Conv1_1, Conv1_2,卷积核为3*3,有64个卷积核),得到结构为224*224*64。
2)然后经过2*2的池化层,得到的结构为112*112*64
3)进入第二段卷积层Conv2(包含两个子卷积层Conv2_1, Conv2_2,卷积核为3*3,有128个卷积核), 得到结构为112*112*128
4)然后经过2*2的池化层,得到的结构为56*56*128
5)进入第三段卷积层Conv3(包含三个子卷积层Conv3_1, Conv3_2,Conv3_3,卷积核为3*3,有512个卷积核), 得到结构为28*28*512
6)然后经过2*2的池化层,得到的结构为14*14*512
…以此类推

GoogleNet:
通过Inception Module提高参数利用效率,基本结构如下(这只是Inception Module V1的结构):
其中有四个分支:第一个分支对输入进行1*1的卷积(1*1卷机所连接的节点相关性是最高的,可以跨通道组织信息);第二个分支先使用了1*1卷积,然后连接
3*3卷积,相当于进行了两次特征变换。第三个分支先用1*1卷积,然后连接5*5卷积。最后一个分支则是3*3最大池化后直接使用1*1卷积。其中3*3卷积,和5*5
卷积所连接的节点相关性也很高。
在整个网络中,会有多个堆叠的Inception Module,靠后的Inception Module可以捕捉更高阶的抽象特征,因此靠后的Inception Module的卷积的空间集中度应该
逐渐降低,越靠后的Inception Module中3*3和5*5这两个大面积的卷积核的占比应该更多

Resnet:
深度学习网络的深度对最后的分类和识别的效果有着很大的影响,所以正常想法就是能把网络设计的越深越好,但是事实上却不是这样,常规的网络的堆叠
(plain network)在网络很深的时候,效果却越来越差了。这里其中的原因之一即是网络越深,梯度消失的现象就越来越明显,网络的训练效果也不会很好。
但是现在浅层的网络(shallower network)又无法明显提升网络的识别效果了,所以现在要解决的问题就是怎样在加深网络的情况下又解决梯度消失的问题。

ResNet引入了残差网络结构(residual network)。残差学习模块的输入是x,期望输出是H(x),如果直接把输入x传到输出作为初始结果,学习目标就是
F(x)=H(x)-x, ResNet相当于将学习目标改变了,不再是学习一个完整的输出H(x),只是输入和输出的差别H(x)-x,即残差。ResNet就是两到三层的残差学习单
元的堆叠,下图是两层的残差学习单元。
```<img src="/uploads/default/original/2X/0/042ff730436c42011951c114dcecea1a349a48d6.png" width="309" height="177">

#17
week4 动手操作---实现word2vec
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 19 16:16:59 2017

@author: Mac
"""

import collections
import math
import os
import random
import zipfile
import numpy as np
import urllib
import tensorflow as tf

#解压缩下载的压缩文件,使用tf.compat.as_str将数据转成单词的列表
def read_data(filename):
    with zipfile.ZipFile(filename) as f:
        data = tf.compat.as_str(f.read(f.namelist()[0])).split()
    return data
words= read_data('C:/Users/Mac/Desktop/text8.zip')
print('Data size',len(words))
#以上输出显示:数据最后被转为了一个包含17005207个单词的列表

#创建vocabulary词汇表,collections.Counter统计单词列表中单词的频数,使用most_common提取前50000频数的单词作为vocabulary
vocabulary_size = 50000
def build_dataset(words):
    count = [['UNK',-1]]
    count.extend(collections.Counter(words).most_common(vocabulary_size-1))
    dictionary = dict()
    for word,_ in count:
        dictionary[word] = len(dictionary)
    data = list()
    unk_count = 0
    for word in words:#遍历单词列表,如果在dictionary中,转为其编号
        if word in dictionary:
            index = dictionary[word]
        else: #如果不在,则转为编号0,并统计这类词汇的数量
            index = 0 
            unk_count += 1
        data.append(index)
    count[0][1] = unk_count
    reverse_dictionary = dict(zip(dictionary.values(),dictionary.keys()))
    return data,count,dictionary,reverse_dictionary
data, count, dictionary, reverse_dictionary = build_dataset(words)
#使用Skip_Gram模式
data_index = 0
#num_skips为对每个单词生成多少个样本,skip_window为单词最远可以联系的距离,设为1表示只能跟紧邻的两个单词生成样本
def generate_batch(batch_size, num_skips, skip_window):
    global data_index #全局变量
    assert batch_size % num_skips == 0
    assert num_skips <= 2 *skip_window
    batch = np.ndarray(shape=(batch_size),dtype=np.int32) #初始化为数组
    labels = np.ndarray(shape=(batch_size,1),dtype=np.int32)
    span = 2* skip_window + 1 #创建一个最大容量为span的双向队列deque
    buffer =collections.deque(maxlen=span) #对这个双向队列使用append方法添加变量时,只会保留最后插入的span个变量
    
    for _ in range(span): #把span个单词顺序读入buffer作为初始值
        buffer.append(data[data_index])
        data_index = (data_index + 1) % len(data)
    for i in range(batch_size // num_skips): #每次循环对一个目标单词形成样本
        target = skip_window #buffer中的第skip_window个变量为目标单词
        targets_to_avoid = [skip_window] #生成样本时需要避免的单词列表,首先包括目标单词
        for j in range(num_skips):
            while target in targets_to_avoid:
                target = random.randint(0,span-1)
            targets_to_avoid.append(target)
            batch[i*num_skips+j] = buffer[skip_window]
            labels[i*num_skips+j,0] = buffer[target]
        buffer.append(data[data_index])
        data_index = (data_index + 1) % len(data)
    return batch, labels
batch, labels = generate_batch(batch_size =8, num_skips=2, skip_window=1)
for i in range(8):
    print(batch[i],reverse_dictionary[batch[i]],'->',labels[i,0],
          reverse_dictionary[labels[i,0]])
    
batch_size = 128
embedding_size = 128
skip_window = 1
num_skips = 2
valid_size = 16
valid_window = 100
valid_examples = np.random.choice(valid_window,valid_size,replace=False)
num_sampled = 64
#以下是定义Skip_Gram word2vec模型的网络结构
graph = tf.Graph()
with graph.as_default():
    train_inputs = tf.placeholder(tf.int32,shape=[batch_size])
    train_labels = tf.placeholder(tf.int32,shape=[batch_size,1])
    valid_dataset = tf.constant(valid_examples,dtype=tf.int32)
    
    with tf.device('/cpu:0'):
        embeddings = tf.Variable(tf.random_uniform([vocabulary_size,embedding_size],-1.0,1.0))
        embed = tf.nn.embedding_lookup(embeddings,train_inputs)
        
        nce_weights = tf.Variable(
                tf.truncated_normal([vocabulary_size,embedding_size],
                                    stddev=1.0 / math.sqrt(embedding_size)))
        nce_biases = tf.Variable(tf.zeros([vocabulary_size]))
        
    loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights,
                                         biases=nce_biases,
                                         labels=train_labels,
                                         inputs=embed,
                                         num_sampled=num_sampled,
                                         num_classes=vocabulary_size))
    optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)
    norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings),1,keep_dims=True))
    normalized_embeddings = embeddings / norm
    valid_embeddings = tf.nn.embedding_lookup(
            normalized_embeddings,valid_dataset)
    similarity = tf.matmul(
            valid_embeddings,normalized_embeddings,transpose_b=True)
    init = tf.global_variables_initializer()
num_steps = 100001
    
with tf.Session(graph=graph) as session:
    init.run()
    print("Initialized")
    average_loss = 0
    for step in range(num_steps):
        batch_inputs,batch_labels=generate_batch(
                batch_size,num_skips,skip_window)
        feed_dict = {train_inputs:batch_inputs,train_labels:batch_labels}
        
        _, loss_val = session.run([optimizer,loss],feed_dict=feed_dict)
        average_loss +=loss_val
        
        if step % 2000 == 0:
            if step>0:
                average_loss /=2000
            print("Average loss at step",step,":",average_loss)
            average_loss = 0
        if step % 10000 == 0 :
            sim = similarity.eval()
            for i in range(valid_size):
                valid_word = reverse_dictionary[valid_examples[i]]
                top_k = 8
                nearest = (-sim[i,:]).argsort()[1:top_k+1]
                log_str = "Nearest to %s:" % valid_word
                for k  in range(top_k):
                    close_word = reverse_dictionary[nearest[k]]
                    log_str = "%s %s," % (log_str,close_word)
                print(log_str)
    final_embeddings = normalized_embeddings.eval()

数据集下载:http://mattmahoney.net/dc/text8


#18

好深奥,虽然没看懂,但还是 了解了一些。感谢分享