【学习笔记】《Python深度学习》第七章:高级的深度学习最佳实践

news2024/11/15 13:52:22

文章目录

  • 1 Keras 函数式 API
    • 1.1 函数式 API 简介
    • 1.2 多输入模型
    • 1.3 多输出模型
    • 1.4 层组成的有向无环图
    • 1.5 共享层权重
    • 1.6 将模型作为层
  • 2 使用 Keras 回调函数 和 TensorBoard 检查并监控深度学习模型
    • 2.1 训练过程中将回调函数作用于模型
    • 2.2 TensorBoard 简介:TensorFlow 的可视化框架
  • 3 让模型性能发挥到极致
    • 3.1 高级架构模式
    • 3.2 超参数优化
    • 3.3 模型集成

1 Keras 函数式 API

1. Sequential 模型

该模型假设网络「只有一个输入」和「只有一个输出」,而且网络都是「层的线性堆叠」。

然而 Sequential模型 过于死板,有些网络需要多个独立的输入,有些网络则需要多个输出,而有些网络在层与层之间具有内部分支,这使得网络看起来像是层构成的,而不是层的线性堆叠。

在这里插入图片描述

2.非线性的网络拓扑结构,网络结构为有向无环图

  • Inception系列网络
    依赖 Inception 模块,其输入被多个并行的卷积分支所处理,然后将这些分支的输出合并为单个张量。
    在这里插入图片描述

  • 添加残差连接
    最早出现于 ResNet 系列网络。残差连接是将前面的输出张量与后面的输出张量相加,从而将前面的表示重新注入下游数据流中。
    在这里插入图片描述

1.1 函数式 API 简介

函数式 API ,可以直接操作张量,也可以把层当作函数使用,接收张量并返回张量。

1. 展示一个简单的 Sequential 模型 以及对应的函数式 API 实现

from keras.models import Sequential, Model
from keras import layers
from keras import Input

# Sequential模型
seq_model = Sequential()
seq_model.add(layers.Dense(32, activation='relu', input_shape=(64,)))
seq_model.add(layers.Dense(32, activation='relu'))
seq_model.add(layers.Desne(10, activation=''softmax'))

# 对应的函数式API实现
input_tensor = Input(shape=(64,))
x = layers.Dense(32, activation='relu')(input_tensor)
x = layers.Dense(32, activation='relu')(x)
output_tentor = layers.Dense(10, activation='softmax')(x)

# Model类将输入张量和输出张量转换为一个模型 
model = Model(input_tensor, output_tensor)

对 Model 实例进行编译、训练或评估时,其 API 与 Sequential 模型相同。

1.2 多输入模型

多输入模可以通过 相加、连接 等张量组合方式将不同输入分支合并,通常利用 Keras 的合并运算实现,比如 keras.layers.add、 keras.layers.concatenate 等。

1. 用函数式 API 实现双输入问答模型

典型的 问答模型 有两个输入: 一个自然语言描述的问题 和 一个文本片段 ,后者用于提供回答问题的信息,然后模型会生成一个 「回答」。

在这里插入图片描述

设置两个独立分支,将文本输入和问题输入分别编码为表示向量,然后连接这些向量,最后,在连接好的表示上添加 softmax 分类器 。

from keras.models import Model
from keras import layers
from keras import Input

text_vocabulary_size = 10000
question_vocabulary_size = 10000
answer_vocabulary_size = 500

# 文本输入是长度可变的整数序列
# 可以选择对输入进行命名
text_input = Input(shape=(None,), dtype='int32', name='text')

# 将输入嵌入长度为64的向量
embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input)

# 利用LSTM将向量编码为单个向量
encoded_text = layers.LSTM(32)(embedded_text)

# 对问题进行相同处理
question_input = Input(shape=(None,), dtype='int32', name='question')

embedded_question = layers.Embedding(question_vocabulary_size, 32)(question_input)

encoded_question = layers.LSTM(16)(embedded_question)

# 将编码后的问题和文本连接起来
concatenated = layers.concatenate([encoded_text, encoded_question], axis=-1)

# 添加softmax分类器
answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated)

# 在模型实例化时,指定两个输入和输出
model = Model([text_input, question_input], answer)
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['acc'])

2. 将数据输入到多输入模型中

训练双输入模型有两个可用的 API :

  • 向模型输入一个由 Numpy 数组组成的列表
  • 输入一个将输入名称映射为 Numpy 数组的字典,该方法只有输入具有名称的时候才能使用。
import numpy as np
import keras

num_samples = 1000
max_length = 100

# 生成虚构的Numpy数据
text = np.random.randint(1, text_vocabulary_size,
                         size=(num_samples, max_length))

question = np.random.randint(1, question_vocabulary_size,
                             size=(num_samples, max_length))

answers = np.random.randint(answer_vocabulary_size, size=(num_samples))
answers = keras.utils.to_categorical(answers, answer_vocabulary_size)

# 使用输入组成的列表来拟合
model.fit([text, question], answers, epochs=10, batch_size=128)

# 使用输入组成的字典来拟合
model.fit({'text': text, 'question': question}, answers, epochs=10, 
	batch_size=128)

1.3 多输出模型

使用函数式 API 构建具有多个输出(或多头)的模型。

实例:输入某个匿名人士的一系列社交媒体发帖,然后尝试预测这个人的属性,比如年龄、性别和收入水平。

在这里插入图片描述

1. 用函数式 API 实现一个三输出模型

from keras import layers 
from keras import Input
from keras.models import Model

vocabulary_size = 50000
num_income_groups = 10

posts_input = Input(shape=(None,), dtype='int32', name='posts')
embedded_posts = layers.Embedding(256, vocabulary_size)(posts_input)
x = layers.Conv1D(128, 5, activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128, activation='relu')(x)

# 输出层具有名称
age_prediction = layers.Dense(1, 
                              name='age')(x)
income_prediction = layers.Dense(num_income_groups,
                                 activation='softmax',
                                 name='income')(x)
gender_prediction = layers.Dense(1, 
                                 activation='sigmoid', 
                                 name='gender')(x)

model = Model(posts_input,
              [age_prediction, income_prediction, gender_prediction])

2. 多输出模型的编译选项:多重损失

多输出模型需要对网络的各个头指定不同的损失函数

例如,年龄预测是标量回归任务,而性别预测是二分类任务,二者需要不同的训练过程。但是,梯度下降要求将 标量 最小化,所以为了能够训练模型,需要「将损失合并为单个标量」。
合并不同损失最简单的方法就是 对所有损失求和
在 Keras 中,可以在编译时使用损失组成的列表字典为不同输出指定不同的损失,然后就得到的损失值相加得到一个全局损失,并在训练过程中将其最小化。

(1)列表

model.compile(optimizer='rmsprop',
              loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'])

(2)字典

model.compile(optimizer='rmsprop',
              loss={'age': 'mse',
                    'income': 'categorical_crossentropy',
                    'gender': 'binary_crossentropy'})

3. 多输出模型编译选项:损失加权

由于严重不平衡的损失贡献会导致模型表示针对单个损失值最大的任务优先进行优化。

为了解决这个问题,可以为每个损失之对最终损失的贡献分配不同大小的重要性,进行损失加权

(1)列表

model.compile(optimizer='rmsprop',
              loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'],
              loss_weight=[0.25, 1., 10.])

(2)字典

model.compile(optimizer='rmsprop',
              loss={'age': 'mse',
                    'income': 'categorical_crossentropy',
                    'gender': 'binary_crossentropy'},
              loss_weights={'age': 0.25,
                            'income': 1.,
                            'gender': 10.})

4. 将数据输入到多输出模型中

# 假设posts, age_targets, income_targets, gender_targets都是Numpy数组
model.fit(posts, [age_targets, income_targets, gender_targets],
          epochs=10, batch_size=64)
# 与上述写法等效
# 只有输出层具有名称时才有效
model.fit(posts, {'age': age_targets, 
                   'income': income_targets, 
                  'gender': gender_targets},
          epochs=10, batch_size=64)

1.4 层组成的有向无环图

1. Inception 模块

(1)Inception 模型的形式

Inception 模块 最基本的形式包含 3~4 个分支,首先是一个 1 * 1 的卷积,然后是一个 3 * 3 的卷积,最后将所得到的特征连接在一起。

Inception 模块也可能具有更复杂的形式, 通常包含池化运算、不同尺寸的空间卷积和不包含空间卷积的分支。

1 * 1 卷积的作用

  • 1 * 1 卷积等价于让每个方块向量经过一个 Dense 层:它计算得到的特征能够将输入张量通道中的信息混合在一起,但不会将跨空间的信息混合在一起。
  • 有助于区分通道特征学习空间特征学习

(2) 下图是 Inception 模块的一个示例,来自于 Inception V3 :

在这里插入图片描述

(3)使用函数式 API 实现图 7-8 中的模块:

from keras import layers

# 假设有一个四维输入张量 x

branch_a = layers.Conv2D(128, 1, activation='relu', strides=2)(x)
branch_b = layers.Conv2D(128, 1, activation='relu')(x)
branch_b = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_b)
branch_c = layers.AveragePooling2D(3, strides=2)(x)
branch_c = layers.Conv2D(128, 3, activation='relu')(branch_c)
branch_d = layers.Conv2D(128, 1, activation='relu')(x)
branch_d = layers.Conv2D(128, 3, activation='relu')(branch_d)
branch_d = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_d)

output = layers.concatenate(
    [branch_a, branch_b, branch_c, branch_d], axis=-1)

2. 残差连接

(1)残差连接解决了两个问题

  • 表示瓶颈
    在 Sequential 模型中,每个连续的表示层都构建于前一层之上,这意味着它只能访问前一层激活中包含的信息。如果某一层太小,那么模型将会受限于该层激活中的信息量。

  • 梯度消失
    反向传播的工作原理是将来自输出损失的反馈信号向下传播到更底部的层,如果信息需要传播很多层,那么信号很可能变得非常微弱,导致网络无法训练。
    残差连接引入了一个「纯线性的信息携带轨道」,与主要的层堆叠方向平行,有助于跨越任意深度的层来传播梯度。

(2)原理

残差连接是让前面某层的输出作为后面某层的输入, 前面层的输出与后面层的激活相加。

如果二者形状不同,则可以用一个线性变换将前面层的激活改变成目标形状。

(3)在 Keras 中实现残差连接

① 假设特征图尺寸相同,使用恒等残差连接

# 假设有一个四维输入张量x

x = ...
y = layers.Conv2D(128, 3, activation='relu', padding='same')(x)
y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)
y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)

y = layers.add([y, x]) # 将原始x与输出特征相加

② 假设特征图尺寸不同,使用线性残差连接

# 假设有一个四维输入张量x

x = ...
y = layers.Conv2D(128, 3, activation='relu', padding='same')(x)
y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)
y = layers.MaxPooling2D(2, strides=2)(y)

# 使用1*1卷积,将原始x张量线性下采样为与y具有相同的形状
residual = layers.Conv2D(128, 1, strides=2, padding='same')(x)
y = layers.add([y, x]) # 将原始x与输出特征相加

1.5 共享层权重

函数式 API 能够多次、重复使用一个层的实例

如果对一个层实例多次调用,每次调用可以重复使用相同的权重。因此可以构建具有共享分支的模型,即几个分支都共享相同的知识并执行相同的运算。

实例:使用一个 LSTM层处理两个输入,将其称为 连体 LSTM ,或 共享 LSTM 模型。代码如下:

from keras import layers
from keras import Input
from keras.models import Model

# 实例化一个LSTM层
lstm = layers.LSTM(32)

# 构建模型的左分支
left_input = Input(shape=(None, 128))
left_output = lstm(left_input)

# 构建模型的右分支
# 如果调用已有层实例,会重复使用它的权重
right_input = Input(shape=(None, 128))
right_output = lstm(right_input)

# 构建一个分类器
merged = layers.concatenate([left_output, right_output], axis=-1)
predictions = layers.Dense(1, activation='sigmoid')(merged)

# 模型实例化并训练
# 基于两个输入对LSTM层的权重进行更新
model = Model([left_input, right_input], predictions)
model.fit([left_data, right_data], targets)

1.6 将模型作为层

在函数式 API 中,可以像层一样使用模型,将模型看作更大的层。

也就是说,可以在一个输入张量上调用模型,并得到一个输出张量:

y = model(x)

如果模型具有多个输入张量和输出张量,那么应该使用张量列表

y1, y2 = model([x1, x2])

在调用模型实例时,就是在重复使用模型的权重,重复使用模型实例学到的表示。

2 使用 Keras 回调函数 和 TensorBoard 检查并监控深度学习模型

2.1 训练过程中将回调函数作用于模型

1. 回调函数

在调用 fit 时传入模型的一个对象(实现特定方法的类实例),它在训练过程中的不同时间点都会被模型调用。

它可以访问关于模型状态与性能的所有可用数据,还可以采取行动:中断训练、保存模型、加载一组不同的权重或改变模型的状态。

2. 回调函数的用法示例

  • 模型检查点(model checkpointing) ,在训练过程中的不同时间点保存模型的当前权重;
  • 提前终止 (early stopping),如果验证损失不再改善,则中断训练(同时保存训练过程中得到的最佳模型);
  • 在训练过程中动态调节某些参数值,比如优化器的学习率;
  • 在训练过程中记录训练指标和验证指标,或将模型学到的表示可视化,比如 Keras 进度条就是一个回调函数。

3. Keras.callbacks 模块包含的回调函数

  • keras.callbacks.ModelCheckpoint
  • keras.callbacks.EarlyStopping
  • keras.callbacks.LearningRateScheduler
  • keras.callbacks.ReduceLROnPlateau
  • keras.callbacks.CSVLogger

4. ModelCheckpoint 与 EarlyStopping 回调函数

如果监控的目标指标在设定的轮数内不再改善,可以用 EarlyStopping 回调函数中断训练。

比如,这个函数可以在刚开始过拟合的时候就中断训练,它通常与 ModelCheckpoint 结合使用,后者可以在训练过程中持续保存模型,也可以选择只保存目前的最佳模型。

import keras 

# 通过fit的callbacks参数将回调函数传入模型
# 这个参数接收一个回调函数列表


callbacks_list = [
    # 如果不再改善,就中断训练
    keras.callbacks.EarlyStopping(
        monitor='acc', # 监控模型的验证精度
        # 如果精度在多于一轮(2轮)的时间内不再改善,中断训练
        patience=1,
    ),
    # 在每轮过后保存当前权重
    keras.callbacks.ModelCheckpoint(
        filepath='my_model.h5', # 目标模型文件的保存路径
        # 如果val_loss没有改善,那么不需要覆盖模型文件
        # 可以始终保存在训练过程中的最佳模型
        monitor='val_loss', 
        save_best_only=True,
    )
]

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc']) # 监控精度,所以它应该是模型指标的一部分

# 由于回调函数要监控验证损失和验证精度
# 所以在调用fit时需要传入验证数据
model.fit(x, y,
          epochs=10,
          batch_size=32,
          callbacks=callbacks_list,
          validation_data=(x_val, y_val))

5. ReduceLROnPlateau 回调函数

如果验证损失不再改善,可以使用这个函数来降低学习率 。在训练过程中出现了 损失平台,那么增大或减小学习率都是跳出局部最小值的有效策略。

callbacks_list = [
    keras.callbacks.ReduceLROnPlateau(
        monitor='val_loss',
        factor=0.1, # 触发时将学习率除以10
        # 如果验证损失在10轮内都没有改善,那么就触发这个回调函数
        patience=10, 
    )
]

model.fit(x, y,
          epochs=10,
          batch_size=32,
          callbacks=callbacks_list,
          validation_data=(x_val, y_val)
         )

6. 编写自己的回调函数

(1)如果需要在训练过程中采取特定行动, 而这项行动没有包含在内置回调函数中,那么可以编写自己的回调函数。

(2)回调函数的实现方式

  • 创建 keras.callbacks.Callback 类的子类

  • 然后实现下列方法,分别在训练过程中的不同时间点被调用。

    • on_epoch_begin # 在每轮开始时被调用
    • on_epoch_end # 在每轮结束时被调用
    • on_batch_begin # 在处理每个批量之前被调用
    • on_batch_end # 在处理每个批量之后被调用
    • on_train_begin # 在训练开始时被调用
    • on_train_end # 在训练结束时被调用
  • 这些方法被调用时都有一个 logs 参数,它是一个字典,里面包含前一个批量、前一个轮次或前一次训练的信息,即训练指标和验证指标等。

(3)回调函数还可以访问以下属性

  • self.model : 调用回调函数的模型实例;
  • self.validation_data :传入 fit 作为验证数据的值。

(4)自定义回调函数的简单示例

在每轮结束后将模型每层的激活保存在硬盘(格式为 Numpy 数组),这个激活是对验证集的第一个样本计算得到的。

import keras
import numpy as np

class ActivationLogger(keras.callback.Callback):
    
    def set_model(self, model):
        # 在训练之前由父模型调用,告诉回调函数是哪个模型在调用它
        self.model = model
        layer_outputs = [layer.output for layer in model.layers]
        # 模型实例,返回每层的激活
        self.activations_model = keras.models.Model(model.input, layer_outputs)
        
    def on_epoch_end(self, epoch, logs=None):
        if self.validation_data is None:
            raise RuntimeError('Requires validation_data. ')
        # 获取验证数据的第一个输入样本 
        validation_sample =self.validation_data[0][0:1]
        activations = self.activations_model.predict(validation_sample)
        # 将数组保存到硬盘
        f = open('activations_at_epoch_' + str(epoch) + '.npz', 'w')
        np.savez(f, activations)
        f.close()

2.2 TensorBoard 简介:TensorFlow 的可视化框架

1. TensorBoard

内置于 TensorFlow 中的基于浏览器的可视化工具。 只有当 Keras 使用 TensorFlow 后端时,这一方法才能用于 Keras 模型。

功能

  • 在训练过程中以可视化的方式监控指标;
  • 将模型架构可视化;
  • 将激活和梯度的直方图可视化;
  • 以三维的形式研究潜入

2. 实例:在 IMDB 情感分析任务上训练一个一维卷积神经网络

只考虑 IMDB 词表中的前 2000 个单词,更易于将词嵌入可视化。

(1) 使用了 TensorBoard 的文本分类模型

import keras 
from keras import layers
from keras.datasets import imdb
from keras.preprocessing import sequence

max_features = 2000 # 作为特征的单词个数
max_len = 500 # 之后的单词都被截断

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
x_train = sequence.pad_sequences(x_train, maxlen=max_len)
x_test = sequence.pad_sequences(x_test, maxlen=max_len)

model = keras.models.Sequential()
model.add(layers.Embedding(max_features, 128,
                           input_length=max_len,
                           name='embed'))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])

(2)为 TensorBoard 日志文件创建一个目录

mkdir my_log_dir

(3)使用一个 TensorBoard 回调函数训练模型

该函数会将日志事件写入硬盘的指定位置。

callbacks = [
    keras.callbacks.TensorBoard(
        log_dir='my_log_dir', # 日志文件将写入这个位置
        histogram_freq=1, # 每一轮之后将记录激活直方图
        embeddings_freq=1, # 每一轮之后记录嵌入数据
    )
]
history = model.fit(x_train, y_train,
                    epochs=20,
                    batch_size=128,
                    validation_split=0.2,
                    callbacks=callbacks)

(4)命令行启动 TensorBoard 服务器

tensorboard --logdir=my_log_dir

(5)查看模型训练过程

浏览器打开 http://localhost:6006。

训练指标验证指标的实时图表;

在这里插入图片描述

②访问 HISTOGRAMS(直方图)标签页,查看美观的直方图可视化,直方图中是每层的激活值。

在这里插入图片描述

③访问 GRAPHS(图)标签页,显示 Keras 模型背后的底层TensorFlow 运算图的交互式可视化。图的内容比想象的多很多,因为在底层需要构建相当复杂的图结构才可能生效。 Keras 让工作流程变简单了。

在这里插入图片描述

④ Keras 中提供了一种简洁的方法—— keras.utils.plot_model 函数,将模型绘制为层组成的图。

from keras.utils import plot_model
plot_model(model, to_file='model.png')

在这里插入图片描述

也可以选择在层组成的图中显示形状信息,使用 plot_model 函数以及 show_shapes 选项将模型拓扑结构可视化。

from keras.utils import plot_model
plot_model(model, show_shapes=True, to_file='model.png')

在这里插入图片描述

3 让模型性能发挥到极致

3.1 高级架构模式

1. 批标准化

批标准化,即 batch normalization,在 keras 中是 BatchNormalization ,在训练过程中均值和方差随时间发生变化,也可以将数据标准化。

  • 工作原理
    训练过程中在内部保存已读取每批数据均值和方差的指数移动平均值

  • 作用
    有助于梯度传播,允许更深的网络。

BatchNormalization 层通常在 卷积层密集连接层 之后使用。

BatchNormalization 层接受一个 axis 参数,指定应该对哪个特征轴做标准化,默认值是 -1 ,即输入张量的最后一个轴(一般指通道),如果通道不是最后一个参数,那么应该修改 axis 参数。

2. 深度可分离卷积

  • 这个层对输入的每个通道分别执行空间卷积,然后通过逐点卷积(1 * 1 卷积)将输出通道混合,相当于将空间特征学习和通道特征学习分开。

  • 作用:适用于输入中的空间位置高度相关、但不同通道之间相对独立的情况。需要的参数更少,计算量也更小,可以得到更小、更快的模型。能够使用更少的数据学到更好的表示,得到性能更好的模型。

在这里插入图片描述

3.2 超参数优化

  • 超参数 :在架构层面的参数。

  • 确定超参数的方法

    • 随机搜索(随机搜索需要评估的超参数,并重复这一过程);
    • Hyperot,一个用于超参数优化的 Python 库,内部使用 Parzen 估计器的树来预测。
    • Hyperas ,一个将 Hyperot 与 Keras 模型集成的库。
  • 在进行超参数优化时,要注意 验证集过拟合,因为是使用验证数据计算出一个信号,然后根据这个信号更新超参数,所以实际上是在验证数据上训练超参数,很快就会对验证数据过拟合。

3.3 模型集成

  • 模型集成 :指将一系列不同模型的预测结果汇集到一起,得到更好的预测结果。

  • 实例:分类器集成
    可以对每个分类器的预测结果使用加权平均,其权重在验证数据上学习到。为了找到好的集成权重,可以使用 随机搜索 或 简单的优化算法。

  • 集成方法想要有效,需要分类器具有多样性
    如果各个模型的偏差在不同方向上,那么这些偏差会彼此抵消,集成结果也会更加稳定和准确。

  • 模型集成的优秀实践基于树的方法 (随机森林或梯度提升树)和 深度神经网络 集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Lilishop商城】No3-4.模块详细设计,店铺店员(店铺店员、店铺部门、店铺角色)的详细设计

仅涉及后端,全部目录看顶部专栏,代码、文档、接口路径在: 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑,其中重点包括接口类、业务类,具体的结合源代码…

exfat文件系统

DBR: DBR偏移量 字段长度(字节) 说明 0x40 - 0x47 8 分区的起始扇区号(隐藏扇区数) 0x48 - 0x4F 8 分区总扇区数 0x50 - 0x53 4 FAT表起始扇区号(从DBR到FAT表的扇区个数) 0x54 - 0x57 4…

【Redis】持久化操作

一、RDB(Redis Database) 1、持久化 redis一般是将数据写到内存中,但也可以将数据写到磁盘中,这个过程称之为持久化 2、什么是RDB 在指定的时间间隔内将内存中的数据集快照写入磁盘中 3、RDB是如何执行备份操作的 redis会单独创建(fork)一个子进程进行…

FPGA 20个例程篇:18.SD卡存放音频WAV播放(下)

第七章 实战项目提升,完善简历 18.SD卡存放音频WAV播放(下) 进一步地我们再结合图1的示意图来分析wav_play模块的时序逻辑设计,大家可以清楚地看到WM8731在Right justified和主从时钟模式下,是先发左声道后发右声道数…

【LeetCode】专题一 二叉树层序遍历

二叉树层序遍历 在本文中,我将会选取LeetCode上二叉树层序遍历的多道例题,并给出解答,通过多道题我们就可以发现,二叉树的层序遍历并不复杂,并且有着共通点。 102. 二叉树的层序遍历 给你二叉树的根节点 root &…

【Labivew】简易计算器

🚩write in front🚩 🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 🏅2021年度博客之星物联网与嵌入式开发TOP5&#xff5…

Secure CRT远程连接很快断线问题

问题描述 我们使用Secure CRT连接远程主机时可能会遇到几分钟没操作就无法操作了,需要断开重新连接,非常的麻烦,假如客户端或者服务端能够在快要超时的时候给对方发送一个心跳,得到对方响应就重置下超时时间,这样就能…

arm架构 --- 中断

ARM的异常 终止程序的正常执行过程而不得不去完成的一些特殊工作 中断是异常的一种,包括外部硬件产生的异常和芯片内部硬件产生的内部中断。 ARM有七种处理器模式,其中用户模式和系统模式之外的5钟处理器模式叫做异常模式,用户模式之外的6…

osgEarth示例分析——osgearth_terrainprofile

前言 osgearth_terrainprofile示例,涉及到一个新的类 TerrainProfileCalculator(地形轮廓计算器类),用来计算两个点连线之间的地形数据。左下角会根据点击的起点和终点进行计算,并更新显示地形信息。 效果 拖动地球,到某一个视…

[附源码]Python计算机毕业设计SSM基于的智慧校园安防综合管理系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

软件安全测试-Web安全测试详解-XSS攻击

目录 1. XSS攻击 1.1 XSS攻击原理 1.2 XSS能做什么 1.3 XSS三种类型 1.4 XSS三种途径 1.5 XSS测试方法 1.5.1 查看代码 1.5.2 准备测试脚本 1.5.3 自动化测试XSS漏洞 1.5.4 XSS注入常用语句 1.6 XSS漏洞防范h3 1.6.1 对输入和URL参数进行过滤(白名单和黑名单) 1.6.…

tensorflow入门(一) 计算图、张量、会话的概念

1、计算图 计算图是tensorflow中最基本的一个概念,tensorflow中的所有计算都被转化成计算图上的节点。tensorflow的名字已经说明了它最重要的两个概念------tensor和flow。张量这个概念在数学或者物理学中可以有不同的解释,在tensorflow中,张…

基于tensorflow的深层神经网络(三)如何用tensorflow优化神经网络

1、神经网络优化算法 梯度下降算法主要用户优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法,从而使神经网络模型在训练数据上的损失函数尽可能小。反向传播算法是训练神经网络的核心算法,它可以根据定义…

红黑树的插入过程

一棵红黑树是一种特殊的二叉查找树,具有以下性质: 每个节点要么是红色,要么是黑色。根节点是黑色。每个叶子节点(NIL)是黑色。如果一个节点是红色的,那么它的两个儿子都是黑色的。从任意一个节点到其每个叶…

71.qt quick-可伸展菜单-抽屉栏示例 通用QML界面(一键换肤)

在我们之前章节已经提供过了抽屉栏和菜单伸展栏: 63.qt quick-QML侧边滑动栏(不需要任何图片资源,支持自定义左右方向和大小)_诺谦的博客-CSDN博客_qml侧边栏68.qt quick-qml多级折叠下拉导航菜单 支持动态添加/卸载 支持qml/widget加载等_诺谦的博客-CSDN博客_qml下拉菜单 由…

三维家发生工商变更:注册资本减少46%,美凯龙、阿里等股东退出

近日,云工业软件服务商广东三维家信息科技有限公司(下称“三维家”)发生工商变更,注册资本由16.9254亿元变更为9亿元,同比减少46.83%。同时,包括红星美凯龙、阿里巴巴等多名股东退出,变更时间为…

01.Spring源码整体脉络介绍及源码编译——四

IOC是核心 IOC 容器加载过程【重要】:所有模块都依赖IOC,aop,循环依赖都依赖IOC IOC控制反转,控制理念,来解决层与层之间的耦合。DI注入实现 怎么讲Bean交给IOC容器来管理 配置类xml,注解 加载spring上下…

java计算机毕业设计ssm学院校友信息管理系统的设计与实现5yqhy(附源码、数据库)

java计算机毕业设计ssm学院校友信息管理系统的设计与实现5yqhy(附源码、数据库) 项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts…

【Java基础篇】基础知识易错集锦(二)

我们同样用几道例题来回顾相对应的基础知识; 解析: 首先我呢区分一下实例变量和局部变量; 局部变量:定义在方法内部的变量;实例变量:定义在类中但在任何方法之外,你也可以理解为全局变量&…

16.C预处理器和C库

文章目录C预处理器和C库16.1翻译程序的第一步16.2明示常量:#define16.3在#define中使用参数16.3.1用宏参数创建字符串:#运算符16.3.2预处理器黏合剂:##运算符16.3.3变参宏:...和__VA_ARGS__16.4宏和函数的选择16.5文件包含&#x…