最近在琢磨一个问题,DL模型读取数据的形式是向量,那么假使存储数据格式为tfrecord。在这种情况下,有几个问题需要解决。
- 需要将里面的数据转换为向量。并且在转换的过程中,会使用feature column的api来进行一些特征加工,比如one-hot。
- 同时,测试集的数据也要转换为同样的向量格式。
- 最后,在线上serving的时候,从后端获取的数据为float或者string形式,也要进行同样的特征加工,才能被送进模型进行预测。
为了解决上面三个点,笔者思考了下具体实现( tf 版本是1.9.0),写了段代码测试。记录如下。
# 首先是生成训练集test1.tfrecord和测试集合test2.tfrecord, 保存到tfrecord
# -*- coding: utf-8 -*-
"""
Created on Sun Feb 13 15:56:26 2022
@author: 86155
"""
import tensorflow as tf
import numpy as np
f0 = np.random.random([3,1])
f1 = np.random.random([3,1])
f2 = np.array([b'b',b'b',b'c'])
data = {
"f0": f0, "f1": f1, "f2":f2
}
writer = tf.python_io.TFRecordWriter('%s.tfrecord' %'test2')
for i in range(3):
features = {}
features['f0'] = tf.train.Feature(float_list=tf.train.FloatList(value=[f0[i,0]]))
features['f1'] = tf.train.Feature(float_list=tf.train.FloatList(value=[f1[i,0]]))
features['f2'] = tf.train.Feature(bytes_list=tf.train.BytesList(value=[f2[i]]))
print(features)
tf_f = tf.train.Features(feature=features)
tf_e = tf.train.Example(features = tf_f)
tf_serialized = tf_e.SerializeToString()
# 写入一个序列化的样本
writer.write(tf_serialized)
# 由于上面有循环3次,所以到此我们已经写了3个样本
# 关闭文件
writer.close()
接下来的代码思路是,对训练集的数据进行特征工程,转换为vector。然后,用测试集,模拟一下特征工程,看得到的结果是否一样。最后,构造一条线上数据,将其送进特征处理的逻辑中,得到vector返回。
# -*- coding: utf-8 -*-
"""
Created on Sun Feb 13 16:16:33 2022
@author: 86155
"""
import tensorflow as tf
import numpy as np
"""
1. 读取tfrecord
2. 对数据进行input layer 处理
"""
data = tf.data.TFRecordDataset("test1.tfrecord")
f0 = tf.feature_column.numeric_column("f0", default_value=0.0, dtype=tf.float32)
f1 = tf.feature_column.numeric_column("f1", default_value=0.0, dtype=tf.float32)
f2 = tf.feature_column.categorical_column_with_hash_bucket("f2", 20, dtype=tf.string)
f2 = tf.feature_column.indicator_column(f2)
def parse_example(sample):
f = tf.feature_column.make_parse_example_spec([f0,f1,f2])
feats = tf.parse_single_example(sample, features=f)
return feats
def parse(sample):
features = {"f0": tf.FixedLenFeature((1,), tf.float32),
"f1": tf.FixedLenFeature((1,), tf.float32),
"f2": tf.FixedLenFeature((), tf.string)
}
parsed_features = tf.parse_single_example(sample, features)
return parsed_features
"""
data_new = data.map(parse)
for i in data_new:
print(i['f2'].numpy())
"""
data_new = data.map(parse_example)
def model_fn(features): # features 为一个dict
inputs_layers =tf.feature_column.input_layer(features,[f0,f1,f2])
return inputs_layers
for i in data_new:
print(type(i))
print("===f2:", i)
print(model_fn(i))
# 测试集
test2 = tf.data.TFRecordDataset("test2.tfrecord")
print("====================================")
data2 = test2.map(parse_example)
for i in data2:
print(type(i))
print("===f2:", i)
print(model_fn(i))
features = {}
# 构造线上样本
features['f0'] = tf.train.Feature(float_list=tf.train.FloatList(value=[0.2]))
features['f1'] = tf.train.Feature(float_list=tf.train.FloatList(value=[0.1]))
features['f2'] = tf.train.Feature(bytes_list=tf.train.BytesList(value=[b'a']))
print(features)
tf_f = tf.train.Features(feature=features)
tf_e = tf.train.Example(features = tf_f)
tf_serialized = tf_e.SerializeToString()
print(model_fn(parse_example(tf_serialized)).numpy())
# [[0.2 0.1 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 1. ]]
代码都跑过了,三种输入经过input_layer后,输出都符合预期。暂时当问题解决了。。当然,这写的非常粗糙,真实应用比这复杂多了,笔者只是想理清一下整个过程。另外希望能帮到读者。