TensorFlow API
使用规范
tf.Variable
: 用于W与b等参数
tf.constant
: 用于超参数
tf.placeholder
: 用于数据
tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
: 进行反向传播, 在优化的时候, 一定要sess.run(optimizer, feed_dict={})
, run的是optimizer, 但是在测试查看损失或者准确率的时候, 要使用sess.run(cost, feed_dict={})
, 不要进行优化
- TensorFlow中主要是要保存的数据都是需要先转为String类型的, 读取也是一样, 得到的数据要将其ParseFromString, 遇到图像与string需要decode; 在TensorFlow中string的语义应该为字节流
常用模块
tf.nn
: TensorFlow的核心模块
tf.train
: 训练模块
tf.image
: 图像增强模块
tf.image模块
tf.image.decode_jpeg
tf.image.decode_png
tf.image.encode_jpeg
tf.image.encode_png
tf.image.convert_image_dtype
: 在大部分的图像API中即使我们输入的0-255的图像, 它在内部还是会转换为0-1之间的实数, 接着在转为0-255返回给用户, 为了避免精度的损失, 推荐调用该函数提前转换类型
tf.image.resize_images
- 缩放算法:
- 0: 双线性插值法
- 1: 最近邻法
- 2: 双三次插值法
- 3: 面积插值法
tf.image.resize_image_with_crop_or_pad
: 对图像进行裁剪或者填充
tf.image.central_crop
: 等比例缩放, 比例在(0,1]
tf.image.flip_up_down
: 上下翻转
tf.image.flip_left_right
: 水平翻转
tf.image.transpose_image
: 沿着对角线翻转
tf.image.adjust_brightness
tf.image.adjust_constrast
tf.image.adjust_hue
tf.image.adjust_saturation
tf.image.per_image_standardization
tf.image.draw_bounding_boxes
: 画出bounding_box
tf.expand_dims(image, 0)
: 将第0维度之前使用1添加一个维度, 该函数在添加维度的时候非常好用
运算
tf.clip_by_value(v, 1e-10, 1)
: 将v限定在min与max
tf.add
tf.reduce_mean
tf.reduce_sum
tf.argmax
tf.matmul
tf.multiply
tf.subtract
- 以上是TensorFlow中提供的运算节点的函数, 同时还提供了方便的操作符重载, 他们的区别仅仅是在生成的计算图时, 节点的名称略有不同, 对于add节点, 在函数中, 为Add, 在操作符重载中, 为add
随机数生成函数
tf.random_normal
: 正态分布, 参数stddev(standard deviation)为标准差
tf.truncated_normal
: 与tf.random_normal
类似, 正态分布, 如果生成的随机数偏移平均值超过2个标准差, 重新生成
tf.random_uniform
: 均匀分布
tf.random_gamma
: Gamma分布
常量生成函数
tf.zeros
tf.ones
tf.fill
tf.constant
非线性激活函数
tf.nn.sigmoid
tf.nn.tanh
tf.nn.relu
默认集合
- 定义在
tf.GraphKeys
中
tf.GraphKeys.TRAINABLE_VARIABLES
: 返回字符串trainable_variables
, 这是一个内置集合的名字; 默认通过tf.Variable
定义时会添加到该集合中, 如果将trainable=False则不会了
tf.GraphKeys.LOSSES
: 默认的损失集合名, 之后使用tf.losses
模块才会使用到该内置集合
tf.GraphKeys.BIASES
: 默认的偏移集合名
tf.GraphKeys.WEIGHTS
: 默认的权重集合名
BIASES和WEIGHTS
不常用
TRAINABLE_VARIABLES
包含在MODEL_VARIABLES
中,MODEL_VARIABLES
包含在GLOBAL_VARIABLES
中
tf.Optimizer
只优化tf.GraphKeys.TRAINABLE_VARIABLES
中的变量
集合操作
tf.add_to_collection(name, value)
: 将value添加到名为name的集合中
tf.get_collection(name)
: 返回名为name的集合的所有元素
tf.get_collection(name, namespace_prefix)
: 返回名为name的集合namespace_prefix
名称空间下的Tensor, 注意末尾不能有/
CNN
tf.nn.conv2d(input, filter, strides, padding)
tf.nn.max_pool(input, ksize, strides, padding)
tf.nn.bias_add(input, bias)
: 注意这里的bias应该为(n, )之类的奇怪的矩阵, 也就是我们在创建bias的时候, 要tf.get_variable('biases', [SIZE], init...)
, 而不能为tf.get_variable('biases', [1, SIZE]或者[1, 1, 1, SIZE], init...)
TF-Slim内置的神经网络模型
- AlexNet, VGG, Inception, ResNet
import tensorflow.contrib.slim as slim
import tensorflow.contrib.slim.python.slim.nets.inception_v3 as inception_v3
: 定义了InceptionV3的网络结构, 但是在Google中已经完成了训练的权重不在这里, 需要从官网上下载过来进行迁移学习
简单的fine-tune
- 加载模型(.ckpt类型的, 不是.pb类型)
- 找出我们需要的冻住的参数
- 找出我们需要重新训练的参数
- 创建一个sess
- 加载冻住的参数
- 初始化需要重新训练的参数
- 优化损失函数
- sess.run进行训练
TFRecord文件
| |
| mnist = input_data.read_data_sets('mnist/', dtype=tf.uint8, one_hot=True) |
| writer = tf.python_io.TFRecordWriter('demo.tfrecord') |
| for i in range(mnist.train.num_examples): |
| image_raw = mnist.train.images[i].tostring() |
| example = tf.train.Example(features=tf.train.Features(feature={ |
| 'pixels': tf.train.Feature(int64_list=tf.train.Int64List(value=[len(mnist.train.images[i])])), |
| 'label': tf.train.Feature(int64_list=tf.train.Int64List(\ |
| value=[np.argmax(len(mnist.train.labels[i]))])), |
| 'image_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])) |
| })) |
| writer.write(example.SerializeToString()) |
| |
| |
| reader = tf.TFRecordReader() |
| |
| filename_queue = tf.train.string_input_producer(['./demo.tfrecord']) |
| _, serialized_example = reader.read(filename_queue) |
| features = tf.parse_single_example(serialized_example, features={ |
| 'pixels': tf.FixedLenFeature([], tf.int64), |
| 'label': tf.FixedLenFeature([], tf.int64), |
| 'image_raw': tf.FixedLenFeature([], tf.string) |
| }) |
| image = tf.decode_raw(features['image_raw'], tf.uint8) |
| pixels = tf.cast(features['pixels'], tf.int32) |
| label = tf.cast(features['label'], tf.int32) |
| |
| with tf.Session() as sess: |
| coord = tf.train.Coordinator() |
| |
| threads = tf.train.start_queue_runners(sess=sess, coord=coord) |
| for i in range(10): |
| print(sess.run([image, pixels, label])) |
| |
神经网络优化
tf.train.exponential_decay(staircase=True)
:
- 如果staircase为True则学习率的衰减为阶梯型的
- 参照公式:
decay_learning_rate=learning_rate*decay_rate^(global_step/decay_step)
- 其中,
learning_rate
为初始学习率(如0.1), decay_rate
为衰减系数(0-1, 如0.1), decay_step
为衰减速率(如50)
内置损失函数
tf.nn.softmax_cross_entropy_with_logits(labels=,logits=)
tf.nn.sigmoid_cross_entropy_with_logits(labels=,logits=)
tf.nn.sparse_softmax_cross_entropy_with_logits(labels=,logits=)
自定义损失函数
tf.greater(v1, v2)
: v1 > v2返回True, 否则返回False
tf.where(tf.greater(v1, v2), v1, v2)
: 分段函数, 当v1>v2是为v1, 否则为v2
模型持久化(.ckpt)
- 保存模型
| |
| saver = tf.train.Saver() |
| with tf.Session() as sess: |
| sess.run(tf.global_variables_initializer()) |
| saver.save(sess, '/path/to/model.ckpt') # .ckpt为CheckpointState |
| # TensofFlow会将模型分成图结构与变量数据分别保存, 其中.meta为图结构, 为MetaGraphDef |
- 生成三个文件:
.meta
, .data
, checkpoint
, 注意没有model.ckpt
文件
- 导入模型
- 只导入变量数据, 而不导入图的结构, 这样我们使用模型的时候, 需要先创建好图的结构, 在使用saver导入变量, 这样我们需要时初始化全局变量, 因为变量的是从外部导入过来的
| |
| saver = tf.train.Saver() |
| with tf.Session() as sess: |
| saver.restore(sess, '/path/to/model.ckpt') |
- 导入图并导入数据
| saver = tf.train.import_meta_graph('/path/to/model.ckpt.meta') |
| with tf.Session() as sess: |
| sess.restore(sess, '/path/to/model.ckpt') |
| |
| print(sess.run(tf.get_default_graph().get_tensor_\ |
| by_name('add:0')) |
- 保存为.ckpt格式, 计算图与变量是分开的, 但是有时候, 尤其是在保存预训练模型的模型的时候, 我们希望freeze一些层, 也就是将一些W和b的变量固定住, 这个时候就需要将Variable转为constant, 见下面
模型持久化(.pb)
-
保存模型
| from tensorflow.python.framework import graph_util |
| with tf.Session() as sess: |
| sess.run(init_op) |
| with tf.gile.GFile('/path/to/model.pb', 'wb') as fd: |
| graph_def = tf.get_default_graph().as_graph_def() |
| ouput_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, ['add']) |
| fd.write(output_graph_def.SerializeToString()) |
-
导入模型
| with tf.Session() as sess: |
| with tf.gile.GFile('/path/to/model.pb', 'rb') as fd: |
| graph_def = tf.GraphDef() |
| graph_def.ParseFromString(f.read()) |
| result = tf.import_graph_def(graph_def, return_elements=['add:0']) |
| print(sess.run(result)) |
ckpt(CheckPointState)对象
tf.get_checkpoint_state(dirpath)
: 返回ckpt对象
ckpt.model_checkpoint_path
: ckpt文件路径
Variables
tf.global_variables()
: 返回所有的Variable, 他们存储在tf.GraphKeys.VARIABLES
tf.Variable
: 创建一个变量
tf.get_variable
: 创建一个变量, 与tf.Variable
不同的是一定要指定变量名
- 在命名空间中创建变量, reuse一定要记得到使用上
| |
| |
| |
| |
| with tf.variable_scope('foo', reuse=False): |
| v = tf.get_variable('v', shape=[1, 1], initializer=tf.constants_initializer()) |
- 创建名为空的名称空间(相当于顶级)
| with tf.variable_scope('', result=True): |
| |
| v = tf.get_variable('foo/v', shape=[1, 1]) |
| print(v) |
- 命名空间的应用
- 当神经网络越来越深的时候, W与b等权重与参数会越来越多, 越来越难管理, 所以我们以一层为单位, 创建一个命名空间, 管理里面的变量, 这样在函数传递参数的时候我们也不需要传递这么多的参数, 只要通过名称空间获取即可
常用API
-
tf.group([train, cost])
: 在sess.run([...])
是我们传入一个列表是为了可以同时计算多个op, 我们也可以通过op = tf.group([...])
的方法返回一个op, 这样在sess.run(op)
就可以写少一点了
-
tf.one_hot(labels, C, axis=0)
: 将labels转为维度为C, 在axis=0方向的填充的one_hot
-
tf.reduce_mean(mat, axis=0)
: 计算均值
-
TensorFlow 文件读取
tf.train.string_input_producer(filename_list, shuffle=False, num_epochs=5)
: 将filename_list
中的文件预先记录加来, 将来要放到文件名队列中, 返回文件名队列
tf.WholeFileReader()
: 返回reader对象, 用于读取文件名队列加载文件
tf.FixLengthRecordReader(record_bytes=bytes)
: 返回reader对象, 每次读取定长record_bytes
tf.train.start_queue_runner(sess=sess)
: 与上面的string_input_producer
, WholeFileReader
, FixLengthRecordReader
关系密切, 调用此方法才真正的将文件名队列加载到队列中, tf读取数据才起步
-
tf.examples.tutorials.mnist.input_data.read_data_sets('MNIST_data', one_hot=True)
: input_data
模块调用read_data_sets
函数读取注明的MNIST数据到MNIST_data
中, 如果不存在则从网上下载, 返回一个Datasets对象
- Datasets的属性:
train.images
, train.labels
, validation.images
, validation.labels
, test.images
, test.labels
, 他们都是np.ndarray; next_batch(50)
: 下一个batch(采用mini-batch)
-
tf.gfile
: 类似于os模块, 可以等价替换掉os模块
-
tf.truncated_normal(shape, stddev=0.1)
: 一般用于W的初始化
-
tf.zeros(shape_tuple)
: 类似于np.zeros
-
运算
tf.matmul
, tf.reshape
, tf.add
, tf.equal
队列
tf.FIFOQueue
tf.RandomShuffleQueue
: 每次出队会随机从队列中取出一个元素
tf.train.Coordinator
: 多线程协同
tf.train.QueueRunner
: 启动多线程操作同一个队列
- 配合
tf.train.Cooridator
和tf.train.QueueRunner
图像增强API
tf.random_crop(img, [h, w, c])
: 裁剪图片
tf.image.random_brightness(img, max_delta=60)
: 亮度
tf.image.random_contrast(img, lower=0.2, upper=1.8)
: 对比度
tf.image.random_flip_left_right(img)
: 随机翻转, 50%水平左右翻转, 50%不会
绘制标注框
| |
| with tf.Session() as sess: |
| image = tf.image.convert_image_dtype(tf.image.decode_jpeg(tf.gfile.FastGFile('/path/to/pic.jpeg', 'rb').read()), tf.float32) |
| |
| batched = tf.expand_dims(image, 0) |
| |
| |
| boxes = tf.constant([[[0.5, 0.5, 0.75, 0.75]]]) |
| image_with_box = tf.image.draw_bounding_boxes(batched, boxes) |
| result = sess.run(image_with_box) |
| plt.imshow(result) |
| plt.show() |
| |
| with tf.Session() as sess: |
| image = tf.image.convert_image_dtype(tf.image.decode_jpeg(tf.gfile.FastGFile('/path/to/pic.jpeg', 'rb').read()), tf.float32) |
| |
| batched = tf.expand_dims(image, 0) |
| |
| |
| boxes = tf.constant([[[0.5, 0.5, 0.75, 0.75]]]) |
| |
| bbox_begin, bbox_size, bbox_for_draw = tf.image.sample_distorted_bounding_boxes(tf.shape(image), bounding_boxes=bboxes, min_object_coverted=0.1) |
| image_with_box = tf.image.draw_bounding_boxes(image, bbox_for_draw) |
| result = sess.run(image_with_box) |
| plt.imshow(result) |
| plt.show() |
| |
图像预处理最佳实践
- 使用到的函数
tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox, min_object_covered=0.1)
tf.image.convert_image_dtype
tf.image.resize_images
tf.image.random_flip_left_right
tf.slice
: 从原始图片中裁剪标注框大小
- 代码
| |
| |
| |
| |
| |
| import tensorflow as tf |
| import numpy as np |
| import matplotlib.pyplot as plt |
| |
| |
| def distort_color(image, color_ordering=0): |
| if color_ordering == 0: |
| image = tf.image.random_brightness(image, max_delta=32./255.) |
| image = tf.image.random_saturation(image, lower=0.5, upper=1.5) |
| image = tf.image.random_hue(image, max_delta=0.2) |
| image = tf.image.random_contrast(image, lower=0.5, upper=1.5) |
| elif color_ordering == 1: |
| image = tf.image.random_saturation(image, lower=0.5, upper=1.5) |
| image = tf.image.random_brightness(image, max_delta=32./255.) |
| image = tf.image.random_hue(image, max_delta=0.2) |
| image = tf.image.random_contrast(image, lower=0.5, upper=1.5) |
| |
| return tf.clip_by_value(image, 0.0, 1.0) |
| |
| |
| def preprocess_for_train(image, height, width, bbox): |
| if bbox is None: |
| bbox = tf.contrast([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4]) |
| if image.dtype != tf.float32: |
| image = tf.image.convert_image_dtype(image, dtype=tf.float32) |
| bbox_begin, bbox_size, _ = tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox, min_object_covered=0.1) |
| distorted_image = tf.slice(image, bbox_begin, bbox_size) |
| distorted_image = tf.image.resize_images(distorted_image, [height, width], method=np.random.randint(4)) |
| distorted_image = tf.image.random_flip_left_right(distorted_image) |
| distorted_image = distort_color(distorted_image, np.random.randint(1)) |
| return distorted_image |
| |
| |
| def main(): |
| with tf.Session() as sess: |
| sess.run(tf.global_variables_initializer()) |
| image_raw_data = tf.gfile.FastGFile('./15.jpg', 'rb').read() |
| img_data = tf.image.decode_jpeg(image_raw_data) |
| boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]]) |
| |
| for i in range(6): |
| result = preprocess_for_train(img_data, 299, 299, boxes) |
| plt.imshow(sess.run(result)) |
| plt.show() |
| |
| |
| if __name__ == '__main__': |
| main() |
| |
TensorBoard
tensorboard --logdir dir/ --port 6006
: 启动tensorboard
MNIST识别
BP神经网络最佳实践
- mnist_inference.py: 提供前向传播
| |
| import os |
| import sys |
| import time |
| import tensorflow as tf |
| from tensorflow.python.framework import graph_util |
| from tensorflow.examples.tutorials.mnist import input_data |
| |
| |
| INPUT_NODES = 784 |
| OUTPUT_NODES = 10 |
| LAYER1_NODES = 50 |
| BATCH_SIZE = 100 |
| LEARNING_RATE = 0.001 |
| REGULARIZATION_RATE = 0.0001 |
| TRAINING_STEP = 30000 |
| |
| |
| def get_weight_variable(shape, regularize): |
| weights = tf.get_variable('weights', shape=shape, \ |
| initializer=tf.truncated_normal_initializer(stddev=0.1, seed=1)) |
| if regularize: |
| tf.add_to_collection('losses', regularize(weights)) |
| return weights |
| |
| |
| def inference(input_tensor, regularize): |
| with tf.variable_scope('layer1', reuse=False): |
| weights = get_weight_variable([INPUT_NODES, LAYER1_NODES], regularize) |
| biases = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODES]), name='biases') |
| layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases) |
| with tf.variable_scope('layer2', reuse=False): |
| weights = get_weight_variable([LAYER1_NODES, OUTPUT_NODES], regularize) |
| biases = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODES]), name='biases') |
| layer2 = tf.matmul(layer1, weights) + biases |
| return layer2 |
- mnist_train.py: 训练网络, 保存模型
| |
| import os |
| import sys |
| import time |
| import tensorflow as tf |
| from tensorflow.python.framework import graph_util |
| from tensorflow.examples.tutorials.mnist import input_data |
| import mnist_inference |
| |
| |
| def train(mnist): |
| X = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODES], name='X') |
| Y = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODES], name='Y') |
| global_step = tf.Variable(0, trainable=False) |
| regularize = tf.contrib.layers.l2_regularizer(0.001) |
| Z2 = mnist_inference.inference(X, regularize) |
| cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=Z2)) \ |
| + tf.add_n(tf.get_collection('losses')) |
| optimizer = tf.train.AdamOptimizer(mnist_inference.LEARNING_RATE).minimize(cost, global_step=global_step) |
| prediction = tf.equal(tf.argmax(Y, 1), tf.argmax(Z2, 1)) |
| accuracy = tf.reduce_mean(tf.cast(prediction, tf.float32)) |
| init_op = tf.global_variables_initializer() |
| saver = tf.train.Saver() |
| with tf.Session() as sess: |
| sess.run(init_op) |
| for i in range(30000): |
| batch = mnist.train.next_batch(mnist_inference.BATCH_SIZE) |
| _, accuracy_score, step = sess.run([optimizer, accuracy, global_step], feed_dict={X:batch[0], Y:batch[1]}) |
| if i % 1000 == 0: |
| print('After %s step(s), accuracy is %g' % (step, accuracy_score)) |
| saver.save(sess, 'models/model.ckpt', global_step=global_step) |
| |
| |
| def main(argv=None): |
| mnist = input_data.read_data_sets('mnist/', one_hot=True) |
| train(mnist) |
| |
| |
| if __name__ == '__main__': |
| tf.app.run() |
| |
- mnist_eval.py: 加载模型, 测试训练的网络
| |
| |
| |
| |
| import os |
| import sys |
| import time |
| import numpy as np |
| import tensorflow as tf |
| from tensorflow.python.framework import graph_util |
| from tensorflow.examples.tutorials.mnist import input_data |
| import mnist_inference |
| import mnist_train |
| |
| |
| def eval(mnist): |
| X = tf.placeholder(tf.float32, shape=[None, mnist_inference.INPUT_NODES], name='X') |
| Y = tf.placeholder(tf.float32, shape=[None, mnist_inference.OUTPUT_NODES], name='Y') |
| Z2 = mnist_inference.inference(X, None) |
| prediction = tf.equal(tf.argmax(Y, 1), tf.argmax(Z2, 1)) |
| accuracy = tf.reduce_mean(tf.cast(prediction, tf.float32)) |
| validate_feed = {X:mnist.validation.images, Y:mnist.validation.labels} |
| saver = tf.train.Saver() |
| while True: |
| with tf.Session() as sess: |
| ckpt = tf.train.get_checkpoint_state('models/') |
| if ckpt and ckpt.model_checkpoint_path: |
| saver.restore(sess, ckpt.model_checkpoint_path) |
| global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1] |
| accuracy_score = sess.run(accuracy, feed_dict=validate_feed) |
| print('After %s training step(s), validation accuracy = %g' % (global_step, accuracy_score)) |
| else: |
| print('Checkpoint File Is Not Found') |
| time.sleep(10) |
| |
| def main(argv=None): |
| mnist = input_data.read_data_sets('mnist/', one_hot=True) |
| eval(mnist) |
| |
| |
| if __name__ == '__main__': |
| tf.app.run() |
| |
LeNet实现手写数字识别
- Conv->ReLU --> Conv->ReLU --> FC->FC
- CNN中使用范式
- Filter的大小一般不会超过5x5, 一般在1x1, 3x3, 5x5, 但是也有些模型有7x7和11x11; Filter的stride一般为[1, 1, 1, 1]; Filter的个数一般从32开始, 接着逐渐翻倍
- MaxPool的大小一般为[1, 2, 2, 1]和[1, 3, 3, 1], strides一般为[1, 2, 2, 1]和[1, 3, 3, 1], 这样做保证了每次都是将图像的宽与高缩小到原来的一半
- Conv层连续最多3层, VGG就是这样的; Pool则一般可有可无, 但是大部分的网络模型都有
- 在原始的输入图像矩阵中, 维度为
[batch_size, h, w, c]
, 但是我们的filter为[h, w, c, num_of_fitlers]
- 从pool得到的矩阵, 它的维度为
[size, h, w, c]
, 因此如果接下来为FC, 则我们需要他变为[node, h * w * c]
指定设备运行
- 在TensorFlow中CPU的设备名都为
/cpu:0
- 使用
with tf.device('/gpu:0'):
的语法, 在上下面管理器中定义OpNode和变量, 但是在Tensorflow不同版本中GPU处理的数据类型不同, 有些版本无法处理float64类型的, 如果人为强制的指定则会报错, 不能把代码写死, 所以这里在sess.run
时要指定一个关键字参数, sess.run(optimizer, allow_soft_placement=True)
, 这样当GPU无法处理时自动使用CPU处理
- 一般将计算密集型放到GPU上处理, 其他操作放在CPU上, 一般将神经网络运算放到GPU上, 将神经网络的优化跑在不同的GPU上, 将简单的运算, 如precition放到CPU上运算
导入模型的实际应用
注意
- cv2.resize与np.resize不要混合时候, 如果是使用cv2.imread读取的图片, 所有的操作都要为cv2的
- 读取tfrecords和写入tfrecord
- 如果要听过tfrecords来制作和读取数据, 应该要保证每一步都执行数据的类型, 在读取tfrecords的时候解码的类型要完全一致, 否则会报错, 差不多会显示(Has insuffcient elements的错误), 因为数据出现了问题
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法