结合Boosting理论与深度ResNet:ICML2018论文代码详解与实现

代码见:JordanAsh/boostresnet: A PyTorch implementation of BoostResNet

原始论文:Huang F, Ash J, Langford J, et al. Learning deep resnet blocks sequentially using boosting theory[C]//International Conference on Machine Learning. PMLR, 2018: 2058-2067.

代码解析及功能实现

这段代码实现了一个训练ResNet块并逐层训练的过程。这个过程结合了Boosting理论,通过逐层训练ResNet块来提高分类性能。

代码前期准备

import torch
import sys
import pickle
import os
import numpy as np
import torchfile
from torch import nn
from torch.autograd import Variable
import argparse

导入了必要的库,包括PyTorch、NumPy、系统操作、数据加载和命令行参数解析库。

解析命令行参数

parser = argparse.ArgumentParser()
parser.add_argument('--gammaFirst', default=0.5, help='initial gamma')
parser.add_argument('--checkEvery', default=10000, help='how frequently to check gamma requirement - 10k for cifar, 5k for svhn')
parser.add_argument('--data', default='SVHN.t7', help='load data')
parser.add_argument('--gammaThresh',default=-0.0001, help='gamma threshold to stop training layer')
parser.add_argument('--lr', default=0.001, help='learning rate')
parser.add_argument('--maxIters', default=10000, help='maximum iterations before stopping train layer')
parser.add_argument("--transform", help='do CIFAR-style image transformations?', action="store_true")
parser.add_argument('--printEvery', default=100, help='how frequently to print')
parser.add_argument('--batchSize', default=100, help='batch size')
parser.add_argument('--modelPath', default='model.pt', help='output model')
opt = parser.parse_args()

解析命令行参数,设置各种训练超参数,包括初始gamma值、检查gamma的频率、数据集路径、gamma阈值、学习率、最大迭代次数、是否进行数据变换、打印频率、批处理大小和模型保存路径。

加载数据

data = torchfile.load(opt.data) # load dataset in torch format (assuming already normalized)
Xtrain = data.Xtrain
Ytrain = data.Ytrain - 1
Xtest = data.Xtest
Ytest = data.Ytest - 1
cut = int(np.shape(Xtrain)[0] / opt.batchSize * opt.batchSize) # cut off a few samples for simplicity
nTrain = cut
Xtrain = Xtrain[:cut]
Ytrain = Ytrain[:cut]
cut = int(np.shape(Xtest)[0] / opt.batchSize * opt.batchSize)
Xtest = Xtest[:cut]
Ytest = Ytest[:cut]
nTest = cut
numClasses = 10

加载并处理数据集,将训练集和测试集按批处理大小进行裁剪,以确保数据大小是批处理大小的整数倍。

定义打印函数

def printer(print_arr):for v in print_arr: sys.stdout.write(str(v) + '\t')sys.stdout.write('\n')sys.stdout.flush()

定义一个打印函数,用于在控制台打印输出。

加载ResNet模型并构建块

import fbrn
model = fbrn.tmp
model.load_state_dict(torch.load('fbrn.pth'))
allBlocks = {}
allBlocks[0] = nn.Sequential(model[0], model[1], model[2])
for i in range(8): allBlocks[1 + i] = model[3][i] 
for i in range(8): allBlocks[9 + i] = model[4][i] 
for i in range(8): allBlocks[17+ i] = model[5][i]
criterion = nn.CrossEntropyLoss().cuda()
nFilters = 15; rounds = 25

加载预训练的ResNet模型,并将其分成多个块,分别存储在allBlocks字典中。定义损失函数为交叉熵损失。

  1. allBlocks[0] 包含 model 的第 0 层到第 2 层,使用 nn.Sequential 将这些层组合在一起。
  2. for i in range(8): allBlocks[1 + i] = model[3][i]model 的第 3 层的 8 个子层分别存储在 allBlocks 的索引 1 到 8。
  3. for i in range(8): allBlocks[9 + i] = model[4][i]model 的第 4 层的 8 个子层分别存储在 allBlocks 的索引 9 到 16。
  4. for i in range(8): allBlocks[17 + i] = model[5][i]model 的第 5 层的 8 个子层分别存储在 allBlocks 的索引 17 到 24。

这样,allBlocks 字典就包含了模型的所有层,并且这些层被分割成了不同的块,每个块对应一个连续的索引范围。

分块的意义

这段代码将模型分为了三个主要的残差块(residual blocks):

  1. 第 0 块:allBlocks[0] 包含模型的第 0 层到第 2 层。
  2. 第 1 块:allBlocks[1]allBlocks[8] 包含模型的第 3 层的 8 个子层。
  3. 第 2 块:allBlocks[9]allBlocks[16] 包含模型的第 4 层的 8 个子层。
  4. 第 3 块:allBlocks[17]allBlocks[24] 包含模型的第 5 层的 8 个子层。

数据增强函数

def transform(X):tmp = np.zeros((np.shape(X)[0], 3, 38, 38))tmp[:, :, 2:34, 2:34] = Xfor i in range(np.shape(X)[0]):r1 = np.random.randint(4)r2 = np.random.randint(4)X[i] = tmp[i, :, r1 : r1 + 32, r2 : r2 + 32]if np.random.uniform() > .5:X[i] = X[i, :, :, ::-1]return X

定义数据增强函数,用于CIFAR样式的图像变换,进行随机裁剪和水平翻转。

模型评估函数

def getPerformance(net, X, Y, n):acc = 0.model.eval()Xoutput = np.zeros((X.shape[0], 10))for batch in range(int(X.shape[0] / opt.batchSize)):start = batch * opt.batchSize; stop = (batch + 1) * opt.batchSize - 1ints = np.linspace(start, stop, opt.batchSize).astype(int)data = Variable(torch.from_numpy(X[ints])).float().cuda()for i in range(n): data = allBlocks[i](data)output = net(data)acc += np.mean(torch.max(output, 1)[1].cpu().data.numpy() == Y[ints])Xoutput[ints] = output.cpu().data.numpy()acc /= (X.shape[0] / opt.batchSize)model.train()return acc, Xoutput

定义模型评估函数,用于在训练和测试数据集上计算模型的准确率。

初始化模型统计数据

a_previous = 0.0
a_current = -1.0
s = np.zeros((nTrain, numClasses))
cost = np.zeros((nTrain, numClasses))
Xoutput_previous = np.zeros((nTrain, numClasses))
Ybatch = np.zeros((opt.batchSize))
YbatchTest = np.zeros((opt.batchSize))
gamma_previous = opt.gammaFirst
totalIterations = 0; tries = 0

初始化一些变量,用于存储模型统计数据、损失、输出和其他辅助数据。

逐层训练模型

for n in range(rounds):gamma = -1Z = 0# create cost function  for i in range(nTrain):localSum = 0for l in range(numClasses):if l != Ytrain[i]:cost[i][l] = np.exp(s[i][l] - s[i][int(Ytrain[i])])localSum += cost[i][l]cost[i][int(Ytrain[i])] = -1 * localSumZ += localSum# fetch the correct classification layersbk = allBlocks[n]ci = nn.Sequential(model[6], model[7], model[8])if n < 17: ci = nn.Sequential(allBlocks[17], ci)if n < 9: ci = nn.Sequential(allBlocks[9], ci)modelTmp = nn.Sequential(bk, ci, nn.Softmax(dim=0))modelTmp = modelTmp.cuda()optimizer = torch.optim.Adam(modelTmp.parameters(), lr=opt.lr) tries = 0XbatchTest = torch.zeros(opt.batchSize, nFilters, 32, 32)while (gamma < opt.gammaThresh and ((opt.checkEvery * tries) < opt.maxIters)):accTrain = 0; accTest = 0; err = 0;for batch in range(1, opt.checkEvery + 1):optimizer.zero_grad()# get batch of training samplesints = np.random.random_integers(np.shape(Xtrain)[0] - 1, size=(opt.batchSize))Xbatch = Xtrain[ints]Ybatch = Variable(torch.from_numpy(Ytrain[ints])).cuda().long()# do transformationsif opt.transform: Xbatch = transform(Xbatch)data = Variable(torch.from_numpy(Xbatch)).float().cuda()for i in range(n): data = allBlocks[i](data)# get gradientsoutput = modelTmp(data)loss = torch.exp(criterion(output, Ybatch))loss.backward()err += loss.data[0]# evaluate training accuracyoutput = modelTmp(data)accTrain += np.mean(torch.max(output, 1)[1].cpu().data.numpy() == Ytrain[ints])# get test accuracy model.eval()ints = np.random.random_integers(np.shape(Xtest)[0] - 1, size=(opt.batchSize))Xbatch = Xtest[ints]data = Variable(torch.from_numpy(Xbatch)).float().cuda()for i in range(n): data = allBlocks[i](data)output = modelTmp(data)accTest += np.mean(torch.max(output, 1)[1].cpu().data.numpy() == Ytest[ints])model.train()if batch % opt.printEvery == 0:accTrain /= opt.printEveryaccTest /= opt.printEveryerr /= opt.printEveryprinter([n, rounds, totalIterations + batch + (opt.checkEvery * tries), err, accTrain, accTest])accTrain = 0;accTest = 0; err = 0;optimizer.step()totalIterations += opt.checkEverytries += 1# get performance of new layera_current, Xoutput_previous = getPerformance(modelTmp, Xtrain, Ytrain, n + 1)gamma = (a_current - a_previous) / (1 - a_current)a_previous = a_currentprinter([n, gamma, opt.gammaThresh])if gamma < opt.gammaThresh:breakelse:s += np.log(Xoutput_previous)

逐层训练ResNet块,使用Boosting理论来增强分类性能。具体步骤包括:

  1. 计算损失函数。
  2. 加载对应的ResNet块。
  3. 进行优化迭代,计算训练和测试集上的准确率,并根据gamma值判断是否继续训练。

保存模型

torch.save(model.state_dict(), opt.modelPath)

保存训练好的模型。

核心代码

初始化部分

a_previous = 0.0
a_current = -1.0
s = np.zeros((nTrain, numClasses))
cost = np.zeros((nTrain, numClasses))
Xoutput_previous = np.zeros((nTrain, numClasses))
Ybatch = np.zeros((opt.batchSize))
YbatchTest = np.zeros((opt.batchSize))
gamma_previous = opt.gammaFirst
totalIterations = 0; tries = 0

这里初始化了一些变量,包括模型的统计信息、训练样本的预测输出、批量训练样本等。其中:

  • a_previousa_current 是当前和之前的提升系数。
  • s 是一个保存每个训练样本在每个类别上的累积输出。
  • cost 是样本的代价矩阵。
  • Xoutput_previous 是上一轮的输出。
  • gamma_previous 是上一轮的提升系数。
  • totalIterationstries 用于记录总迭代次数和尝试次数。

1.初始化阶段(主循环)

for n in range(rounds):gamma = -1Z = 0
  • gamma = -1Z = 0 初始化了一些用于计算的变量。
  • rounds 是算法的迭代轮数。在代码中设置为25,每轮迭代都会添加一个新的残差块,并调整模型参数。
  • 每一轮次训练前将 gammaZ 置零。

2.计算代价函数

    for i in range(nTrain):localSum = 0for l in range(numClasses):if l != Ytrain[i]:cost[i][l] = np.exp(s[i][l] - s[i][int(Ytrain[i])])localSum += cost[i][l]cost[i][int(Ytrain[i])] = -1 * localSumZ += localSum

这个部分计算每个训练样本的代价函数,并将计算所有错误分类的代价,存储在 cost 数组中。

每个训练样本的成本通过计算每个类别的错误分类代价 cost。如果样本 i 的真实类别为 Ytrain[i],则计算该样本在其他类别上的成本之和 localSum,并将 localSum 赋值给该样本真实类别的成本(取负值)。

  • cost[i][l] = np.exp(s[i][l] - s[i][int(Ytrain[i])]) 计算样本 i i i 在类别 l l l 上的代价。
  • cost[i][int(Ytrain[i])] = -1 * localSum 将当前样本在其真实类别上的代价设为负的 localSum
  • Z 是所有样本的总代价。

3. 获取当前分类层

    bk = allBlocks[n]ci = nn.Sequential(model[6], model[7], model[8])if n < 17: ci = nn.Sequential(allBlocks[17], ci)if n < 9:  ci = nn.Sequential(allBlocks[9], ci)modelTmp = nn.Sequential(bk, ci, nn.Softmax(dim=0))modelTmp = modelTmp.cuda()

这段代码的作用是创建一个临时模型 modelTmp,它由当前迭代的残差块 bk 和一些预定义的分类层 ci 组成。以下是具体解释:

  • bk 表示当前迭代的残差块。
  • ci 表示后续的分类层,包含模型中的一些层。

根据当前迭代次数 n,动态调整 ci 的层次结构:

  • 如果当前迭代次数 n 小于 17,那么在分类层 ci 前面加上第 17 块的残差块。
  • 如果当前迭代次数 n 小于 9,那么在分类层 ci 前面加上第 9 块的残差块。

这样的设计使得模型在不同的迭代次数 n 下,分类层 ci 的结构不同,逐步增加模型的复杂性。这个结构确保了模型能够逐层学习和调整,从而提高分类性能。

4.1 优化器设置

    optimizer = torch.optim.Adam(modelTmp.parameters(), lr=opt.lr) tries = 0XbatchTest = torch.zeros(opt.batchSize, nFilters, 32, 32)

使用 Adam 优化器,并初始化 XbatchTest 用于测试。

Adam 优化器是什么?大概的数学原理是什么?是对应的梯度下降算法吗?还是什么其他的算法?

Adam(Adaptive Moment Estimation)是一种基于一阶梯度的优化算法,结合了动量和自适应学习率两个方法。它在深度学习中被广泛使用,因为它在处理稀疏梯度和非平稳目标上表现良好。
Adam的数学原理:

  • 计算每个参数的梯度的一阶动量(平均值)和二阶动量(方差)。
  • 对每个参数的更新使用动量和学习率的校正。

具体来说,Adam 优化器的步骤如下:

  1. 初始化动量和二阶动量。
  2. 在每次迭代中更新动量和二阶动量。
  3. 根据动量和二阶动量校正参数更新步长。

具体的更新公式为:

  1. m t = β 1 m t − 1 + ( 1 − β 1 ) g t m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t mt=β1mt1+(1β1)gt
  2. v t = β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 vt=β2vt1+(1β2)gt2
  3. m ^ t = m t 1 − β 1 t \hat{m}_t = \frac{m_t}{1 - \beta_1^t} m^t=1β1tmt
  4. v ^ t = v t 1 − β 2 t \hat{v}_t = \frac{v_t}{1 - \beta_2^t} v^t=1β2tvt
  5. θ t = θ t − 1 − η m ^ t v ^ t + ϵ \theta_t = \theta_{t-1} - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} θt=θt1ηv^t +ϵm^t
    其中:
  • g t g_t gt 是梯度。
  • m t m_t mt v t v_t vt 分别是一阶和二阶动量。
  • β 1 \beta_1 β1 β 2 \beta_2 β2 是动量系数,通常取 0.9 0.9 0.9 0.999 0.999 0.999
  • ϵ \epsilon ϵ 是一个小常数,用于防止分母为零,通常取 1 0 − 8 10^{-8} 108
  • η \eta η 是学习率。

4.2 训练循环

在这里插入图片描述

while (gamma < opt.gammaThresh and ((opt.checkEvery * tries) < opt.maxIters)):accTrain = 0; accTest = 0; err = 0;for batch in range(1, opt.checkEvery+1):optimizer.zero_grad()

zero_grad():在每次反向传播之前,将所有参数的梯度缓存清零。在 PyTorch 中,梯度是累加的,所以需要在每次迭代开始前清零。

在满足 gamma 小于阈值和最大迭代次数限制的条件下,开始训练循环。

关于 opt.gammaThreshgamma

这里的 opt.gammaThresh 对应算法中的 γ t \gamma_t γt,而 gamma 对应的是 γ \gamma γ。代码中的逻辑 while (gamma < opt.gammaThresh) 实际上在检查当前的 γ \gamma γ 是否小于阈值。这是因为我们希望 γ \gamma γ 足够大,代表模型的分类能力足够强,当 γ \gamma γ 小于阈值时,停止训练。

具体来说:

  • gamma 初始化为 -1,表示最差情况。
  • 当训练时,更新 gamma 的值,如果 gamma 达到或超过 opt.gammaThresh,则说明模型性能达到预期,可以停止训练。
获取训练样本批次
            ints = np.random.random_integers(np.shape(Xtrain)[0] - 1, size=(opt.batchSize))Xbatch = Xtrain[ints]Ybatch = Variable(torch.from_numpy(Ytrain[ints])).cuda().long()

从训练集中随机选择一个批次样本,并将其转换为 PyTorch 变量。

数据变换和前向传播
            if opt.transform: Xbatch = transform(Xbatch)data = Variable(torch.from_numpy(Xbatch)).float().cuda()for i in range(n): data = allBlocks[i](data)

如果指定了数据变换,则对数据进行变换,然后进行前向传播,通过前 n 个残差块处理数据。

获取梯度和更新权重
            output = modelTmp(data)loss = torch.exp(criterion(output, Ybatch))loss.backward()err += loss.data[0]output = modelTmp(data)accTrain += np.mean(torch.max(output,1)[1].cpu().data.numpy() == Ytrain[ints])model.eval()ints = np.random.random_integers(np.shape(Xtest)[0] - 1, size=(opt.batchSize))Xbatch = Xtest[ints]data = Variable(torch.from_numpy(Xbatch)).float().cuda()for i in range(n): data = allBlocks[i](data)output = modelTmp(data)accTest += np.mean(torch.max(output,1)[1].cpu().data.numpy() == Ytest[ints])model.train()

在训练过程中,通过交叉熵+指数损失函数计算并累积损失 err

criterion = nn.CrossEntropyLoss().cuda()

计算训练准确率 accTrain 和测试准确率 accTest

打印和梯度裁剪
            if batch % opt.printEvery == 0:accTrain /= opt.printEveryaccTest  /= opt.printEveryerr /= opt.printEveryprinter([n, rounds, totalIterations + batch + (opt.checkEvery * tries), err, accTrain, accTest])accTrain = 0; accTest = 0; err = 0;for p in modelTmp.parameters(): p.grad.data.clamp_(-.1, .1)            optimizer.step()
  • 每隔 opt.printEvery 次批量训练输出一次当前状态,包括错误率、训练准确率和测试准确率。
  • 进行梯度裁剪,防止梯度爆炸。
  • step():执行一步优化算法,即根据当前的梯度和动量更新模型参数。

梯度裁剪对应的代码是:

for p in modelTmp.parameters(): p.grad.data.clamp_(-.1, .1)

这段代码通过限制梯度的值在 [-0.1, 0.1] 范围内,防止梯度爆炸。这对于稳定训练过程非常重要,尤其是深度神经网络,梯度可能会在反向传播过程中变得非常大。

计算 gamma

        accTrain, Xoutput = getPerformance(modelTmp, Xtrain, Ytrain, n)gamma_current = -1 * np.sum(Xoutput * cost) / Zgamma = (gamma_current ** 2 - gamma_previous ** 2)/(1 - gamma_previous ** 2) if gamma > 0: gamma = np.sqrt(gamma)else: gamma = -1 * np.sqrt(-1 * gamma)a_current = 0.5 * np.log((1 + gamma_current) / (1 - gamma_current))

更新模型参数,并在每个批量训练后进行一次梯度下降。

  1. 计算当前模型的性能,得到 gamma_current
  2. 根据 gamma_currentgamma_previous 更新 gamma

公式:
γ t ← γ ~ t + 1 2 − γ ~ t 2 1 − γ ~ t 2 \gamma_t \leftarrow \sqrt{\frac{\tilde{\gamma}_{t+1}^2 - \tilde{\gamma}_t^2}{1 - \tilde{\gamma}_t^2}} γt1γ~t2γ~t+12γ~t2

其中:

  • gamma_current 是当前训练轮次的 γ t \gamma_t γt
  • gamma_previous 是前一次训练轮次的 γ t \gamma_t γt
为什么这样处理负数的情况?

γ \gamma γ 为负数时,我们使用以下公式进行更新:
γ = − 1 ∗ − 1 ∗ γ ~ t + 1 2 − γ ~ t 2 1 − γ ~ t 2 \gamma = -1 * \sqrt{-1 * \frac{\tilde{\gamma}_{t+1}^2 - \tilde{\gamma}_t^2}{1 - \tilde{\gamma}_t^2}} γ=111γ~t2γ~t+12γ~t2

这样处理的原因是:

  • γ \gamma γ 的计算可能会因为 γ ~ t + 1 2 − γ ~ t 2 \tilde{\gamma}_{t+1}^2 - \tilde{\gamma}_t^2 γ~t+12γ~t2 的值而导致根号内出现负数。这在数学上是不可接受的。
  • 为了避免这种情况,取负号后再开方,以确保 γ \gamma γ 的计算结果是一个实数。负号处理后仍然保持 γ \gamma γ 的真实值,因为 γ \gamma γ 本身可以是负数或正数。

这个处理方式巧妙地避免了计算过程中根号内为负数的问题,同时保持了 γ \gamma γ 的实际含义。

尝试次数和权重更新

        tries += 1if (gamma > opt.gammaThresh or ((opt.checkEvery * tries) >= opt.maxIters)):totalIterations = totalIterations + (tries * opt.checkEvery)printer([gamma, gamma_current, gamma_previous])printer(['a_{t+1}:', a_current, 'gamma_t:', gamma])    s += Xoutput * a_current - Xoutput_previous * a_previousaccTest, _ = getPerformance(modelTmp, Xtest, Ytest, n)    printer(['t', rounds, 'numBatches:', tries * opt.checkEvery, 'test accuracy:', accTest])    gamma_previous = gamma_current

更新 tries,如果 gamma 达到阈值或尝试次数达到最大迭代次数,则记录迭代次数并打印信息。最后更新累积输出 sgamma_previous

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

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

相关文章

axure9设置组件自适应浏览器大小

问题&#xff1a;预览时不展示下方的滚动条 方法一&#xff1a;转化为动态面板 1.在页面上创建一个矩形 2.右键-转化为动态面板 3.双击进入动态面板设置 4.设置动态面板矩形的颜色 5.删除原来的矩形 6.关闭动态面板&#xff0c;点击预览 7.此时可以发现底部没有滚动条了 方法…

AI大模型之争:通用与垂直,谁将拔得头筹?

✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点赞、关注、收藏、评论&#xff0c;是对我最大…

移植案例与原理 - startup子系统之syspara_lite系统属性部件 (2)

系统属性部件syspara_lite负责提供获取与设置操作系统相关的系统属性&#xff0c;包括默认系统属性、OEM厂商系统属性和自定义系统属性。为满足OpenHarmony产品兼容性规范&#xff0c;产品解决方案需要实现获取设备信息的接口&#xff0c;如&#xff1a;产品名、品牌名、厂家名…

苹果Mac电脑遭恶意软件攻击 Mac第三方恶意软件删除不了

苹果Mac电脑一直以来都以安全性和稳定性著称&#xff0c;许多用户认为Mac电脑不会受到恶意软件的侵害&#xff0c;但事实上&#xff0c;Mac电脑也不是绝对安全的&#xff0c;近年来&#xff0c;有越来越多的恶意软件针对Mac电脑进行攻击&#xff0c;甚至有些恶意软件可以绕过苹…

如何看待SD3 版本,和SDXL相比有何优势?

胖友们好&#xff01;&#xff01;&#xff01;痴迷AI的本枕又来写Stable Diffusion了…… SD社区群众们翘首企盼的SD3的weights总算在huggingface上发布了 于是我也在当天非常激动地用ComfyUI生成了一些图像…… 这篇文章算是半个评测半个心得吧&#xff0c;因为有些东西是…

解禁日大涨,爱玛科技的投资前景值得信任吗?

6月17日&#xff0c;爱玛迎来6.28亿股、金额超190亿元的解禁&#xff0c;占总股本72.91%。不过&#xff0c;爱玛股价在巨量解禁中反而迎来涨势&#xff0c;因为这部分股票中&#xff0c;创始人张剑持有的限售股数量几乎就占了爱玛总股本的七成。某种意义上&#xff0c;市场认为…

Windows系统下制作Windows Server系统U盘启动及安装指导

Windows系统下制作Windows Server系统U盘启动及安装指导 一、准备工作 U盘不得小于8G(推荐使用usb3.0接口)&#xff1b;下载好对应的系统镜像&#xff1b;下载RUFUS或者软通碟U盘制作启动软件&#xff1b; 二、Windows操作系统下制作U盘启动&#xff08;这里以使用RUFUS软件…

面向对象和面向过程

Python完全采用了面向对象的思想&#xff0c;是真正面向对象的编程语言&#xff0c;完全支持面向对象的基本功能&#xff0c;例如&#xff1a;继承、多态、封装等。 Python支持面向过程、面向对象、函数式编程等多种编程方式。而Java编程语言支持面向对象的编程方式&#xff0…

基于WPF技术的换热站智能监控系统16--动态数据绑定

1、实现思路 1&#xff09;实时读取到的数据绑定到前台UI控件上&#xff0c;这个通过MVVM模式实现&#xff0c;同时注意实时读取必须通过任务task异步方式&#xff0c;这就需要读取PLC数据。 2&#xff09;UI控件的动作&#xff0c;如开或关水泵&#xff0c;必定能够将值写入…

Java基础 - 练习(一)打印等腰三角形

Java基础练习 打印等腰三角形&#xff0c;先上代码&#xff1a; public static void main(String[] args) {// 打印等腰三角形System.out.println("打印等腰三角形&#xff1a;");isoscelesTriangle(); } public static void isoscelesTriangle() {// for循环控制行…

ollama模型CPU轻量化部署

一、定义 ollama 定义环境部署demo加载本地模型方法基本指令关闭开启ollamaollama 如何同时 运行多个模型, 多进程ollama 如何分配gpu修改模型的存储路径 二、实现 ollama 定义 ollama 是llama-cpp 的进一步封装&#xff0c;更加简单易用&#xff0c;类似于docker. 模型网址…

【深度学习】AI换脸,EasyPhoto: Your Personal AI Photo Generator【一】

论文&#xff1a;https://arxiv.org/abs/2310.04672 文章目录 摘要IntroductionTraining Process3 推理过程3.1 面部预处理3.3 第二扩散阶段3.4 多用户ID 4 任意ID5 实验6 结论 下篇文章进行实战。 摘要 稳定扩散Web UI&#xff08;Stable Diffusion Web UI&#xff0c;简称…

Linux_理解程序地址空间和页表

目录 1、进程地址空间示意图 2、验证进程地址空间的结构 3、验证进程地址空间是虚拟地址 4、页表-虚拟地址与物理地址 5、什么是进程地址空间 6、进程地址空间和页表的存在意义 6.1 原因一&#xff08;效率性&#xff09; 6.2 原因二&#xff08;安全性&#xff09; …

DOS INT 21H中断 2号功能暗改AL

注意此时AX0200&#xff0c;DX0057 执行INT 21H之后&#xff1a; 可以看到执行完“??? [BXSI]”之后&#xff0c;AL就变为了57H&#xff0c;和DL相同。 部分INT 21H功能表&#xff1a; 所以究竟是什么原因呢&#xff1f; -------------------------------------------…

MDK 代码烧录到RAM区运行

MDK 代码烧录到RAM区运行 环境配置设置分散加载文件启动文件修改设置外部调试器烧录 建立函数入口半主机问题导致BKPT 0xAB 有一个需求&#xff0c;除了IAR以及GCC的版本工程还需要MDK版本&#xff0c;为了实现最小的工程环境&#xff0c;flash烧录算法也没有&#xff0c;这时需…

【C++】:list容器的基本使用

目录 &#x1f680;前言一&#xff0c;list的介绍二&#xff0c;list的基本使用2.1 list的构造2.2 list迭代器的使用2.3 list的头插&#xff0c;头删&#xff0c;尾插和尾删2.4 list的插入和删除2.5 list 的 resize/swap/clear &#x1f680;前言 list中的接口比较多&#xff…

SpringBootWeb 篇-入门了解 Apache POI 使用方法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Apache POI 概述 2.0 使用 Apache POI 读写 Excel 文件 2.1 写入 Excel 文件 2.2 写入 Excel 文件代码演示 2.3 读取 Excel 文件 2.4 读取 Excel 文件代码演示 1.…

使用Multipass编译OpenHarmony工程

Multipass 是一个轻量级虚拟机管理器&#xff0c;支持 Linux、Windows 与 macOS&#xff0c;这是为希望使用单个命令提供全新 Ubuntu 环境的开发人员而设计的。使用 Linux 上的 KVM、Windows 上的 Hyper-V 和 macOS 上的 HyperKit 来以最小的开销运行 VM&#xff0c;同时它还可…

【网络安全学习】使用Kali做渗透情报收集-02-<指纹识别+目录扫描>

1.指纹识别 指纹识别是指通过一些特征或特定文件来识别目标网站或系统的类型、版本、组件等信息&#xff0c;以便寻找相应的漏洞或攻击方法。 主动指纹识别 通过向目标系统发送正常和异常的请求以及对文件内容的查找&#xff0c;记录响应方式&#xff0c;然后与指纹库进行对比…

【系统架构设计师】一、计算机系统基础知识(指令系统|存储系统|输入输出技术|总线结构)

目录 一、指令系统 1.1 计算机指令 1.2 指令寻址方式 1.3 CISC 与 RISC 1.4 指令流水线 二、存储系统 2.1 分级存储体系 2.2 地址映射 2.3 替换算法 2.4 磁盘 2.4.1 磁盘结构和参数 2.4.2 磁盘调度算法 三、输入输出技术 四、总线结构 五、考试真题练习 一、指令…