tensorflow 1.4学习

 tensorflow已经更新到2.0版本了,大多数公司还在用1.4的版本,去过了一遍网上tensorflow1.4的教程,记录下。1.4版本的官网教程貌似已下架,主要是api参考:https://github.com/tensorflow/docs/tree/r1.14/site/en/api_docs/python

   Tensorflow数据的核心单位是张量 (tensor),就像numpy中的array一样。Tensorflow中还有一个核心知识点就是计算图(computation graph),  tensorflow的大多数程序都可以认为包含两部分:

  1. 构建计算图

  2. 执行计算图

1. 计算图

  tensorflow的代码中,有一个默认图概念(default graph),当我们开始一个线程时,tensorflow就会为我们创造一张默认图,在线程中进行的操作(加减乘除),定义的变量和常量,都会被加入到这张默认图中,成为默认图的节点,这个默认图就是常说的计算图,是为了记录各给节点之前的关系,方便tensorflow进行前向的计算和反向的梯度计算。当我们构建完计算图后,需要运行这张图,才能执行图上的操作(即我们定义的加减乘除, 变量赋值等)。如下代码所示:

默认图理解:

import tensorflow as tf
import numpy as np
# tensorflow 创建了一张默认图
# print(tf.get_default_graph())  # 可以获取默认图对象


# 1. 下面的两个matrix常量,和一个矩阵成分操作,会被加入到默认图中
matrix1 = tf.ones(shape=(2, 2), dtype=np.float32)  # 构建一个tensor,值全为1
matrix2 = tf.constant([[1, 2], [3, 4]], dtype=tf.dtypes.float32) # 构建一个常量tensor, 值为[1, 2], [3, 4]
product = tf.matmul(matrix1, matrix2)
# 默认图现在有三个节点, 两个 constant() op, 和一个matmul() op.

# 显示shape,dyupe,没有具体的值
print(matrix1)
print(matrix2)
print(product)


# 2. 创建一个会话session,在session中,可以运行默认图
ses = tf.Session()   # 有一个参数graph, 可以传入需要计算的图,不传参数时,表示默认图


# 3. 在session中计算默认图中的操作
# 调用 sess 的 'run()' 方法来执行矩阵乘法 op, 传入 'product' 作为该方法的参数.
# 'product' 代表了矩阵乘法 op 的输出, 传入它是向方法表明, 我们希望取回矩阵乘法 op 的输出.
# 整个执行过程是自动化的, 会话负责传递 op 所需的全部输入. op 通常是并发执行的.
# 函数调用 'run(product)' 触发了图中三个 op (两个常量 op 和一个矩阵乘法 op) 的执行.
result = ses.run(product)  # 计算product的值,并返回, 注意返回值 'result' 是一个 numpy `ndarray` 对象.

# tensor, 只显示shape,dyupe,没有具体的值
print(matrix1)
print(matrix2)
print(product)

# np.array, 有具体的值
print(result, type(result))


# 4. 关闭session
ses.close()  # 关闭会话

'''
session对象在使用完后需要关闭以释放资源. 除了显式调用 close 外, 也可以使用 “with” 代码块来自动完成关闭动作.

with tf.Session() as sess:
  result = sess.run([product])
  print (result)
'''

 

2.计算图获取数据和输入数据

  上面已经了解到了,可以从计算图中获取计算得到的数据,可以一次性计算和获取多个数据,如下代码中同时获取计算图中两个节点的值:

import tensorflow as tf

matrix1 = tf.constant([[1, 1], [2, 2]])
value1 = tf.constant(3)
value2 = tf.constant(4)

inter_value = tf.add(matrix1, value1)
product = tf.multiply(inter_value, value2)

with tf.Session() as sess:
    result = sess.run([inter_value, product])  #需要获取的多个 tensor 值,在 op 的一次运行中一起获得(而不是逐个去获取 tensor)

  print(result, type(result))  # 输出为两个np.array组成的list; 注意:若run输入的为list,返回结果则为list,

  print(sess.run(product)) # [product]:返回结果则为list; product:返回结果为单个array

上面计算图中,输入的数据都是固定值,我们可以采用占位符来代替这些数据,构建完计算图后,可以通过向计算图中输入数据,从而实习动态数据,如下代码所示:

import tensorflow as tf
import numpy as np

x_value = tf.random.normal((2, 3), 0, 1)
y_value = tf.random.uniform((2, 1), 0, 2)

x = tf.placeholder(dtype=np.float32, shape=(2, 3))
y = tf.placeholder(dtype=np.float32, shape=(2, 1))

weight = tf.constant([[1, 1.5, 0.5]])
bias = tf.constant(0.5)
loss = tf.matmul(x, tf.transpose(weight)) + bias - y

with tf.Session() as sess:
    # 1. 输入数据为np.array类型
    result = sess.run([loss], feed_dict={x: np.array([[1, 2, 3], [4, 5, 6]]),
                                         y: np.array([[1], [2]])})  #np.array数据
    print(result, type(result))

    # 2. 输入数据为list
    result = sess.run([loss], feed_dict={x: [[1, 2, 3], [4, 5, 6]],
                                         y: [[1], [2]]})  # 自动转化为np.array
    print(result, type(result))
    
    # 3. 输入数据为np.array
    result = sess.run([loss], feed_dict={x: sess.run(x_value),
                                         y: sess.run(y_value)})  # 随机数据
    print(result, type(result))

 

3. 变量数据

  上述数据中涉及到了常量constant,占位符placeholder, tensorflow中还有一种数据:变量Variable。tf.Variable表示的数据,其值时可以更改的,一般用来存储网络的参数,变量在进行计算前,必须进行初始化,下面代码展示了变量和常量的区别:

import tensorflow as tf
import numpy as np

constant_value = tf.constant([2, 3])
variable_value = tf.Variable(initial_value=[1, 2], name="x")  # 设置初始化值为【1, 2】
init = tf.global_variables_initializer()

result = variable_value.assign_add(constant_value)

with tf.Session() as sess:
    # 1. 必须先初始化全部全局变量, 否则会报错:Attempting to use uninitialized value x
    sess.run(init)      
    print(sess.run(variable_value))
    print(sess.run(constant_value))
    
    # 2.相加,并更新变量的值
    print(sess.run(result))
    print(sess.run(variable_value))  #变量的值可以更新 
    print(sess.run(constant_value)) # 常量的值保持不变

 

4.计算图可视化

  tensorfboard能用来绘制和可视化tensorflow中的计算图,安装tensorflow的过程中应该会自动安装tensorboard。(也可以直接安装:pip install tensorbaord)

  使用tensorboard可视化计算图包括两步:

    1. 在代码中将计算图绘制到文件中

    2. 在命令中使用tensorboard指向绘制的文件,示例命令如:tensorboard --logdir="./logs"。  随后在浏览器打开指定的网址即可,一般是http://localhost:6006/

   下面打代码中,实现了一个简单的线性模型,并绘制了其计算图,如下所示:

import tensorflow as tf
# import tensorflow.compat.v1 as tf

w = tf.Variable([0.3], dtype=tf.float32)
b = tf.Variable([-0.3], dtype=tf.float32)
x = tf.placeholder(dtype=tf.float32)
y = tf.placeholder(dtype=tf.float32)
linear_model = w*x+b
square_deltas = tf.square(linear_model-y)
loss = tf.reduce_sum(square_deltas)

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)  # 初始权重值
    print("初始loss:", sess.run(loss, feed_dict={x: [1,  2,  3,  4], y: [0,  -1,  -2,  -3]}))

    fix_w = tf.assign(w, [-1])
    fix_b = tf.assign(b, [1])
    sess.run([fix_w, fix_b])  # 更新权重值
    print("更新权重后loss: ", sess.run(loss, feed_dict={x: [1,  2,  3,  4], y: [0,  -1,  -2,  -3]}))

    tf.summary.FileWriter("./logs", sess.graph)  # 在tensorboard中绘制计算图

对应的计算图:

 5.  tf.train 相关API

  了解上述知识点后,可以开始搭建简单的网络,并进行训练。tf.train提供了关于优化器相关的函数,可以实现梯度梯度下降和参数更新。

   常用优化器:

  

  常用损失函数:

  • tf.nn

  在tensorflow原生库中,只有最常见的几种loss函数。

    [公式]

上面是softmax交叉熵loss,参数为网络最后一层的输出和onehot形式的标签。切记输入一定不要经过softmax,因为在函数中内置了softmax操作,如果再做就是重复使用了。在计算loss的时候,输出Tensor要加上tf.reduce_mean(Tensor)或者tf.reduce_sum(Tensor),作为tensorflow优化器(optimizer)的输入。

 

    [公式]

这个函数和上面的区别就是labels参数应该是没有经过onehot的标签,其余的都是一样的。另外加了sparse的loss还有一个特性就是标签可以出现-1,如果标签是-1代表这个数据不再进行梯度回传。

 

    [公式]

sigmoid交叉熵loss,与softmax不同的是,该函数首先进行sigmoid操作之后计算交叉熵的损失函数,其余的特性与 [公式] 一致。

    

    [公式]

这个loss与众不同的地方就是加入了一个权重的系数,其余的地方与 [公式] 这个损失函数是一致的,加入的pos_weight函数可以适当的增大或者缩小正样本的loss,可以一定程度上解决正负样本数量差距过大的问题。

  • tf.keras

    [公式] 中是全部的loss函数库,但是也只是非常普通有限的函数。

   

下面代码中采用tensorflow实现了一个多层感知机,并对minist数据集进行分类:(minist数据集:手写数字灰度图片)

import tensorflow as tf
from keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
# print(x_train.shape, y_train.shape, x_test.shape)


nClass = tf.placeholder(tf.int32)
x = tf.placeholder(tf.float32, shape=[None, 784])
y = tf.placeholder(tf.int32, shape=[None])
y_hot = tf.one_hot(indices=y, depth=nClass, on_value=1.0, off_value=0.0, axis=-1)

# 网络层
w1 = tf.Variable(initial_value=tf.random_normal(shape=[784, 100], stddev=0.1), name="weight1")
b1 = tf.Variable(initial_value=tf.constant(0.1, shape=(1, 100)), name="bias1")
h1 = tf.nn.relu(tf.matmul(x, w1)+b1)

w2 = tf.Variable(initial_value=tf.random_normal(shape=[100, 20], stddev=0.1), name="weight2")
b2 = tf.Variable(initial_value=tf.constant(0.1, shape=(1, 20)), name="bias2")
h2 = tf.nn.relu(tf.matmul(h1, w2)+b2)

w3 = tf.Variable(initial_value=tf.random_normal(shape=[20, 10], stddev=0.1), name="weight2")
b3 = tf.Variable(initial_value=tf.constant(0.1, shape=(1, 10)), name="bias2")
h3 = tf.matmul(h2, w3)+b3

cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_hot, logits=h3))
# train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)   # 梯度下降法,学习率为0.01
train_step = tf.train.AdamOptimizer(0.0001).minimize(cross_entropy)   # 梯度下降法,学习率为0.01


# 测试
prediction = tf.equal(tf.argmax(h3, axis=1), tf.argmax(y_hot, axis=1))
accuracy = tf.reduce_mean(tf.cast(prediction, dtype=tf.float32))

with tf.Session() as sess:
    epochs = 300
    batch_size = 8
    n = x_train.shape[0]
    # n = 10000
    sess.run(tf.global_variables_initializer())

    for epoch in range(epochs):
        epoch_loss = 0.0
        iter_count = 0
        for i in range(0, n, batch_size):
            j = min(i + batch_size, n)
            batch_data = x_train[i:j, :, :].reshape(-1, 28 * 28)
            batch_label = y_train[i:j]
            _, loss = sess.run([train_step, cross_entropy], feed_dict={x: batch_data, y: batch_label, nClass: 10})
            # if epoch % 40 == 0:
            #     train_accuracy = accuracy.eval(feed_dict={
            #         x: batch_data, y: batch_label, nClass: 10})
            #     print('step %d, training accuracy %g' % (i, train_accuracy))
            epoch_loss += loss
            iter_count += 1

        print("[Epoch {}/{}], train loss: {}".format(epoch, epochs, epoch_loss/iter_count))



    # 测试:
    acc = 0
    iter_count = 0
    n = x_test.shape[0]
    for i in range(0, n, batch_size):
        j = min(i + batch_size, n)
        batch_data = x_test[i:j, :, :].reshape(-1, 28 * 28)
        batch_label = y_test[i:j]
        acc += sess.run(accuracy, feed_dict={x:batch_data, y:batch_label, nClass:10})
        iter_count += 1

    print('Test accuracy {:.4f}%'.format(100*acc/iter_count))    # Test accuracy 92.3077%
minist数据分类

 

 6. 正则化损失

  一般为了防止过拟合,会采用L2正则化,tensorflow中的L2正则化使用起来有点特别。

 

  

  下面代码中实现了cifar10数据集的分类,并采用了tf.nn.l2_loss来实现网络参数的L2正则化,限制网络规模,从而达到抑制过拟合的目的:

import tensorflow as tf
# import tensorflow.compat.v1 as tf
import Cifar10_data
import time
import math
import numpy as np

# 创建一个variable_with_weight_loss()函数,该函数的作用是:
#   1.使用参数w1控制L2 loss的大小
#   2.使用函数tf.nn.l2_loss()计算权重L2 loss
#   3.使用函数tf.multiply()计算权重L2 loss与w1的乘积,并赋值给weights_loss
#   4.使用函数tf.add_to_collection()将最终的结果放在名为losses的集合里面,方便后面计算神经网络的总体loss,
def variable_with_weight_loss(shape, stddev, w):
    var = tf.Variable(tf.truncated_normal(shape=shape, stddev=0.1))   # 截断的正态分布,超过两倍标准偏差的被舍弃掉
    if w is not None:
        weight_loss = tf.multiply(tf.nn.l2_loss(var), w, name="weight_loss")
        tf.add_to_collection("losses", weight_loss)
    return var


def conv2d(x, w, strides):
    return tf.nn.conv2d(x, w, strides, padding='SAME')
    #图片X:shape(batch,h,w,channel); 卷积核w:(h,w,in_channel, out_channel); strides:[1, stride, stride, 1];
    # padding: 'SAME'考虑边界,填充0,'VALID'不填充边界


# 1. 参数设置
batch_size = 32
cifar_data_dir = r"./cifar_data/cifar-10-batches-bin"  # 二进制文件格式存放
num_examples_for_eval = 10000   # 10000张测试图片
num_examples_for_train = 50000  # 50000 张训练图片;   (一个epoch训练:50000/8 个batch)
max_steps =  int(math.ceil(num_examples_for_train)/batch_size)*300   # 训练300个epoch


# 2. 数据加载
# from keras.datasets import cifar10
# (x_train, y_train), (x_test, y_test) = cifar10.load_data()
images_train, labels_train = Cifar10_data.inputs(data_dir=cifar_data_dir, batch_size=batch_size, distorted=True)
images_test, labels_test = Cifar10_data.inputs(data_dir=cifar_data_dir, batch_size=batch_size, distorted=None)
print(images_train.shape, labels_train.shape, images_test.shape, labels_test.shape)


# 3. 网络搭建
x = tf.placeholder(dtype=tf.float32, shape=[batch_size, 24, 24, 3])  # cifar10: 32*32*3, 前处理crop到24*24*3
y_ = tf.placeholder(dtype=tf.int32, shape=[batch_size])

# 卷积层1
w_conv1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=5e-2, w=0)  # 卷积核输入channel是3,输出channel是64
b_conv1 = tf.Variable(tf.constant(0.0, shape=[64]))  # 初始化为0
h_conv1 = tf.nn.relu(conv2d(x, w_conv1, strides=[1, 1, 1, 1])+b_conv1)
h_pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')

# 卷积层2
w_conv2 = variable_with_weight_loss([5,5,64,64], stddev=5e-2, w=0)
b_conv2 = tf.Variable(tf.constant(0.1, shape=[64]))
h_conv2 = tf.nn.relu(conv2d(h_pool1, w_conv2, strides=[1, 1, 1, 1])+b_conv2)
h_pool2 = tf.nn.max_pool(h_conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')

# reshape
x_flat = tf.reshape(h_pool2, shape=[batch_size, -1])  # h_pool2:shape(7,7,64),需要reshape,方便全连接
dim = x_flat.get_shape()[1].value

# 全连接层1
w_fc1 = variable_with_weight_loss([dim, 384], stddev=0.04, w=0.004)
b_fc1 = tf.Variable(tf.constant(0.1, shape=[384]))
h_fc1 = tf.nn.relu(tf.matmul(x_flat, w_fc1) + b_fc1)

# 全连接层2
w_fc2 = variable_with_weight_loss([384, 192], stddev=0.04, w=0.004)
b_fc2 = tf.Variable(tf.constant(0.1, shape=[192]))
h_fc2 = tf.nn.relu(tf.matmul(h_fc1, w_fc2) + b_fc2)

# dropout
keep_prob = tf.placeholder(tf.float32)  # train是设置丢弃概率;eval时可以设置为1
h_fc2_drop = tf.nn.dropout(h_fc2, keep_prob)

# 全连接层3,预测输出
w_fc3 = variable_with_weight_loss([192, 10], stddev=1 / 192.0, w=0.0)
b_fc3 = tf.Variable(tf.constant(0.1, shape=[10]))
y_output = tf.add(tf.matmul(h_fc2_drop, w_fc3), b_fc3)

# 损失函数
#loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_logits(labels=y_, logits=y_output))
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.cast(y_,tf.int64), logits=y_output)
weights_with_l2_loss = tf.add_n(tf.get_collection("losses"))
loss = tf.reduce_mean(cross_entropy) + weights_with_l2_loss

# 训练优化器
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)


# 测试
top_k_op = tf.nn.in_top_k(y_output, y_, 1)  # 计算输出结果中top k的准确率,函数默认的k值是1,即top 1的准确率,也就是输出分类准确率最高时的数值
# correct_prediction = tf.equal(tf.argmax(y_output, 1), tf.argmax(y_, 1))
# accuracy = tf.reduce_mean(tf.cast(correct_prediction, dtype=tf.float32))  # cast数据转换

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())  # 初始化定义的变量
    # 启动线程操作,这是因为之前数据增强的时候使用train.shuffle_batch()函数的时候通过参数num_threads()配置了16个线程用于组织batch的操作
    tf.train.start_queue_runners()

    for step in range(max_steps):
            t1 = time.time()
            image_batch, label_batch = sess.run([images_train, labels_train])   #返回一个batch的数据
            # print(step, image_batch.shape, label_batch)
            loss_value, _ = sess.run([loss, train_step], feed_dict={x: image_batch, y_: label_batch, keep_prob: 0.5})
            duration = time.time() - t1
            if step % 100 == 0:
                # train_accuracy = accuracy.eval(feed_dict={
                #     x: image_batch, y_: label_batch, keep_prob: 1.0})
                print("[Step {}/{}] loss={:.4f}, {:.1f} images/sec, {} sec/batch".format(
                    step, max_steps, loss_value, batch_size/duration, duration))

    # 测试阶段
    num_batch = int(math.ceil(num_examples_for_eval/batch_size))  # 有多少个batch
    true_count = 0
    total_sample_count=num_batch * batch_size   # 若最后一个batch,图片不够一个batch_size时,注意是如何处理的?
    for i in range(num_batch):
        image_batch, label_batch = sess.run([images_test, labels_test])
        predictions = sess.run([top_k_op], feed_dict={x: image_batch, y_: label_batch, keep_prob: 1})
        true_count += np.sum(predictions)
    print("Test accuracy: {:.4f}%".format(100*true_count/total_sample_count))
cifar10数据集分类模型
# 该文件负责读取Cifar-10数据并对其进行数据增强预处理
import os
import tensorflow as tf

num_classes = 10

# 设定用于训练和评估的样本总数
num_examples_pre_epoch_for_train = 50000
num_examples_pre_epoch_for_eval = 10000


# 定义一个空类,用于返回读取的Cifar-10的数据
class CIFAR10Record(object):
    pass


# 定义一个读取Cifar-10的函数read_cifar10(),这个函数的目的就是读取目标文件里面的内容
def read_cifar10(file_queue):
    result = CIFAR10Record()

    label_bytes = 1  # 如果是Cifar-100数据集,则此处为2
    result.height = 32
    result.width = 32
    result.depth = 3  # 因为是RGB三通道,所以深度是3

    image_bytes = result.height * result.width * result.depth  # 图片样本总元素数量
    record_bytes = label_bytes + image_bytes  # 因为每一个样本包含图片和标签,所以最终的元素数量还需要图片样本数量加上一个标签值

    reader = tf.FixedLengthRecordReader(
        record_bytes=record_bytes)  # 使用tf.FixedLengthRecordReader()创建一个文件读取类。该类的目的就是读取文件
    result.key, value = reader.read(file_queue)  # 使用该类的read()函数从文件队列里面读取文件

    record_bytes = tf.decode_raw(value, tf.uint8)  # 读取到文件以后,将读取到的文件内容从字符串形式解析为图像对应的像素数组

    # 因为该数组第一个元素是标签,所以我们使用strided_slice()函数将标签提取出来,并且使用tf.cast()函数将这一个标签转换成int32的数值形式
    result.label = tf.cast(tf.strided_slice(record_bytes, [0], [label_bytes]), tf.int32)

    # 剩下的元素再分割出来,这些就是图片数据,因为这些数据在数据集里面存储的形式是depth * height * width,我们要把这种格式转换成[depth,height,width]
    # 这一步是将一维数据转换成3维数据
    depth_major = tf.reshape(tf.strided_slice(record_bytes, [label_bytes], [label_bytes + image_bytes]),
                             [result.depth, result.height, result.width])

    # 我们要将之前分割好的图片数据使用tf.transpose()函数转换成为高度信息、宽度信息、深度信息这样的顺序
    # 这一步是转换数据排布方式,变为(h,w,c)
    result.uint8image = tf.transpose(depth_major, [1, 2, 0])

    return result  # 返回值是已经把目标文件里面的信息都读取出来


def inputs(data_dir, batch_size, distorted):  # 这个函数就对数据进行预处理---对图像数据是否进行增强进行判断,并作出相应的操作
    filenames = [os.path.join(data_dir, "data_batch_%d.bin" % i) for i in range(1, 6)]  # 拼接地址

    file_queue = tf.train.string_input_producer(filenames)  # 根据已经有的文件地址创建一个文件队列
    read_input = read_cifar10(file_queue)  # 根据已经有的文件队列使用已经定义好的文件读取函数read_cifar10()读取队列中的文件

    reshaped_image = tf.cast(read_input.uint8image, tf.float32)  # 将已经转换好的图片数据再次转换为float32的形式

    num_examples_per_epoch = num_examples_pre_epoch_for_train

    if distorted != None:  # 如果预处理函数中的distorted参数不为空值,就代表要进行图片增强处理
        cropped_image = tf.random_crop(reshaped_image, [24, 24, 3])  # 首先将预处理好的图片进行剪切,使用tf.random_crop()函数

        flipped_image = tf.image.random_flip_left_right(
            cropped_image)  # 将剪切好的图片进行左右翻转,使用tf.image.random_flip_left_right()函数

        adjusted_brightness = tf.image.random_brightness(flipped_image,
                                                         max_delta=0.8)  # 将左右翻转好的图片进行随机亮度调整,使用tf.image.random_brightness()函数

        adjusted_contrast = tf.image.random_contrast(adjusted_brightness, lower=0.2,
                                                     upper=1.8)  # 将亮度调整好的图片进行随机对比度调整,使用tf.image.random_contrast()函数

        float_image = tf.image.per_image_standardization(
            adjusted_contrast)  # 进行标准化图片操作,tf.image.per_image_standardization()函数是对每一个像素减去平均值并除以像素方差

        float_image.set_shape([24, 24, 3])  # 设置图片数据及标签的形状
        read_input.label.set_shape([1])

        min_queue_examples = int(num_examples_pre_epoch_for_eval * 0.4)
        print("Filling queue with %d CIFAR images before starting to train.    This will take a few minutes."
              % min_queue_examples)

        images_train, labels_train = tf.train.shuffle_batch([float_image, read_input.label], batch_size=batch_size,
                                                            num_threads=4,
                                                            capacity=min_queue_examples + 3 * batch_size,
                                                            min_after_dequeue=min_queue_examples,
                                                            )
        # 使用tf.train.shuffle_batch()函数随机产生一个batch的image和label

        return images_train, tf.reshape(labels_train, [batch_size])

    else:  # 不对图像数据进行数据增强处理
        resized_image = tf.image.resize_image_with_crop_or_pad(reshaped_image, 24,
                                                               24)  # 在这种情况下,使用函数tf.image.resize_image_with_crop_or_pad()对图片数据进行剪切

        float_image = tf.image.per_image_standardization(resized_image)  # 剪切完成以后,直接进行图片标准化操作

        float_image.set_shape([24, 24, 3])
        read_input.label.set_shape([1])

        min_queue_examples = int(num_examples_per_epoch * 0.4)

        images_test, labels_test = tf.train.batch([float_image, read_input.label],
                                                  batch_size=batch_size, num_threads=4,
                                                  capacity=min_queue_examples + 3 * batch_size)
        # 这里使用batch()函数代替tf.train.shuffle_batch()函数
        return images_test, tf.reshape(labels_test, [batch_size])
Cifar10_data

 

 

7. 数据集加载

  tensorflow中tf.data.Dataset 和tf.train.slice_input_producer都提供了数据集的批量加载方式。

 1. tf.train.slice_input_producer

  如果我们的数据保存在txt文件中,txt文件格式如下, 即每一行是图片路径和label

 

 

   则加载图片的dataloder,数据加载代码如下:

def read_images(dataset_path, batch_size, transform=False):
    # 1. slice_input_producer构建一个任务队列
    imagepaths, labels = list(), list()

    with open(dataset_path) as f:
        data = f.read().splitlines()
    for d in data:
        imagepaths.append(d.split(' ')[0])
        labels.append(int(d.split(' ')[1]))

    # Convert to Tensor
    imagepaths = tf.convert_to_tensor(imagepaths, dtype=tf.string)
    labels = tf.convert_to_tensor(labels, dtype=tf.int32)
    # Build a TF Queue, shuffle data
    image, label = tf.train.slice_input_producer([imagepaths, labels],
                                                 shuffle=True)
    # 2. 对图片和lable可以进行预处理
    # Read images from disk
    image = tf.read_file(image)
    image = tf.image.decode_jpeg(image, channels=CHANNELS)

    if transform:  # 是否要进行图片增强处理
        cropped_image = tf.random_crop(image, [24, 24, 3])  # 首先将预处理好的图片进行剪切,使用tf.random_crop()函数

        flipped_image = tf.image.random_flip_left_right(
            cropped_image)  # 将剪切好的图片进行左右翻转,使用tf.image.random_flip_left_right()函数

        adjusted_brightness = tf.image.random_brightness(flipped_image,
                                                         max_delta=0.8)  # 将左右翻转好的图片进行随机亮度调整,使用tf.image.random_brightness()函数

        adjusted_contrast = tf.image.random_contrast(adjusted_brightness, lower=0.2,
                                                     upper=1.8)  # 将亮度调整好的图片进行随机对比度调整,使用tf.image.random_contrast()函数

        float_image = tf.image.per_image_standardization(
            adjusted_contrast)  # 进行标准化图片操作,tf.image.per_image_standardization()函数是对每一个像素减去平均值并除以像素方差

        image = float_image
        image.set_shape([24, 24, 3])  # 设置图片数据及标签的形状
        label.set_shape([1])

    # Resize images to a common size
    image = tf.image.resize_images(image, [IMG_HEIGHT, IMG_WIDTH])

    # Normalize
    image = image * 1.0 / 127.5 - 1.0

    # 3. 创建一个batch生成器
    # Create batches
    X, Y = tf.train.batch([image, label], batch_size=batch_size,
                          capacity=batch_size * 8,   # 任务队列的大小
                          num_threads=4)  # 四个线程进行数据加载

    # X,Y = tf.train.shuffle_batch([image, label], batch_size=batch_size,
    #                                                     num_threads=4,
    #                                                     capacity=min_queue_examples + 3 * batch_size,
    #                                                     min_after_dequeue=min_queue_examples,
    #                                                     )

    return X, Y
image加载代码

  图片加载和整个训练代码如下,使用tf.train.slice_input_producer()产生队列后,注意在训练时得通过tf.train.start_queue_runners()开始队列

import tensorflow as tf
import os

# Dataset Parameters - CHANGE HERE
MODE = 'folder' # or 'file', if you choose a plain text file (see above).
DATASET_PATH = '/path/to/dataset/' # the dataset file or root folder path.

# Image Parameters
N_CLASSES = 2 # CHANGE HERE, total number of classes
IMG_HEIGHT = 64 # CHANGE HERE, the image height to be resized to
IMG_WIDTH = 64 # CHANGE HERE, the image width to be resized to
CHANNELS = 3 # The 3 color channels, change to 1 if grayscale


def read_images(dataset_path, batch_size, transform=False):
    # 1. slice_input_producer构建一个任务队列
    imagepaths, labels = list(), list()

    with open(dataset_path) as f:
        data = f.read().splitlines()
    for d in data:
        imagepaths.append(d.split(' ')[0])
        labels.append(int(d.split(' ')[1]))

    # Convert to Tensor
    imagepaths = tf.convert_to_tensor(imagepaths, dtype=tf.string)
    labels = tf.convert_to_tensor(labels, dtype=tf.int32)
    # Build a TF Queue, shuffle data
    image, label = tf.train.slice_input_producer([imagepaths, labels],
                                                 shuffle=True)
    # 2. 对图片和lable可以进行预处理
    # Read images from disk
    image = tf.read_file(image)
    image = tf.image.decode_jpeg(image, channels=CHANNELS)

    if transform:  # 是否要进行图片增强处理
        cropped_image = tf.random_crop(image, [24, 24, 3])  # 首先将预处理好的图片进行剪切,使用tf.random_crop()函数

        flipped_image = tf.image.random_flip_left_right(
            cropped_image)  # 将剪切好的图片进行左右翻转,使用tf.image.random_flip_left_right()函数

        adjusted_brightness = tf.image.random_brightness(flipped_image,
                                                         max_delta=0.8)  # 将左右翻转好的图片进行随机亮度调整,使用tf.image.random_brightness()函数

        adjusted_contrast = tf.image.random_contrast(adjusted_brightness, lower=0.2,
                                                     upper=1.8)  # 将亮度调整好的图片进行随机对比度调整,使用tf.image.random_contrast()函数

        float_image = tf.image.per_image_standardization(
            adjusted_contrast)  # 进行标准化图片操作,tf.image.per_image_standardization()函数是对每一个像素减去平均值并除以像素方差

        image = float_image
        image.set_shape([24, 24, 3])  # 设置图片数据及标签的形状
        label.set_shape([1])

    # Resize images to a common size
    image = tf.image.resize_images(image, [IMG_HEIGHT, IMG_WIDTH])

    # Normalize
    image = image * 1.0 / 127.5 - 1.0

    # 3. 创建一个batch生成器
    # Create batches
    X, Y = tf.train.batch([image, label], batch_size=batch_size,
                          capacity=batch_size * 8,   # 任务队列的大小
                          num_threads=4)  # 四个线程进行数据加载

    # X,Y = tf.train.shuffle_batch([image, label], batch_size=batch_size,
    #                                                     num_threads=4,
    #                                                     capacity=min_queue_examples + 3 * batch_size,
    #                                                     min_after_dequeue=min_queue_examples,
    #                                                     )

    return X, Y




# Parameters
learning_rate = 0.001
num_steps = 10000
batch_size = 128
display_step = 100

# Network Parameters
dropout = 0.75 # Dropout, probability to keep units

# Build the data input
X, Y = read_images(DATASET_PATH, MODE, batch_size)



# 模型搭建

# Create model
def conv_net(x, n_classes, dropout, reuse, is_training):
    # Define a scope for reusing the variables
    with tf.variable_scope('ConvNet', reuse=reuse):

        # Convolution Layer with 32 filters and a kernel size of 5
        conv1 = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu)
        # Max Pooling (down-sampling) with strides of 2 and kernel size of 2
        conv1 = tf.layers.max_pooling2d(conv1, 2, 2)

        # Convolution Layer with 32 filters and a kernel size of 5
        conv2 = tf.layers.conv2d(conv1, 64, 3, activation=tf.nn.relu)
        # Max Pooling (down-sampling) with strides of 2 and kernel size of 2
        conv2 = tf.layers.max_pooling2d(conv2, 2, 2)

        # Flatten the data to a 1-D vector for the fully connected layer
        fc1 = tf.contrib.layers.flatten(conv2)

        # Fully connected layer (in contrib folder for now)
        fc1 = tf.layers.dense(fc1, 1024)
        # Apply Dropout (if is_training is False, dropout is not applied)
        fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training)

        # Output layer, class prediction
        out = tf.layers.dense(fc1, n_classes)
        # Because 'softmax_cross_entropy_with_logits' already apply softmax,
        # we only apply softmax to testing network
        out = tf.nn.softmax(out) if not is_training else out

    return out



# 训练代码

# Because Dropout have different behavior at training and prediction time, we
# need to create 2 distinct computation graphs that share the same weights.

# Create a graph for training
logits_train = conv_net(X, N_CLASSES, dropout, reuse=False, is_training=True)
# Create another graph for testing that reuse the same weights
logits_test = conv_net(X, N_CLASSES, dropout, reuse=True, is_training=False)

# Define loss and optimizer (with train logits, for dropout to take effect)
loss_op = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
    logits=logits_train, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)

# Evaluate model (with test logits, for dropout to be disabled)
correct_pred = tf.equal(tf.argmax(logits_test, 1), tf.cast(Y, tf.int64))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# Initialize the variables (i.e. assign their default value)
init = tf.global_variables_initializer()

# Saver object
saver = tf.train.Saver()

# Start training
with tf.Session() as sess:

    # Run the initializer
    sess.run(init)

    # Start the data queue
    tf.train.start_queue_runners()

    # Training cycle
    for step in range(1, num_steps+1):

        if step % display_step == 0:
            # Run optimization and calculate batch loss and accuracy
            _, loss, acc = sess.run([train_op, loss_op, accuracy])
            print("Step " + str(step) + ", Minibatch Loss= " + \
                  "{:.4f}".format(loss) + ", Training Accuracy= " + \
                  "{:.3f}".format(acc))
        else:
            # Only run the optimization op (backprop)
            sess.run(train_op)

    print("Optimization Finished!")

    # Save your model
    saver.save(sess, 'my_tf_model')
image加载和训练代码

 

 2. tf.data.Dataset:

  如果我们的数据和标签都是np.array类似,可以采用如下的加载方式:

import numpy as np
import tensorflow as tf

evens = np.arange(0, 100, step=2, dtype=np.int32)
evens_label = np.zeros(50, dtype=np.int32)
odds = np.arange(1, 100, step=2, dtype=np.int32)
odds_label = np.ones(50, dtype=np.int32)
# Concatenate arrays
features = np.concatenate([evens, odds])      # 数据:shape(100, )
labels = np.concatenate([evens_label, odds_label]) # 标签:shape(100,)
# print(features.shape, labels.shape)


def dataloader(features, labels):
    # Slice the numpy arrays (each row becoming a record).
    data = tf.data.Dataset.from_tensor_slices((features, labels))
    # Refill data indefinitely.
    data = data.repeat()
    # Shuffle data.
    data = data.shuffle(buffer_size=100)
    # Batch data (aggregate records together).
    data = data.batch(batch_size=4)
    # Prefetch batch (pre-load batch for faster consumption).
    data = data.prefetch(buffer_size=1)

    # Create an iterator over the dataset.
    iterator = data.make_initializable_iterator()

    return iterator

    # # Initialize the iterator.
    # sess.run(iterator.initializer)
    #
    # # Get next data batch.
    # d = iterator.get_next()
    #
    # return d

with tf.Session() as sess:

    iterator = dataloader(features, labels)
    sess.run(iterator.initializer)   # Initialize the iterator.
    dataloader = iterator.get_next()  

    # Display data.
    for i in range(5):
        x, y = sess.run(dataloader)
        print(x, y)
加载numpy数据

  如果我们加载如下的图片数据, 下面有一个加载 Oxford Flowers dataset的示例代码:

d = requests.get("http://www.robots.ox.ac.uk/~vgg/data/flowers/17/17flowers.tgz")
with open("17flowers.tgz", "wb") as f:
    f.write(d.content)
# Extract archive.
with tarfile.open("17flowers.tgz") as t:
    t.extractall()

# Create a file to list all images path and their corresponding label.
with open('jpg/dataset.csv', 'w') as f:
    c = 0
    for i in range(1360):
        f.write("jpg/image_%04i.jpg,%i\n" % (i+1, c))
        if (i+1) % 80 == 0:
            c += 1

with tf.Graph().as_default():
    
    # Load Images.
    with open("jpg/dataset.csv") as f:
        dataset_file = f.read().splitlines()
    
    # Create TF session.
    sess = tf.Session()

    # Load the whole dataset file, and slice each line.
    data = tf.data.Dataset.from_tensor_slices(dataset_file)
    # Refill data indefinitely.
    data = data.repeat()
    # Shuffle data.
    data = data.shuffle(buffer_size=1000)

    # Load and pre-process images.
    def load_image(path):
        # Read image from path.
        image = tf.io.read_file(path)
        # Decode the jpeg image to array [0, 255].
        image = tf.image.decode_jpeg(image)
        # Resize images to a common size of 256x256.
        image = tf.image.resize(image, [256, 256])
        # Rescale values to [-1, 1].
        image = 1. - image / 127.5
        return image
    # Decode each line from the dataset file.
    def parse_records(line):
        # File is in csv format: "image_path,label_id".
        # TensorFlow requires a default value, but it will never be used.
        image_path, image_label = tf.io.decode_csv(line, ["", 0])
        # Apply the function to load images.
        image = load_image(image_path)
        return image, image_label
    # Use 'map' to apply the above functions in parallel.
    data = data.map(parse_records, num_parallel_calls=4)

    # Batch data (aggregate images-array together).
    data = data.batch(batch_size=2)
    # Prefetch batch (pre-load batch for faster consumption).
    data = data.prefetch(buffer_size=1)
    
    # Create an iterator over the dataset.
    iterator = data.make_initializable_iterator()
    # Initialize the iterator.
    sess.run(iterator.initializer)

    # Get next data batch.
    d = iterator.get_next()

for i in range(1):
    batch_x, batch_y = sess.run(d)
    print(batch_x, batch_y)
加载图片数据集

 

 8. 模型的保存和加载

Tensorflow有专门保存模型的tf.train.Saver(). 使用Saver保存模型的参数时,一定要将saver = tf.train.Saver定义在你保存的的参数定义之后,定义在saver之后的参数无法被保存。

如下面的代码,能将当前模型和其权值参数保存在tmp目录下

saver = tf.train.Saver()
saver.save(sess, "./tmp/model.ckpt")

上述代码会保存的文件如下:

其中后三个文件比较重要,依次存储的信息如下:

    •     .data文件:保存了当前参数值
    •     .index文件:保存了当前参数名
    •     .meta文件:保存了当前图结构

saver.save() 保存模型示例代码:

import numpy as np
import tensorflow as tf



class Network():
    x = tf.placeholder(shape=[1, None], dtype=tf.float32)
    y = tf.placeholder(shape=[1, None], dtype=tf.float32)

    inputW = tf.Variable(tf.random_normal([10, 1]))
    inputB = tf.Variable(tf.random_normal([10, 1]))

    hideW = tf.Variable(tf.random_normal([1, 10]))
    hideB = tf.Variable(tf.random_normal([1, 1]))

    h1 = tf.nn.sigmoid(tf.add(tf.matmul(inputW, x), inputB))
    output = tf.add(tf.matmul(hideW, h1), hideB)

    loss = tf.reduce_mean(tf.reduce_sum(tf.square(y - output)))

    opt = tf.train.AdamOptimizer(1)

    train_step = opt.minimize(loss)


if __name__ == '__main__':

    x_data = np.linspace(-1, 1, 100).reshape(1, 100)
    noise = np.random.normal(0, 0.05, x_data.shape)
    y_data = x_data ** 3 + 1 + noise

    net = Network()
    sess = tf.Session()
    init = tf.global_variables_initializer()

    sess.run(init)
    saver = tf.train.Saver()


    train_step = 200
    for step in range(train_step):
        print('', step + 1, '次训练')
        sess.run(net.train_step, feed_dict={net.x: x_data, net.y: y_data})
        pre = sess.run(net.output, feed_dict={net.x: x_data})

    saver.save(sess, "./tmp/model.ckpt")
save模型

saver.load()载入上面保存的模型:

import tensorflow as tf
import numpy as np
import pylab as pl
from tensorflowtest import Network

sess = tf.Session()
saver = tf.train.Saver().restore(sess, "./tmp/model.ckpt")

net = Network()

x_data = np.linspace(-1,1,100).reshape(1,100)
pre = sess.run(net.output,feed_dict={net.x:x_data})


pl.plot(x_data.T,pre.T)
pl.grid()
pl.show()
load保存的模型

 

参考: https://zhuanlan.zhihu.com/p/333791572

    https://www.cnblogs.com/hellcat/p/6925757.html

    https://zhuanlan.zhihu.com/p/31362241

posted @ 2021-08-28 16:51  silence_cho  阅读(75)  评论(0)    收藏  举报