深度学习总结(8)

模型工作流程

模型由许多链接在一起组成,并将输入数据映射为预测值。随后,损失函数将这些预测值与目标值进行比较,得到一个损失值,用于衡量模型预测值与预期结果之间的匹配程度。优化器将利用这个损失值来更新模型权重

在这里插入图片描述

下面是输入数据。

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype("float32") / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype("float32") / 255

输入图像保存在float32类型的NumPy张量中,其形状分别为(60000,784)(训练数据)和(10000, 784)(测试数据)​。
下面是模型。

model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(10, activation="softmax")
])

这个模型包含两个链接在一起的Dense层,每层都对输入数据做一些简单的张量运算,这些运算都涉及权重张量。权重张量是该层的属性,里面保存了模型所学到的知识。
下面是模型编译。

model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])

sparse_categorical_crossentropy是损失函数,是用于学习权重张量的反馈信号,在训练过程中应使其最小化。降低损失值是通过小批量随机梯度下降来实现的。梯度下降的具体方法由第一个参数给定,即rmsprop优化器。

下面是训练循环。

model.fit(train_images, train_labels, epochs=5, batch_size=128)

在调用fit时:模型开始在**训练数据(共60000个样本)**上进行迭代(每个小批量包含128个样本)​,共迭代5轮[在所有训练数据上迭代一次叫作一轮(epoch)]。对于每批数据,模型会计算损失相对于权重的梯度(利用反向传播算法,这一算法源自微积分的链式法则)​,并将权重沿着减小该批量对应损失值的方向移动。5轮之后,模型共执行2345次梯度更新(每轮469次)​,模型损失值将变得足够小,使得模型能够以很高的精度对手写数字进行分类。

用TensorFlow从头开始重新实现模型

简单的Dense类

Dense层实现了下列输入变换,其中W和b是模型参数,activation是一个逐元素的函数(通常是relu,但最后一层是softmax)​。

output = activation(dot(W, input) + b)

我们实现一个简单的Python类NaiveDense,它创建了两个TensorFlow变量W和b,并定义了一个__call__()方法供外部调用,以实现上述变换。

import tensorflow as tf

class NaiveDense:
    #构造函数
    def __init__(self, input_size, output_size, activation):
        #模拟keras的dense层可以设置激活函数
        self.activation = activation
        w_shape = (input_size, output_size)
        #创建一个形状为(input_size, output_size)的矩阵W,并将其随机初始化
        w_initial_value = tf.random.uniform(w_shape, minval=0, maxval=1e-1)
        self.W = tf.Variable(w_initial_value)

        b_shape = (output_size,)
        #创建一个形状为(output_size,)的零向量b
        b_initial_value = tf.zeros(b_shape)
        self.b = tf.Variable(b_initial_value)
    #前向传播
    def __call__(self, inputs):
        return self.activation(tf.matmul(inputs, self.W) + self.b)

    #获取该层权重的便捷方法
    @property
    def weights(self):
        #以列表的形式返回本层的权重
        return [self.W, self.b]

我们总结一下NaiveDense实现了哪些步骤:
1.根据输入输出的形状初始化权重(kernel和bias)以实现仿射变换
2.初始化激活函数
3.实现前向传播函数(反向传播可以通过tensorflow的梯度带实现)
4.提供获取权重的方式

扫描二维码关注公众号,回复: 17618427 查看本文章

简单的Sequential类

我们创建一个NaiveSequential类来实现模型,将这些层链接起来。它封装了一个层列表(正如我们前面提到的模型由一系列层构成),并定义了一个__call__()方法供外部调用。这个方法将按顺序调用输入的层。它还有一个weights属性,用于记录所有层的权重。

class NaiveSequential:
    def __init__(self, layers):
        self.layers = layers

    def __call__(self, inputs):
        x = inputs
        for layer in self.layers:
            x = layer(x)
        return x

    @property
    def weights(self):
       weights = []
       for layer in self.layers:
           weights += layer.weights
       return weights

按照惯例,总结一下这个Sequential实现了哪些行为:
1.封装层列表
2.一次调用层列表中的层进行前向传播

实例化模型

利用NaiveSequential来实例化模型

model = NaiveSequential([
    NaiveDense(input_size=28 * 28, output_size=512, activation=tf.nn.relu),
    NaiveDense(input_size=512, output_size=10, activation=tf.nn.softmax)
])
assert len(model.weights) == 4

批量生成器(batch)

对MNIST数据进行小批量迭代。

import math

class BatchGenerator:
    def __init__(self, images, labels, batch_size=128):
        assert len(images) == len(labels)
        self.index = 0
        self.images = images
        self.labels = labels
        self.batch_size = batch_size
        self.num_batches = math.ceil(len(images) / batch_size)

    def next(self):
        images = self.images[self.index : self.index + self.batch_size]
        labels = self.labels[self.index : self.index + self.batch_size]
        self.index += self.batch_size
        return images, labels

批量生成器很简单,就是将训练数据保存下来,每次迭代产生批量大小的数据。

本文所有的代码汇总如下:

import tensorflow as tf

class NaiveDense:
    #构造函数
    def __init__(self, input_size, output_size, activation):
        #模拟keras的dense层可以设置激活函数
        self.activation = activation
        w_shape = (input_size, output_size)
        #创建一个形状为(input_size, output_size)的矩阵W,并将其随机初始化
        w_initial_value = tf.random.uniform(w_shape, minval=0, maxval=1e-1)
        self.W = tf.Variable(w_initial_value)

        b_shape = (output_size,)
        #创建一个形状为(output_size,)的零向量b
        b_initial_value = tf.zeros(b_shape)
        self.b = tf.Variable(b_initial_value)
    #前向传播
    def __call__(self, inputs):
        return self.activation(tf.matmul(inputs, self.W) + self.b)

    #获取该层权重的便捷方法
    @property
    def weights(self):
        #以列表的形式返回本层的权重
        return [self.W, self.b]

class NaiveSequential:
    def __init__(self, layers):
        self.layers = layers

    def __call__(self, inputs):
        x = inputs
        for layer in self.layers:
            x = layer(x)
        return x

    @property
    def weights(self):
       weights = []
       for layer in self.layers:
           weights += layer.weights
       return weights


model = NaiveSequential([
    NaiveDense(input_size=28 * 28, output_size=512, activation=tf.nn.relu),
    NaiveDense(input_size=512, output_size=10, activation=tf.nn.softmax)
])
assert len(model.weights) == 4


import math

class BatchGenerator:
    def __init__(self, images, labels, batch_size=128):
        assert len(images) == len(labels)
        self.index = 0
        self.images = images
        self.labels = labels
        self.batch_size = batch_size
        self.num_batches = math.ceil(len(images) / batch_size)

    def next(self):
        images = self.images[self.index : self.index + self.batch_size]
        labels = self.labels[self.index : self.index + self.batch_size]
        self.index += self.batch_size
        return images, labels

猜你喜欢

转载自blog.csdn.net/weixin_52370850/article/details/147154507
今日推荐