版本tensorflow2.2.0
学习github网址
docker pull binzhouchn/tensorflow:2.2.0-cuda10.1-cudnn7
- 自变量转换成tf.float32
- Tensorflow一般使用梯度磁带tf.GradientTape来记录正向运算过程,然后反播磁带自动得到梯度值
- 利用梯度磁带和优化器求最小值
- 取切片数据
- 矩阵乘法
- tf2低阶api-张量的结构操作(维度变换、合并分割)
- 如果调用被@tf.function装饰的函数时输入的参数不是Tensor类型,则每次都会重新创建计算图。因此,一般建议调用@tf.function时应传入Tensor类型
- 查看模型文件相关信息,红框标出来的输出信息在模型部署和跨平台使用时有可能会用到
- 数据管道Dataset
- tf.keras.layers内置了非常丰富的各种功能的模型层
- 训练模型的3种方法
- 查看是否有GPU及相关设置
基于AI的信道信息反馈性能提升(自定义metrics和callback)
1. 自变量转换成tf.float32
x = tf.cast(x, tf.float32)
2. Tensorflow一般使用梯度磁带tf.GradientTape来记录正向运算过程,然后反播磁带自动得到梯度值
# 一阶导
x = tf.Variable(0.0,name = "x",dtype = tf.float32)
with tf.GradientTape() as tape:
y = a*tf.pow(x,2) + b*x + c
tape.gradient(y,x)
# 二阶导
with tf.GradientTape() as tape2:
with tf.GradientTape() as tape1:
y = a*tf.pow(x,2) + b*x + c
dy_dx = tape1.gradient(y,x)
dy2_dx2 = tape2.gradient(dy_dx,x)
3. 利用梯度磁带和优化器求最小值
# 求f(x) = a*x**2 + b*x + c的最小值
# 使用optimizer.apply_gradients
x = tf.Variable(0.0,name = "x",dtype = tf.float32)
a = tf.constant(1.0)
b = tf.constant(-2.0)
c = tf.constant(1.0)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
for _ in range(1000):
with tf.GradientTape() as tape:
y = a*tf.pow(x,2) + b*x + c
dy_dx = tape.gradient(y,x)
optimizer.apply_gradients(grads_and_vars=[(dy_dx,x)])
tf.print("y =",y,"; x =",x)
4. 取切片数据
x = tf.Variable([1,2,3,4,5,6])
slice_idx = tf.constant([0,3,5])
tf.gather(x, slice_idx)
#得到<tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 4, 6], dtype=int32)>
5. 矩阵乘法
用tf.matmul或者@
6. tf2低阶api - 张量的结构操作
- 6.1 维度变换
tf.reshape 可以改变张量的形状
tf.squeeze 可以减少维度
tf.expand_dims 可以增加维度
tf.transpose 可以交换维度,比如tf.transpose(x,perm=[0,2,1])
- 6.2 合并分割
4.1 tf.concat和tf.stack有略微的区别,tf.concat是连接,不会增加维度,而tf.stack是堆叠,会增加维度
4.2 tf.split是tf.concat的逆运算,可以指定分割份数平均分割,也可以通过指定每份的记录数量进行分割。tf.split(c,3,axis = 0) #指定分割份数,平均分割
7. 如果调用被@tf.function装饰的函数时输入的参数不是Tensor类型,则每次都会重新创建计算图。因此,一般建议调用@tf.function时应传入Tensor类型
8. 查看模型文件相关信息,红框标出来的输出信息在模型部署和跨平台使用时有可能会用到
!saved_model_cli show --dir ./data/demo/1 --all
9. 数据管道Dataset
/构建/
- 1,从Numpy array构建数据管道
- 2,从 Pandas DataFrame构建数据管道
- 3,从Python generator构建数据管道
- 4,从csv文件构建数据管道
- 5,从文本文件构建数据管道
- 6,从文件路径构建数据管道
- 7,从tfrecords文件构建数据管道
/加速/
- 1,使用 prefetch 方法让数据准备和参数迭代两个过程相互并行
- 2,使用 interleave 方法可以让数据读取过程多进程执行,并将不同来源数据夹在一起
- 3,使用 map 时设置num_parallel_calls 让数据转换过程多进行执行
- 4,使用 cache 方法让数据在第一个epoch后缓存到内存中,仅限于数据集不大情形
- 5,使用 map转换时,先batch, 然后采用向量化的转换方法对每个batch进行转换
10. tf.keras.layers内置了非常丰富的各种功能的模型层
- layers.Dense
- layers.Flatten
- layers.Input
- layers.DenseFeature
- layers.Dropout
- layers.Conv2D
- layers.MaxPooling2D
- layers.Conv1D
- layers.Embedding
- layers.GRU
- layers.LSTM
- layers.Bidirectional
如果这些内置模型层不能够满足需求,我们也可以通过编写tf.keras.Lambda匿名模型层或继承tf.keras.layers.Layer基类构建自定义的模型层。
其中tf.keras.Lambda匿名模型层只适用于构造没有学习参数的模型层。
11. 训练模型的3种方法
12. 查看是否有GPU及相关设置
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
gpu2 = gpus[2] #如果有多个GPU,仅使用第3个GPU
tf.config.experimental.set_memory_growth(gpu2, True) #设置GPU显存用量按需使用,可以不需要这行
# 或者也可以设置GPU显存为固定使用量(例如:4G)
#tf.config.experimental.set_virtual_device_configuration(gpu0,
# [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=4096)])
tf.config.experimental.set_visible_devices(gpu2, 'GPU') #GPU='2'即用第三个GPU
还有一种方法
import os
gpu_list = '0,1'
os.environ['CUDA_VISIBLE_DEVICES'] = gpu_list
使用多GPU训练模型,待补充
代码在基于AI的信道信息反馈性能提升文件夹中,其中modelDesign.py文件中用model.fit跑模型的时候自定义metrics和callback
#自定义metrics
class NMSE_tf(keras.metrics.Metric):
def __init__(self, name="nmse", **kwargs):
super(NMSE_tf, self).__init__(name=name, **kwargs)
self.totalLoss = self.add_weight(name="totalLoss", initializer="zeros")
self.totalCount = self.add_weight(name="totalCount", dtype=tf.int32, initializer="zeros")
def update_state(self, y_true, y_pred):
x_real = tf.reshape(y_true[:, :, :, 0], (tf.shape(y_true)[0], -1))-0.5
x_imag = tf.reshape(y_true[:, :, :, 1], (tf.shape(y_true)[0], -1))-0.5
x_hat_real = tf.reshape(y_pred[:, :, :, 0], (tf.shape(y_pred)[0], -1))-0.5
x_hat_imag = tf.reshape(y_pred[:, :, :, 1], (tf.shape(y_pred)[0], -1))-0.5
power = tf.reduce_sum(x_real ** 2 + x_imag ** 2, axis=1)
mse = tf.reduce_sum((x_real - x_hat_real) ** 2 + (x_imag - x_hat_imag) ** 2, axis=1)
nmse = tf.reduce_sum(mse / power)
self.totalCount.assign_add(tf.shape(y_true)[0])
self.totalLoss.assign_add(nmse)
def result(self):
return self.totalLoss / tf.cast(self.totalCount, tf.float32)#必须要转化成一样的类型才能相除
def reset_states(self):
# The state of the metric will be reset at the start of each epoch.
self.totalLoss.assign(0.0)
self.totalCount.assign(0)
#自定义callback用于评估与保存
class CheckPointer(keras.callbacks.Callback):
"""自定义评估与保存
"""
def __init__(self, valid_generator):
self.valid_generator = valid_generator
self.best_val_nmse = 0.55
def evaluate(self, data):
y_true = data #autoencoder中y_true就是输入数据
y_pred = autoencoderModel.predict(y_true, batch_size=512)
res = NMSE(y_true, y_pred)
return res
def on_epoch_end(self, epoch, logs=None):
val_nmse = self.evaluate(self.valid_generator)
if val_nmse < self.best_val_nmse:
self.best_val_nmse = val_nmse
# Encoder Saving
encModel.save('./modelSubmit/encoder.h5')
# Decoder Saving
decModel.save('./modelSubmit/decoder.h5')
print("tf model saved!")
print('\nval NMSE = ' + np.str(val_nmse))
见代码mnist_demo.py
见代码myLayer.py
1.1 保存模型参数(推荐)
# 保存
model.save_weights('my_model_weights', save_format='tf')
# 读取
new_model = get_model() # 之前设计好的模型结构
new_model.compile(loss='sparse_categorical_crossentropy',
optimizer=keras.optimizers.RMSprop())
new_model.load_weights('my_model_weights')
#保存成h5模型例子看AI信道信息代码
1.2 保持全模型(子类模型的结构无法保存和序列化,只能保持参数)
可以对整个模型进行保存,其保持的内容包括:
- 该模型的架构
- 模型的权重(在训练期间学到的)
- 模型的训练配置(你传递给编译的),如果有的话
- 优化器及其状态(如果有的话)(这使您可以从中断的地方重新启动训练)
import numpy as np
model.save('the_save_model.h5')
new_model = keras.models.load_model('the_save_model.h5')
new_prediction = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_prediction, atol=1e-6) # 预测结果一样
见代码5.csv_binary_classify.py
以mlp为基础模型,然后介绍一些深度学习常见技巧, 如: 权重初始化, 激活函数, 优化器, 批规范化, dropout,模型集成
使用Tensor, Variable和GradientTape这些简单的要是,就可以构建一个简单的模型。步骤如下:
见代码6.low_api_demo.py
见代码files/002-DCGAN.ipynb
已讲网页保存至files,还有001-Transformer.ipynb也在files中
保存:linear_model/1/下有三个文件;并启动服务
# docker pull tensorflow/serving
# cd到linear_model文件夹的上一层目录,然后运行如下命令
docker run -t --rm -p 8501:8501 \
-v $PWD/linear_model:/models/linear_model\
-e MODEL_NAME=linear_model \
tensorflow/serving & >server.log 2>&1
shell调用
curl -d '{"instances": [[1.0, 2.0], [5.0,7.0]]}' -X POST http://localhost:8501/v1/models/linear_model:predict
python调用
import json,requests
data = json.dumps({"signature_name": "serving_default", "instances": [[1.0, 2.0], [5.0,7.0]]})
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/linear_model:predict', data=data, headers=headers)
predictions = json.loads(json_response.text)["predictions"]
print(predictions)
15. tf-serving多模型部署
其中models.config文件写法如下:
model_config_list: {
config: {
name: "ner_model",
base_path: "/models/multimodel/ner_model/",
model_platform: "tensorflow"
},
config: {
name: "linear_model",
base_path: "/models/multimodel/linear_model/",
model_platform: "tensorflow"
}
}
15.2 启动docker
# cd到multimodel文件夹的上一层目录,然后运行如下命令
docker run -t --rm -p 8501:8501 -v $PWD/multimodel:/models/multimodel tensorflow/serving --model_config_file=/models/multimodel/models.config --model_config_file_poll_wait_seconds=60 & >server.log 2>&1
15.3 调用方法和之前一样,调用不同的模型只要把:predict前面的模型换成想要用的模型名即可