TensorFlow笔记
这篇笔记包括了从读取数据开始,模型初始化和拟合,到使用TensorBoard查看结果的全流程。整理了一些常见的、包括版本更新引起的bug。
1. 读取数据1
TF似乎没有直接读取Excel的API,需要经过pandas传数据。但是似乎可以读取CSV2。
注意:TensorFlow 2.0中已经将tf.contrib
模块取消,需要去官网搜索对应的功能,或者退回TensorFlow 1.0版本!似乎改成了tf.data.experimental.make_csv_dataset
。
training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
filename=IRIS_TRAINING, target_dtype=np.int, features_dtype=np.float32)
有以下几种数据输入的方式:
- 一次性从内存中读取数据到矩阵中,直接输入;(少量数据)
- 从文件中边读边输入,而且已经设计好了多线程读写模型;(大量数据分批次读取)
- 把网络或者内存中的数据转化为tensorflow的专用格式tfRecord,存文件后再读取。
1.1 如何将特征数据转换成tensors形式
如果特征/标签是存储在pandas的dataframe中或者numpy的array中的话,就需要在返回特征与标签的时候将它们转换成tensor形式。
(1)对于连续型数据,可以使用tf.constant
创建一个tensor:
feature_column_data = [1, 2.4, 0, 9.9, 3, 120]
feature_tensor = tf.constant(feature_column_data)
(2)对于稀疏型数据,可以使用tf.SparseTensor
来创建tensor:
sparse_tensor = tf.SparseTensor(indices=[[0,1], [2,4]], #索引所在的位置是非0值,其余都是0
values=[6, 0.5], #非0值具体是多少。其元素与indices中的索引一一对应
dense_shape=[3, 5]) # tensor的维度,这里是3*5
>>[[0, 6, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0.5]] #打印出来是这样的
2. 定义feature_columns
只在TensorFlow 1.0版中生效:
# Specify that all features have real-value data
feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]
#在TensorFlow 2.0版中取消
TensorFlow 2.0版需要使用tf.feature_column.numeric_column
:3
my_feature_columns = []
for key in train_x.keys(): #鸢尾花数据集
my_feature_columns.append(tf.feature_column.numeric_column(key=key))
print(my_feature_columns)
# feature_columns的构造如下:
>> [NumericColumn(key='SepalLength', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=None), NumericColumn(key='SepalWidth', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=None), NumericColumn(key='PetalLength', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=None), NumericColumn(key='PetalWidth', shape=(1,), default_value=None, dtype=tf.float32, normalizer_fn=None)]
实际上(另一种)标准流程:
- 构建特征列:
feature_column = tf.feature_column
… - 构建
features{ }
,其中key要与feature_column
的key对齐,features = {key:value}
- 构建特征层
layer = tf.keras.layers.DenseFeatures(feature_column|| List(feature_column))
- 将
features
喂给特征层DenseFeatures
,input = layer(features)
,将带输入的样本数据封装成字典类型的对象。4
number = tf.feature_column.numeric_column("number", normalizer_fn=lambda x: (x - 1.0) / 2.0)
feature_layer = tf.keras.layers.DenseFeatures(number)
feature_dict = {"number": [1.1, 1.2, 1.3]} # 特征列字典
output = feature_layer(feature_dict)
print(output)
3. DNN模型初始化
在TensorFlow 2.0版中为tf.contrib.learn.DNNClassifier
;TensorFlow 2.0版为tf.estimator.DNNClassifier
。
classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
hidden_units=[10, 20, 10], #隐藏层所含结点数量分别为10, 20, 10.
n_classes=3, #分三类
model_dir="E:/tmp/iris_model") #训练好的模型储存的位置
4. 如何使用input_fn
自定义输入管道
当使用tf.contrib.learn
来训练一个神经网络时,可以直接将特征、标签数据输入到.fit(), .evaluate(), .predict()
操作中。当原始数据不需要预处理时,用以上的方式较为方便。然而实际的业务中往往需要做大量的特征工程,于是tf.contrib.learn
支持使用一个用户自定义的输入函数input_fn来封装数据预处理,并将数据通过管道输送到模型中。
输入函数的主体包括一个特定的预处理输入数据的逻辑,比如去除一些脏数据,弥补缺失数据,归一化等等。输入函数的返回是两个部分:
- 处理后的特征:feature_cols,格式是一个map,key是特征的名称,value是tensor形式的对应的特征列数据。
- 标签数据:labels,一个包含标签数据的tensor。
def my_input_fn():
# Preprocess your data here...(首先预处理你的数据)
# 然后返回新的特征数据与标签数据(都是以tensor的形式)
# ...then return 1) a mapping of feature columns to Tensors with the corresponding feature data,
# 2) a Tensor containing labels
return feature_cols, labels
例[1]:这里我们构建一个输入函数预处理数据,内容比较简单,只是将用pandas读进来的dataframe数据转换成tensor.1
FEATURES = df_train.columns
def input_fn(data_set):
feature_cols = {k: tf.constant(data_set[k].values)
for k in FEATURES}
labels = tf.constant(data_set[LABEL].values)
return feature_cols, labels
例[2]:使用内置函数numpy_input_fn
。5
train_input_fn = tf.estimator.inputs.numpy_input_fn(
x={"image": mnist.train.images}, #需要给出所有的输入数据
y=mnist.train.labels.astype(np.int32), #对应x的正确标签
num_epochs=None, #数据循环使用轮数,这里不循环使用
batch_size=128, #每个batch的大小
shuffle=True) #是否要对数据进行随机打乱操作
estimator.train(input_fn=train_input_fn, steps=10000)
例[3]:TensorFlow中,一般是先定义好神经网络输入的特征列,然后使用Dataset读取特征列。注意,读取的时候,要把每一个特征列添加上列的名称,然后进行字典化处理。之后,初始化DNNClassifier的特征列,使得两者的特征列的名称相同。之后处理好一次数据的batch_size等。最后进行读取。6
def train_input_fn(features, labels, batch_size):
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
dataset = dataset.shuffle(1000).repeat().batch(batch_size)
return dataset
或者3:(关于dataset.shuffle(), dataset.batch()
参见7)
# 定义函数,将数据存储为dataset格式,可以节省内存,并且方便并行读取
def input_fn(features, labels, training=True, batch_size=256):
"An input function for training or evaluating"
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #将输入转换为数据集。
if training:
dataset = dataset.shuffle(1000) #如果在训练模式下,混淆并重复数据。
dataset = dataset.repeat() #无限重复
return dataset.batch(batch_size)
5 拟合:如何将input_fn
数据传给模型
在.fit()
操作中有一个参数:input_fn
,只要将我们定义好的输入函数传给这个参数即可:
注意:2.0版中没有.fit
,改为classifier.train
。
classifier.fit(input_fn=my_input_fn, steps=2000)
但是,注意绝不能直接这样做:
classifier.fit(input_fn=my_input_fn(training_set), steps=2000)
如果想直接传参数给输入函数,可以选择另外几个方法:
(1)再写一个封装函数:
def my_input_function_training_set():
return my_input_function(training_set)
classifier.fit(input_fn=my_input_fn_training_set, steps=2000)
(2)使用Python的functools.partial
方法:
classifier.fit(input_fn=functools.partial(my_input_function, data_set=training_set), steps=2000)
(3) (推荐) 在lambda
中调用输入函数,然后将参数传入input_fn
中:
classifier.fit(input_fn=lambda: my_input_fn(train_x, train_y), steps=2000)
6. 如何使用TensorBoard
TensorBoard是TensorFlow推出的可视化工具,可以可视化模型结构、跟踪并以表格形式显示模型指标。TensorBoard的使用包括两个步骤:8
- 在代码中设置TensorBoard,在训练的过程中将会根据设置产生日志文件。
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir='E:/logs/tf')
:初始化日志文件。其中,log_dir
是日志文件的存放位置,可自己指定或生成一个临时地址 - 在浏览器中可视化该日志文件,查看网络结构、loss的变化情况等。
model.fit(callbacks=[tensorboard_callback])
:设置回调函数,在模型训练期间将会调用tensorboard_callback
从而向日志文件中写入数据
#import tempfile #(可选)临时文件系统
def create_model():
return tf.keras.models.Sequential([ #支持自定义各类神经网络模型
tf.keras.layers.InputLayer(input_shape=(5)), #输入层,输入形状为(None, 5),None表示不限制样本数
tf.keras.layers.Dense(30, activation='relu'), #全连接层,输出维度为30,激活函数为relu,输出形状为(None, 30)
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(3, activation='softmax')#全连接层,激活函数为softmax,用于多分类,输出形状为(None,3)
])
model = create_model()
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
metrics=['accuracy'], steps_per_execution=10)
log_dir = r'E:\temp' #(可选)自定义一个输出目录
#log_dir = tempfile.mkdtemp() #(可选)或者创建一个临时目录,并返回该临时目录的路径。
# Enable histogram computation with each epoch.
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=2)
model.fit(x=df_train_x, #你的训练集x
y=df_train_y, #你的训练集y
epochs=1000,
validation_data=(df_test_x, df_test_y), #你的测试集
callbacks=[tensorboard_callback])
#shutil.rmtree(temp_dir) #递归删除文件夹下的所有子文件夹和子文件。
#若是在jupyter notebook中运行tensorboard,在前面加%符号:
%tensorboard --logdir "E:\temp"
#如果最后一步报错,可先运行以下代码
#%load_ext tensorboard
6.1 在浏览器中打开Tensorboard
注意:也可以通过Anaconda Prompt在Web中打开TensorBoard。可对照以下步骤执行
- (可选)查看所有环境:
conda info --envs
- 激活装有TensorFlow的环境:
(base) C:\Users>activate base
- 确保路径下存在events文件,注意是文件夹路径,不是直接输入events文件文件名:
(base) C:\Users>tensorboard --logdir "E:\temp"
- 若运行正常,会出现:
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all TensorBoard 2.10.0 at http://localhost:6006/ (Press CTRL+C to quit)
此时在浏览器中打开端口,即可正常查看和下载loss、accuracy等数据。若打开发现提示No dashboards are active for the current data set
,可能有多种原因:11
- 路径不对,程序找不到events文件;
- 文件路径太长,超过255字符。
- TensorBoard版本与TensorFlow不兼容。删除并重新下载。实测将TensorBoard 2.10.0升级到2.16.2后成功解决。
pip uninstall tensorboard``pip install tensorboard
6.2 Tensorboard Web端解释12
最上面橙色栏菜单,有7个栏目,一一对应着我们程序中定义信息的类型。(这里只展示部分)
(1)SCALARS:展示的是标量的信息
- 点开accuracy,红线表示test集的结果,蓝线表示train集的结果,可以看到随着循环次数的增加,两者的准确度也在通趋势增加
- 点开layer1,查看第一个隐藏层的参数信息。第一排是偏执项b的信息,随着迭代的加深,最大值越来越大,最小值越来越小,与此同时,也伴随着方差越来越大,这样的情况是我们愿意看到的,神经元之间的参数差异越来越大。因为理想的情况下每个神经元都应该去关注不同的特征,所以他们的参数也应有所不同。第二排是权值w的信息,同理,最大值,最小值,标准差也都有与b相同的趋势,神经元之间的差异越来越明显。w的均值初始化的时候是0,随着迭代其绝对值也越来越大。
- 点开loss,可见损失的降低趋势。
(2)GRAPHS:这里展示的是整个训练过程的计算图graph,从中我们可以看到整个程序的逻辑与过程。单击某个节点,可以查看属性,输入,输出等信息。单击节点上的“+”字样,可以看到该节点的内部信息。
另外还可以选择图像颜色的模型,基于结构structure的模式,相同的节点会有同样的颜色;基于device预算硬件的,同一个硬件上的会有相同颜色。
(3)DISTRIBUTIONS:查看神经元输出的分布,有激活函数之前的分布,激活函数之后的分布等。
(4)HISTOGRAMS:看以上数据的直方图
备注
设置logging verbosity
为INFO,这样可以获取更多的日志信息。
tf.logging.set_verbosity(tf.logging.INFO)
Reference
Tensorflow高级API的进阶–利用tf.contrib.learn建立输入函数;https://www.jianshu.com/p/cb28341b7fec ↩︎ ↩︎
TensorFlow 入门(2):使用DNN分类器对数据进行分类;https://zhuanlan.zhihu.com/p/28412173 ↩︎
Tensorflow2.0学习(11):Estimator;https://blog.csdn.net/Smile_mingm/article/details/104532746/ ↩︎ ↩︎
CSDN 特征处理之tf.feature_column;https://blog.csdn.net/qq_43283527/article/details/122845343 ↩︎
Tensorflow高层封装Estimator-DNNClassifier;https://blog.csdn.net/qq_36289191/article/details/83828873 ↩︎
Tensorflow Estimator之DNNClassifier;https://blog.csdn.net/qq_35976351/article/details/80793487 ↩︎
浅谈tensorflow中dataset.shuffle和dataset.batch dataset.repeat注意点;https://www.jb51.net/article/188263.htm ↩︎
使用TensorBoard进行可视化;https://blog.csdn.net/qq_41100617/article/details/132125115 ↩︎
tf.keras.models.Sequential函数介绍;https://blog.csdn.net/qq_24951479/article/details/132493333 ↩︎
迁移 TensorBoard:TensorFlow 的呈现工具包;https://tensorflow.google.cn/guide/migrate/tensorboard?hl=zh-cn ↩︎
解决tensorboard中events.out.tfevents出现No dashboards are active for the current data set错误;https://blog.csdn.net/q7w8e9r4/article/details/133855384 ↩︎
06:Tensorflow的可视化工具Tensorboard的初步使用; https://blog.csdn.net/sinat_33761963/article/details/62433234 ↩︎