深度学习(6)--Keras项目详解

news2024/9/25 11:19:44

目录

一.项目介绍

二.项目流程详解

2.1.导入所需要的工具包

2.2.输入参数

2.3.获取图像路径并遍历读取数据

2.4.数据集的切分和标签转换 

2.5.网络模型构建

2.6.绘制结果曲线并将结果保存到本地

三.完整代码

四.首次运行结果

五.学习率对结果的影响

六.Dropout操作对结果的影响

七.权重初始化对结果的影响

7.1.RandomNormal

7.2.TruncatedNormal(推荐)

八.正则化对结果的影响

九.加载模型进行测试


一.项目介绍

用Keras工具包搭建训练自己的一个传统神经网络,用来识别猫/狗/羊三种图片。

数据集:

二.项目流程详解

2.1.导入所需要的工具包

# 导入所需要的工具包
# 将建模的结果画出来
import matplotlib
# 做标签,数据切分,展示结果的对比
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# keras工具包的操作
from keras.models import Sequential
from keras.layers import Dropout
# from keras.layers.core import Dense
from tensorflow.python.keras.layers.core import Dense
from keras.optimizers import SGD
from keras import initializers
from keras import regularizers
# 图像路径处理操作
from my_utlis import utlis_paths
# 一些基本库
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os

os.environ["CUDA_VISIBLE_DEVICES"] = "0"

(1).如果只安装了keras工具包没安装cv2库,可以参考以下链接在Anaconda的虚拟环境中安装cv2库。

https://blog.csdn.net/u011204487/article/details/86497431icon-default.png?t=N7T8https://blog.csdn.net/u011204487/article/details/86497431

(2).如果 from keras.layers.core import Dense 显示此结果

可以将导入代码改为如下方式

from tensorflow.python.keras.layers.core import Dense

(3).在代码开头加入os.environ["CUDA_VISIBLE_DEVICES"] = "0"这行代码可以用gpu训练网络,“0”为可以使用的gpu编号,可以在cmd中输入nvidia -smi查询可用的gpu编号:

2.2.输入参数

# --dataset --model --label-bin --plot
# 输入参数
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
                help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,
                help="path to output trained model")
ap.add_argument("-L", "--Label-bin", required=True,
                help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,
                help="path to output accuracy/loss plot")
args = vars(ap.parse_args())

设置参数

右键项目点击修改运行配置

设置参数的值

设置好参数后在对应处创建文件夹

2.3.获取图像路径并遍历读取数据

# 获取图像数据路径,方便后续读取
imagePaths = sorted(list(utlis_paths.list_images('./dataset')))
random.seed(42)
random.shuffle(imagePaths)

# 遍历读取数据
for imagePath in imagePaths:
    # 读取图像数据,后续步骤中使用了神经网络,需要将图像数据设置成一维
    image = cv2.imread(imagePath)  # cv2.imread方法读取数据
    image = cv2.resize(image, (32, 32)).flatten()  # 将读取的图片数据设置成相同的大小
    data.append(image)

    # 读取标签
    label = imagePath.split(os.path.sep)[-2]
    labels.append(label)

# scale图像数据
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)

调用utlis_paths.list_images,获取路径的文件

通过from my_utlis import utlis_paths引入utlis_paths,所以需要在my_utlis文件夹中生成一个utlis_paths文件并在其中完成相应的函数定义:

import os


image_types = (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")


def list_images(basePath, contains=None):
    # 返回有效的图片路径数据集
    return list_files(basePath, validExts=image_types, contains=contains)


def list_files(basePath, validExts=None, contains=None):
    # 遍历图片数据目录,生成每张图片的路径
    for (rootDir, dirNames, filenames) in os.walk(basePath):
        # 循环遍历当前目录中的文件名
        for filename in filenames:
            # if the contains string is not none and the filename does not contain
            # the supplied string, then ignore the file
            if contains is not None and filename.find(contains) == -1:
                continue

            # 通过确定.的位置,从而确定当前文件的文件扩展名
            ext = filename[filename.rfind("."):].lower()

            # 检查文件是否为图像,是否应进行处理
            if validExts is None or ext.endswith(validExts):
                # 构造图像路径
                imagePath = os.path.join(rootDir, filename)
                yield imagePath

指定一个随机种子,确保每次的切割相同,同时将数据洗牌,打乱数据 

random.seed(42)  # 指定随机种子
random.shuffle(imagePaths)  # 把数据重新洗牌,即将数据打乱

读取数据,并将所有的数据设置为统一规格

image = cv2.imread(imagePath)  # cv2.imread方法读取数据
image = cv2.resize(image, (32, 32)).flatten()  # 将读取的图片数据设置成相同的大小
data.append(image)  # append()函数向列表末尾添加一个元素

flatten()函数将图片参数拉长。

eg.32x32x3大小的图片,拉长为3072个像素点,即变为1x3072的矩阵

给读取出来的数据设置标签(读取数据和设置标签一般放在一起)

label = imagePath.split(os.path.sep)[-2]
labels.append(label)

scale归一化获得的图片数据,使得特征值在0~1之间浮动

# scale图像数据
data = np.array(data, dtype="float") / 255.0

2.4.数据集的切分和标签转换 

# 数据集切分
(trainX, testX, trainY, testY) = train_test_split(data, 
                         labels, test_size=0.25, random_state=42)

# 转换标签,one-hot格式
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)

划分训练集和测试集:

(trainX, testX, trainY, testY) = train_test_split(data, 
                         labels, test_size=0.25, random_state=42)

函数原型:

X_train, X_test, y_train, y_test = train_test_split(train_data, train_target, test_size, random_state, shuffle)

变量:
X_train:划分的训练集数据
X_test:划分的测试集数据
y_train:划分的训练集标签
y_test:划分的测试集标签
参数:
train_data:还未划分的数据集
train_target:还未划分的标签
test_size:分割比例,默认为0.25,即测试集占完整数据集的比例
random_state:随机数种子,应用于分割前对数据的洗牌。可以是int,RandomState实例或None,默认值=None。设成定值意味着,对于同一个数据集,只有第一次运行是随机的,随后多次分割只要rondom_state相同,则划分结果也相同。
shuffle:是否在分割前对完整数据进行洗牌(打乱),默认为True,打乱

转换标签:

lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)

最后得到的结果是对应三个动物种类狗、猫、羊的概率值,所以就应当有三个标签,需要对当前的标签进行转换,转换为满足要求的one-hot标签格式。

2.5.网络模型构建

# 网络模型结构 3072-512-256-3
model = Sequential()
# kernel_regularizer=regularizers.12(0.01)
# keras.initializers.TruncatedNormal(mean=0.0, stddex=0.05, seed=None)
# initializers.random_normal
# #model.add(Dropout(0.8))
model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu"))
model.add(Dense(256, activation="relu"))
model.add(Dense(len(lb.classes_), activation="softmax",))

# 初始化参数
INIT_LR = 0.01
EPOCHS = 200

# 给定损失函数和评估方法
print("[INFO] 准备训练网络...")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
              metrics=["accuracy"])

# 训练网络模型
H = model.fit(trainX, trainY, validation_data=(testX,testY),
              epochs=EPOCHS, batch_size=32)

# 测试网络模型
print("[INFO] 正在评估模型")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
      predictions.argmax(axis=1), target_names=lb.classes_))

该网络模型的共有三层,初始特征值有3072个,由3072-512-256-3,最后得到对应三个图像类别的概率值。

设置模型的类型为Sequential :

model = Sequential()

对于Sequential模型的相关信息,可以查询下述keras的官方网站:

https://keras.io/guides/sequential_model/icon-default.png?t=N7T8https://keras.io/guides/sequential_model/

向神经网络中添加三层:

第一层:

model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu"))

首先第一层一般要通过Input(n,)函数告诉网络起始层有多少个神经元,然后512表示的是转换为下一层的神经元为512个,激活函数设置的是relu。

第二层:

model.add(Dense(256, activation="relu"))

经过这一层得到的下一层的神经元应当有256个,同时激活函数设置的为relu。

第三层:

model.add(Dense(len(lb.classes_), activation="softmax",))

经过这一层得到下一层的神经元个数为len(lb.classes_)的返回值,此处为3,同时激活函数为softmax,最后得到对应的不同类别的概率值。

初始化参数:

INIT_LR = 0.01
EPOCHS = 200

INIT_LR为学习率,EPOCHS为遍历整个数据集的次数

设置损失函数和评估方法:

opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
              metrics=["accuracy"])

SGD为随机梯度下降,将opt优化器设置为随机梯度下降,同时将学习率告诉SGD。

选择的损失函数为categorical_crossentropy,即为交叉熵损失函数 。

最后再获取accuracy准确率

训练网络模型:

H = model.fit(trainX, trainY, validation_data=(testX,testY),
              epochs=EPOCHS, batch_size=32)

测试网络模型:

print("[INFO] 正在评估模型")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
      predictions.argmax(axis=1), target_names=lb.classes_)))

2.6.绘制结果曲线并将结果保存到本地

# 调试完成后,绘制结果曲线
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["acc"], label="train_acc")
plt.plot(N, H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig('./output/simple_nn_plot.png')   # 参数为保存的路径

# 保存模型到本地
print("[INFO] 正在保存模型")
model.save(args["model"])
f = open('./output/simple_nn_lb.pickle', "wb")  # 保存标签数据
f.write(pickle.dumps(lb))
f.close()

对于acc参数,不同版本的keras对应的写法不同,如果引入acc和val_acc报错,可以尝试改为accuracy和val_accuracy,反之亦然。

三.完整代码

项目结构:

nn_train.py:

# 导入所需要的工具包
# 将建模的结果画出来
import keras
import matplotlib
# 做标签,数据切分,展示结果的对比
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# keras工具包的操作
from keras.models import Sequential
from keras.layers import Dropout
# from keras.layers.core import Dense
from tensorflow.python.keras.layers.core import Dense
from keras.optimizers import SGD
from keras import initializers
from keras import regularizers
# 图像路径处理操作
from my_utlis import utlis_paths
# 一些基本库
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os

# --dataset --model --label-bin --plot
# 输入参数
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
                help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,
                help="path to output trained model")
ap.add_argument("-L", "--Label-bin", required=True,
                help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,
                help="path to output accuracy/loss plot")
args = vars(ap.parse_args())


print("[INFO] 开始读取数据")
data = []
labels = []

# 获取图像数据路径,方便后续读取
imagePaths = sorted(list(utlis_paths.list_images('./dataset')))
random.seed(42)  # 指定随机种子
random.shuffle(imagePaths)  # 把数据重新洗牌,即将数据打乱

# 遍历读取数据
for imagePath in imagePaths:
    # 读取图像数据,后续步骤中使用了神经网络,需要将图像数据设置成一维
    image = cv2.imread(imagePath)  # cv2.imread方法读取数据
    image = cv2.resize(image, (32, 32)).flatten()  # 将读取的图片数据设置成相同的大小
    data.append(image)

    # 读取标签
    label = imagePath.split(os.path.sep)[-2]
    labels.append(label)

# scale图像数据
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)

# 数据集切分
(trainX, testX, trainY, testY) = train_test_split(data,
                         labels, test_size=0.25, random_state=42)

# 转换标签,one-hot格式
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)

# 网络模型结构 3072-512-256-3
model = Sequential()
# kernel_regularizer=regularizers.12(0.01)
# keras.initializers.TruncatedNormal(mean=0.0, stddex=0.05, seed=None)
# initializers.random_normal
# #model.add(Dropout(0.8))
model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu"))
model.add(Dense(256, activation="relu"))
model.add(Dense(len(lb.classes_), activation="softmax",))

# 初始化参数
INIT_LR = 0.01
EPOCHS = 200

# 给定损失函数和评估方法
print("[INFO] 准备训练网络...")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
              metrics=["accuracy"])

# 训练网络模型
H = model.fit(trainX, trainY, validation_data=(testX,testY),
              epochs=EPOCHS, batch_size=32)

# 测试网络模型
print("[INFO] 正在评估模型")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
      predictions.argmax(axis=1), target_names=lb.classes_))

# 调试完成后,绘制结果曲线
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig('./output/simple_nn_plot.png')   # 参数为保存的路径

# 保存模型到本地
print("[INFO] 正在保存模型")
model.save(args["model"])
f = open('./output/simple_nn_lb.pickle', "wb")  # 保存标签数据
f.write(pickle.dumps(lb))
f.close()

utlis_paths.py:

import os


image_types = (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")


def list_images(basePath, contains=None):
    # 返回有效的图片路径数据集
    return list_files(basePath, validExts=image_types, contains=contains)


def list_files(basePath, validExts=None, contains=None):
    # 遍历图片数据目录,生成每张图片的路径
    for (rootDir, dirNames, filenames) in os.walk(basePath):
        # 循环遍历当前目录中的文件名
        for filename in filenames:
            # if the contains string is not none and the filename does not contain
            # the supplied string, then ignore the file
            if contains is not None and filename.find(contains) == -1:
                continue

            # 通过确定.的位置,从而确定当前文件的文件扩展名
            ext = filename[filename.rfind("."):].lower()

            # 检查文件是否为图像,是否应进行处理
            if validExts is None or ext.endswith(validExts):
                # 构造图像路径
                imagePath = os.path.join(rootDir, filename)
                yield imagePath

四.首次运行结果

相关参数介绍参考文章:

https://blog.csdn.net/weixin_48964486/article/details/122881350

在训练集上的accuracy为1.0,与测试集上的accuracy差距过大,可能出现过拟合现象。

五.学习率对结果的影响

初始学习率为0.01(学习率过大可能产生过拟合现象)

将学习率改为0.001:

# 初始化参数
INIT_LR = 0.001
EPOCHS = 200

训练结果:

仍有过拟合现象,但是相较于学习率lr=0.01的情况略有改善。

六.Dropout操作对结果的影响

The Dropout layer randomly sets input units to 0 with a frequency of rate at each step during training time, which helps prevent overfitting

Dropout layer (keras.io)icon-default.png?t=N7T8https://keras.io/api/layers/regularization_layers/dropout/

添加Drop-out操作:

一般添加在全连接层中

from keras.layers import Dropout

model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu"))
model.add(Dropout(0.5))
model.add(Dense(256, activation="relu"))
model.add(Dropout(0.5))
model.add(Dense(len(lb.classes_), activation="softmax",))

Dropout=0.5,LR=0.001的训练结果:

从结果可以看出,添加Dropout层可以有效避免过拟合现象的出现。

七.权重初始化对结果的影响

查询不同的初始化方法:

Layer weight initializers (keras.io)icon-default.png?t=N7T8https://keras.io/api/layers/initializers/查看全连接层的参数设置发现,如果不初始化kernel_initializer,起默认的参数为'glorot_uniform',即正态分布初始化,常常不能满足训练的要求。

7.1.RandomNormal

将kernel_initializer设置为‘RandomNormal’,即高斯正太分布:

from keras import initializers

model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu", kernel_initializer=keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)))
# model.add(Dropout(0.5))
model.add(Dense(256, activation="relu", kernel_initializer=keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)))
# model.add(Dropout(0.5))
model.add(Dense(len(lb.classes_), activation="softmax", kernel_initializer=keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)))

其中mean为均值,stddev为标准差。

正太高斯分布初始化,不使用Dropout层,LR=0.001的训练结果:

7.2.TruncatedNormal(推荐)

将kernel_initializer设置为‘TruncatedNormal’,即截断正太分布:

model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)))
# model.add(Dropout(0.5))
model.add(Dense(256, activation="relu", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)))
# model.add(Dropout(0.5))
model.add(Dense(len(lb.classes_), activation="softmax", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)))

其中mean为均值,stddev为标准差。

截断正太分布初始化,不使用Dropout层,LR=0.001的训练结果:

在此基础上再加上Dropout层的结果:

八.正则化对结果的影响

Regularizers allow you to apply penalties on layer parameters or layer activity during optimization. These penalties are summed into the loss function that the network optimizes.

Layer weight regularizers (keras.io)icon-default.png?t=N7T8https://keras.io/api/layers/regularizers/

 在全连接层添加正则化:

from keras import regularizers

model.add(keras.Input(shape=(3072,)))
model.add(Dense(512, activation="relu", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None), kernel_regularizer=regularizers.L2(0.01)))
model.add(Dropout(0.5))
model.add(Dense(256, activation="relu", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None), kernel_regularizer=regularizers.L2(0.01)))
model.add(Dropout(0.5))
model.add(Dense(len(lb.classes_), activation="softmax", kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None), kernel_regularizer=regularizers.L2(0.01)))

有两种正则化方法,L1为取绝对值,L2是求权重的欧几里得范数(常用L2),括号里的参数为惩罚力度\lambda(越大的惩罚力度,过拟合的风险越低)。

惩罚力度为0.01正则化,截断正态分布初始化,加入Dropout=0.5,LR=0.001的训练结果:

惩罚力度为0.1正则化,截断正态分布初始化,加入Dropout=0.5,LR=0.001的训练结果:

九.加载模型进行测试

保存模型到本地:

保存的模型:惩罚力度为0.1正则化,截断正态分布初始化,加入Dropout=0.5,LR=0.001,EPOCHS=1000.

# 保存模型到本地
print("[INFO] 正在保存模型")
model.save(args["model"])
f = open('./output/simple_nn_lb.pickle', "wb")  # 保存标签数据
f.write(pickle.dumps(lb))
f.close()

 

编写一个predict.py程序来加载模型进行测试:

# 导入所需工具包
from keras.models import load_model
import argparse
import pickle
import cv2


# 加载测试数据并进行相同预处理操作
image = cv2.imread('./cs_image/dog.jpeg')  # 读取一张图片进行测试 dog/cat/sheet
output = image.copy()  # 复制图片的一份副本给output
image = cv2.resize(image, (32, 32))

# scale图像数据
image = image.astype("float") / 255.0

# 对图像进行拉平操作
image = image.flatten()
image = image.reshape((1, image.shape[0]))

# 读取模型和标签
print("------读取模型和标签------")
model = load_model('./output/simple_nn.model')  # 设置模型
lb = pickle.loads(open('./output/simple_nn_lb.pickle', "rb").read())  # 设置标签

# 预测
preds = model.predict(image)

# 得到预测结果以及其对应的标签
i = preds.argmax(axis=1)[0]
label = lb.classes_[i]

# 在图像中把结果画出来
text = "{}: {:.2f}%".format(label, preds[0][i] * 100)
cv2.putText(output, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(0, 0, 255), 2)

# 绘图
cv2.imshow("Image", output)
cv2.waitKey(0)

若出现下述报错

error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support.

在对应的虚拟环境中安装OpenCV的拓展开发包即可解决

pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple/

测试的结果:

发现对于猫的预测结果不准确,对于图片的预测,一般会用到卷积神经网络而不是本项目中构建的传统神经网络。

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

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

相关文章

N-141基于springboot,vue网上拍卖平台

开发工具:IDEA 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 系统分前后台,项目采用前后端分离 前端技术:vueelementUI 服务端技术:springbootmybatis-plusredi…

一张图区分Spring Task的3种模式

是的,只有一张图: fixedDelay 模式cron 模式fixedRate 模式

2024/1/28周报

文章目录 摘要Abstract文献阅读题目引言方法The ARIMA modelTime delay neural network (TDNN) modelLSTM and DLSTM model 评估准则实验数据描述实验结果 深度学习AttentionAttention思想公式步骤 Attention代码实现注意力机制seq2seq解码器Model验证 总结 摘要 本周阅读了一…

腾讯云幻兽帕鲁4核16G/8核32G/16核64G服务器配置价格表

腾讯云幻兽帕鲁服务器4核16G、8核32G和16核64G配置可选,4核16G14M带宽66元一个月、277元3个月,8核32G22M配置115元1个月、345元3个月,16核64G35M配置580元年1个月、1740元3个月、6960元一年,腾讯云百科txybk.com分享腾讯云幻兽帕鲁…

uniapp组件库fullScreen 压窗屏的适用方法

目录 #平台差异说明 #基本使用 #触发压窗屏 #定义压窗屏内容 #注意事项 所谓压窗屏,是指遮罩能盖住原生导航栏和底部tabbar栏的弹窗,一般用于在APP端弹出升级应用弹框,或者其他需要增强型弹窗的场景。 警告 由于uni-app的Bug&#xff0…

深度强化学习(王树森)笔记04

深度强化学习(DRL) 本文是学习笔记,如有侵权,请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接:https://github.com/wangshusen/DRL 源代码链接:https://github.c…

探索IOC和DI:解密Spring框架中的依赖注入魔法

IOC与DI的详细解析 IOC详解1 bean的声明2 组件扫描 DI详解 IOC详解 1 bean的声明 IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。 要把某个对象交给IOC容器管理,需要在类上…

基于springboot+vue的在线教育系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

如何看待程序员抄代码还拿着高薪这一说法?

程序员的工资构成:会复制粘贴值1块,知道去哪复制值5K,知道粘贴在哪值10K,粘贴完了能跑起来值15 有人说:能带领一伙人复制粘贴值20k。 有人说:能写一个自动复制粘贴的系统值30k。 有人纳闷问到&#xff1a…

兄弟DCP-7057黑白激光多功能一体机加粉后清零方法

硒鼓加粉机器上清零,方法如下: 打开安装硒鼓的前盖。按“清除”键,显示“更换硒鼓”。不用管提示,接着按“启用Start”,再按“”,屏幕上显示“01”。继续按“”,直到屏幕上显示“11”。按“OK”…

【C/C++】C/C++编程——变量和常量

文章目录 变量变量的声明变量命名规则变量的类型 常量常量的定义与初始化字面量常量整型常量浮点型常量字符常量常量表达式(constexpr) 大家好,我是 shopeeai,也可以叫我虾皮,中科大菜鸟研究生。今天我们来一起来学习C…

软考之项目管理

一、考点分布 盈亏平衡分析(※)进度管理(※※※)软件质量管理(※※)软件配置管理(※※) 二、盈亏平衡分析 正常情况下,销售额固定成本可变成本税费利润 盈亏平衡下&#…

微信朋友圈新功能:多账号同步发圈,定时发圈!

​你是否会有这种烦恼 想要发布一条朋友圈,但是却因为忙着搞其他事情无暇顾及,甚至忘记了需要发布朋友圈这个事情? 有多个微信号想要同时为它们发布同一条内容的朋友圈,但又不想要分别登录进去进行操作? 你是否厌倦了每…

算法刷题:p1387 最大正方形

解题思路: 利用动态规划的思想设置一个标记数组flag[][],flag[i][j]用来记录矩阵op[][]中以op[i][j]为右下角的子矩阵中最大的正方形边长,那么动态方程就是 flag[i][j]min(flag[i-1][j],min(flag[i-1][j-1],flag[i][j-1]))1;左侧和上方以及左…

Java基础—面向对象OOP—17类与对象(创建、构造器、创建对象时简单内存分析)

把握重点,重点已标注,这篇笔记分了4个章节,重点看二、三、四 一、整体思维--重点把握面向对象的本质和特点 1、面向对象编程OOP: Object-Oriented programming 2、面向过程与面向对象 面向过程:线性思维 面向对象…

k8s从初识到上天系列第二篇:kubernetes的组件和架构

😉😉 欢迎加入我们的学习交流群呀! ✅✅1:这是孙哥suns给大家的福利! ✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring、SpringSecurity、Docker、Grpc、各种MQ、Rpc、SpringCloud等等很多应用和源码…

【word visio绘图】关闭visio两线交叉的跳线(跨线)

【visio绘图】关闭visio两线交叉的跳线(跨线) 1 如何在Visio绘图中关闭visio两线交叉的跳线(跨线)第一步:打开Visio并创建您的图形第二步:绘制您的连接线第三步:关闭跳线第四步:手动…

用友U8接口-获取token数据字段(2)

概括 本文的操作需要正确部署U8HttpApi ,绑定IIS端口获取erp账套信息获取token访问令牌传入JSON的参数如何设置 账套数据库 方式一 查看数据库,UFDATA开头的 方式二 调用接口 此接口返回所有erp账套数据库信息 Token 访问有鉴权的接口&#x…

Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法

前言: 本篇博客超级详细,请尽量使用电脑端结合目录阅读 阅读时请打开右侧 “只看目录” 方便阅读 一、什么是Python 1.1 Python的诞生 1989年,为了打发圣诞节假期,Gudio van Rossum吉多 范罗苏姆(龟叔)决…

Javaweb之SpringBootWeb案例本地存储的详细解析

2.2 本地存储 前面我们已分析了文件上传功能前端和后端的基础代码实现,文件上传时在服务端会产生一个临时文件,请求响应完成之后,这个临时文件被自动删除,并没有进行保存。下面呢,我们就需要完成将上传的文件保存在服…