python學習打卡day50

DAY 50 預訓練模型+CBAM模塊

知識點回顧:

  1. resnet結構解析
  2. CBAM放置位置的思考
  3. 針對預訓練模型的訓練策略
    1. 差異化學習率
    2. 三階段微調

ps:今日的代碼訓練時長較長,3080ti大概需要40min的訓練時長

作業:

  1. 好好理解下resnet18的模型結構
  2. 嘗試對vgg16+cbam進行微調策略

1.CBMA定義

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 定義通道注意力
class ChannelAttention(nn.Module):def __init__(self, in_channels, ratio=16):"""通道注意力機制初始化參數:in_channels: 輸入特征圖的通道數ratio: 降維比例,用于減少參數量,默認為16"""super().__init__()# 全局平均池化,將每個通道的特征圖壓縮為1x1,保留通道間的平均值信息self.avg_pool = nn.AdaptiveAvgPool2d(1)# 全局最大池化,將每個通道的特征圖壓縮為1x1,保留通道間的最顯著特征self.max_pool = nn.AdaptiveMaxPool2d(1)# 共享全連接層,用于學習通道間的關系# 先降維(除以ratio),再通過ReLU激活,最后升維回原始通道數self.fc = nn.Sequential(nn.Linear(in_channels, in_channels // ratio, bias=False),  # 降維層nn.ReLU(),  # 非線性激活函數nn.Linear(in_channels // ratio, in_channels, bias=False)   # 升維層)# Sigmoid函數將輸出映射到0-1之間,作為各通道的權重self.sigmoid = nn.Sigmoid()def forward(self, x):"""前向傳播函數參數:x: 輸入特征圖,形狀為 [batch_size, channels, height, width]返回:調整后的特征圖,通道權重已應用"""# 獲取輸入特征圖的維度信息,這是一種元組的解包寫法b, c, h, w = x.shape# 對平均池化結果進行處理:展平后通過全連接網絡avg_out = self.fc(self.avg_pool(x).view(b, c))# 對最大池化結果進行處理:展平后通過全連接網絡max_out = self.fc(self.max_pool(x).view(b, c))# 將平均池化和最大池化的結果相加并通過sigmoid函數得到通道權重attention = self.sigmoid(avg_out + max_out).view(b, c, 1, 1)# 將注意力權重與原始特征相乘,增強重要通道,抑制不重要通道return x * attention #這個運算是pytorch的廣播機制## 空間注意力模塊
class SpatialAttention(nn.Module):def __init__(self, kernel_size=7):super().__init__()self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):# 通道維度池化avg_out = torch.mean(x, dim=1, keepdim=True)  # 平均池化:(B,1,H,W)max_out, _ = torch.max(x, dim=1, keepdim=True)  # 最大池化:(B,1,H,W)pool_out = torch.cat([avg_out, max_out], dim=1)  # 拼接:(B,2,H,W)attention = self.conv(pool_out)  # 卷積提取空間特征return x * self.sigmoid(attention)  # 特征與空間權重相乘## CBAM模塊
class CBAM(nn.Module):def __init__(self, in_channels, ratio=16, kernel_size=7):super().__init__()self.channel_attn = ChannelAttention(in_channels, ratio)self.spatial_attn = SpatialAttention(kernel_size)def forward(self, x):x = self.channel_attn(x)x = self.spatial_attn(x)return ximport torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 設置中文字體支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題# 檢查GPU是否可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用設備: {device}")# 數據預處理(與原代碼一致)
train_transform = transforms.Compose([transforms.RandomCrop(32, padding=4),transforms.RandomHorizontalFlip(),transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),transforms.RandomRotation(15),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])test_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 加載數據集(與原代碼一致)
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_transform)
test_dataset = datasets.CIFAR10(root='./data', train=False, transform=test_transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

2.VGG16模型結構

VGG16 的模型結構如下2:

?
  1. 輸入層:輸入圖片的尺寸(imagenet)是 224×224×3,即彩色圖像,通道為 3。
  2. 第一層卷積層
    • 卷積:使用 64 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 224×224×64。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:使用 64 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 224×224×64。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 池化:使用 2×2,stride=2 的池化單元進行最大池化操作,輸出為 112×112×64。
  3. 第二層卷積層
    • 卷積:輸入是 112×112×64,使用 128 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 112×112×128。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 112×112×128,使用 128 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 112×112×128。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 池化:使用 2×2,stride=2 的池化單元進行最大池化操作,輸出為 56×56×128。
  4. 第三層卷積層
    • 卷積:輸入是 56×56×128,使用 256 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 56×56×256。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 56×56×256,使用 256 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 56×56×256。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 56×56×256,使用 256 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 56×56×256。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 池化:使用 2×2,stride=2 的池化單元進行最大池化操作,輸出為 28×28×256。
  5. 第四層卷積層
    • 卷積:輸入是 28×28×256,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 28×28×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 28×28×512,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 28×28×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 28×28×512,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 28×28×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 池化:使用 2×2,stride=2 的池化單元進行最大池化操作,輸出為 14×14×512。
  6. 第五層卷積層
    • 卷積:輸入是 14×14×512,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 14×14×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 14×14×512,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 14×14×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 卷積:輸入是 14×14×512,使用 512 個 3×3 的卷積核進行卷積,padding=1,stride=1,輸出是 14×14×512。
    • ReLU:將卷積層輸出的 FeatureMap 輸入到 ReLU 函數中。
    • 池化:使用 2×2,stride=2 的池化單元進行最大池化操作,輸出為 7×7×512。
  7. 全連接層
    • FC-4096:第一個全連接層,包含 4096 個神經元(工程上的經驗)。
    • FC-4096:第二個全連接層,包含 4096 個神經元。
    • FC-1000:第三個全連接層,包含 1000 個神經元,用于輸出分類結果。

3.VGG16_CBAM的定義

class VGG16_CBAM(nn.Module):def __init__(self, num_classes=10, pretrained=True, cbam_ratio=16, cbam_kernel=7):super().__init__()# 加載預訓練VGG16vgg16 = models.vgg16(pretrained=pretrained)# 提取特征部分self.features = vgg16.features# 修改首層卷積以適應32x32輸入(CIFAR10)self.features[0] = nn.Conv2d(3, 64, kernel_size=3, padding=1)# 在每個最大池化層后添加CBAM模塊self.cbam1 = CBAM(in_channels=64, ratio=cbam_ratio, kernel_size=cbam_kernel)self.cbam2 = CBAM(in_channels=128, ratio=cbam_ratio, kernel_size=cbam_kernel)self.cbam3 = CBAM(in_channels=256, ratio=cbam_ratio, kernel_size=cbam_kernel)self.cbam4 = CBAM(in_channels=512, ratio=cbam_ratio, kernel_size=cbam_kernel)self.cbam5 = CBAM(in_channels=512, ratio=cbam_ratio, kernel_size=cbam_kernel)# 分類部分self.classifier = nn.Sequential(nn.Linear(512 * 1 * 1, 4096),  # 因為輸入尺寸為32x32,經過多次下采樣后變為1x1nn.ReLU(True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(True),nn.Dropout(0.5),nn.Linear(4096, num_classes),)def forward(self, x):# 第一組卷積 + 池化 + CBAMx = self.features[:5](x)  # 到第一個MaxPool2dx = self.cbam1(x)# 第二組卷積 + 池化 + CBAMx = self.features[5:10](x)  # 到第二個MaxPool2dx = self.cbam2(x)# 第三組卷積 + 池化 + CBAMx = self.features[10:17](x)  # 到第三個MaxPool2dx = self.cbam3(x)# 第四組卷積 + 池化 + CBAMx = self.features[17:24](x)  # 到第四個MaxPool2dx = self.cbam4(x)# 第五組卷積 + 池化 + CBAMx = self.features[24:31](x)  # 到第五個MaxPool2dx = self.cbam5(x)# 全局平均池化x = nn.AdaptiveAvgPool2d((1, 1))(x)# 展平并分類x = torch.flatten(x, 1)x = self.classifier(x)return x
# 初始化模型并移至設備
model = VGG16_CBAM().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=3, factor=0.5)

在每一組卷積后+CBAM模塊

4.凍結和微調策略

3階段解凍策略:

  • 階段 1:epoch=1 時,解凍注意力模塊 (cbam) 和分類頭 (classifier),使用較高的學習率 (1e-3)
  • 階段 2:epoch=6 時,解凍高層特征提取層 (features.24 及之后),學習率降低 (1e-4)
  • 階段 3:epoch=21 時,解凍所有層,進行全局微調,學習率進一步降低 (1e-5)
  • 階段解凍時機(epoch)解凍模塊學習率代碼對應邏輯
    階段 11cbam、classifier1e-3if epoch == 1分支,調用set_trainable_layers并設置優化器
    階段 26新增 features.24 及之后的高層卷積層1e-4elif epoch == 6分支,擴展解凍范圍并降低學習率
    階段 321所有層1e-5elif epoch == 21分支,設置param.requires_grad = True并進一步降低學習率
import time# ======================================================================
# 4. 結合了分階段策略和詳細打印的訓練函數
# ======================================================================
def set_trainable_layers(model, trainable_parts):print(f"\n---> 解凍以下部分并設為可訓練: {trainable_parts}")for name, param in model.named_parameters():param.requires_grad = Falsefor part in trainable_parts:if part in name:param.requires_grad = Truebreakdef train_staged_finetuning(model, criterion, train_loader, test_loader, device, epochs):optimizer = None# 初始化歷史記錄列表all_iter_losses, iter_indices = [], []train_acc_history, test_acc_history = [], []train_loss_history, test_loss_history = [], []for epoch in range(1, epochs + 1):epoch_start_time = time.time()# --- 動態調整學習率和凍結層 ---if epoch == 1:print("\n" + "="*50 + "\n🚀 **階段 1:解凍注意力模塊和分類頭**\n" + "="*50)set_trainable_layers(model, ["cbam", "classifier"])optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-3)elif epoch == 6:print("\n" + "="*50 + "\n?? **階段 2:解凍高層特征提取層 (features.24及之后)**\n" + "="*50)set_trainable_layers(model, ["cbam", "classifier", "features.24", "features.25", "features.26", "features.27", "features.28", "features.29", "features.30"])optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-4)elif epoch == 21:print("\n" + "="*50 + "\n🛰? **階段 3:解凍所有層,進行全局微調**\n" + "="*50)for param in model.parameters(): param.requires_grad = Trueoptimizer = optim.Adam(model.parameters(), lr=1e-5)# --- 訓練循環 ---model.train()running_loss, correct, total = 0.0, 0, 0for batch_idx, (data, target) in enumerate(train_loader):data, target = data.to(device), target.to(device)optimizer.zero_grad()output = model(data)loss = criterion(output, target)loss.backward()optimizer.step()# 記錄每個iteration的損失iter_loss = loss.item()all_iter_losses.append(iter_loss)iter_indices.append((epoch - 1) * len(train_loader) + batch_idx + 1)running_loss += iter_loss_, predicted = output.max(1)total += target.size(0)correct += predicted.eq(target).sum().item()# 每100個batch打印一次if (batch_idx + 1) % 100 == 0:print(f'Epoch: {epoch}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} 'f'| 單Batch損失: {iter_loss:.4f} | 累計平均損失: {running_loss/(batch_idx+1):.4f}')epoch_train_loss = running_loss / len(train_loader)epoch_train_acc = 100. * correct / totaltrain_loss_history.append(epoch_train_loss)train_acc_history.append(epoch_train_acc)# --- 測試循環 ---model.eval()test_loss, correct_test, total_test = 0, 0, 0with torch.no_grad():for data, target in test_loader:data, target = data.to(device), target.to(device)output = model(data)test_loss += criterion(output, target).item()_, predicted = output.max(1)total_test += target.size(0)correct_test += predicted.eq(target).sum().item()epoch_test_loss = test_loss / len(test_loader)epoch_test_acc = 100. * correct_test / total_testtest_loss_history.append(epoch_test_loss)test_acc_history.append(epoch_test_acc)# 打印每個epoch的最終結果print(f'Epoch {epoch}/{epochs} 完成 | 耗時: {time.time() - epoch_start_time:.2f}s | 訓練準確率: {epoch_train_acc:.2f}% | 測試準確率: {epoch_test_acc:.2f}%')# 訓練結束后調用繪圖函數print("\n訓練完成! 開始繪制結果圖表...")plot_iter_losses(all_iter_losses, iter_indices)plot_epoch_metrics(train_acc_history, test_acc_history, train_loss_history, test_loss_history)# 返回最終的測試準確率return epoch_test_acc# ======================================================================
# 3. 繪圖函數定義
# ======================================================================
def plot_iter_losses(losses, indices):plt.figure(figsize=(10, 4))plt.plot(indices, losses, 'b-', alpha=0.7, label='Iteration Loss')plt.xlabel('Iteration(Batch序號)')plt.ylabel('損失值')plt.title('每個 Iteration 的訓練損失')plt.legend()plt.grid(True)plt.tight_layout()plt.show()def plot_epoch_metrics(train_acc, test_acc, train_loss, test_loss):epochs = range(1, len(train_acc) + 1)plt.figure(figsize=(12, 4))plt.subplot(1, 2, 1)plt.plot(epochs, train_acc, 'b-', label='訓練準確率')plt.plot(epochs, test_acc, 'r-', label='測試準確率')plt.xlabel('Epoch')plt.ylabel('準確率 (%)')plt.title('訓練和測試準確率')plt.legend(); plt.grid(True)plt.subplot(1, 2, 2)plt.plot(epochs, train_loss, 'b-', label='訓練損失')plt.plot(epochs, test_loss, 'r-', label='測試損失')plt.xlabel('Epoch')plt.ylabel('損失值')plt.title('訓練和測試損失')plt.legend(); plt.grid(True)plt.tight_layout()plt.show()# ======================================================================
# 6. 執行訓練
# ======================================================================
model = VGG16_CBAM().to(device)
criterion = nn.CrossEntropyLoss()
epochs = 50print("開始使用帶分階段微調策略的ResNet18+CBAM模型進行訓練...")
final_accuracy = train_staged_finetuning(model, criterion, train_loader, test_loader, device, epochs)
print(f"訓練完成!最終測試準確率: {final_accuracy:.2f}%")# torch.save(model.state_dict(), 'resnet18_cbam_finetuned.pth')
# print("模型已保存為: resnet18_cbam_finetuned.pth")

@浙大疏錦行

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

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

相關文章

54、錯誤處理-【源碼流程】異常處理流程

54、錯誤處理-【源碼流程】異常處理流程 #### 異常處理流程概述 1. **執行目標方法**: - 程序執行目標方法,期間若發生異常,會被捕獲并記錄,標志當前請求結束。 - 將異常信息賦值給 dispatchException 變量。 2. **進入視圖解析…

使用 VSCode 開發 FastAPI 項目(1)

一、引言 FastAPI 是一款現代、快速(高性能)的 Web 框架,用于構建 API,使用 Python 3.7 及更高版本。它基于標準 Python 類型提示,具有自動生成文檔等出色功能。而 VSCode 憑借其輕量、強大的特性,為開發者…

Bash 腳本中的特殊變量

在 Bash 腳本和命令行中,?特殊變量?(Special Variables)主要用于獲取腳本或命令的上下文信息,如參數、進程狀態、返回值等。以下是常見的特殊變量及其典型應用場景: ?1. 腳本參數處理? $0、$1、$2 ... $9、${10}.…

免部署的數字人 API 調用教程:基于 wav2lip模型訓練的開放API,附 PHP 代碼示例

前言 去年我開始研究數字人模型算法,測試了市面上幾乎所有開源數字人模型,過程中踩了不少坑。最大的痛點就是訓練太燒顯卡了,光租顯卡的費用就花了我6個月的薪資,每次看到賬單都心疼。不過現在終于把基于wav2lip的數字人API做出來…

力扣HOT100之貪心算法:45. 跳躍游戲 II

這道題刷代碼隨想錄的時候也刷過,本來以為有了上一題55.跳躍游戲的基礎,這道題會好做一點,但是依舊想不出來思路,回去看了下自己當時寫的博客,沒想到今天的感受和當時的感受都一模一樣。。。What can I say?看了下代碼…

使用Docker申請Let‘s Encrypt證書

1、安裝Docker # 安裝Docker https://docs.docker.com/get-docker/# 安裝Docker Compose https://docs.docker.com/compose/install/# CentOS安裝Docker https://mp.weixin.qq.com/s/nHNPbCmdQs3E5x1QBP-ueA 2、申請Lets Encrypt證書 詳見: https://docs.linuxse…

算法題(167):FBI樹

審題: 本題需要我們將字符串按照題目要求進行遞歸展開,并按照后序遍歷的順序輸出 思路: 方法一:遞歸 首先我們需要模擬一下題目的意思 其實就是第一步判斷屬于什么字符,然后將字符串分兩半進行下一輪判斷。而由于題目要…

從“分散開發”到“智能協同” —— Gitee 如何賦能河南農擔構建金融級研發體系?

河南省農業信貸擔保有限責任公司(以下簡稱「河南農擔」)成立于 2016 年,是河南省屬骨干國有企業,承擔破解“三農”融資難題的重要職責。截至 2024 年底,河南農擔累計實現擔保規模 1037.05 億元,位居全國農擔…

青少年編程與數學 01-011 系統軟件簡介 14 Foxpro數據庫

青少年編程與數學 01-011 系統軟件簡介 14 Foxpro數據庫 一、歷史沿革二、技術架構三、主要功能四、應用場景五、產品版本六、使用方法七、技術價值八、歷史意義全文總結 **摘要:**FoxPro 是一款經典的桌面數據庫管理系統,起源于 1984 年的 FoxBASE&…

android studio向左向右滑動頁面

本文演示了Android Studio中使用ViewPager實現頁面切換的方法。通過創建包含3個頁面的ViewPager示例,詳細展示了實現步驟:1)在XML布局中配置ViewPager和切換按鈕;2)使用LayoutInflater動態加載頁面布局;3)自定義SimplePagerAdapte…

數據可視化新姿勢:Altair的聲明式魔法

文章目錄 一、告別編程式繪圖的苦日子二、5分鐘極速入門安裝篇(記得先備好虛擬環境!)核心三劍客 三、高階玩法揭秘1. 交互功能秒實現2. 復合圖表so easy3. 魔改樣式有套路 四、避坑指南(血淚經驗)五、Altair vs 其他庫…

PostgreSQL --數據庫操作

一、基本操作 1、登錄 #切換pg用戶 su - postgres#重啟服務 pg_ctl -D /usr/local/pgsql/data -l logfile restart#進入pg psql2、數據庫操作 2.1、列出庫 \l\lselect datname from database; \l:輸出比\l多了Size,Tablespace 和 Description 列 :擴展輸…

樹莓派超全系列教程文檔--(63)rpicam-apps可用選項介紹之常用選項

rpicam-apps可用選項介紹之常用選項 rpicam-apps 選項參考常用選項helpversionlist-camerascameraconfigtimeoutpreviewfullscreenqt-previewnopreviewinfo-textwidth 和 heightviewfinder-width 和 viewfinder-heightmode打包格式詳細信息解壓格式詳細信息 viewfinder-modelor…

AI的發展過程:深度學習中的自然語言處理(NLP);大語言模型(LLM)詳解;Transformer 模型結構詳解;大模型三要素:T-P-G 原則

AI的發展過程:深度學習中的自然語言處理(NLP);大語言模型(LLM)詳解;Transformer 模型結構詳解;大模型三要素:T-P-G 原則 AI的發展過程與大模型原理詳解一、AI的發展過程符…

SDXL 和 SDXL-Turbo 的區別

(1) SDXL(Stable Diffusion XL) 標準擴散模型,基于傳統的多步去噪(通常 20~50 步)。 訓練充分,特征更穩定,適合用于特征提取、方向學習(如 LoRA、SAE)。 計算成本高&am…

PyTorch:讓深度學習像搭積木一樣簡單!!!

文章目錄 🚀 一、 PyTorch的王炸:動態圖 vs 靜態圖靜態圖的“痛苦回憶”(前方高能吐槽!)PyTorch動態圖的降維打擊🔥 🔥 二、 不只是靈活!PyTorch的三大殺器1. 張量(Tenso…

LeetCode--27.移除元素

解題思路: 1.獲取信息: 給定一個數組和一個值,刪除數組中等于這個值的值 要求是,返回數組中不等于這個值的數的數目 并且要求在數組上刪除,不能使用額外輔助空間 還是給了評測標準(你可以根據它的原理來實現…

WebRTC(二):工作機制

核心組成 GetUserMedia:獲取本地音視頻設備(攝像頭、麥克風)數據流。RTCPeerConnection:實現點對點的媒體流傳輸和網絡連接管理。RTCDataChannel:點對點的任意數據通道(除音視頻外傳輸數據)。 …

機器學習+城市規劃第十五期:時空地理加權回歸(STGWR)

機器學習城市規劃第十五期:時空地理加權回歸(STGWR) 引言 隨著城市化進程的加速,城市規劃面臨越來越多復雜的挑戰。在傳統的城市規劃中,通常會考慮到地理位置的影響,但往往忽略了時間維度。而在現代城市的…