菜鸟学NLP(三)

不打算重新开一个系列了,直接在之前学习NLP的地方进行j记录学习,反正本来就是菜鸟.

本次任务是:

  1. Anaconda 安装
  2. Conda 学习
  3. Python编辑器安装与学习: jupyter notebook 或者 pycharm
  4. Tensorflow 库安装与学习
    安装的东西就不记录了网上的有,而且早就装过一遍了.主要就是记录Conda学习以及Tensorflow学习.

Conda

Conda是一个开源包管理系统和环境管理系统,意思就是它不仅能够管理软件包的安装与删除、更新,还可以创建环境进行环境管理。
conda包括Ananconda和Miniconda.
Anconda包括conda,conda-build,python和超过150个自动安装的科学包及其依赖包.
Miniconda是一个缩小版,只包括conda,python和他们的依赖包.
它们都支持用conda install来安装软件包.

管理conda

1
2
conda --version#检查版本
conda update conda #升级当前版本的conda

管理环境

这个我用的特别6,已经创建了6个环境….

1
2
3
4
5
6
conda create -n yif python=3.6#创建一个名为yif的带python3.6的环境
conda remove -n yif --all #删除环境
source activate yif #激活环境,Linux要有source,如果是windows可以不加source
source deactivate#推出环境,同上
conda info --envs#列出所有环境
conda create -n yifdu --clone yif#这是用来克隆环境的

管理包

使用此选项可查看环境中安装的是哪个版本的Python或其他程序,或者确认已添加或删除了包。

1
2
3
conda list#查看所有软件包列表
conda search tqdm#搜索包
conda install -n yif tqdm#安装tqdm包,指定环境名称yif,如果没有则默认安装在当前环境

分享环境

(好骚啊)
如果你想把你当前的环境配置与别人分享,这样ta可以快速建立一个与你一模一样的环境(同一个版本的python及各种包)来共同开发/进行新的实验。一个分享环境的快速方法就是给ta一个你的环境的.yml文件。
首先通过source activate yif切换到分享的环境yif,然后输入下面的命令会在当前工作目录下生成一个environment.yml文件,

1
conda env export > environment.yml

小伙伴拿到environment.yml文件后,将该文件放在工作目录下,可以通过以下命令从该文件创建环境

1
conda env create -f environment.yml

移除conda

Linux,OS X:
移除Anaconda 或 Miniconda 安装文件夹

1
rm -rf ~/miniconda OR  rm -rf ~/anaconda

Windows:
去控制面板,点击“添加或删除程序”,选择“Python2.7(Anaconda)”或“Python2.7(Miniconda)”并点击删除程序。

Tensorflow学习

之前用过tensorflow,感觉流程比较繁琐,有点像在用C++一样,要先声明然后再使用,后来改用了pytorch,这就比较贴合python.但是还是知道工业是比较普及的还是tensorflow,所以想趁着这次机会再学一遍,争取能熟练使用.

tensorflow2.0

一转眼tensorflow都2.0了….
这里都是学习参考文献1的记录

keras快速入门

之前放弃tensorflow的原因就是一些复杂实现,想要直接调库,你查阅资料可能会发现keras里怎么实现,slim里怎么实现,很不统一….(归根结底是菜)

tensorflow2推荐使用keras构建网络,常见的神经网络都在keras.layer中(最新的tf.keras的版本可能和keras不同)

1
2
3
4
import tensorflow as tf
from tensorflow.keras import layers
print(tf.__version__)
print(tf.keras.__version__)

模型的堆叠
最常见的模型类型是层的堆叠:tf.keras.Sequential模型

1
2
3
4
model=tf.keras.Sequential()
model.add(layers.Dense(32,activation=‘relu’))#这里数字表示输出
model.add(layers.Dense(32,activation='relu'))
model.add(layers.Dense(10,activation='softmax'))

上述是最简单的网络形式.
看一下构建层的参数:

  1. activation:激活函数,内置了一些函数名称,默认情况,不应用任何激活函数
  2. kernel_initializer和bias_initializer:创建层权重(核和偏差)的初始化方案.默认为”Glorot uniform”初始化器
  3. kernel_regularizer和bias_regularizer:应用层权重(核和偏差)的正则化方案,例如L1或L2正则化.默认,系统不会应用正则化函数.
1
2
3
4
5
6
layers.Dense(32, activation='sigmoid')
layers.Dense(32, activation=tf.sigmoid)
layers.Dense(32, kernel_initializer='orthogonal')
layers.Dense(32, kernel_initializer=tf.keras.initializers.glorot_normal)
layers.Dense(32, kernel_regularizer=tf.keras.regularizers.l2(0.01))
layers.Dense(32, kernel_regularizer=tf.keras.regularizers.l1(0.01))

训练和评估
当我们像上面一样构建好一个完整的网络结构以后,可以开始训练

1
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),loss=tf.keras.categorical_crossentropy,metrics=[tf.keras.metrics.categorical_accuracy])

有没有发现这里的调用学习的命令显得特别紧凑,当然,这有一个好处就是很直观,loss是什么,metric是什么.但是总觉得pytorch显得更加灵活,而这种形式比较死板(可能是我太菜,还不会自定义)。

输入Numpy 数据

1
2
3
4
5
6
7
8
9
10
import numpy as np

train_x = np.random.random((1000, 72))
train_y = np.random.random((1000, 10))

val_x = np.random.random((200, 72))
val_y = np.random.random((200, 10))

model.fit(train_x, train_y, epochs=10, batch_size=100,
validation_data=(val_x, val_y))

这里相比pytorch,只要直接输入numpy数据就行了,不用转变为tensor形式,但看到没有,model.fit()这一步也被封装的很死,在pytorch中往往是自己实现的,当然这也能显得tensorflow的优点是简便.

tf.data输入数据

1
2
3
4
5
6
7
8
9
dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y))
dataset = dataset.batch(32)
dataset = dataset.repeat()
val_dataset = tf.data.Dataset.from_tensor_slices((val_x, val_y))
val_dataset = val_dataset.batch(32)
val_dataset = val_dataset.repeat()

model.fit(dataset, epochs=10, steps_per_epoch=30,
validation_data=val_dataset, validation_steps=3)

tf.data API感觉有点像torch.utils.Dataset和torch.utils.Dataloader,就是为了用简单的代码来构建复杂的输入pipeline。

  1. tf.data.Dataset:表示一系列元素,其中每个元素包含一个或多个Tensor对象.可以通过两种方式来创建数据集
    (1)直接从Tensor创建Dataset(例如Dataset.from_tensor_slices());当然Numpy也是可以的,Tensorflow会自动将其转换为tensor
    (2)通过对一个或多个tf.data.Dataset对象来使用变换(例如Dataset.batch())来创建Dataset

  2. tf.data.Iterator:这是从数据集中提取元素的主要方法.Iterator.get_next()命令会在执行时生成Dataset的下一个元素,并且此命令通常充当输入管道和模型之间的接口.最简单的迭代器是”单词迭代器”,他会对处理好的Dataset进行单词迭代,可以通过Iterator.initializer指令使用不同的数据集重新初始化和参数化迭代器,这样一来,您就可以在同一个程序中对训练和验证数据进行多次迭代
    来自优秀学长的介绍
    这一部分比较复杂,先贴这儿以后细说.

评估和预测

1
2
3
4
5
6
7
8
9
test_x = np.random.random((1000, 72))
test_y = np.random.random((1000, 10))
model.evaluate(test_x, test_y, batch_size=32)
test_data = tf.data.Dataset.from_tensor_slices((test_x, test_y))
test_data = test_data.batch(32).repeat()
model.evaluate(test_data, steps=30)
# predict
result = model.predict(test_x, batch_size=32)
print(result)

构建高级API
刚刚的tf.keras.Sequential模型是层层堆叠的,如果遇到了需要多输入多输出的模型怎么办?
可以采用函数式API

1
2
3
4
5
6
7
8
9
10
input_x = tf.keras.Input(shape=(72,))
hidden1 = layers.Dense(32, activation='relu')(input_x)
hidden2 = layers.Dense(16, activation='relu')(hidden1)
pred = layers.Dense(10, activation='softmax')(hidden2)

model = tf.keras.Model(inputs=input_x, outputs=pred)
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.categorical_crossentropy,
metrics=['accuracy'])
model.fit(train_x, train_y, batch_size=32, epochs=5)

输入张量input_x和输出张量pred用于定义tf.keras.Model实例.后续的训练方式则和Sequential模型一样.

模型子类化
通过tf.keras.Model进行子类化并定义自己前向传播来构建完全可自定义的模型.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyModel(tf.keras.Model):
def __init__(self, num_classes=10):
super(MyModel, self).__init__(name='my_model')
self.num_classes = num_classes
self.layer1 = layers.Dense(32, activation='relu')
self.layer2 = layers.Dense(num_classes, activation='softmax')
def call(self, inputs):
h1 = self.layer1(inputs)
out = self.layer2(h1)
return out

def compute_output_shape(self, input_shape):
shape = tf.TensorShapej(input_shape).as_list()
shape[-1] = self.num_classes
return tf.TensorShape(shape)

model = MyModel(num_classes=10)
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss=tf.keras.losses.categorical_crossentropy,
metrics=['accuracy'])

model.fit(train_x, train_y, batch_size=16, epochs=5)

与Pytorch一样是在init中初始化,然后在call中定义前向传播(pytorch是用forward来定义)
compute_output_shape(input_shape):如果层修改了输入数据的shape,你应该在这里指定shape变化的方法,这个函数使得Keras可以做自动shape推断。

自定义层:
通过tf.keras.layers.Layer进行子类化并实现以下方法来创建自定义层:
build:创建层的权重.使用add_weight方法添加权重
call:定义前向传播
compute_output_shape:指定在给定输入形状的情况下如何计算层的输出形状.或者,可以通过实现get_config方法和from_config类方法序列化层.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MyLayer(layers.Layer):
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
super(MyLayer, self).__init__(**kwargs)

def build(self, input_shape):
shape = tf.TensorShape((input_shape[1], self.output_dim))
self.kernel = self.add_weight(name='kernel1', shape=shape,
initializer='uniform', trainable=True)
super(MyLayer, self).build(input_shape)

def call(self, inputs):
return tf.matmul(inputs, self.kernel)

def compute_output_shape(self, input_shape):
shape = tf.TensorShape(input_shape).as_list()
shape[-1] = self.output_dim
return tf.TensorShape(shape)

def get_config(self):
base_config = super(MyLayer, self).get_config()
base_config['output_dim'] = self.output_dim
return base_config

@classmethod
def from_config(cls, config):
return cls(**config)

model = tf.keras.Sequential(
[
MyLayer(10),
layers.Activation('softmax')
])


model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss=tf.keras.losses.categorical_crossentropy,
metrics=['accuracy'])

model.fit(train_x, train_y, batch_size=16, epochs=5)

回调(感觉算是一种训练策略)

1
2
3
4
5
6
callbacks = [
tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
tf.keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(train_x, train_y, batch_size=16, epochs=5,
callbacks=callbacks, validation_data=(val_x, val_y))

权重保存:

1
2
3
4
5
6
7
8
9
10
11
12
model = tf.keras.Sequential([
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')])

model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])

model.save_weights('./weights/model')
model.load_weights('./weights/model')
model.save_weights('./model.h5')
model.load_weights('./model.h5')

保存网络结构

1
2
3
4
5
6
7
8
9
10
11
# 序列化成json
import json
import pprint
json_str = model.to_json()
pprint.pprint(json.loads(json_str))
fresh_model = tf.keras.models.model_from_json(json_str)
# 保持为yaml格式 #需要提前安装pyyaml

yaml_str = model.to_yaml()
print(yaml_str)
fresh_model = tf.keras.models.model_from_yaml(yaml_str)

保存整个模型

1
2
3
4
5
6
7
8
9
10
model = tf.keras.Sequential([
layers.Dense(10, activation='softmax', input_shape=(72,)),
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(train_x, train_y, batch_size=32, epochs=5)
model.save('all_model.h5')
model = tf.keras.models.load_model('all_model.h5')

keras用于Estimator
Estimator API 用于针对分布式环境训练模型。它适用于一些行业使用场景,例如用大型数据集进行分布式训练并导出模型以用于生产(感觉这个好方便啊)

1
2
3
4
5
6
7
8
model = tf.keras.Sequential([layers.Dense(10,activation='softmax'),
layers.Dense(10,activation='softmax')])

model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])

estimator = tf.keras.estimator.model_to_estimator(model)

eager模式

这个模式很早前就听过了但还没有用过.
像前面说的,tensorflow的弊端在于它是静态图,计算的定义和执行分开,非常不方便.但是引入Eager Execution模式以后,Tensorflow就拥有了类似于pytorch一样的动态图模型能力,我们可以不必等到session.run(* )才看到执行结果,可以方便的在IDE随时调试代码,查看OPs执行结果.

1
2
import tensorflow as tf
tf.enable_eager_execution()

那这个很爽啊.
Eager 模式下能够使用Python的debug调试工具、数据结构、控制流, 且不必再使用placeholder、session, 操作结果直接可以得到。在此种执行模式下, tensor的表现如同numpy array一般, 可以和numpy的库函数兼容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 在eager模式下可以直接进行运算
x = [[3.]]
m = tf.matmul(x, x)
print(m.numpy())

a = tf.constant([[1,9],[3,6]])
print(a)

b = tf.add(a, 2)
print(b)
print(a*b)

import numpy as np
s = np.multiply(a,b)
print(s)
[[9.]]
tf.Tensor(
[[1 9]
[3 6]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[ 3 11]
[ 5 8]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[ 3 99]
[15 48]], shape=(2, 2), dtype=int32)
[[ 3 99]
[15 48]]

动态控制流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def fizzbuzz(max_num):
counter = tf.constant(0)
max_num = tf.convert_to_tensor(max_num)
for num in range(1, max_num.numpy()+1):
num = tf.constant(num)
if int(num % 3) == 0 and int(num % 5) == 0:
print('FizzBuzz')
elif int(num % 3) == 0:
print('Fizz')
elif int(num % 5) == 0:
print('Buzz')
else:
print(num.numpy())
counter += 1
fizzbuzz(16)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16

构建模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 如果必须强制执行该层,则在构造函数中设置self.dynamic = True:
class MySimpleLayer(tf.keras.layers.Layer):
def __init__(self, output_units):
super(MySimpleLayer, self).__init__()
self.output_units = output_units
self.dynamic = True

def build(self, input_shape):
self.kernel = self.add_variable(
"kernel", [input_shape[-1], self.output_units])

def call(self, input):
return tf.matmul(input, self.kernel)
# 构造一个模型
class MNISTModel(tf.keras.Model):
def __init__(self):
super(MNISTModel, self).__init__()
self.dense1 = tf.keras.layers.Dense(units=10)
self.dense2 = tf.keras.layers.Dense(units=10)

def call(self, inputs):
"""Run the model."""
result = self.dense1(inputs)
result = self.dense2(result)
result = self.dense2(result) # reuse variables from dense2 layer
return result

model = MNISTModel()

注意上面的层需要设置self.dynamic = True

使用eager模式训练

1
2
3
4
5
6
7
8
# 计算梯度
w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
loss = w*w
grad = tape.gradient(loss, w)
print(grad)

tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 训练一个模型
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
(tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
mnist_model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,[3,3], activation='relu',
input_shape=(None, None, 1)),
tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(10)
])
for images,labels in dataset.take(1):
print("Logits: ", mnist_model(images[0:1]).numpy())

optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

loss_history = []
for (batch, (images, labels)) in enumerate(dataset.take(400)):
if batch % 10 == 0:
print('.', end='')
with tf.GradientTape() as tape:
logits = mnist_model(images, training=True)
loss_value = loss_object(labels, logits)

loss_history.append(loss_value.numpy().mean())
grads = tape.gradient(loss_value, mnist_model.trainable_variables)
optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
Logits: [[-0.05677134 0.00057287 0.00242344 0.04665339 -0.07706797 0.00323912
0.01508885 -0.07409166 -0.01701452 0.05076526]]
........................................

变量求导优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel, self).__init__()
self.W = tf.Variable(5., name='weight')
self.B = tf.Variable(10., name='bias')
def call(self, inputs):
return inputs * self.W + self.B

# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# The loss function to be optimized
def loss(model, inputs, targets):
error = model(inputs) - targets
return tf.reduce_mean(tf.square(error))

def grad(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return tape.gradient(loss_value, [model.W, model.B])

# Define:
# 1. A model.
# 2. Derivatives of a loss function with respect to model parameters.
# 3. A strategy for updating the variables based on the derivatives.
model = MyModel()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

# Training loop
for i in range(300):
grads = grad(model, training_inputs, training_outputs)
optimizer.apply_gradients(zip(grads, [model.W, model.B]))
if i % 20 == 0:
print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))

print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
Initial loss: 68.801
Loss at step 000: 66.129
Loss at step 020: 30.134
Loss at step 040: 14.026
Loss at step 060: 6.816
Loss at step 080: 3.589
Loss at step 100: 2.144
Loss at step 120: 1.497
Loss at step 140: 1.207
Loss at step 160: 1.078
Loss at step 180: 1.020
Loss at step 200: 0.994
Loss at step 220: 0.982
Loss at step 240: 0.977
Loss at step 260: 0.974
Loss at step 280: 0.973
Final loss: 0.973
W = 3.0180840492248535, B = 2.0045783519744873

eager模式下的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 变量即对象
if tf.test.is_gpu_available():
with tf.device("gpu:0"):
v = tf.Variable(tf.random.normal([1000, 1000]))
v = None # v no longer takes up GPU memory
# 对象保存
x = tf.Variable(6.0)
checkpoint = tf.train.Checkpoint(x=x)

x.assign(1.0)
checkpoint.save('./ckpt/')

x.assign(8.0)
checkpoint.restore(tf.train.latest_checkpoint('./ckpt/'))
print(x)
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 模型保存
import os
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = './ck_model_dir'
if not os.path.exists(checkpoint_dir):
os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
model=model)

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))

variable

之前一直搞不懂为什么有的地方可以直接输入Numpy型数据,有的地方则要用tf.Variable进行转换,后来搞懂了,直接输入Numpy的地方是用到了高级的API(tf.keras)实现的模型训练,而在写低级别的tf时要加上tf.Variable

创建变量

1
2
3
4
5
6
7
8
9
10
11
12
13
import tensorflow as tf
my_var = tf.Variable(tf.ones([2,3]))
print(my_var)
try:
with tf.device("/device:GPU:0"):
v = tf.Variable(tf.zeros([10, 10]))
print(v)
except:
print('no gpu')
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[1., 1., 1.],
[1., 1., 1.]], dtype=float32)>
no gpu

使用变量

1
2
3
4
5
6
7
8
a = tf.Variable(1.0)
b = (a+2) *3
print(b)
tf.Tensor(9.0, shape=(), dtype=float32)
a = tf.Variable(1.0)
b = (a.assign_add(2)) *3
print(b)
tf.Tensor(9.0, shape=(), dtype=float32)

AutoGraph

tf.function的一个很酷的新功能是AutoGraph,它允许使用自然的Python语法编写图形代码。(就是直接用python语句构建tf的计算图)

  1. tf.function装饰器
    当使用tf.function注释函数时,可以像调用任何其他函数一样调用它。 它将被编译成图,这意味着可以获得更快执行,更好地在GPU或TPU上运行或导出到SavedModel。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @tf.function
    def simple_nn_layer(x, y):
    return tf.nn.relu(tf.matmul(x, y))


    x = tf.random.uniform((3, 3))
    y = tf.random.uniform((3, 3))

    simple_nn_layer(x, y)
    <tf.Tensor: id=25, shape=(3, 3), dtype=float32, numpy=
    array([[0.75023645, 0.19047515, 0.10737072],
    [1.1521267 , 0.49491584, 0.19416495],
    [0.5541876 , 0.24642248, 0.09543521]], dtype=float32)>

如果代码使用多个函数,则无需对它们进行全部注释 - 从带注释函数调用的任何函数也将以图形模式运行。

1
2
3
4
5
6
7
8
9
10
11
def linear_layer(x):
return 2 * x + 1


@tf.function
def deep_net(x):
return tf.nn.relu(linear_layer(x))


deep_net(tf.constant((1, 2, 3)))
<tf.Tensor: id=39, shape=(3,), dtype=int32, numpy=array([3, 5, 7], dtype=int32)>

在tf.function中使用依赖于数据的控制流时,可以使用Python控制流语句,AutoGraph会将它们转换为适当的TensorFlow操作。 例如,如果语句依赖于Tensor,则语句将转换为tf.cond()

1
2
3
4
5
6
7
8
9
10
11
12
13
@tf.function
def square_if_positive(x):
if x > 0:
x = x * x
else:
x = 0
return x


print('square_if_positive(2) = {}'.format(square_if_positive(tf.constant(2))))
print('square_if_positive(-2) = {}'.format(square_if_positive(tf.constant(-2))))
square_if_positive(2) = 4
square_if_positive(-2) = 0

AutoGraph支持常见的Python语句,例如while,if,break,continue和return,支持嵌套。 这意味着可以在while和if语句的条件下使用Tensor表达式,或者在for循环中迭代Tensor。

1
2
3
4
5
6
7
8
9
10
11
12
@tf.function
def sum_even(items):
s = 0
for c in items:
if c % 2 > 0:
continue
s += c
return s


sum_even(tf.constant([10, 12, 15, 20]))
<tf.Tensor: id=149, shape=(), dtype=int32, numpy=42>

AutoGraph还为高级用户提供了低级API。 例如,我们可以使用它来查看生成的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
print(tf.autograph.to_code(sum_even.python_function, experimental_optional_features=None))
from __future__ import print_function

def tf__sum_even(items):
do_return = False
retval_ = None
s = 0

def loop_body(loop_vars, s_2):
c = loop_vars
continue_ = False
cond = c % 2 > 0

def if_true():
continue_ = True
return continue_

def if_false():
return continue_
continue_ = ag__.if_stmt(cond, if_true, if_false)
cond_1 = ag__.not_(continue_)

def if_true_1():
s_1, = s_2,
s_1 += c
return s_1

def if_false_1():
return s_2
s_2 = ag__.if_stmt(cond_1, if_true_1, if_false_1)
return s_2,
s, = ag__.for_stmt(items, None, loop_body, (s,))
do_return = True
retval_ = s
return retval_

一个更复杂的控制流程的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@tf.function
def fizzbuzz(n):
msg = tf.constant('')
for i in tf.range(n):
if tf.equal(i % 3, 0):
msg += 'Fizz'
elif tf.equal(i % 5, 0):
msg += 'Buzz'
else:
msg += tf.as_string(i)
msg += '\n'
return msg


print(fizzbuzz(tf.constant(15)).numpy().decode())
Fizz
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
  1. keras和AutoGraph
    也可以将tf.function与对象方法一起使用。 例如,可以通过注释模型的调用函数来装饰自定义Keras模型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class CustomModel(tf.keras.models.Model):

    @tf.function
    def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
    return input_data
    else:
    return input_data // 2


    model = CustomModel()

    model(tf.constant([-2, -4]))
    <tf.Tensor: id=281, shape=(2,), dtype=int32, numpy=array([-1, -2], dtype=int32)>

副作用 就像在eager模式下一样,你可以使用带有副作用的操作,比如通常在tf.function中的tf.assign或tf.print,它会插入必要的控件依赖项以确保它们按顺序执行。

1
2
3
4
5
6
7
8
9
10
11
12
v = tf.Variable(5)

@tf.function
def find_next_odd():
v.assign(v + 1)
if tf.equal(v % 2, 0):
v.assign(v + 1)


find_next_odd()
v
<tf.Variable 'Variable:0' shape=() dtype=int32, numpy=7>
  1. 用AutoGraph训练一个简单模型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    def prepare_mnist_features_and_labels(x, y):
    x = tf.cast(x, tf.float32) / 255.0
    y = tf.cast(y, tf.int64)
    return x, y

    def mnist_dataset():
    (x, y), _ = tf.keras.datasets.mnist.load_data()
    ds = tf.data.Dataset.from_tensor_slices((x, y))
    ds = ds.map(prepare_mnist_features_and_labels)
    ds = ds.take(20000).shuffle(20000).batch(100)
    return ds

    train_dataset = mnist_dataset()
    model = tf.keras.Sequential((
    tf.keras.layers.Reshape(target_shape=(28 * 28,), input_shape=(28, 28)),
    tf.keras.layers.Dense(100, activation='relu'),
    tf.keras.layers.Dense(100, activation='relu'),
    tf.keras.layers.Dense(10)))
    model.build()
    optimizer = tf.keras.optimizers.Adam()
    compute_loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

    compute_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()


    def train_one_step(model, optimizer, x, y):
    with tf.GradientTape() as tape:
    logits = model(x)
    loss = compute_loss(y, logits)

    grads = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    compute_accuracy(y, logits)
    return loss


    @tf.function
    def train(model, optimizer):
    train_ds = mnist_dataset()
    step = 0
    loss = 0.0
    accuracy = 0.0
    for x, y in train_ds:
    step += 1
    loss = train_one_step(model, optimizer, x, y)
    if tf.equal(step % 10, 0):
    tf.print('Step', step, ': loss', loss, '; accuracy', compute_accuracy.result())
    return step, loss, accuracy

    step, loss, accuracy = train(model, optimizer)
    print('Final step', step, ': loss', loss, '; accuracy', compute_accuracy.result())
    Step 10 : loss 1.85892391 ; accuracy 0.37
    ...
    Step 190 : loss 0.213473886 ; accuracy 0.848105252
    Step 200 : loss 0.224886 ; accuracy 0.85145
    Final step tf.Tensor(200, shape=(), dtype=int32) : loss tf.Tensor(0.224886, shape=(), dtype=float32) ; accuracy tf.Tensor(0.85145, shape=(), dtype=float32)

关于批处理的说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def square_if_positive(x):
return [i ** 2 if i > 0 else i for i in x]


square_if_positive(range(-5, 5))
[-5, -4, -3, -2, -1, 0, 1, 4, 9, 16]
# 在tensorflow中上面的代码应该改成下面所示
@tf.function
def square_if_positive_naive(x):
result = tf.TensorArray(tf.int32, size=x.shape[0])
for i in tf.range(x.shape[0]):
if x[i] > 0:
result = result.write(i, x[i] ** 2)
else:
result = result.write(i, x[i])
return result.stack()


square_if_positive_naive(tf.range(-5, 5))
<tf.Tensor: id=1544, shape=(10,), dtype=int32, numpy=array([-5, -4, -3, -2, -1, 0, 1, 4, 9, 16], dtype=int32)>
# 也可以怎么写
def square_if_positive_vectorized(x):
return tf.where(x > 0, x ** 2, x)


square_if_positive_vectorized(tf.range(-5, 5))
<tf.Tensor: id=1554, shape=(10,), dtype=int32, numpy=array([-5, -4, -3, -2, -1, 0, 1, 4, 9, 16], dtype=int32)>

参考文献

  1. https://github.com/czy36mengfei/tensorflow2_tutorials_chinese
  2. https://github.com/ageron/tf2_course
-------------本文结束感谢您的阅读-------------

本文标题:菜鸟学NLP(三)

文章作者:Yif Du

发布时间:2019年04月06日 - 14:04

最后更新:2019年04月06日 - 20:04

原始链接:http://yifdu.github.io/2019/04/06/菜鸟学NLP(三)/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。