深度学习在NLP上的应用:
1.语言模型 2.机器翻译 3.词性标注 4.实体识别 5.情感分析 6.广告推荐 7.搜索排序
语料库:
WordNet, ConceptNet, FrameNet
概念:将我们平时说的句子,一些文学作品的语句段落,报刊杂志上出现过的语句段落等在现实生活中真实出现过的语言材料整理在一起,形成一个语料库,以便在做研究时可以从中取材获得到数据佐证。
特点:语料库中存放的是在语言的实际使用中真实出现过的语言材料;语料库是以电子计算机为载体承载语言知识的基础资源;真实语料需要经过加工(分析和处理),才能成为有用的资源。
Tensorflow主要依赖包:
Protocol Buffer, Bazel
Protocol Buffer
处理结构化数据的工具
结构化数据:拥有多种属性的数据
‘name’ : ‘Tom’,
‘id’ : 1234
‘email’ : ‘[email protected]’
上面的用户信息就是一个结构化数据。要将结构化持久化或者进行网络传输时,需要将它们先序列化。序列化是将结构化的数据变成数据流的格式,简单地说就是变成一个字符串。将结构化的数据序列化,并从序列化之后的数据流中还原出原来的结构化数据,通称为处理结构化数据。这就是Protocol Buffer解决的主要问题。
除Protocol Buffer外,XML, JSON是两种比较常用的结构化数据处理工具,比如上面的用户信息使用XML格式表达,那么数据的格式为:
XML格式:
‘name’ : ‘Tom’,
‘id’ : 1234
‘email’ : ‘[email protected]’
JSON格式:
{
‘name’ : ‘Tom’,
‘id’ : 1234
‘email’ : ‘[email protected]’
}
Protocol Buffer格式的数据和XML或者JSON格式的数据有比较大的差别。首先,Protocol Buffer序列化之后得到的数据不是可读的字符串,而是二进制流。其次,XML或者JSON格式的数据信息都包含在了序列化之后的数据中,不需要任何其他信息就能还原序列化之后的数据。但使用Protocol Buffer时需要先定义数据的格式。还原一个序列化之后的数据将需要使用到这个定义好的数据格式。以下代码是上面用户信息样例的数据格式定义文件。因为这样的差别,Protocol Buffer序列化出来的数据要比XML或者JSON格式的数据小3到10倍,解析时间要快到20-100倍
message user{
optional string name = 1;
required int32 id = 2;
repeated string email = 3;
}
Protocol Buffer定义的数据格式的文件一般保存在.proto文件中。每一个message代表了一类结构化的数据。message中定义了每一个属性的类型和名字。在message中,Protocol Buffer定义了一个属性是必需的(required)还是可选的(optional)或者是可重复的(repeated)。
Bazel
Bazel是从Google开源的自动化构建工具,谷歌内部绝大部分的应用都是通过它来编译的。
项目空间是Bazel的一个基本概念。一个项目框架可以简单的理解为一个文件夹,在这个文件夹中包含了编译一个软件所需要的源代码以及输出编译结果的软连接地址。一个项目空间可以包含一个或多个应用。一个项目空间所对应的文件夹是这个项目的根目录,在这个根目录中需要有一个WORKSPACE文件,此文件定义了对外部资源的依赖关系。
在一个项目空间内,Bazel通过BUILD文件来找到需要编译的目标。Bazel的编译方式是事先定义好的。Bazel对Python支持的编译方式只有三种:py_binary, py_library, py_test. 其中py_binary将Python程序编译为可执行文件,py_test编译Python测试程序,py_library将Python程序编译成库函数供其他py_binary或py_test调用。
BUILD文件是由一系列编译目标组成的。定义编译目标的先后顺序不会影响编译结果。
Tensorflow中的计算可以表示为一个有向图,其中每一个运算操作将作为一个节点,节点与节点之间的连接称为边。这个计算图描述了数据的计算流程,它也负责维护和更新状态,用户可以对计算图的分支进行条件控制或循环操作。计算图中每一个节点可以有任意多个输入和任意多个输出,每一个节点描述了一种运算操作,节点可以算是运算操作的实例化。在计算图的边中流动的数据被称为张量(tensor),而tensor的数据类型,可以是事先定义的,也可以根据计算图的结构推断得到的。有一类特殊的边中没有数据流动,这种边是依赖控制,作用是让他的起始节点执行完之后再执行目标节点,用户可以使用这样的边进行灵活的条件控制,比如限制内存使用的最高峰值。
Tensorflow程序一般分为两个阶段。第一个阶段需要定义计算图中所有的计算;第二阶段为执行阶段。
# 定义阶段,这个过程中,TensorFlow会自动将定义的计算转化为计算图上的节点
import tensorflow as tf
a = tf.constant([1, 2], name = 'a')
b = tf.constant([3, 4], name = 'b')
result = a + b
# 执行阶段
with tf.Session() as sess:
print(sess.run(result))
# 通过a.graph可以查看张量所属的计算图,如果没有特定指定,张量的计算图属于默认的计算图
print(a.graph is tf.get_default_graph()) # True
import tensorflow as tf
g1 = tf.Graph() # 定义g1计算图
with g1.as_default():
# 在计算图g1中定义变量'v',并设置初始值0
v = tf.get_variable('v', shape=[1], initializer=tf.zeros_initializer())
g2 = tf.Graph() # 定义g2计算图
with g2.as_default():
# 在计算图g1中定义变量'v',并设置初始值1
v = tf.get_variable('v', shape=[1], initializer=tf.ones_initializer())
# 在计算图g1中读取变量'v'的值
with tf.Session(graph=g1) as sess:
tf.global_variables_initializer().run()
with tf.variable_scope('', reuse=True):
print(sess.run(tf.get_variable('v'))) # 输出[0.]
# 在计算图g2中读取变量'v'的值
with tf.Session(graph=g2) as sess:
tf.global_variables_initializer().run()
with tf.variable_scope('', reuse=True):
print(sess.run(tf.get_variable('v'))) # 输出[1.]
with tf.Session(graph=g1) as sess:
tf.global_variables_initializer().run()
with tf.variable_scope('zyy'):
v = tf.get_variable('v', [1])
with tf.variable_scope('zyy', reuse=True):
vv = tf.get_variable('v', [1])
print(v == vv) # 输出True
with tf.variable_scope('zyy', reuse=True, initializer=tf.zeros_initializer()):
vvv = tf.get_variable('v', [1])
print(vv == vvv) # 输出True
with tf.variable_scope('zyy'):
v = tf.get_variable('k', [2, 3], initializer=tf.random_normal_initializer(mean=0, stddev=1))
所有数据都通过张量的形式来表示。从功能的角度上看,张量可以被简单理解为多维数组。其中零阶张量表示标量,也就是一个数;一阶张量表示向量,也就是一个数组;n阶张量可以理解为一个n维数组。
张量在TensorFlow中的实现并不是直接采用数组的形式,它只是TensorFlow中的运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。
import tensorflow as tf
a = tf.constant([1, 2], name = 'a')
b = tf.constant([3, 4], name = 'b')
result = a + b
print(result)
# 输出:Tensor('add:0', shape=(2,), dtype=int32
# 得到的是对结果的一个引用,是一个张量结构。主要保存了三个属性:名字、维度、类型
# 第一种
sess = tf.Session()
sess.run(...)
sess.close()
# 第二种
with tf.Session() as sess:
sess.run(...)
sess = tf.Session()
with sess.as_default():
print(result.eval())
# 以下代码与上面代码有同样功能
with tf.Session() as sess:
print(sess.run(result))
# print(result.eval(session = sess))
sess = tf.InteractiveSession()
print(result.eval())
sess.close()
tf.Variable(tf.random_normal([2, 3], stddev=2))
TensorFlow支持随机数生成函数和常数生成函数
tf.global_variables_initializer().run() # 初始化所有变量
在TensorFlow中,变量的声明函数tf.Variable是一个运算。这个运算的输出结果就是一个张量。
Tensorflow中集合(collection):所有的变量都会被自动地加入到GraphKeys.VARIABLES这个集合中。通过tf.global.variables()函数可以拿到当前计算图上所有变量。拿到计算图上所有的变量有助于持久化整个计算图的运行状态。当构建机器学习模型时,如神经网络,可以通过变量声明函数中的trainable参数来区分需要优化的参数和其他参数。如果声明变量是参数trainable为True,那么这个变量将会被加入到GraphKeys.TRAINABLE_VARIABLES集合。在Tensorflow中可以通过tf.trainable_variables函数得到所有需要优化的参数。
一个变量在构建之后,他的类型不会改变,但是维度在程序运行过程中可以改变,通过设置参数validate_shape=False
w1 = tf.Variable(tf.random_normal((2, 3), stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal((3, 1), stddev=1, seed=1))
tf.assign(w1, w2, validate=False)
w1 = tf.Variable(tf.random_normal((2, 3), stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal((3, 1), stddev=1, seed=1))
x = tf.placeholder(tf.float32, shape=(None, 2), name='x_input')
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
sess = tf.Session()
tf.global_variable_initializer().run()
sess.run(y, feed_dict={x : [[0.7, 0.9]]})
在这段程序中替换了原来通过常量定义的输入x。需要提供一个feed_dict来指定x的取值,feed_dict是一个字典,在字典中需要给出每个用到的placeholder取值。
'''
训练一个完整的神经网络
'''
from numpy.random import RandomState
import tensorflow as tf
batch_size = 8
learningRate = 0.001
w1 = tf.Variable(tf.random_normal((2, 3), stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal((3, 1), stddev=1, seed=1))
x = tf.placeholder(tf.float32, shape=(None, 2), name='x_input')
y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y_input')
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
y = tf.sigmoid(y)
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)) + (1-y_) * tf.log(tf.clip_by_value(1-y, 1e-10, 1.0)))
train_step = tf.train.AdamOptimizer(learningRate).minimize(cross_entropy)
rdm = RandomState(1)
dataSize = 128
X = rdm.rand(dataSize, 2)
Y = [[int(x1+x2<1)] for (x1, x2) in X]
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(w1))
print(sess.run(w2))
step = 5000
for i in range(step):
start = (i * batch_size) % dataSize
end = min(start+batch_size, dataSize)
sess.run(train_step, feed_dict={x:X[start:end], y_:Y[start:end]})
if i % 1000 == 0:
total_cross_entropy = sess.run(cross_entropy, feed_dict={x:X, y_:Y})
print('After %d training step(s),cross entropy on all data is %g' % (i, total_cross_entropy))
print(sess.run(w1))
print(sess.run(w2))
训练神经网络的过程:
1. 定义神经网络的结构和前向传播的输出结果
2. 定义损失函数以及选择反向传播优化算法
3. 生成会话(tf.Session())并且在训练数据上反复运行反向传播优化算法