10、模型概览与一个实例

一、模型概览

#基本概念

#0Keras 有两个重要的概念: 模型(Model) 和 层(Layer) 

#1层将各种计算流程和变量进行了封装(例如基本的全连接层,CNN 的卷积层、池化层等)

#2模型则将各种层进行组织和连接,并封装成一个整体,描述了如何将输入数据通过各种层以及运算而得到输出。

#3Keras 在 tf.keras.layers 下内置了深度学习中大量常用的的预定义层,同时也允许我们自定义层。

#4Keras 模型以类的形式呈现,我们可以通过继承 tf.keras.Model 这个 Python 类来定义自己的模型。

#5在继承类中,我们需要重写 init() (构造函数,初始化)和 call(input) (模型调用)两个方法,同时也可以根据需要增加自>    定义的方法。

class MyModel(tf.keras.Model):

    def __init__(self):

        super().__init__()    # Python 2 下使用 super(MyModel, self).__init__()

        # 此处添加初始化代码(包含 call 方法中会用到的层),例如

        # layer1 = tf.keras.layers.BuiltInLayer(...)

        # layer2 = MyCustomLayer(...)

    def call(self, input):

        # 此处添加模型调用的代码(处理输入并返回输出),例如

        # x = layer1(input)

        # output = layer2(x)

        return output

    # 还可以添加自定义的方法

模型图示

例子:

import tensorflow as tf

X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])

y = tf.constant([[10.0], [20.0]])


class Linear(tf.keras.Model):

    def __init__(self):

        super().__init__()

        self.dense = tf.keras.layers.Dense(

            units=1,

            activation=None,

            kernel_initializer=tf.zeros_initializer(),

            bias_initializer=tf.zeros_initializer()

        )


    def call(self, input):

        output = self.dense(input)

        return output



# 以下代码结构与前节类似

model = Linear()

optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

for i in range(100):

    with tf.GradientTape() as tape:

        y_pred = model(X)      # 调用模型 y_pred = model(X) 而不是显式写出 y_pred = a * X + b

        loss = tf.reduce_mean(tf.square(y_pred - y))

    grads = tape.gradient(loss, model.variables)    # 使用 model.variables 这一属性直接获得模型中的所有变量

    optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))

print(model.variables)

1、我们没有显式地声明 a 和 b 两个变量并写出 y_pred = a X + b 这一线性变换,而是建立了一个继承了 tf.keras.Model 的模型类 Linear 。这个类在初始化部分实例化了一个 *全连接层 ( tf.keras.layers.Dense ),并在 call 方法中对这个层进行调用,实现了线性变换的计算。

2、Keras 的全连接层:线性变换 + 激活函数

全连接层
主要参数

3、为什么模型类是重载 call() 方法而不是 call() 方法?

在 Python 中,对类的实例 myClass 进行形如 myClass() 的调用等价于 myClass.call() (具体请见本章初 “前置知识” 的 call() 部分)。那么看起来,为了使用 ypred = model(X) 的形式调用模型类,应该重写 call() 方法才对呀?原因是 Keras 在模型调用的前后还需要有一些自己的内部操作,所以暴露出一个专门用于重载的 call() 方法。 tf.keras.Model 这一父类已经包含 call() 的定义。 _call() 中主要调用了 call() 方法,同时还需要在进行一些 keras 的内部操作。这里,我们通过继承 tf.keras.Model 并重载 call() 方法,即可在保持 keras 结构的同时加入模型调用的代码。

二、一个实例:使用多层感知机完成 MNIST 手写体数字图片数据集 [LeCun1998] 的分类任务。

模型的构建: tf.keras.Model 和 tf.keras.layers

多层感知机的模型类实现与上面的线性模型类似,使用 tf.keras.Model 和 tf.keras.layers 构建,所不同的地方在于层数增加了(顾名思义,“多层” 感知机),以及引入了非线性激活函数(这里使用了 ReLU 函数 , 即下方的 activation=tf.nn.relu )。该模型输入一个向量(比如这里是拉直的 1×784 手写体数字图片),输出 10 维的向量,分别代表这张图片属于 0 到 9 的概率。

代码主要分为几个部分:

1、引入/导入包

2、定义训练数据处理

3、定义模型

4、进行训练

5、评估结果

代码如下:它跑成功了呀~~~

10 import tensorflow as tf

 11import numpy as np

 12 

 13 class MNISTLoader():

 14    def __init__(self):

 15        mnist = tf.keras.datasets.mnist

 16        (self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()

 17        # MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道

 18        self.train_data = np.expand_dims(self.train_data.astype(np.float32) /255.0, axis=-1)      # [60000, 28, 28, 1]

 19        self.test_data = np.expand_dims(self.test_data.astype(np.float32) /255.0, axis=-1)        # [10000, 28, 28, 1]

 20        self.train_label = self.train_label.astype(np.int32)    # [60000]

 21        self.test_label = self.test_label.astype(np.int32)      # [10000]

 22        self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]

 23 

 24    def get_batch(self, batch_size):

 25        # 从数据集中随机取出batch_size个元素并返回

 26        index = np.random.randint(0, np.shape(self.train_data)[0], batch_size)

 27        return self.train_data[index, :], self.train_label[index]

 28 

 29 class MLP(tf.keras.Model):

 30    def __init__(self):

 31        super().__init__()

 32        self.flatten = tf.keras.layers.Flatten()    # Flatten层将除第一维(batch_size)以外的维度展平

 33        self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)

 34        self.dense2 = tf.keras.layers.Dense(units=10)

 35 

 36    def call(self, inputs):        # [batch_size, 28, 28, 1]

 37        x = self.flatten(inputs)    # [batch_size, 784]

 38        x = self.dense1(x)          # [batch_size, 100]

 39        x = self.dense2(x)          # [batch_size, 10]

 40        output = tf.nn.softmax(x)

 41        return output

 42 

 43num_epochs = 5

 44batch_size = 50

 45learning_rate = 0.001

 46 

 47model = MLP()

 48data_loader = MNISTLoader()

 49optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)

 50 

 51num_batches = int(data_loader.num_train_data // batch_size * num_epochs)

 52 for batch_index in range(num_batches):

 53        X, y = data_loader.get_batch(batch_size)

 54        with tf.GradientTape() as tape:

 55            y_pred = model(X)

 56            loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)

 57            loss = tf.reduce_mean(loss)

 58            print("batch %d: loss %f" % (batch_index, loss.numpy()))

 59        grads = tape.gradient(loss, model.variables)

 60        optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))

 61 

 62sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()

 63num_batches = int(data_loader.num_test_data // batch_size)

 64 for batch_index in range(num_batches):

 65        start_index, end_index = batch_index * batch_size, (batch_index +1) * batch_size

 66        y_pred = model.predict(data_loader.test_data[start_index: end_index])

 67        sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index: end_index], y_pred=y_pred)

 68print("test accuracy: %f" % sparse_categorical_accuracy.result())


参考资料

1、简单粗暴 TensorFlow 2.0 模型(Model)与层(Layer)

https://www.bookstack.cn/read/TensorFlow2.0/spilt.1.c868281a01ad8ec0.md

2、简单粗暴 TensorFlow 2.0 基础示例:多层感知机(MLP) 

https://www.bookstack.cn/read/TensorFlow2.0/spilt.2.c868281a01ad8ec0.md

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

推荐阅读更多精彩内容