TensorFlow入门

一、Model类

(1)初始化方法

1.可扩展参数:kwargs字典里获取,可限制key的取值

  • name: model变量域scope名称,获取不到采用self.__class__.__name__.lower()取类的名字
  • logging: 是否开启TensorBoard直方图仪表板,获取不到为False
  1. 其他参数

vars: name scope下的变量(字典)
placeholders: 外部变量占位,一般是特征和标签(字典)
layers: 神经网络的layer(列表)
activations: 每个layer的输出结果(列表)
inputs: 输入
output: 输出
loss: 损失
accuracy: 准确率
optimizer:优化器
opt_op:最优化的op操作

def __init__(self, **kwargs):
    allowed_kwargs = {'name', 'logging'}
    for kwarg in kwargs.keys():
        assert kwarg in allowed_kwargs, 'Invalid keyword argument: ' + kwarg
    name = kwargs.get('name')
    if not name:
        name = self.__class__.__name__.lower()
    self.name = name

    logging = kwargs.get('logging', False)
    self.logging = logging

    self.vars = {}
    self.placeholders = {}

    self.layers = []
    self.activations = []

    self.inputs = None
    self.outputs = None

    self.loss = 0
    self.accuracy = 0
    self.optimizer = None
    self.opt_op = None_build 

(2)build方法

_build 是私有build方法,在继承Model的具体实现时对layers进行append操作,下面介绍build方法:

调用_build,所有变量设置共享空间(self.name
构建模型序列:给输入,通过layer()返回输出,又将这个输出再次作为输入到下一个layer()中,循环这一过程;最终,取最后一层layer的结果作为output
保存name scope下的变量到self.vars
模型效果度量:_loss方法,_accuracy方法

def _build(self):
    raise NotImplementedError

def build(self):
    """ Wrapper for _build() """
    with tf.variable_scope(self.name):
        self._build()

    # Build sequential layer model
    self.activations.append(self.inputs)
    for layer in self.layers:
        hidden = layer(self.activations[-1])
        self.activations.append(hidden)
    self.outputs = self.activations[-1]

    # Store model variables for easy access
    variables = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=self.name)
    self.vars = {var.name: var for var in variables}

    # Build metrics
    self._loss()
    self._accuracy()

    self.opt_op = self.optimizer.minimize(self.loss)

(3)保存与加载方法

def save(self, sess=None):
        if not sess:
            raise AttributeError("TensorFlow session not provided.")
        saver = tf.train.Saver(self.vars)
        save_path = saver.save(sess, "tmp/%s.ckpt" % self.name)
        print("Model saved in file: %s" % save_path)

def load(self, sess=None):
        if not sess:
            raise AttributeError("TensorFlow session not provided.")
        saver = tf.train.Saver(self.vars)
        save_path = "tmp/%s.ckpt" % self.name
        saver.restore(sess, save_path)
        print("Model restored from file: %s" % save_path)    

二、数据读取

常用的结构化数据文件格式有csv、txt 、libsvm,本篇文章主要说明结构化数据(csv/txt)如何在TF框架进行高效、灵活的读取,避免一些不合理的方式,迈出算法开发标准化、工程化的第一步。

使用pandas读取数据

def load_data_with_pandas(filename):
    # load data as DataFrame to the memory
    data = pd.read_csv(filename, sep=',', header=0)
    features_df = data.iloc[:, :-1]
    label_df = data.iloc[:, -1]
    features = features_df.astype(np.float32).values
    labels = label_df.astype(np.int64).values
    return features, labels

最常见的读取数据的方式是利用pandas包将csv、txt读取为DataFrame,一次全部放入内存。这是一种非常低效的方式,应该尽量避免这种读取方法。其他第三方封装python读取方式的包(TFLearn等)也不建议使用,推荐使用TF框架的OP操作进行数据读取。

TensorFlow的数据读取机制

一、tensorflow读取机制图解

首先需要思考的一个问题是,什么是数据读取?以图像数据为例,读取数据的过程可以用下图来表示:


假设我们的硬盘中有一个图片数据集0001.jpg,0002.jpg,0003.jpg……我们只需要把它们读取到内存中,然后提供给GPU或是CPU进行计算就可以了。这听起来很容易,但事实远没有那么简单。事实上,我们必须要把数据先读入后才能进行计算,假设读入用时0.1s,计算用时0.9s,那么就意味着每过1s,GPU都会有0.1s无事可做,这就大大降低了运算的效率。

如何解决这个问题?方法就是将读入数据和计算分别放在两个线程中,将数据读入内存的一个队列,如下图所示:


读取线程源源不断地将文件系统中的图片读入到一个内存的队列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了。这样就可以解决GPU因为IO而空闲的问题!

而在tensorflow中,为了方便管理,在内存队列前又添加了一层所谓的“文件名队列”

为什么要添加这一层文件名队列?我们首先得了解机器学习中的一个概念:epoch。对于一个数据集来讲,运行一个epoch就是将这个数据集中的图片全部计算一遍。如一个数据集中有三张图片A.jpg、B.jpg、C.jpg,那么跑一个epoch就是指对A、B、C三张图片都计算了一遍。两个epoch就是指先对A、B、C各计算一遍,然后再全部计算一遍,也就是说每张图片都计算了两遍。

tensorflow使用文件名队列+内存队列双队列的形式读入文件,可以很好地管理epoch。下面我们用图片的形式来说明这个机制的运行方式。如下图,还是以数据集A.jpg, B.jpg, C.jpg为例,假定我们要跑一个epoch,那么我们就在文件名队列中把A、B、C各放入一次,并在之后标注队列结束。

程序运行后,内存队列首先读入A(此时A从文件名队列中出队):

再依次读入B和C:


此时,如果再尝试读入,系统由于检测到了“结束”,就会自动抛出一个异常(OutOfRange)。外部捕捉到这个异常后就可以结束程序了。这就是tensorflow中读取数据的基本机制。如果我们要跑2个epoch而不是1个epoch,那只要在文件名队列中将A、B、C依次放入两次再标记结束就可以了。

二、tensorflow读取数据机制的对应函数

如何在tensorflow中创建上述的两个队列呢?

对于文件名队列,我们使用tf.train.string_input_producer函数。这个函数需要传入一个文件名list,系统会自动将它转为一个文件名队列。

此外tf.train.string_input_producer还有两个重要的参数,一个是num_epochs,它就是我们上文中提到的epoch数。另外一个就是shuffle,shuffle是指在一个epoch内文件的顺序是否被打乱。若设置shuffle=False,如下图,每个epoch内,数据还是按照A、B、C的顺序进入文件名队列,这个顺序不会改变:


如果设置shuffle=True,那么在一个epoch内,数据的前后顺序就会被打乱,如下图所示:

在tensorflow中,内存队列不需要我们自己建立,我们只需要使用reader对象从文件名队列中读取数据就可以了,具体实现可以参考下面的实战代码。

除了tf.train.string_input_producer外,我们还要额外介绍一个函数:tf.train.start_queue_runners。初学者会经常在代码中看到这个函数,但往往很难理解它的用处,在这里,有了上面的铺垫后,我们就可以解释这个函数的作用了。

在我们使用tf.train.string_input_producer创建文件名队列后,整个系统其实还是处于“停滞状态”的,也就是说,我们文件名并没有真正被加入到队列中(如下图所示)。此时如果我们开始计算,因为内存队列中什么也没有,计算单元就会一直等待,导致整个系统被阻塞。

而使用tf.train.start_queue_runners之后,才会启动填充队列的线程,这时系统就不再“停滞”。此后计算单元就可以拿到数据并进行计算,整个程序也就跑起来了,这就是函数tf.train.start_queue_runners的用处。

image

三、实战代码

我们用一个具体的例子感受tensorflow中的数据读取。如图,假设我们在当前文件夹中已经有A.jpg、B.jpg、C.jpg三张图片,我们希望读取这三张图片5个epoch并且把读取的结果重新存到read文件夹中。


对应的代码如下:

# 导入tensorflow
import tensorflow as tf 

# 新建一个Session
with tf.Session() as sess:
   # 我们要读三幅图片A.jpg, B.jpg, C.jpg
  filename = ['A.jpg', 'B.jpg', 'C.jpg']
   # string_input_producer会产生一个文件名队列
   filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)
   # reader从文件名队列中读数据。对应的方法是reader.read
   reader = tf.WholeFileReader()
   key, value = reader.read(filename_queue)
   # tf.train.string_input_producer定义了一个epoch变量,要对它进行初始化
   tf.local_variables_initializer().run()
   # 使用start_queue_runners之后,才会开始填充队列
   threads = tf.train.start_queue_runners(sess=sess)
   i = 0
   while True:
       i += 1
       # 获取图片数据并保存
       image_data = sess.run(value)
       with open('read/test_%d.jpg' % i, 'wb') as f:
           f.write(image_data)

我们这里使用filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)建立了一个会跑5个epoch的文件名队列。并使用reader读取,reader每次读取一张图片并保存。
运行代码后,我们得到就可以看到read文件夹中的图片,正好是按顺序的5个epoch:


如果我们设置filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)中的shuffle=True,那么在每个epoch内图像就会被打乱,如图所示:

这里只是用三张图片举例,实际应用中一个数据集肯定不止3张图片,不过涉及到的原理都是共通的。

高效的 TensorFlow 读取方式是将数据读取转换成 OP,通过 session run的方式拉去数据。读取线程源源不断地将文件系统中的文件读入到一个内存的队列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了,这样就可以解决GPU因为IO而空闲的问题。同时,不会一次性的preload到内存,再大的数据量也不会超出内存的限制。

三、TensorFlow API

1.TensorFlow 相关函数理解


  • tf.nn.conv2d ————卷积
conv2d(
    input,
    filter,
    strides,
    padding,
    use_cudnn_on_gpu=True,
    data_format='NHWC',
    name=None
)

#Example
import tensorflow as tf
a = tf.constant([1,1,1,0,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,1,0,0],dtype=tf.float32,shape=[1,5,5,1])
b = tf.constant([1,0,1,0,1,0,1,0,1],dtype=tf.float32,shape=[3,3,1,1])
c = tf.nn.conv2d(a,b,strides=[1, 2, 2, 1],padding='VALID')
d = tf.nn.conv2d(a,b,strides=[1, 2, 2, 1],padding='SAME')
with tf.Session() as sess:
    print ("c shape:")
    print (c.shape)
    print ("c value:")
    print (sess.run(c))
    print ("d shape:")
    print (d.shape)
    print ("d value:")
    print (sess.run(d))
参数名 必选 类型 说明
input tensor 是一个 4 维的 tensor,即 [ batch, in_height, in_width, in_channels ](若 input 是图像,[ 训练时一个 batch 的图片数量, 图片高度, 图片宽度, 图像通道数 ])
filter tensor 是一个 4 维的 tensor,即 [ filter_height, filter_width, in_channels, out_channels ](若 input 是图像,[ 卷积核的高度,卷积核的宽度,图像通道数,卷积核个数 ]),filter 的 in_channels 必须和 input 的 in_channels 相等
strides 列表 长度为 4 的 list,卷积时候在 input 上每一维的步长,一般 strides[0] = strides[3] = 1
padding string 只能为 " VALID "," SAME " 中之一,这个值决定了不同的卷积方式。VALID 丢弃方式;SAME:补全方式
use_cudnn_on_gpu bool 是否使用 cudnn 加速,默认为 true
data_format string 只能是 " NHWC ", " NCHW ",默认 " NHWC "
name string 运算名称
image

  • tf.nn.relu ————relu激活函数
relu(
    features,
    name=None
)

#Example
import tensorflow as tf

a = tf.constant([1,-2,0,4,-5,6])
b = tf.nn.relu(a)
with tf.Session() as sess:
    print (sess.run(b))
参数名 必选 类型 说明
features tensor 是以下类型float32, float64, int32, int64, uint8, int16, int8, uint16, half
name string 运算名称

  • tf.nn.max_pool————池化
max_pool(
    value,
    ksize,
    strides,
    padding,
    data_format='NHWC',
    name=None
)


#Example
import tensorflow as tf

a = tf.constant([1,3,2,1,2,9,1,1,1,3,2,3,5,6,1,2],dtype=tf.float32,shape=[1,4,4,1])
b = tf.nn.max_pool(a,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='VALID')
c = tf.nn.max_pool(a,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME')
with tf.Session() as sess:
    print ("b shape:")
    print (b.shape)
    print ("b value:")
    print (sess.run(b))
    print ("c shape:")
    print (c.shape)
    print ("c value:")
    print (sess.run(c))
参数名 必选 类型 说明
value tensor 4 维的张量,即 [ batch, height, width, channels ],数据类型为 tf.float32
ksize 列表 池化窗口的大小,长度为 4 的 list,一般是 [1, height, width, 1],因为不在 batch 和 channels 上做池化,所以第一个和最后一个维度为 1
strides 列表 池化窗口在每一个维度上的步长,一般 strides[0] = strides[3] = 1
padding string 只能为 " VALID "," SAME " 中之一,这个值决定了不同的池化方式。VALID 丢弃方式;SAME:补全方式
data_format string 只能是 " NHWC ", " NCHW ",默认" NHWC "
name string 运算名称

  • tf.nn.dropout————防止或减轻过拟合
dropout(
    x,
    keep_prob,
    noise_shape=None,
    seed=None,
    name=None
)

#Example
import tensorflow as tf

a = tf.constant([1,2,3,4,5,6],shape=[2,3],dtype=tf.float32)
b = tf.placeholder(tf.float32)
c = tf.nn.dropout(a,b,[2,1],1)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print (sess.run(c,feed_dict={b:0.75}))
参数名 必选 类型 说明
x tensor 输出元素是 x 中的元素以 keep_prob 概率除以 keep_prob,否则为 0
keep_prob scalar Tensor dropout 的概率,一般是占位符
noise_shape tensor 默认情况下,每个元素是否 dropout 是相互独立。如果指定 noise_shape,若 noise_shape[i] == shape(x)[i],该维度的元素是否 dropout 是相互独立,若 noise_shape[i] != shape(x)[i] 该维度元素是否 dropout 不相互独立,要么一起 dropout 要么一起保留
seed 数值 如果指定该值,每次 dropout 结果相同
name string 运算名称

  • tf.nn.sigmoid_cross_entropy_with_logits————先对 logits 通过 sigmoid 计算,再计算交叉熵
sigmoid_cross_entropy_with_logits(
    _sentinel=None,
    labels=None,
    logits=None,
    name=None
)

#Example
import tensorflow as tf
x = tf.constant([1,2,3,4,5,6,7],dtype=tf.float64)
y = tf.constant([1,1,1,0,0,1,0],dtype=tf.float64)
loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = y,logits = x)
with tf.Session() as sess:
    print (sess.run(loss))
参数名 必选 类型 说明
_sentinel None 没有使用的参数
labels Tensor type, shape 与 logits相同
logits Tensor type 是 float32 或者 float64
name string 运算名称

  • tf.truncated_normal————产生截断正态分布随机数,取值范围为 [ mean - 2 * stddev, mean + 2 * stddev ]
truncated_normal(
    shape,
    mean=0.0,
    stddev=1.0,
    dtype=tf.float32,
    seed=None,
    name=None
)

#Example
import tensorflow as tf
initial = tf.truncated_normal(shape=[3,3], mean=0, stddev=1)
print(tf.Session().run(initial))
参数名 必选 类型 说明
shape 1 维整形张量或 array 输出张量的维度
mean 0 维张量或数值 均值
stddev 0 维张量或数值 标准差
dtype dtype 输出类型
seed 数值 随机种子,若 seed 赋值,每次产生相同随机数
name string 运算名称

  • tf.constant————根据 value 的值生成一个 shape 维度的常量张量
constant(
    value,
    dtype=None,
    shape=None,
    name='Const',
    verify_shape=False
)
参数名 必选 类型 说明
value 常量数值或者 list 输出张量的值
dtype dtype 输出张量元素类型
shape 1 维整形张量或 array 输出张量的维度
name string 张量名称
verify_shape Boolean 检测 shape 是否和 value 的 shape 一致,若为 Fasle,不一致时,会用最后一个元素将 shape 补全

  • tf.placeholder————是一种占位符,在执行时候需要为其提供数据
placeholder(
    dtype,
    shape=None,
    name=None
)

#Example
import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32,[None,3])
y = tf.matmul(x,x)
with tf.Session() as sess:
    rand_array = np.random.rand(3,3)
    print(sess.run(y,feed_dict={x:rand_array}))
参数名 必选 类型 说明
dtype dtype 占位符数据类型
shape 1 维整形张量或 array 占位符维度
name string 占位符名称

  • tf.nn.bias_add————将偏差项 bias 加到 value 上面,可以看做是 tf.add 的一个特例,其中 bias 必须是一维的,并且维度和 value 的最后一维相同,数据类型必须和 value 相同。
bias_add(
    value,
    bias,
    data_format=None,
    name=None
)

#Example
import tensorflow as tf
import numpy as np

a = tf.constant([[1.0, 2.0],[1.0, 2.0],[1.0, 2.0]])
b = tf.constant([2.0,1.0])
c = tf.constant([1.0])
sess = tf.Session()
print (sess.run(tf.nn.bias_add(a, b)))
#print (sess.run(tf.nn.bias_add(a,c))) error
print ("##################################")
print (sess.run(tf.add(a, b)))
print ("##################################")
print (sess.run(tf.add(a, c)))
参数名 必选 类型 说明
value 张量 数据类型为 float, double, int64, int32, uint8, int16, int8, complex64, or complex128
bias 一维张量 维度必须和 value 最后一维维度相等
data_format string 数据格式,支持 ' NHWC ' 和 ' NCHW '
name string 运算名称

  • tf.reduce_mean————计算张量 input_tensor 平均值
reduce_mean(
    input_tensor,
    axis=None,
    keep_dims=False,
    name=None,
    reduction_indices=None
)

#Example
import tensorflow as tf
import numpy as np

initial = [[1.,1.],[2.,2.]]
x = tf.Variable(initial,dtype=tf.float32)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init_op)
    print(sess.run(tf.reduce_mean(x)))
    print(sess.run(tf.reduce_mean(x,0))) #Column
    print(sess.run(tf.reduce_mean(x,1))) #row
参数名 必选 类型 说明
input_tensor 张量 输入待求平均值的张量
axis None、0、1 None:全局求平均值;0:求每一列平均值;1:求每一行平均值
keep_dims Boolean 保留原来的维度(例如不会从二维矩阵降为一维向量)
name string 运算名称
reduction_indices None 和 axis 等价,被弃用

  • tf.squared_difference————计算张量 x、y 对应元素差平方
squared_difference(
    x,
    y,
    name=None
)
参数名 必选 类型 说明
x 张量 是 half, float32, float64, int32, int64, complex64, complex128 其中一种类型
y 张量 是 half, float32, float64, int32, int64, complex64, complex128 其中一种类型
name string 运算名称

  • tf.square————计算张量对应元素平方
square(
    x,
    name=None
    )
参数名 必选 类型 说明
x 张量 是half, float32, float64, int32, int64, complex64, complex128 其中一种类型
name string 运算名称

2.Tensorflow相关类理解

  • tf.Variable————维护图在执行过程中的状态信息,例如神经网络权重值的变化
__init__(
    initial_value=None,
    trainable=True,
    collections=None,
    validate_shape=True,
    caching_device=None,
    name=None,
    variable_def=None,
    dtype=None,
    expected_shape=None,
    import_scope=None
)
参数名 类型 说明
initial_value 张量 Variable 类的初始值,这个变量必须指定 shape 信息,否则后面 validate_shape 需设为 False
trainable Boolean 是否把变量添加到 collection GraphKeys.TRAINABLE_VARIABLES 中(collection 是一种全局存储,不受变量名生存空间影响,一处保存,到处可取)
collections Graph collections 全局存储,默认是 GraphKeys.GLOBAL_VARIABLES
validate_shape Boolean 是否允许被未知维度的 initial_value 初始化
caching_device string 指明哪个 device 用来缓存变量
name string 变量名
dtype dtype 如果被设置,初始化的值就会按照这个类型初始化
expected_shape TensorShape 要是设置了,那么初始的值会是这种维度


四、LeNet网络的构建

#模型训练
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt


#打开数据集
path='C:/Users/86769/.keras/datasets/mnist.npz'
f = np.load(path)
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
f.close()

#格式化
x_train = np.pad(x_train,((0,0),(2,2),(2,2)),'constant',constant_values=0)
x_train = x_train.astype('float32')
x_train /=255
x_train=x_train.reshape(x_train.shape[0],32,32,1)

x_test = np.pad(x_test,((0,0),(2,2),(2,2)),'constant',constant_values=0)
x_test = x_test.astype('float32')
x_test /=255
x_test=x_test.reshape(x_test.shape[0],32,32,1)

#创建模型
model=tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(filters=6,kernel_size=(5,5),padding='valid',activation=tf.nn.relu,input_shape=(32,32,1)),
    tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
    tf.keras.layers.Conv2D(filters=16,kernel_size=(5,5),padding='valid',activation=tf.nn.relu),
    tf.keras.layers.AveragePooling2D(pool_size=(2,2),strides=(2,2),padding='same'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=120,activation=tf.nn.relu),
    # tf.keras.layers.Conv2D(filters=120,kernel_size=(5,5),strides=(1,1),activation='tanh',padding='valid'),
    # tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=84,activation=tf.nn.relu),
    tf.keras.layers.Dense(units=10,activation=tf.nn.softmax)
])

model.summary()


#超参数配置
num_epochs=10          #训练轮数
batch_size=64          #批大小
learning_rate=0.001    #学习率

#优化器
adam_optimizer=tf.keras.optimizers.Adam(learning_rate)

model.compile(optimizer=adam_optimizer,
              loss=tf.keras.losses.sparse_categorical_crossentropy,metrics=['accuracy'])

import datetime
start_time=datetime.datetime.now()

model.fit(x=x_train,
          y=y_train,
          batch_size=batch_size,
          epochs=num_epochs)
end_time=datetime.datetime.now()
time_cost=end_time-start_time
print("time_cost = ",time_cost) #CPU time cost: 5min, GPU time cost: less than 1min

#模型保存
model.save('E:/ML/LeNet_Model.hui')

#评估指标
print(model.evaluate(x_test, y_test))  #loss value & metrics value

#预测
image_index=4444
print(x_test[image_index].shape)
plt.imshow(x_test[image_index].reshape(32,32),cmap='Greys')

pred = model.predict((x_test[image_index].reshape(1,32,32,1)))
print(pred.argmax())

神经网络中的几个重要概念

梯度下降:梯度下降是一个在机器学习中用于寻找较佳结果(曲线的最小值)的迭代优化算法。梯度的含义是斜率或者斜坡的倾斜度。下降的含义是代价函数的下降。
 算法是迭代的,意思是需要多次使用算法获取结果,以得到最优化结果。梯度下降的迭代性质能使欠拟合演变成获得对数据的较佳拟合。

 梯度下降中有一个称为学习率的参量。如上图左所示,刚开始学习率较大,因此下降步长更大。随着点的下降,学习率变得越来越小,从而下降步长也变小。同时,代价函数也在减小,或者说代价在减小,有时候也称为损失函数或者损失,两者是一样的。(损失/代价的减小是一个概念)。

 只有在数据很庞大的时候(在机器学习中,数据一般情况下都会很大),我们才需要使用epochs,batch size,iteration这些术语,在这种情况下,一次性将数据输入计算机是不可能的。因此,为了解决这个问题,我们需要把数据分成小块,一块一块的传递给计算机,在每一步的末端更新神经网络的权重,拟合给定的数据。

(1)batchsize:批大小。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;
(2)iteration:1个iteration等于使用batchsize个样本训练一次;
(3)epoch:1个epoch等于使用训练集中的全部样本训练一次;

  • batchsize:批大小(批尺寸)
    批大小将决定我们一次训练的样本数目。
    batch_size将影响到模型的优化程度和速度。

batchsize的正确选择是为了在内存效率和内存容量之间寻找最佳平衡。
Batch_Size的取值:

BatchSize

全批次(蓝色)
如果数据集比较小,我们就采用全数据集。全数据集确定的方向能够更好的代表样本总体,从而更准确的朝向极值所在的方向。
注:对于大的数据集,我们不能使用全批次,因为会得到更差的结果。

迷你批次(绿色)
选择一个适中的Batch_Size值。就是说我们选定一个batch的大小后,将会以batch的大小将数据输入深度学习的网络中,然后计算这个batch的所有样本的平均损失,即代价函数是所有样本的平均。

随机(Batch_Size等于1的情况)(红色)
每次修正方向以各自样本的梯度方向修正,横冲直撞各自为政,难以达到收敛。

适当的增加Batch_Size的优点:

  • 1.通过并行化提高内存利用率。
  • 2.单次epoch的迭代次数减少,提高运行速度。(单次epoch=(全部训练样本/batchsize)/iteration=1)
  • 3.适当的增加Batch_Size,梯度下降方向准确度增加,训练震动的幅度减小。(看上图便可知晓)
经验总结:

相对于正常数据集,如果Batch_Size过小,训练数据就会非常难收敛,从而导致underfitting。
增大Batch_Size,相对处理速度加快,所需内存容量增加(epoch的次数需要增加以达到最好的结果)
这里我们发现上面两个矛盾的问题,因为当epoch增加以后同样也会导致耗时增加从而速度下降。因此我们需要寻找最好的Batch_Size。

iteration:迭代
迭代是重复反馈的动作,神经网络中我们希望通过迭代进行多次的训练以达到所需的目标或结果。
每一次迭代得到的结果都会被作为下一次迭代的初始值。
一个迭代=一个正向通过+一个反向通过

Epoch
当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一次epoch。然而,当一个epoch对于计算机而言太庞大的时候,就需要把它分成多个小块。
为什么要使用多于一个epoch?
在神经网络中传递完整的数据集一次是不够的,而且我们需要将完整的数据集在同样的神经网络中传递多次。但请记住,我们使用的是有限的数据集,并且我们使用一个迭代过程即梯度下降来优化学习过程。如下图所示。因此仅仅更新一次或者说使用一个epoch是不够的。

Epoch Influence

随着epoch数量增加,神经网络中的权重的更新次数也在增加,曲线从欠拟合变得过拟合。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343