【NLP实战】基于Bert和双向LSTM的情感分类【上篇】

news2024/10/6 20:36:54

文章目录

  • 前言
  • 简介
  • 数据获取与提取
  • 数据清洗
    • 读取数据,查看数据
    • 清洗训练集
      • 观察数据分布
      • 去除空数据
      • 去除重复数据
      • 关于去除停用词
      • 关于特殊符号
      • 储存清洗后的数据集
    • 清洗测试集
      • 观察数据分布
      • 去除空数据
      • 去除重复数据(并储存)
    • 清洗验证集
      • 观察数据分布
      • 去除空行
      • 去除重复数据(并储存)
  • 总结
  • 代码汇总

前言

最近自己找了个实验做,写了很多实验记录和方法,现在我将它们整理成文章,希望能对不熟悉NLP的伙伴们起到些许帮助。如有疑问请及时联系作者。

博主page:issey的博客 - 愿无岁月可回首

本系列文章中不会说明环境和包如何安装,这些应该是最基础的东西,可以自己边查边安装。

许多函数用法等在代码里有详细解释,但还是希望各位去看它们的官方文档,我的代码还有很多可以改进的方法,需要的函数等在官方文档都有说明。

简介

本系列将带领大家从数据获取、数据清洗、模型构建、训练,观察loss变化,调整超参数再次训练,并最后进行评估整一个过程。我们将获取一份公开竞赛中文数据,并一步步实验,到最后,我们的评估可以达到排行榜13位的位置。但重要的不是排名,而是我们能在其中学到很多。

本系列将分为三篇文章,分别是:

  • 上篇:数据获取,数据分割与数据清洗
  • 中篇:模型构建,改进pytorch结构,开始第一次训练
  • 下篇:测试与评估,绘图与过拟合,超参数调整

本文为该系列第一篇文章,在本文中,我们将一同观察原始数据,进行数据清洗。样本是很重要的一个部分,学会观察样本并剔除一些符合特殊条件的样本,对模型在学习时有很大的帮助。

数据获取与提取

数据来源:Weibo nCoV Data | Kaggle

竞赛官网:疫情期间网民情绪识别 竞赛 - DataFountain

关于kaggle如何下载数据,本文不再赘述。

为了把数据分割也作为我们实验的一部分,假设我们现在拿到的nCoV_100k_train.labled.csv就是我们爬取到的原始数据。

先来看看我们用到的数据长什么样。

思考:

  • 我们只需要text和情感倾向的列,其他列都不需要。
  • 分割数据时,训练集:测试集:验证集 = 6:2:2。这只是博主自己选择的比例,各位可以自行调整。

编写代码。这部分比较简单,就不一步步运行了,但是各位应该逐行运行观察变化,写文章不能像jupyter notebook那样一行行运行,为了方便起见,文章涉及的代码都将以块状给出。但是运行实际上很多都是逐行调整的。

数据获取.py

import pandas as pd
from sklearn.model_selection import train_test_split

# todo: 读取数据
df = pd.read_csv('./data/archive/nCoV_100k_train.labled.csv')
print(df)
# 只要text和标签
df = df[['微博中文内容', '情感倾向']]
df = df.rename(columns={'微博中文内容': 'text', '情感倾向': 'label'})
print(df)

# todo: 分割数据集,储存.0.6/0.2/0.2
train, test = train_test_split(df, test_size=0.2)
train, val = train_test_split(train, test_size=0.25)
print(train)
print(test)
print(val)
train.to_csv('./data/archive/train.csv', index=None)
val.to_csv('./data/archive/val.csv', index=None)
test.to_csv('./data/archive/test.csv', index=None)

运行结束后,这三个文件就是我们需要的文件。

数据清洗

我的清洗思路来源于这篇:Emotion analysis and Classification using LSTM 93% | Kaggle

该部分需要的库:

  • seaborn:一个适合数据分析的绘图库,需要matplotlib作为前置库

读取数据,查看数据

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# todo:读取数据
df_train = pd.read_csv('./data/archive/train.csv')
df_test = pd.read_csv('./data/archive/test.csv')
df_val = pd.read_csv('./data/archive/val.csv')

# 输出前5行
print(df_train.head())
print(df_train.shape)

print(df_test.head())
print(df_test.shape)

print(df_val.head())
print(df_val.shape)

输出:

清洗训练集

观察数据分布

# todo: 清洗Train
# 观察数据是否平衡
print(df_train.label.value_counts())
print(df_train.label.value_counts() / df_train.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_train)
plt.show()

可以发现,-2.0,9.0,10.0都只有一个样本,当作异常数据处理,我选择直接丢掉不要。

另外,这个样本分布略微存在分布不平衡imbalance的情况,至于要不要用smote等方法过采样,暂时先不进行讨论,我们暂时保持数据不变。

print(df_train[df_train.label > 5.0])
print(df_train[(df_train.label < -1.1)])
# 丢掉异常数据
df_train.drop(df_train[(df_train.label < -1.1) | (df_train.label > 5)].index, inplace=True, axis=0)
df_train.reset_index(inplace=True, drop=True)
print(df_train.label.value_counts())
sns.countplot(x='label', data=df_train)
plt.show()

去除空数据

# 观察是否有空行
print(df_train.isnull().sum())
# 删除空行数据
df_train.dropna(axis=0, how='any', inplace=True)
df_train.reset_index(inplace=True, drop=True)
print(df_train.isnull().sum())

去除重复数据

# 查看重复数据
print(df_train.duplicated().sum())
# print(df_train[df_train.duplicated()==True])
# 删除重复数据
index = df_train[df_train.duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
print(df_train.duplicated().sum())

然后我们还需要去除text一样但是label不一样的数据。

# 我们还需要关心的重复数据是text一样但是label不一样的数据。
print(df_train['text'].duplicated().sum())
print(df_train[df_train['text'].duplicated() == True])
# 查看例子
print(df_train[df_train['text'] == df_train.iloc[856]['text']])
print(df_train[df_train['text'] == df_train.iloc[3096]['text']])

# 去掉text一样但是label不一样的数据
index = df_train[df_train['text'].duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# 检查
print(df_train['text'].duplicated().sum())  # 0

关于去除停用词

去不去除停用词和构建word embedding选择的方法有关,去查了一下,使用Bert构建时,不需要去除停用词处理,否则还会丢失上下文。于是这里没有进一步去除停用词。

问题解答:nlp - Is it necessary to do stopwords removal ,Stemming/Lemmatization for text classification while using Spacy,Bert? - Stack Overflow

关于特殊符号

观察我们现在的数据:

很容易发现里面有特殊字符。

待会儿用到的bert,它会用到一个中文字典,这个字典是它自己有的,如果出现字典里没有的字符,它会自动替换成[UNK],所以不用管。

储存清洗后的数据集

df_train.to_csv('./data/archive/train_clean.csv', index=None)

清洗测试集

整体步骤和清洗训练集的一样。这里为了巩固处理思路,自己还是详细做一遍吧。

观察数据分布

# 观察数据是否平衡
print(df_test.label.value_counts())
print(df_test.label.value_counts() / df_test.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_test)
plt.show()

输出就不放了,放个图。

没有特殊label,不用进行去除的操作。

哦对,执行时可以把上面清洗train的代码注释了,用不着重新跑。

去除空数据

# 观察是否有空行
print(df_test.isnull().sum())
# 删除空行数据
df_test.dropna(axis=0, how='any', inplace=True)
df_test.reset_index(inplace=True, drop=True)
print(df_test.isnull().sum())

去除重复数据(并储存)

# 查看重复数据
print(df_test.duplicated().sum())
# print(df_test[df_test.duplicated()==True])
# 删除重复数据
index = df_test[df_test.duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
print(df_test.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_test['text'].duplicated().sum())
print(df_test[df_test['text'].duplicated() == True])
# 查看例子
# print(df_test[df_test['text'] == df_test.iloc[2046]['text']])
# print(df_test[df_test['text'] == df_test.iloc[3132]['text']])
# 去掉text一样但是label不一样的数据
index = df_test[df_test['text'].duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# 检查
print(df_test['text'].duplicated().sum())  # 0
# print(df_test)
# 检查形状与编号
print(df_test.tail())
print(df_test.shape)
df_test.to_csv('./data/archive/test_clean.csv', index=None)

有的注释可以打开自己看着调。

清洗验证集

观察数据分布

# 观察数据是否平衡
print(df_val.label.value_counts())
print(df_val.label.value_counts() / df_val.shape[0] * 100)
plt.figure(figsize=(8, 4))
sns.countplot(x='label', data=df_val)
plt.show()

有三个取值我们需要剔除。

# 丢掉异常数据
df_val.drop(df_val[(df_val.label == '4') |
                   (df_val.label == '-') |
                   (df_val.label == '·')].index, inplace=True, axis=0)
df_val.reset_index(inplace=True, drop=True)
print(df_val.label.value_counts())
sns.countplot(x='label', data=df_val)
plt.show()

去除空行

# 观察是否有空行
print(df_val.isnull().sum())
# 删除空行数据
df_val.dropna(axis=0, how='any', inplace=True)
df_val.reset_index(inplace=True, drop=True)
print(df_val.isnull().sum())

去除重复数据(并储存)

# 查看重复数据
print(df_val.duplicated().sum())
# print(df_val[df_val.duplicated()==True])
# 删除重复数据
index = df_val[df_val.duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
print(df_val.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_val['text'].duplicated().sum())
# print(df_val[df_val['text'].duplicated() == True])
# 查看例子
# print(df_val[df_val['text'] == df_val.iloc[1817]['text']])
# print(df_val[df_val['text'] == df_val.iloc[2029]['text']])
# 去掉text一样但是label不一样的数据
index = df_val[df_val['text'].duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# 检查
print(df_val['text'].duplicated().sum())  # 0
# print(df_val)
# 检查形状与编号
print(df_val.tail())
print(df_val.shape)
df_val.to_csv('./data/archive/val_clean.csv', index=None)

总结

到此为止,我们已经清洗好了数据。让我们来看看在本次清洗时,忽略了哪些在其他实验中可以继续改进的地方:

  • 本次清洗没有去除停用词,因为使用bert时去除停用词可能会丢失上下文。
  • 本次清洗没有去除特殊字符,因为bert会自动将未知字符转化为[UKN]
  • 本次没有对样本进行过采样/欠采样来解决imbalance问题,这个问题留到评估模型后再考虑要不要讨论。

下一篇文章中,我们将会使用Pytorch搭建Bert和双向LSTM实现多分类。

代码汇总

数据清洗.py

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# todo:读取数据
df_train = pd.read_csv('./data/archive/train.csv')
df_test = pd.read_csv('./data/archive/test.csv')
df_val = pd.read_csv('./data/archive/val.csv')

# 输出前5行
# print(df_train.head())
# print(df_train.shape)

# print(df_test.head())
# print(df_test.shape)

# print(df_val.head())
# print(df_val.shape)

# todo: 清洗Train
# 观察数据是否平衡
# print(df_train.label.value_counts())
# print(df_train.label.value_counts() / df_train.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_train)
# plt.show()
# print(df_train[df_train.label > 5.0])
# print(df_train[(df_train.label < -1.1)])
# 丢掉异常数据
df_train.drop(df_train[(df_train.label < -1.1) | (df_train.label > 5)].index, inplace=True, axis=0)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.label.value_counts())
# sns.countplot(x='label', data=df_train)
# plt.show()

# 观察是否有空行
# print(df_train.isnull().sum())
# 删除空行数据
df_train.dropna(axis=0, how='any', inplace=True)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.isnull().sum())

# 查看重复数据
# print(df_train.duplicated().sum())
# print(df_train[df_train.duplicated()==True])
# 删除重复数据
index = df_train[df_train.duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# print(df_train.duplicated().sum())

# 我们还需要关心的重复数据是text一样但是label不一样的数据。
# print(df_train['text'].duplicated().sum())
# print(df_train[df_train['text'].duplicated() == True])
# 查看例子
# print(df_train[df_train['text'] == df_train.iloc[856]['text']])
# print(df_train[df_train['text'] == df_train.iloc[3096]['text']])
# 去掉text一样但是label不一样的数据
index = df_train[df_train['text'].duplicated() == True].index
df_train.drop(index, axis=0, inplace=True)
df_train.reset_index(inplace=True, drop=True)
# 检查
# print(df_train['text'].duplicated().sum())  # 0
# print(df_train)
# 检查形状与编号
print("======train-clean======")
print(df_train.tail())
print(df_train.shape)
df_train.to_csv('./data/archive/train_clean.csv', index=None)

# todo: 清洗test
# 观察数据是否平衡
# print(df_test.label.value_counts())
# print(df_test.label.value_counts() / df_test.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_test)
# plt.show()
# 观察是否有空行
# print(df_test.isnull().sum())
# 删除空行数据
df_test.dropna(axis=0, how='any', inplace=True)
df_test.reset_index(inplace=True, drop=True)
# print(df_test.isnull().sum())
# 查看重复数据
# print(df_test.duplicated().sum())
# print(df_test[df_test.duplicated()==True])
# 删除重复数据
index = df_test[df_test.duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# print(df_test.duplicated().sum())
# 重复数据是text一样但是label不一样的数据。
# print(df_test['text'].duplicated().sum())
# print(df_test[df_test['text'].duplicated() == True])
# 查看例子
# print(df_test[df_test['text'] == df_test.iloc[2046]['text']])
# print(df_test[df_test['text'] == df_test.iloc[3132]['text']])
# 去掉text一样但是label不一样的数据
index = df_test[df_test['text'].duplicated() == True].index
df_test.drop(index, axis=0, inplace=True)
df_test.reset_index(inplace=True, drop=True)
# 检查
# print(df_test['text'].duplicated().sum())  # 0
# print(df_test)
# 检查形状与编号
print("======test-clean======")
print(df_test.tail())
print(df_test.shape)
df_test.to_csv('./data/archive/test_clean.csv', index=None)

# todo: 清洗验证集
# 观察数据是否平衡
# print(df_val.label.value_counts())
# print(df_val.label.value_counts() / df_val.shape[0] * 100)
# plt.figure(figsize=(8, 4))
# sns.countplot(x='label', data=df_val)
# plt.show()
# 丢掉异常数据
df_val.drop(df_val[(df_val.label == '4') |
                   (df_val.label == '-') |
                   (df_val.label == '·')].index, inplace=True, axis=0)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.label.value_counts())
# sns.countplot(x='label', data=df_val)
# plt.show()

# 观察是否有空行
# print(df_val.isnull().sum())
# 删除空行数据
df_val.dropna(axis=0, how='any', inplace=True)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.isnull().sum())

# 查看重复数据
# print(df_val.duplicated().sum())
# print(df_val[df_val.duplicated()==True])
# 删除重复数据
index = df_val[df_val.duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# print(df_val.duplicated().sum())

# 重复数据是text一样但是label不一样的数据。
print(df_val['text'].duplicated().sum())
# print(df_val[df_val['text'].duplicated() == True])
# 查看例子
# print(df_val[df_val['text'] == df_val.iloc[1817]['text']])
# print(df_val[df_val['text'] == df_val.iloc[2029]['text']])
# 去掉text一样但是label不一样的数据
index = df_val[df_val['text'].duplicated() == True].index
df_val.drop(index, axis=0, inplace=True)
df_val.reset_index(inplace=True, drop=True)
# 检查
print(df_val['text'].duplicated().sum())  # 0
# print(df_val)
# 检查形状与编号
print("======val-clean======")
print(df_val.tail())
print(df_val.shape)
df_val.to_csv('./data/archive/val_clean.csv', index=None)

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

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

相关文章

Go分布式爬虫(二十四)

文章目录24 存储引擎爬取结构化数据step1 从首页获取热门标签信息step2 获取图书列表step3 获取图书详情完整规则存储到MySQL数据抽象数据存储存储引擎实现存储引擎验证dockerdocker-compose使用Navicat查看使用DataGrip查看24 存储引擎 爬虫项目的一个重要的环节就是把最终的…

Mysql逻辑架构和语句执行流程

文章目录1. 逻辑架构剖析1.1 连接管理--连接层1.2 解析与优化--服务层1.3 存储引擎2. SQL语句的执行流程2.1 执行原理2.2 语法顺序1. 逻辑架构剖析 当一个客户端连接mysql服务器执行一条查询语句时&#xff0c;会发生以下处理过程&#xff1a; 1.1 连接管理–连接层 客户端想…

1.半导体基础知识

1.半导体基础知识本征半导体什么是半导体&#xff1f;什么是本征半导体&#xff1f;本征半导体的结构本征半导体中的两种载流子为什么将自然界导电性能中等的半导体材料制成本征半导体杂质半导体N型半导体P型半导体PN结PN结中的扩散运动漂移运动和PN结的形成PN结的单向导电性PN…

Spring中Bean对象的作用域和生命周期详解

Spring作为一个具有众多工具方法的IoC容器&#xff0c;其核心功能就是Bean对象的存储和取出&#xff0c;那么学习Bean对象的作用域和生命周期能让我们更清楚地了解Bean对象在Spring容器中的整个加载过程&#xff01; 一&#xff0c;案例演示&#xff08;Bean对象的修改&#xf…

4.搜索辅助功能

ES 既有基本的搜索功能、又有字段类型的精确搜索、分词匹配、范围搜索、坐标搜索、分页查询等等。 4.1 搜索辅助功能 俗话说“工欲善其事&#xff0c;必先利其器”。在介绍ES提供的各种搜索匹配功能之前&#xff0c;我们先介绍ES提供的各种搜索辅助功能。例如&#xff0c;为优化…

【让你的灵感立刻落地】在线代码运行平台InsCode

文章目录官网地址详解1. 导入项目2. 在线演示、在线修改3. 发布作品参考InsCode 是一个在线代码运行平台&#xff0c;可以在线上运行代码&#xff0c;并且支持多种语言&#xff0c;同时还可以在线修改和提交代码&#xff0c;支持发布和分享项目。InsCode 平台在编写博客、演示项…

二叉树练习题(递归展开图详解哦)

全文目录引言单值二叉树题目描述及思路实现二叉树的最大深度题目描述及思路实现翻转二叉树题目描述及思路实现相同的树题目描述及思路实现总结引言 前面我们介绍了二叉树的相关基础知识&#xff0c;并且了解到二叉树的表示有两种结构&#xff1a;顺序结构与链式结构。即&#…

手把手教您注册/使用Claude

文章目录注册slack注意事项最近几天出现了一个很火的AI聊天项目——Claude&#xff0c;据说可以媲美ChatGPT&#xff0c;最主要的就是可以很好的解决我们国内的使用痛点&#xff0c;可以完全免费无限制的使用&#xff0c;下面就和大家分享一下正确的注册和使用Claude的流程&…

想成为一名【黑客】,你该如何快速的入门?

假设你有一台个人电脑&#xff0c;或者可以访问一台电脑&#xff0c;那么你就可以着手【黑客】技能的学习了。【黑客】文化演化而来的的时候&#xff0c;电脑是很昂贵的&#xff0c;个人不能拥有他们。所以最重要的一个步骤就是新手可以拥有一台属于自己的电脑&#xff0c;新手…

【Cisco Packet Tracer| 一.交换机配置模式与基本参数配置】

文章目录一.交换机的多种模式以及切换1.如何进入到交换机配置的命令行用户界面(Command Line Interface)2.普通模式模式3.特权用户模式4.全局配置模式5.模式切换图二.交换机名称&#xff0c;口令等设置1.全局模式下-交换机改名2.接口模式下-配置端口速度和工作模式2.1配置端口速…

项目8:用户注册和登录的前后端联调

项目8&#xff1a;用户注册和登录的前后端联调 1.前端项目使用 2.前端项目注册模块 3.后端完成项目注册 4.前端项目登录模块 5.后端完成项目登录 6.用户认证&#xff08;校验用户是否登录&#xff09; 项目8&#xff1a;用户注册和登录的前后端联调 1.前端项目使用 直接…

20230413在CV1826平台配置开机自启动程序

20230413在CV1826平台配置开机自启动程序 2023/4/13 10:51 1、项目需求&#xff1a;硬件需要测量摄像头开机之后的电压/时钟信号&#xff0c;但是不想每次开机的时候都通过adb连接cv1826来开启摄像头。 C:\Users\Sun>adb shell / # / # cd /mnt/ /mnt # /mnt # ls -l total …

Go 语言性能优化指南

编写高性能的 Go 程序~ 前言&#xff1a; 继上次课程的高质量编程内容讲解&#xff0c;本次课程主要介绍了在满足正确性、可靠性、健壮性、可读性等质量因素的前提下提高程序效率的性能优化建议&#xff1b;性能优化分析工具&#xff1b;以及性能调优的实战案例&#xff0c;分…

叶酸聚乙二醇羟基FA-PEG-OH;一文带你了解高分子试剂OH-PEG-Folate

FA-PEG-OH&#xff0c;叶酸-聚乙二醇-羟基 中文名称&#xff1a;叶酸聚乙二醇羟基 英文名称&#xff1a;FA-PEG-OH HO-PEG-FA Folate-PEG-OH 性状&#xff1a;黄色液体或固体&#xff0c;取决于分子量 溶剂&#xff1a;溶于水&#xff0c;DMSO、DMF等常规性有机溶剂 活性基…

城市地下综合管廊安全运营与智慧管控的分层架构研究

安科瑞 李亚俊 1、引言 1833年&#xff0c;市政管线综合管廊在巴黎城市地下建成至今&#xff0c;经过百年来的探索、研究、改良和实践&#xff0c;法国、英国、德国、俄罗斯、日本、美国等发达国家的管廊规划建设与安全运维体系已经日臻完善&#xff0c;截止目前&#xff0c;…

《花雕学AI》17:关注提示工程—本世纪最重要的技能可能就是与AI人工智能对话

本文目录与主要结构 引言&#xff1a;介绍提示工程的概念和背景&#xff0c;说明为什么它是本世纪最重要的技能之一。 正文&#xff1a; 一、提示工程的基本原理和方法&#xff1a;介绍什么是提示、如何设计和优化提示、如何使用提示与语言模型进行交互。 二、提示工程的应用和…

Direct3D 12——混合——混合

混合运算 typedef enum D3D12_BLEND_OP {D3D12_BLEND_OP_ADD 1, //添加源 1 和源 2。D3D12_BLEND_OP_SUBTRACT 2,//从源 2 中减去源 1。D3D12_BLEND_OP_REV_SUBTRACT 3,//从源 1 中减去源 2。D3D12_BLEND_OP_MIN 4,//查找源 1 和源 2 的最小值。D3D12_BLEND_OP_MAX 5//查…

【云原生|Docker】13-Docker-compose详解

【云原生Docker】13-Docker-compose详解 文章目录【云原生Docker】13-Docker-compose详解前言docker-compose简介docker-compose安装docker-compose基本示例Docker Compose常用命令说明Docker Compose文件详解versionserviceimagebuildcommandlinksexternal_linksportsexposeen…

Win11的两个实用技巧系列之找不到wifi网络的解决方法、双系统开机选择系统方法

Win11装了VMware后找不到wifi网络的解决方法 有用户在电脑上安装了VMware虚拟机来使用的时候&#xff0c;发现虚拟机中无法进行无线网络的连接了&#xff0c;本文就为大家带来了详细的解决方法&#xff0c;一起看看吧 Win11装了VMware后找不到wifi网络的解决方法教学分享。有用…

助力信创国产化,Solon v2.2.9 发布

Solon 是一个高效的 Java 应用开发框架&#xff1a;更快、更小、更简单。它不是 Spring、没有使用 Servlet、JavaEE 接口&#xff0c;是一个有自己接口标准的开放生态。可以为应用软件国产化提供支持&#xff0c;助力信创建设。 150来个生态插件&#xff0c;覆盖各种不同的应用…