图像分类项目2:鸟类图像分类
1 数据集处理
1.1数据集下载
数据集来源:kaggle,网址:https://www.kaggle.com/,点击进入网站,左侧选择Datasets。

进入后搜索栏搜索关键词bird。此时出现很多数据集可以选择,推荐选择第一个或者第三个。这里以第三个为例进行演示。

点击进入,注册登录账号后,点击Download进行下载。下载后选择第一个压缩包进行解压。

1.2 数据集划分
先观察数据集。进入数据集文件夹,直接选择images进入。

此时我们可以观察到有200个文件夹,代表200个鸟的种类。当我们知道文件结构后需要对其进行划分了。按照常用比例8:1:1划分为训练集、验证集和测试集。
import os
import shutil
import random
# 数据集根目录,这里选择自己的目录
data_dir = './bird200/CUB_200_2011/images'
# 划分后的数据集根目录
output_dir = './bird200_new'# 创建训练集、验证集和测试集的文件夹
train_dir = os.path.join(output_dir, 'train')
val_dir = os.path.join(output_dir, 'val')
test_dir = os.path.join(output_dir, 'test')os.makedirs(train_dir, exist_ok=True)
os.makedirs(val_dir, exist_ok=True)
os.makedirs(test_dir, exist_ok=True)# 遍历每个类别文件夹
for class_name in os.listdir(data_dir):class_dir = os.path.join(data_dir, class_name)if os.path.isdir(class_dir):# 创建训练集、验证集和测试集的类别文件夹train_class_dir = os.path.join(train_dir, class_name)val_class_dir = os.path.join(val_dir, class_name)test_class_dir = os.path.join(test_dir, class_name)os.makedirs(train_class_dir, exist_ok=True)os.makedirs(val_class_dir, exist_ok=True)os.makedirs(test_class_dir, exist_ok=True)# 获取该类别下的所有文件files = os.listdir(class_dir)random.shuffle(files) # 随机打乱文件顺序# 计算划分的索引num_files = len(files)train_size = int(num_files * 0.8)val_size = int(num_files * 0.1)# 划分文件train_files = files[:train_size]val_files = files[train_size:train_size + val_size]test_files = files[train_size + val_size:]# 复制文件到对应的文件夹for file in train_files:src_path = os.path.join(class_dir, file)dst_path = os.path.join(train_class_dir, file)shutil.copyfile(src_path, dst_path)for file in val_files:src_path = os.path.join(class_dir, file)dst_path = os.path.join(val_class_dir, file)shutil.copyfile(src_path, dst_path)for file in test_files:src_path = os.path.join(class_dir, file)dst_path = os.path.join(test_class_dir, file)shutil.copyfile(src_path, dst_path)print("数据集划分完成!")
2.前期准备工作
2.1 导入需要的库
import warnings
from sklearn.exceptions import ConvergenceWarning
warnings.filterwarnings("ignore", category=ConvergenceWarning)
warnings.simplefilter(action='ignore', category=FutureWarning)
warnings.simplefilter(action='ignore', category=UserWarning)# 导入必要的库
import itertools
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from PIL import Image
from sklearn.metrics import classification_report, f1_score , confusion_matrix# 导入TensorFlow库
import tensorflow as tf
from tensorflow import keras
from keras.layers import Dense, Dropout , BatchNormalization
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import layers,models,Model
from keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers.experimental import preprocessing
from tensorflow.keras.callbacks import Callback, EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
from tensorflow.keras import mixed_precision
mixed_precision.set_global_policy('float32')# 输出TensorFlow版本
print(tf.__version__)
进行测试运行结果:

2.2加载数据
这里进行数据集载入,遍历文件夹读取照片和标签信息。并对其转化格式,使其符合TensorFlow运行。
# 定义数据集路径
dataset = {"train_data" : "./lty/input/bird-species/train","valid_data" : "./lty/input/bird-species/valid","test_data" : "./lty/input/bird-species/test"}all_data = []# 遍历数据集文件夹并读取图片和标签信息
for path in dataset.values():data = {"imgpath": [] , "labels": [] }category = os.listdir(path)for folder in category:folderpath = os.path.join(path , folder)filelist = os.listdir(folderpath)for file in filelist:fpath = os.path.join(folderpath, file)data["imgpath"].append(fpath)data["labels"].append(folder)# 将数据加入列表中all_data.append(data.copy())data.clear()# 将列表转化为DataFrame格式
train_df = pd.DataFrame(all_data[0] , index=range(len(all_data[0]['imgpath'])))
valid_df = pd.DataFrame(all_data[1] , index=range(len(all_data[1]['imgpath'])))
test_df = pd.DataFrame(all_data[2] , index=range(len(all_data[2]['imgpath'])))# 将标签转化为数字编码
lb = LabelEncoder()
train_df['encoded_labels'] = lb.fit_transform(train_df['labels'])
valid_df['encoded_labels'] = lb.fit_transform(valid_df['labels'])
test_df['encoded_labels'] = lb.fit_transform(test_df['labels'])
进行一个可视化展示,展示每个类别数量以及标签。
# 获取训练集中每个类别的图像数量和标签
train = train_df["labels"].value_counts()
label = train.tolist()
index = train.index.tolist()# 设置颜色列表
colors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd","#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf","#aec7e8", "#ffbb78", "#98df8a", "#ff9896", "#c5b0d5","#c49c94", "#f7b6d2", "#c7c7c7", "#dbdb8d", "#9edae5","#5254a3", "#6b6ecf", "#bdbdbd", "#8ca252", "#bd9e39","#ad494a", "#8c6d31", "#6b6ecf", "#e7ba52", "#ce6dbd","#9c9ede", "#cedb9c", "#de9ed6", "#ad494a", "#d6616b","#f7f7f7", "#7b4173", "#a55194", "#ce6dbd"
]# 绘制水平条形图
plt.figure(figsize=(30,30))
plt.title("Training data images count per class",fontsize=38)
plt.xlabel('Number of images', fontsize=35)
plt.ylabel('Classes', fontsize=35)
plt.barh(index,label, color=colors)
plt.grid(True)
plt.show()
展示如图:

2.3检查训练集、验证集和测试集的内容
通过打印输出训练集、验证集和测试集的内容,确保分配没有出现问题。
import os# 设置训练集文件夹路径
path = "C:/Users/z/lty/bird-species/train"# 获取train训练集文件夹列表
dirs = os.listdir(path)# 遍历文件夹列表并打印文件名
for file in dirs:print(file)
展示如图:

# 打印训练集信息
print("----------Train-------------")
print(train_df[["imgpath", "labels"]].head(5)) # 打印前5行的图像路径和标签
print(train_df.shape) # 打印训练集的形状,即行数和列数# 打印验证集信息
print("--------Validation----------")
print(valid_df[["imgpath", "labels"]].head(5)) # 打印前5行的图像路径和标签
print(valid_df.shape) # 打印验证集的形状,即行数和列数# 打印测试集信息
print("----------Test--------------")
print(test_df[["imgpath", "labels"]].head(5)) # 打印前5行的图像路径和标签
print(test_df.shape) # 打印测试集的形状,即行数和列数
展示如图:

随机展示数据集的照片,用于直观体验:
import matplotlib.pyplot as plt
from PIL import Image# 创建一个大小为15x12的画布
plt.figure(figsize=(15, 12))# 从验证集中随机选择16个样本,重置索引并逐行处理
for i, row in valid_df.sample(n=16).reset_index().iterrows():# 在4x4的子图中的第i+1个位置创建一个子图plt.subplot(4, 4, i+1)# 获取图像路径image_path = row['imgpath']image = Image.open(image_path)plt.imshow(image)# 设置子图的标题为标签值plt.title(row["labels"])plt.axis('off')
plt.show()
如图所示:

2.4数据预处理
再对数据进行处理,例如进行数据增强等操作。
%%timeBATCH_SIZE = 35
IMAGE_SIZE = (224, 224)# 导入图像数据生成器 ImageDataGenerator
from keras.preprocessing.image import ImageDataGenerator# 定义数据增强生成器
generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.efficientnet.preprocess_input, # 预处理函数rescale=1./255, # 将像素值缩放到0-1之间width_shift_range=0.2, # 水平和垂直方向上的随机平移范围height_shift_range=0.2,zoom_range=0.2 # 随机缩放图像的范围
)# 将训练集数据分批生成并进行数据增强
train_images = generator.flow_from_dataframe(dataframe=train_df, # 使用train_df作为数据源x_col='imgpath', # 图像路径的列名y_col='labels', # 标签的列名target_size=IMAGE_SIZE, # 图像的目标大小color_mode='rgb', # 图像的颜色通道模式class_mode='categorical', # 分类模式,输出是一个one-hot编码的向量batch_size=BATCH_SIZE, # 批次大小shuffle=True, # 是否打乱数据顺序seed=42 # 随机种子
)# 将验证集数据分批生成
val_images = generator.flow_from_dataframe(dataframe=valid_df, # 使用valid_df作为数据源x_col='imgpath',y_col='labels',target_size=IMAGE_SIZE,color_mode='rgb',class_mode='categorical',batch_size=BATCH_SIZE,shuffle=False
)# 将测试集数据分批生成
test_images = generator.flow_from_dataframe(dataframe=test_df, # 使用test_df作为数据源x_col='imgpath',y_col='labels',target_size=IMAGE_SIZE,color_mode='rgb',class_mode='categorical',batch_size=BATCH_SIZE,shuffle=False
)经过这些处理后,照片的大小就是一致的了。最后一步就是调整子图间的空白部分。
labels = [k for k in train_images.class_indices]
sample_images = train_images.__next__()images = sample_generate[0]
titles = sample_generate[1]
plt.figure(figsize = (15 , 15))for i in range(20):plt.subplot(5 , 5 , i+1)plt.subplots_adjust(hspace = 0.3 , wspace = 0.3)#调整子图之间的空白区域plt.imshow(images[i])plt.title(f'Class: {labels[np.argmax(titles[i],axis=0)]}')plt.axis("off")
运行结果如下:

3.进行模型训练
3.1 模型加载
先进行模型加载,我们可以下载一个适合的预训练模型,再其基础上进行训练和微调可以减少训练时间。
# 加载预训练模型
pretrained_model = tf.keras.applications.EfficientNetB5(input_shape=(224, 224, 3),include_top=False, # 不加载或重新初始化顶层(输出层)的参数weights='imagenet',pooling='max'
)# 冻结预训练神经网络的层
for i, layer in enumerate(pretrained_model.layers):pretrained_model.layers[i].trainable = False
3.2 构建模型
这一步构建我们自己的训练模型。
# 获取类别数
num_classes = len(set(train_images.classes))# 对数据进行增强
augment = tf.keras.Sequential([layers.experimental.preprocessing.RandomFlip("horizontal"),layers.experimental.preprocessing.RandomRotation(0.15),layers.experimental.preprocessing.RandomZoom(0.12),layers.experimental.preprocessing.RandomContrast(0.12),
], name='AugmentationLayer')# 输入层
inputs = layers.Input(shape=(224, 224, 3), name='inputLayer')
x = augment(inputs) # 应用数据增强
pretrain_out = pretrained_model(x, training=False)# 添加全连接层和激活函数
x = layers.Dense(1024)(pretrain_out)
x = layers.Activation(activation="relu")(x)
x = BatchNormalization()(x)
x = layers.Dropout(0.45)(x)
x = layers.Dense(512)(x)
x = layers.Activation(activation="relu")(x)
x = BatchNormalization()(x)
x = layers.Dropout(0.3)(x)
x = layers.Dense(num_classes)(x)
outputs = layers.Activation(activation="softmax", dtype=tf.float32, name='activationLayer')(x)# 创建模型
model = Model(inputs=inputs, outputs=outputs)# 编译模型
model.compile(optimizer=Adam(0.0005),loss='categorical_crossentropy',metrics=['accuracy']
)# 打印模型结构摘要
print(model.summary())
展示如图,可以查看模型具体参数:

3.3 模型训练
这一步就可以正式训练模型了。在 transfer learning 中,我们可以选择保持预训练模型的一部分或全部参数不变(称为冻结),只对最后几层或某些层进行微调,以适应新任务的特定要求。这样做的原因是预训练模型已经学习到了通用的特征,我们可以认为这些特征对于新任务也是有用的。通过仅微调少量参数,我们可以在较小的数据集上快速训练出具有良好性能的模型。
# 训练模型
history = model.fit(train_images,steps_per_epoch=len(train_images),validation_data=val_images,validation_steps=len(val_images),epochs=10,callbacks=[# 提前停止回调,如果验证集损失在连续3个epoch中没有改善,则提前停止训练EarlyStopping(monitor="val_loss", patience=3, restore_best_weights=True),# 学习率调整,在验证集损失没有改善时降低学习率ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=2, mode='min')]
)# 保存模型权重
model.save_weights('./lty/input/bird-species/my_checkpoint')
训练如图所示:

4.结果与评估
4.1 结果展示
绘制训练过程图。
# 定义所需的变量
tr_acc = history.history['accuracy']
tr_loss = history.history['loss']
val_acc = history.history['val_accuracy']
val_loss = history.history['val_loss']
index_loss = np.argmin(val_loss)
val_lowest = val_loss[index_loss]
index_acc = np.argmax(val_acc)
acc_highest = val_acc[index_acc]
Epochs = [i+1 for i in range(len(tr_acc))]
loss_label = f'best epoch= {str(index_loss + 1)}'
acc_label = f'best epoch= {str(index_acc + 1)}'# 绘制训练历史
plt.figure(figsize= (20, 8))
plt.style.use('fivethirtyeight')plt.subplot(1, 2, 1)
plt.plot(Epochs, tr_loss, 'r', label= 'Training loss')
plt.plot(Epochs, val_loss, 'g', label= 'Validation loss')
plt.scatter(index_loss + 1, val_lowest, s= 150, c= 'blue', label= loss_label)
plt.title('Training and Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()plt.subplot(1, 2, 2)
plt.plot(Epochs, tr_acc, 'r', label= 'Training Accuracy')
plt.plot(Epochs, val_acc, 'g', label= 'Validation Accuracy')
plt.scatter(index_acc + 1 , acc_highest, s= 150, c= 'blue', label= acc_label)
plt.title('Training and Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.tight_layout
plt.show()
展示结果:

4.2 评估
评估模型在当前数据集上的性能,包括测试损失和测试的准确率,并打印分数报告。
results = model.evaluate(test_images, verbose=0)# 对测试集进行评估,返回测试损失和测试准确率print(" Test Loss: {:.5f}".format(results[0]))# 打印测试损失,保留小数点后5位
print("Test Accuracy: {:.2f}%".format(results[1] * 100))
# 打印测试准确率,乘以100后保留两位小数
y_true = test_images.classes # 获取测试集样本的真实标签
y_pred = np.argmax(model.predict(test_images), axis=1)
# 获取模型对测试集样本的预测标签# 计算并打印F1 Score和分类报告
f1 = f1_score(y_true, y_pred, average='macro') # 计算F1 Score
print("F1 Score:", f1)
print(classification_report(y_true, y_pred, target_names=test_images.class_indices.keys())) # 打印分类报告
展示:

为了获得结果展示,我能可以打印预测结果。这里展示前8条。
# 创建一个字典,将类别索引和对应的类别名称进行关联
classes = dict(zip(test_images.class_indices.values(), test_images.class_indices.keys()))# 创建一个DataFrame来存储预测结果
Predictions = pd.DataFrame({"Image Index": list(range(len(test_images.labels))), # 图像索引"Test Labels": test_images.labels, # 真实标签"Test Classes": [classes[i] for i in test_images.labels], # 真实类别"Prediction Labels": y_pred, # 预测标签"Prediction Classes": [classes[i] for i in y_pred], # 预测类别"Path": test_images.filenames, # 图像路径"Prediction Probability": [x for x in np.asarray(tf.reduce_max(model.predict(test_images), axis=1))] # 预测概率
})Predictions.head(8) # 输出前8行预测结果
展示:

4.3 优化方向
在这里我们展示了最容易出错的样本,用于后续。
plt.figure(figsize=(20, 20))
# 选择分类错误的预测结果中概率最高的20个样本
subset = Predictions[Predictions["Test Labels"] != Predictions["Prediction Labels"]].sort_values("Prediction Probability").tail(20).reset_index()for i, row in subset.iterrows():plt.subplot(5, 4, i+1)image_path = row['Path']image = Image.open(image_path)# 显示图像plt.imshow(image)# 设置图像标题,包括真实类别和预测类别plt.title(f'TRUE: {row["Test Classes"]} | PRED: {row["Prediction Classes"]}', fontsize=8)plt.axis('off')plt.show()
展示如图:

混淆矩阵(Confusion Matrix)和分类报告(Classification Report)
import numpy as np
from sklearn.metrics import confusion_matrix
import itertools
import matplotlib.pyplot as plt# 使用模型对测试图片进行预测
preds = model.predict_generator(test_images)
# 找到每个预测结果中概率最高的类别作为预测标签
y_pred = np.argmax(preds, axis=1)# 获取测试图片的真实标签和对应的类别字典
g_dict = test_images.class_indices
# 创建一个包含所有类别名称的列表
classes = list(g_dict.keys())# 计算混淆矩阵
cm = confusion_matrix(test_images.classes, y_pred)plt.figure(figsize=(30, 30))
plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
plt.title('Confusion Matrix')
plt.colorbar()tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):plt.text(j, i, cm[i, j], horizontalalignment='center', color='white' if cm[i, j] > thresh else 'black')plt.tight_layout()
plt.ylabel('True Label')
plt.xlabel('Predicted Label')plt.show()
使用matplotlib库绘制了一个大小为30x30的图像窗口,显示了混淆矩阵的热力图。热力图的颜色越深,表示预测结果越准确。图像中的数字表示每个混淆矩阵单元格中的样本数量。图像上方的标题为"Confusion Matrix",颜色条表示每个颜色对应的样本数量范围。x轴标签为预测标签,y轴标签为真实标签。

相关文章:
图像分类项目2:鸟类图像分类
1 数据集处理 1.1数据集下载 数据集来源:kaggle,网址:https://www.kaggle.com/,点击进入网站,左侧选择Datasets。 进入后搜索栏搜索关键词bird。此时出现很多数据集可以选择,推荐选择第一个或者第三个。…...
Redis数据结构-List列表
1.List列表 列表类型适用于存储多个有序的字符串(这里的有序指的是强调数据排列顺序的重要,不是升序降序的意思),列表中的每个字符串称为元素(element),一个列表最多可以存储2^32-1个元素。在R…...
启动你的RocketMQ之旅(三)-Producer启动和发送流程(上)
前言: 👏作者简介:我是笑霸final。 📝个人主页: 笑霸final的主页2 📕系列专栏:java专栏 📧如果文章知识点有错误的地方,请指正!和大家一起学习,一…...
Unity UGUI SuperScrollView介绍
先铺垫一下ScrollView Unity中常用的ScrollView 是 Unity 中的一个常见 UI 组件,主要用于创建可滚动的视图。当内容超过其显示区域时,ScrollView 可以让用户通过滚动查看全部内容。它通常包含一个显示区域和一个内容区域,内容区域可以超过显…...
pandas 数据透视表
数据的透视表 数据的透视表: 使用函数 pivot_table( ) # 引用pandas import pandas as pd # pivot_table 使用 pd.pivot_table(data,values,index,aggfunc,fill_value,columns)参数1:data DataFrame的源数据参数2:values 要进行聚合操作的列参数3:index 进行分组…...
【STM32安全性研究】STM32F103RCT6固件读取
最近从飞哥那买了个stm32固件提取器,效果很好。下面记录对某产品主控STM32F103RCT6固件的提取过程,说明提取时的注意事项。 注意本文的目的仅用于stm32安全性研究,不提供涉及产品本身的内容,包括固件、软件等。 stm32固件提取可参考论坛https://www.aisec.fraunhofer.de/en…...
塔子哥Python算法基础课
【入门题】【输入篇1】AB Problem 题目描述: 给定两个整数 A 和 B,请计算它们的和并输出结果。 输入: 输入包含一行,包含两个整数 A 和 B,以空格分隔。 输出: 输出一行,包含一个整数&#…...
C++ 内存管理:深入理解 new、malloc、delete 和 free
引言 在 C 中,内存管理是一个非常重要的主题。正确使用动态内存分配和释放工具(如 new、malloc、delete 和 free)可以避免内存泄漏和程序崩溃。本文将深入探讨这些工具的区别,并介绍池化计数技术。 1. new 与 malloc 在动态申请内…...
基于互联网协议的诊断通信(DoIP)
1、ISO 13400标准和其他汽车网络协议标准有何不同? ISO 13400 标准即 DoIP 协议标准,与其他常见汽车网络协议标准(如 CAN、LIN、FlexRay 等)有以下不同: 通信基础与适用场景 ISO 13400:基于互联网协议&a…...
Android15 am命令 APP安装流程
一. PM 安装命令 使用命令 pm install -r xxx.apk pm命令安装app 会触发PackageManagerShellCommand 中runInstall()方法 frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java1. onCommand 函数: public int onCommand(String cmd…...
SpringMVC学习(初识与复习Web程序的工作流程)(1)
目录 一、SpringMVC(框架)的简要概述。 (1)SpringMVC与Servlet。 (2)技术方向。 (3)最终学习目标。 二、Web程序的基本工作流程。 (1)工作流程。 <1>浏览器。前后端任务。 <…...
解锁网络防御新思维:D3FEND 五大策略如何对抗 ATTCK
D3FEND 简介 背景介绍 2021年6月22日(美国时间),美国MITRE公司正式发布了D3FEND——一个网络安全对策知识图谱。该项目由美国国家安全局(NSA)资助,并由MITRE的国家安全工程中心(NSECÿ…...
评估自动驾驶(AD)策略性能的关键指标
以下是针对自动驾驶(AD)策略性能评测指标的详细解读,结合其物理意义与工程价值: 核心评测指标分类与含义 1. 安全性指标(Safety) 动态碰撞率(Dynamic Collision Ratio, DCR) 定义&a…...
【领域】百度OCR识别
一、定义 OCR(Optical Character Recognition,光学字符识别)是计算机视觉重要方向之一。传统定义的OCR一般面向扫描文档类对象,现在我们常说的OCR一般指场景文字识别(Scene Text Recognition,STRÿ…...
Docker 学习(一)
一、Docker 核心概念 Docker 是一个开源的容器化平台,允许开发者将应用及其所有依赖(代码、运行时、系统工具、库等)打包成一个轻量级、可移植的“容器”,实现 “一次构建,随处运行”。 1、容器(Container…...
15. C++多线程编程-网络编程-GUI编程(如Qt)学习建议
1. 多线程编程 多线程编程允许程序同时执行多个任务,从而提高性能和响应速度。多线程常用于处理并发任务、提高CPU利用率、优化I/O操作等。 学习内容: 线程与进程的区别:理解线程和进程的基本概念及其区别。 线程的创建与管理:…...
【vscode-解决方案】vscode 无法登录远程服务器的两种解决办法
解决方案一: 查找原因 命令 ps ajx | grep vscode 可能会看到一下这堆信息(如果没有大概率不是这个原因导致) 这堆信息的含义:当你使用 vscode 远程登录服务器时,我们远程机器服务端要给你启动一个叫做 vscode serv…...
5个GitHub热点开源项目!!
1.自托管 Moonlight 游戏串流服务:Sunshine 主语言:C,Star:14.4k,周增长:500 这是一个自托管的 Moonlight 游戏串流服务器端项目,支持所有 Moonlight 客户端。用户可以在自己电脑上搭建一个游戏…...
化学工业领域 - 基础化工、精细化工、煤化工极简理解
引入 基础化工、精细化工和煤化工是化学工业中的三个重要分支 它们在原料、产品、工艺、应用方面各有特点 一、基础化工(Basic Chemical Industry) 1、基本介绍 基础化工是指以石油、天然气、煤炭等为原料,生产大宗化学品和基础化学原料的…...
慢sql治理
一、慢SQL的定义与影响 慢SQL通常指的是执行时间超过合理阈值的SQL语句。这个阈值可以根据系统的实际情况进行设定,例如1秒或更长。慢SQL会导致系统响应时间延迟、资源占用增加、数据库连接池被占满、锁竞争增加等一系列问题,严重影响系统的稳定性和用户…...
基于SpringBoot的美妆购物网站系统设计与实现现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
计算机毕业设计Hadoop+Spark+DeepSeek-R1大模型音乐推荐系统 音乐数据分析 音乐可视化 音乐爬虫 知识图谱 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
mysql5.7离线安装及问题解决
这次主要是讲解mysql5.7离线安装教程和一主一从数据库配置 1、去官网下载自己对应的mysql https://downloads.mysql.com/archives/community/2、查看需要安装mysql服务器的linux的类型 uname -a第二步看一下系统有没有安装mysql rpm -qa|grep -i mysql3、上传安装包 用远程…...
Matlab 大量接单
分享一个matlab接私活、兼职的平台 1、技术方向满足任一即可 2、技术要求 3、最后 技术方向满足即可 MATLAB:熟练掌握MATLAB编程语言,能够使用MATLAB进行数据处理、机器学习和深度学习等相关工作。 机器学习、深度学习、强化学习、仿真、复现、算法、…...
C++数据结构之数组(详解)
1.介绍 在C中,数组是一种基本的数据结构,用于存储相同类型的元素的集合。数组的元素在内存中是连续存储的,可以通过索引访问。下面将详细介绍C数组的相关内容。 2.数组的定义 数组的定义需要指定元素的类型和数组的大小。 type arrayName[a…...
AWS API Gateway灰度验证实现
在微服务架构中,灰度发布(金丝雀发布)是验证新版本稳定性的核心手段。通过将小部分流量(如 10%)导向新版本服务,可以在不影响整体系统的情况下快速发现问题。AWS API Gateway 原生支持流量按比例分配功能,无需复杂编码即可实现灰度验证。本文将详细解析其实现方法、最佳…...
【Elasticsearch】Elasticsearch 的`path.settings`是用于配置 Elasticsearch 数据和日志存储路径的重要设置
Elasticsearch 的path.settings是用于配置 Elasticsearch 数据和日志存储路径的重要设置,这些路径在elasticsearch.yml配置文件中定义。以下是关于 Elasticsearch 的路径设置(path.data和path.logs)以及快照存储库配置的详细说明:…...
Redis 实战篇 ——《黑马点评》(下)
《引言》 (下)篇将记录 Redis 实战篇 最后的一些学习内容,希望大家能够点赞、收藏支持一下 Thanks♪ (・ω・)ノ,谢谢大家。 传送门(上):Redis 实战篇 ——《黑马…...
蓝桥杯自我复习打卡
总复习,打卡1. 一。排序 1。选段排序 太可恶了,直接全排输出,一个测试点都没过。 AC 首先,这个【l,r】区间一定要包含p,或者q,pq一个都不包含的,[l,r]区间无论怎么变,都对ans没有影响。 其次&…...
Spring Boot拦截器(Interceptor)与过滤器(Filter)详细教程
Spring Boot拦截器(Interceptor)与过滤器(Filter)详细教程 目录 概述 什么是拦截器(Interceptor)?什么是过滤器(Filter)?两者的核心区别 使用场景 拦截器的典…...
