TensorFlow笔记:从零开始的代码实现

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)

有以下几种数据输入的方式:

  1. 一次性从内存中读取数据到矩阵中,直接输入;(少量数据)
  2. 从文件中边读边输入,而且已经设计好了多线程读写模型;(大量数据分批次读取)
  3. 把网络或者内存中的数据转化为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_column3

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)]

实际上(另一种)标准流程:

  1. 构建特征列:feature_column = tf.feature_column
  2. 构建features{ },其中key要与feature_column的key对齐,features = {key:value}
  3. 构建特征层 layer = tf.keras.layers.DenseFeatures(feature_column|| List(feature_column))
  4. features喂给特征层DenseFeaturesinput = 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来封装数据预处理,并将数据通过管道输送到模型中。

输入函数的主体包括一个特定的预处理输入数据的逻辑,比如去除一些脏数据,弥补缺失数据,归一化等等。输入函数的返回是两个部分:

  1. 处理后的特征:feature_cols,格式是一个map,key是特征的名称,value是tensor形式的对应的特征列数据。
  2. 标签数据: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_fn5

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从而向日志文件中写入数据

**例:**完整代码910

#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。可对照以下步骤执行

  1. (可选)查看所有环境:conda info --envs
  2. 激活装有TensorFlow的环境:(base) C:\Users>activate base
  3. 确保路径下存在events文件,注意是文件夹路径,不是直接输入events文件文件名:(base) C:\Users>tensorboard --logdir "E:\temp"
  4. 若运行正常,会出现: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

  1. 路径不对,程序找不到events文件;
  2. 文件路径太长,超过255字符。
  3. 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


  1. Tensorflow高级API的进阶–利用tf.contrib.learn建立输入函数;https://www.jianshu.com/p/cb28341b7fec ↩︎ ↩︎

  2. TensorFlow 入门(2):使用DNN分类器对数据进行分类;https://zhuanlan.zhihu.com/p/28412173 ↩︎

  3. Tensorflow2.0学习(11):Estimator;https://blog.csdn.net/Smile_mingm/article/details/104532746/ ↩︎ ↩︎

  4. CSDN 特征处理之tf.feature_column;https://blog.csdn.net/qq_43283527/article/details/122845343 ↩︎

  5. Tensorflow高层封装Estimator-DNNClassifier;https://blog.csdn.net/qq_36289191/article/details/83828873 ↩︎

  6. Tensorflow Estimator之DNNClassifier;https://blog.csdn.net/qq_35976351/article/details/80793487 ↩︎

  7. 浅谈tensorflow中dataset.shuffle和dataset.batch dataset.repeat注意点;https://www.jb51.net/article/188263.htm ↩︎

  8. 使用TensorBoard进行可视化;https://blog.csdn.net/qq_41100617/article/details/132125115 ↩︎

  9. tf.keras.models.Sequential函数介绍;https://blog.csdn.net/qq_24951479/article/details/132493333 ↩︎

  10. 迁移 TensorBoard:TensorFlow 的呈现工具包;https://tensorflow.google.cn/guide/migrate/tensorboard?hl=zh-cn ↩︎

  11. 解决tensorboard中events.out.tfevents出现No dashboards are active for the current data set错误;https://blog.csdn.net/q7w8e9r4/article/details/133855384 ↩︎

  12. 06:Tensorflow的可视化工具Tensorboard的初步使用; https://blog.csdn.net/sinat_33761963/article/details/62433234 ↩︎

  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值