基于深度學習的貓狗識別系統【深度學習課設】

🏆 作者簡介:席萬里
? 個人網站:https://dahua.bloggo.chat/
?? 一名后端開發小趴菜,同時略懂Vue與React前端技術,也了解一點微信小程序開發。
🍻 對計算機充滿興趣,愿意并且希望學習更多的技術,接觸更多的大神,提高自己的編程思維和解決問題的能力。

文章目錄

  • 作品演示
    • 代碼
      • 1.train_and_test.py
      • 2、view.py(可視化界面)

作品演示

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

代碼

采用模型VGG16、ALEXNet、Resnet18,訓練測試。python版本3.10.11 。

數據集:和鯨社區貓狗圖像數據集。https://www.heywhale.com/mw/project/631aedb893f47b16cb062b2a

1.train_and_test.py

# 導入 PyTorch 庫和相關模塊
import torch                                 # PyTorch 的核心庫,提供張量計算和自動求導功能
import torchvision.transforms as transforms  # 提供圖像數據增強和預處理的功能
from torch.utils.data import Dataset         # 用于自定義數據集
from torch import nn, optim                  # nn 用于構建神經網絡,optim 用于優化算法
from PIL import Image                        # 用于加載和處理圖像文件
import time                                  # 用于記錄訓練時長和其他時間相關操作
import torchvision.models as models          # 包含一些預訓練模型,如 AlexNet、ResNet 等
import os                                    # 用于與操作系統交互,如文件路徑處理、創建目錄等
import matplotlib.pyplot as plt              # 用于繪制圖表,如準確率曲線、損失曲線等
from tqdm import tqdm                        # 用于顯示訓練過程中的進度條
from sklearn.metrics import confusion_matrix # 用于計算混淆矩陣,評估分類性能
import seaborn as sns                        # 用于繪制混淆矩陣的熱圖,提供美觀的圖表風格device = torch.device('cpu')# 數據預處理:縮放到224x224大小,并轉換為Tensor
transformer = transforms.Compose([transforms.Resize((224, 224)), transforms.ToTensor()])# 加載訓練數據集
DogTrainImageList = os.listdir(r"./catsdogs/train/Dog")  # 加載訓練集中的狗圖片列表
CatTrainImageList = os.listdir(r"./catsdogs/train/Cat")  # 加載訓練集中的貓圖片列表
train_label = []  # 存儲訓練數據的標簽
train_data = []  # 存儲訓練數據的圖像數據
dog_train_data_dir = r"./catsdogs/train/Dog/"  # 狗的圖片目錄路徑
cat_train_data_dir = r"./catsdogs/train/Cat/"  # 貓的圖片目錄路徑# 將狗的圖片加載進訓練數據集
for i in range(len(DogTrainImageList)):train_label.append(1)  # 狗的標簽為1dog_img = Image.open(dog_train_data_dir + DogTrainImageList[i]).convert('RGB')  # 打開圖片并轉換為RGBdog_img = transformer(dog_img)  # 進行預處理train_data.append(dog_img)  # 添加到訓練數據# 將貓的圖片加載進訓練數據集
for i in range(len(CatTrainImageList)):train_label.append(0)  # 貓的標簽為0cat_img = Image.open(cat_train_data_dir + CatTrainImageList[i]).convert('RGB')  # 打開圖片并轉換為RGBcat_img = transformer(cat_img)  # 進行預處理train_data.append(cat_img)  # 添加到訓練數據# 加載測試數據集(與訓練集類似)
DogTestImageList = os.listdir(r"./catsdogs/train/Dog")
CatTestImageList = os.listdir(r"./catsdogs/train/Cat")
test_label = []  # 存儲測試數據的標簽
test_data = []  # 存儲測試數據的圖像數據
dog_test_data_dir = r"./catsdogs/train/Dog/"  # 狗的測試圖片目錄路徑
cat_test_data_dir = r"./catsdogs/train/Cat/"  # 貓的測試圖片目錄路徑# 將狗的測試圖片加載進測試數據集
for i in range(len(DogTestImageList)):test_label.append(1)  # 狗的標簽為1dog_img = Image.open(dog_test_data_dir + DogTestImageList[i]).convert('RGB')dog_img = transformer(dog_img)test_data.append(dog_img)# 將貓的測試圖片加載進測試數據集
for i in range(len(CatTestImageList)):test_label.append(0)  # 貓的標簽為0cat_img = Image.open(cat_test_data_dir + CatTestImageList[i]).convert('RGB')cat_img = transformer(cat_img)test_data.append(cat_img)# 自定義的數據集類,用于加載圖像數據
class DealDataset(Dataset):def __init__(self, data, label, transform=None):self.data = data  # 圖像數據self.label = label  # 圖像標簽self.transform = transform  # 圖像預處理def __getitem__(self, index):data, label = self.data[index], int(self.label[index])  # 獲取指定索引的數據和標簽return data, label  # 返回數據和標簽def __len__(self):return len(self.data)  # 返回數據集的大小# 將訓練數據集和測試數據集包裝為DealDataset對象
TrainDataSet = DealDataset(train_data, train_label, transform=transformer)
TestDataSet = DealDataset(test_data, test_label, transform=transformer)# 定義AlexNet模型
class AlexNet(nn.Module):def __init__(self):super(AlexNet, self).__init__()# 定義卷積層部分self.conv = nn.Sequential(nn.Conv2d(3, 64, kernel_size=11, stride=4),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.BatchNorm2d(64),nn.Conv2d(64, 192, kernel_size=5, padding=2),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.BatchNorm2d(192),nn.Conv2d(192, 384, kernel_size=3, padding=1),nn.ReLU(),nn.Conv2d(384, 256, kernel_size=3, padding=1),nn.ReLU(),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.BatchNorm2d(256))# 定義全連接層部分self.fc = nn.Sequential(nn.Linear(256 * 5 * 5, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 2)  # 輸出2個類別:貓或狗)def forward(self, img):feature = self.conv(img)  # 通過卷積層提取特征output = self.fc(feature.view(img.shape[0], -1))  # 展開特征并通過全連接層進行分類return output# 使用預訓練的VGG16模型,并修改最后的全連接層以適應2個輸出類別
class VGG16(nn.Module):def __init__(self, num_classes=2):super(VGG16, self).__init__()self.model = models.vgg16(pretrained=True)  # 加載預訓練的VGG16模型self.model.classifier[-1] = nn.Linear(self.model.classifier[-1].in_features, num_classes)  # 修改輸出層def forward(self, x):return self.model(x)  # 返回模型的輸出# 使用ResNet18模型,并修改最后的全連接層以適應2個輸出類別
class ResNet18(nn.Module):def __init__(self):super(ResNet18, self).__init__()self.model = models.resnet18(pretrained=False)  # 加載ResNet18模型self.model.fc = nn.Linear(self.model.fc.in_features, 2)  # 修改輸出層為2個類別def forward(self, x):return self.model(x)  # 返回模型的輸出# 繪制混淆矩陣的函數
def plot_combined_confusion_matrix(true_labels_dict, predicted_labels_dict, classes,save_path='combined_confusion_matrix.png'):# 創建一個子圖,用來顯示多個模型的混淆矩陣fig, axes = plt.subplots(1, len(true_labels_dict), figsize=(15, 5))# 遍歷每個模型并繪制其混淆矩陣for i, (model_name, true_labels) in enumerate(true_labels_dict.items()):predicted_labels = predicted_labels_dict[model_name]cm = confusion_matrix(true_labels, predicted_labels)  # 計算混淆矩陣# 使用Seaborn繪制熱圖sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=classes, yticklabels=classes,ax=axes[i], cbar=False, annot_kws={"size": 14})axes[i].set_xlabel('Predicted labels', fontsize=12)axes[i].set_ylabel('True labels', fontsize=12)axes[i].set_title(f'{model_name} Confusion Matrix', fontsize=14)# 調整布局并保存圖像plt.tight_layout()plt.savefig(save_path)plt.show()# 計算模型在測試集上的準確率
def evaluate_accuracy(data_iter, net, device=None):if device is None and isinstance(net, torch.nn.Module):device = list(net.parameters())[0].device  # 獲取模型的設備acc_sum, n = 0.0, 0predicted_labels = []true_labels = []with torch.no_grad():  # 在測試時不需要計算梯度for X, y in tqdm(data_iter, desc="加載中:", leave=True):net.eval()  # 將模型設置為評估模式outputs = net(X.to(device))  # 獲取模型輸出predicted = outputs.argmax(dim=1)  # 獲取預測的標簽true_labels.extend(y.cpu().numpy())  # 存儲真實標簽predicted_labels.extend(predicted.cpu().numpy())  # 存儲預測標簽acc_sum += (predicted == y.to(device)).float().sum().cpu().item()  # 累加準確的樣本數n += y.shape[0]  # 累加樣本總數return acc_sum / n, true_labels, predicted_labels  # 返回準確率,真實標簽和預測標簽# 訓練和評估模型
def train_and_evaluate_models(models, model_names, train_iter, test_iter, batch_size, optimizer_dict, device,num_epochs, save_model_paths, plot_path):train_acc_history = {name: [] for name in model_names}  # 存儲訓練過程中每個模型的訓練準確率test_acc_history = {name: [] for name in model_names}  # 存儲測試過程中每個模型的測試準確率train_loss_history = {name: [] for name in model_names}  # 存儲每個模型的訓練損失# 存儲每個模型的混淆矩陣數據true_labels_dict = {name: [] for name in model_names}predicted_labels_dict = {name: [] for name in model_names}# 迭代訓練周期for epoch in range(num_epochs):for model, model_name in zip(models, model_names):  # 遍歷每個模型model.train()optimizer = optimizer_dict[model_name]  # 獲取當前模型的優化器loss_fn = torch.nn.CrossEntropyLoss()  # 定義損失函數scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.7)  # 學習率衰減策略train_l_sum, train_acc_sum, n, batch_count, start = 0.0, 0.0, 0, 0, time.time()# 訓練每個模型for X, y in train_iter:X, y = X.to(device), y.to(device)y_hat = model(X)  # 獲取模型預測loss = loss_fn(y_hat, y)  # 計算損失optimizer.zero_grad()  # 清空梯度loss.backward()  # 反向傳播optimizer.step()  # 更新參數train_l_sum += loss.item()  # 累加損失train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()  # 累加準確的樣本數n += y.shape[0]batch_count += 1scheduler.step()  # 學習率衰減# 計算訓練集和測試集的準確率train_acc = train_acc_sum / ntest_acc, true_labels, predicted_labels = evaluate_accuracy(test_iter, model, device)# 存儲每個模型的混淆矩陣數據true_labels_dict[model_name].extend(true_labels)predicted_labels_dict[model_name].extend(predicted_labels)train_acc_history[model_name].append(train_acc)test_acc_history[model_name].append(test_acc)train_loss_history[model_name].append(train_l_sum / batch_count)print(f'{model_name} epoch {epoch + 1}, loss {train_l_sum / batch_count:.4f}, 'f'train acc {train_acc:.3f}, test acc {test_acc:.3f}, time {time.time() - start:.1f} sec')# 保存模型torch.save(model.state_dict(), save_model_paths[model_name])  # 保存模型的權重print(f"{model_name} Model saved to {save_model_paths[model_name]} after epoch {epoch + 1}")# 在所有訓練完成后生成混淆矩陣的綜合圖plot_combined_confusion_matrix(true_labels_dict, predicted_labels_dict, ['Cat', 'Dog'],save_path=os.path.join(plot_path, 'combined_confusion_matrix.png'))return train_acc_history, test_acc_history, train_loss_history# 可視化訓練結果并保存
def plot_and_save_results(train_acc_history, test_acc_history, train_loss_history, num_epochs, save_plots_path):plt.figure(figsize=(10, 5))# 繪制每個模型的訓練與測試準確率曲線for model_name in ['AlexNet', 'ResNet18', 'VGG16']:if model_name in train_acc_history and model_name in test_acc_history:plt.plot(range(num_epochs), train_acc_history[model_name], label=f'{model_name} Train Accuracy')plt.plot(range(num_epochs), test_acc_history[model_name], label=f'{model_name} Test Accuracy')plt.xlabel('Epochs')plt.ylabel('Accuracy')plt.title('AlexNet, ResNet18, VGG16 - Training and Test Accuracy Comparison')plt.legend()plt.grid(True)plt.savefig(os.path.join(save_plots_path, 'accuracy_plot.png'))  # 保存準確率圖像plt.show()plt.figure(figsize=(10, 5))# 繪制每個模型的訓練損失曲線for model_name in ['AlexNet', 'ResNet18', 'VGG16']:if model_name in train_loss_history:plt.plot(range(num_epochs), train_loss_history[model_name], label=f'{model_name} Train Loss')plt.xlabel('Epochs')plt.ylabel('Loss')plt.title('Training Loss Comparison')plt.legend()plt.grid(True)plt.savefig(os.path.join(save_plots_path, 'loss_plot.png'))  # 保存損失圖像plt.show()if __name__ == '__main__':# 設置訓練參數num_epochs = 25  # 設置為可配置參數batch_size = 16  # 設置為可配置參數learning_rate = 0.009  # 設置為可配置參數save_model_paths = {'AlexNet': 'AlexNet.pth','ResNet18': 'ResNet18.pth','VGG16': 'VGG16.pth'}save_plots_path = './python'os.makedirs(save_plots_path, exist_ok=True)  # 創建保存模型和圖像的文件夾# 創建模型實例alexnet_model = AlexNet().to(device)resnet_model = ResNet18().to(device)vgg_model = VGG16().to(device)# 創建數據加載器train_iter = torch.utils.data.DataLoader(TrainDataSet, batch_size=batch_size, shuffle=True, num_workers=2)test_iter = torch.utils.data.DataLoader(TestDataSet, batch_size=batch_size, shuffle=False, num_workers=2)# 優化器字典optimizer_dict = {'AlexNet': torch.optim.SGD(alexnet_model.parameters(), lr=learning_rate),'ResNet18': torch.optim.SGD(resnet_model.parameters(), lr=learning_rate),'VGG16': torch.optim.SGD(vgg_model.parameters(), lr=learning_rate)}# 訓練并評估models = [alexnet_model, resnet_model, vgg_model]model_names = ['AlexNet', 'ResNet18', 'VGG16']train_acc_history, test_acc_history, train_loss_history = train_and_evaluate_models(models, model_names, train_iter, test_iter, batch_size, optimizer_dict, device, num_epochs, save_model_paths, save_plots_path)# 繪制并保存準確率和損失曲線plot_and_save_results(train_acc_history, test_acc_history, train_loss_history, num_epochs, save_plots_path)

2、view.py(可視化界面)

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QFileDialog, QVBoxLayout, QGridLayout, \QTextEdit, QComboBox, QSpacerItem, QSizePolicy
from PyQt5.QtGui import QPixmap, QFont, QTextCursor
import torch
import torch.nn as nn
import torchvision.transforms as transforms
from PIL import Image
import torchvision.models as modelsclass AnimalClassifierApp(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):self.setWindowTitle('貓狗識別系統')self.resize(600, 400)  # 更小的窗口尺寸# 創建布局grid = QGridLayout()grid.setContentsMargins(10, 10, 10, 10)  # 設置間距grid.setSpacing(5)  # 設置控件間距# 顯示圖像的標簽self.image_label = QLabel(self)self.image_label.setFixedSize(250, 250)  # 調整圖像顯示尺寸self.image_label.setAlignment(Qt.AlignCenter)grid.addWidget(self.image_label, 1, 0, 2, 1)# 識別結果的標簽self.result_label = QTextEdit(self)self.result_label.setFixedSize(250, 80)self.result_label.setReadOnly(True)self.result_label.setStyleSheet("color: red; font-size: 14px;")self.result_label.setAlignment(Qt.AlignCenter)grid.addWidget(self.result_label, 1, 1, 1, 2)# 模型選擇下拉框self.model_selector = QComboBox(self)self.model_selector.addItem("AlexNet")self.model_selector.addItem("VGG16")self.model_selector.addItem("ResNet18")grid.addWidget(self.model_selector, 2, 0, 1, 2)# 按鈕布局button_layout = QVBoxLayout()button_layout.setSpacing(5)  # 設置按鈕間距# 上傳圖像按鈕upload_btn = QPushButton('上傳', self)upload_btn.clicked.connect(self.load_image)button_layout.addWidget(upload_btn)# 識別按鈕recognize_btn = QPushButton('識別', self)recognize_btn.clicked.connect(self.classify_image)button_layout.addWidget(recognize_btn)# 添加按鈕布局button_layout.addSpacerItem(QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding))grid.addLayout(button_layout, 3, 1, 1, 2)self.setLayout(grid)# 加載模型self.device = torch.device('cpu')# 定義數據轉換self.transform = transforms.Compose([transforms.Resize((148, 148)),transforms.ToTensor(),transforms.Normalize(mean=[0.4, 0.4, 0.4], std=[0.2, 0.2, 0.2])])self.image_path = ''self.model = None  # 模型初始化為空def load_image(self):options = QFileDialog.Options()options |= QFileDialog.ReadOnlyfile_name, _ = QFileDialog.getOpenFileName(self, "上傳圖片", "", "圖片文件 (*.jpg *.jpeg *.png)",options=options)if file_name:self.image_path = file_namepixmap = QPixmap(file_name)pixmap = pixmap.scaled(self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio)self.image_label.setPixmap(pixmap)self.result_label.setText('識別結果: ')def classify_image(self):if self.image_path:# 根據選擇的模型加載相應的模型selected_model = self.model_selector.currentText()if selected_model == "AlexNet":self.model = self.load_alexnet_model()elif selected_model == "VGG16":self.model = self.load_vgg16_model()elif selected_model == "ResNet18":self.model = self.load_resnet18_model()image = Image.open(self.image_path).convert('RGB')image_tensor = self.transform(image).unsqueeze(0).to(self.device)with torch.no_grad():output = self.model(image_tensor)probabilities = torch.nn.functional.softmax(output, dim=1)confidence, predicted = torch.max(probabilities, 1)label = 'cat' if predicted.item() == 0 else 'dog'confidence = confidence.item()# 將圖像轉換為QPixmappixmap = QPixmap(self.image_path)pixmap = pixmap.scaled(self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio)self.image_label.setPixmap(pixmap)# 設置識別結果字體顏色和對齊方式self.result_label.setText(f'識別結果: {label} \n\n置信度: {confidence:.2f}')self.result_label.setAlignment(Qt.AlignCenter)cursor = self.result_label.textCursor()cursor.select(QTextCursor.Document)self.result_label.setTextCursor(cursor)def load_alexnet_model(self):model = models.alexnet(pretrained=True)model.classifier[6] = nn.Linear(model.classifier[6].in_features, 2)  # 修改最后一層model = model.to(self.device)model.eval()return modeldef load_vgg16_model(self):model = models.vgg16(pretrained=True)model.classifier[6] = nn.Linear(model.classifier[6].in_features, 2)  # 修改最后一層model = model.to(self.device)model.eval()return modeldef load_resnet18_model(self):model = models.resnet18(pretrained=True)model.fc = nn.Linear(model.fc.in_features, 2)  # 修改最后一層model = model.to(self.device)model.eval()return modelif __name__ == '__main__':app = QApplication(sys.argv)ex = AnimalClassifierApp()ex.show()sys.exit(app.exec_())

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63043.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63043.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63043.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

05、GC基礎知識

JVM程序在跑起來之后,在數據的交互過程中,就會有一些數據是過期不用的,這些數據可以看做是垃圾,JVM中,這些垃圾是不用開發者管的,它自己會有一套垃圾回收系統自動回收這些內存垃圾,以備后面繼續…

什么是戰略思想?

古今中外,關于戰略是什么?有非常多的理論,也有不同的視角。 中國最早的涉及戰略的書籍據傳是黃帝所著的《握奇文》,后有較為系統的兵法戰略書籍為周朝姜太公(亦稱姜尚、姜子牙等)所著的《六韜》&#xff0c…

2024.12.15 TCP/IP 網絡模型有哪幾層?(二)

2024.12.15 TCP/IP 網絡模型有哪幾層?(二) 上節課我們學習了網絡模型有四部分構成,有應用層、傳輸層、網絡層、網絡接口層。 生成了 IP 頭部之后,接下來要交給網絡接口層(Link Layer)在 IP 頭部的前面加上 MAC 頭部&#xff0c…

51c深度學習~合集9

我自己的原文哦~ https://blog.51cto.com/whaosoft/12750420 #傅里葉特征 (Fourier Feature)與核回歸 位置編碼背后的理論解釋 本文探討了位置編碼背后的理論基礎,特別是傅里葉特征(Fourier Feature)與核回歸(Kern…

Flutter Navigator2.0的原理和Web端實踐

01 背景與動機 在Navigator 2.0推出之前,Flutter主要通過Navigator 1.0和其提供的 API(如push(), pop(), pushNamed()等)來管理頁面路由。然而,Navigator 1.0存在一些局限性,如難以實現復雜的頁面操作(如移…

代碼隨想錄算法訓練營第三天 | 鏈表理論基礎 | 707.設計鏈表

要求太多&#xff0c;代碼量太大&#xff0c;實在難以完成 在以前聽說&#xff0c;好的程序員&#xff0c;可以在短時生成大量的代碼&#xff0c;本題只方法才只有6個&#xff0c;根本不算多 每天手敲代碼量太少&#xff0c;才是問題 #include <iostream>class MyLink…

數據冒險、控制冒險、結構冒險

計算機組成原理 數據冒險、控制冒險、結構冒險 對所有用戶&#xff08;所有程序員&#xff09;可見&#xff1a;PSW、PC、通用寄存器 PSW&#xff08;條件轉移需要用到&#xff0c;程序員使用CMP指令的時候也需要用到所以是對用戶可見&#xff09;PC&#xff08;跳轉指令需要…

基于32單片機的RS485綜合土壤傳感器檢測土壤PH、氮磷鉀的使用(超詳細)

1-3為RS485綜合土壤傳感器的基本內容 4-5為基于STM32F103C8T6單片機使用RS485傳感器檢測土壤PH、氮磷鉀并顯示在OLED顯示屏的相關配置內容 注意&#xff1a;本篇文件講解使用的是PH、氮磷鉀四合一RS485綜合土壤傳感器&#xff0c;但里面的講解內容適配市面上的所有多合一的RS…

SpringBoot【十一】mybatis-plus實現多數據源配置,開箱即用!

一、前言&#x1f525; 環境說明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 正常情況下我們在開發系統的時候都是使用一個數據源&#xff0c;但是由于有些項目同步數據的時候不想造成數據庫io消耗壓力過大&#xff0c;便會一個項目對應多個數據源…

Node.js教程入門第一課:環境安裝

對于一個程序員來說&#xff0c;每學習一個新東西的時候&#xff0c;第一步基本上都是先進行環境的搭建&#xff01; 從本章節開始讓我們開始探索Node.js的世界吧! 什么是Node.js? 那么什么是Node.js呢&#xff1f;簡單的說Node.js 就是運行在服務端的 JavaScript JavaScript…

vim優化

1.編輯如下內容&#xff1a; cat > /root/.vimrc <<EOF set tabstop2 " 設置 Tab 為 2 個空格 set shiftwidth2 " 設置自動縮進為 2 個空格 set expandtab " 將 Tab 轉換為空格 " 基本設置 set number syntax on" 快捷鍵設置…

字符串性能對比

效率(1) : String.indexOf與String.contains效率測試_string contains效率-CSDN博客 結論是前者效率高&#xff0c;源碼里面conatins是使用indexof 在jdk8中contains直接調用的indexOf(其他版本沒有驗證),所以要說效率來說肯定是indexOf高,但contains也就多了一層方法棧,so 什…

移動網絡的原理

無線網絡是如何解決移動通信問題的 場景&#xff1a;用戶在一輛轎車內以150km/h的時速沿高速公路急速行駛時穿過多個無線接入網&#xff0c;用戶希望在整個旅程中保持一個與遠程應用的不間斷的TCP連接。 解決方案&#xff1a;移動節點的間接路由選擇方法可解決TCP鏈接不間斷的…

python學opencv|讀取圖像(十三)BGR圖像和HSV圖像互相轉換深入

【1】引言 前序學習過程中&#xff0c;我們偶然發現&#xff1a;如果原始圖像是png格式&#xff0c;將其從BGR轉向HSV&#xff0c;再從HSV轉回BGR后&#xff0c;圖像的效果要好于JPG格式。 文章鏈接為&#xff1a; python學opencv|讀取圖像&#xff08;十二&#xff09;BGR圖…

解決node.js的req.body為空的問題

從昨晚一直在試&#xff0c;明明之前用的封裝的axios發送請求給其他的后端&#xff08;springboot&#xff09;是可以的&#xff0c;但昨天用了新項目的后端&#xff08;node.js&#xff09;就不行。 之前用了代理&#xff0c;所以瀏覽器發送的post請求不會被攔截&#xff0c;…

【嵌入式】嵌入式面試題 36 問

1. volatile 是否可以修飾 const 是的&#xff0c;volatile 可以修飾 const。const 表示變量的值不能被修改&#xff0c;而 volatile 表示變量的值可能在程序之外被修改&#xff08;例如&#xff0c;由硬件修改&#xff09;。 將 volatile 用于 const 變量意味著該變量的值雖然…

java基礎概念49-數據結構2

一、樹 1-1、樹的基本概念 1、樹的節點 2、二叉樹 3、樹的高度 1-2、二叉查找樹 普通二叉樹沒有規律&#xff0c;不方便查找&#xff0c;沒什么作用。 1、基本概念 2、添加節點 此時&#xff0c;該方式添加形成的二叉查找樹&#xff0c;根節點就是第一個節點。 3、查找節點 4…

GhatGPT缺陷不足和商業應用

1. 引言 ChatGPT的興起&#xff1a; 2022年末推出&#xff0c;迅速在自然語言處理和人工智能領域引起廣泛關注。數億用戶體驗其強大智能&#xff0c;感嘆機器智能的飛速發展。 存在的缺陷&#xff1a; 事實性錯誤&#xff1a;生成的文本中包含錯誤信息。無法實時更新&#xff1…

【Linux】Macvlan介紹及LInux下例子實現

Macvlan Macvlan 是一種網絡虛擬化技術&#xff0c;允許在同一物理網絡接口上創建多個虛擬網絡接口&#xff0c;每個虛擬接口都有自己獨立的 MAC 地址。這對于需要在同一物理主機上運行多個網絡隔離的應用程序或容器時非常有用。 Macvlan 的特點和用途 獨立的 MAC 地址 每個 …

Jackson @JsonInclude 注解

1. 概述 Jackson 是一個著名的Java庫&#xff0c;以轉換Java對象為JSON格式以及從JSON反序列化回Java對象而聞名。有時候&#xff0c;我們可能希望僅在某些字段滿足特定條件時才將其包含在JSON輸出中&#xff0c;而Jackson的JsonInclude注解正是為此目的量身定制的。 JsonInc…