分类学习(加入半监督学习)
#随机种子固定,随机结果也固定
def seed_everything(seed):torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)torch.backends.cudnn.benchmark = Falsetorch.backends.cudnn.deterministic = Truerandom.seed(seed)np.random.seed(seed)os.environ['PYTHONHASHSEED'] = str(seed)#################################################################
seed_everything(0)
###############################################
#seed_everything(0)这一行调用了上述函数并传入了种子值0,
# 这意味着所有的随机操作都将基于这个种子值来进行初始化,从而确保了实验的可重复性。
固定随机种子:
首先,通过seed_everything(seed)函数设置所有随机数生成器的种子,确保实验结果的可重复性。这对于调试和复现实验结果非常重要。
---------------------------------------------------------------------------------------------------------------------------------
train_transform = transforms.Compose( #进行模型变换[transforms.ToPILImage(), #就是把224,224,3模型 -> 3,224,22transforms.RandomResizedCrop(224), #对图片放大裁剪,裁切出来224*224transforms.RandomRotation(50), #在50度以内进行旋转transforms.ToTensor()#变为张量]
)val_transform = transforms.Compose( #进行模型变换[transforms.ToPILImage(), #就是把224,224,3模型 -> 3,224,22 验证集的话就不用进行transforms模型变换# transforms.RandomResizedCrop(224), #对图片放大裁剪,裁切出来224*224# transforms.RandomRotation(50), #在50度以内进行旋转transforms.ToTensor()#变为张量]
)
图像变换:
定义了两种不同的图像变换方法train_transform和val_transform。训练集使用了包括随机裁剪、旋转等在内的数据增强技术,以增加模型的泛化能力;而验证集只进行了基本的转换操作,如调整大小和转为张量。
---------------------------------------------------------------------------------------------------------------------------------
class food_Dataset(Dataset):def __init__(self,path,mode="train"):self.mode=modeif mode == "semi":self.X=self.read_file(path)else:self.X,self.Y=self.read_file(path) #给一个路径,读出来X,Yself.Y = torch.LongTensor(self.Y) #将标签转化成长整型if mode=="train":self.transform = train_transformelse:self.transform = val_transformdef read_file(self,path):#读semi文件(没有标签的)if self.mode=="semi":file_list = os.listdir(path) # 列出文件下所有文件名字xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)for j, img_name in enumerate(file_list): # enumerate既可以读到下表,也可以读到下表里的东西img_path = os.path.join(path, img_name)img = Image.open(img_path) # 可以把图片读进来img = img.resize((HW, HW))xi[j, ...] = imgprint("读到了%d个训练数据" % len(xi))return xielse:for i in tqdm(range(11)):file_dir = path + "/%02d" % ifile_list = os.listdir(file_dir) # 列出文件下所有文件名字xi = np.zeros((len(file_list), HW, HW, 3), dtype=np.uint8)yi = np.zeros(len(file_list), dtype=np.uint8)for j, img_name in enumerate(file_list): # enumerate既可以读到下表,也可以读到下表里的东西img_path = os.path.join(file_dir, img_name)img = Image.open(img_path) # 可以把图片读进来img = img.resize((HW, HW))xi[j, ...] = imgyi[j] = iif i == 0:X = xiY = yielse:X = np.concatenate((X, xi), axis=0)Y = np.concatenate((Y, yi), axis=0)print("读到了%d个训练数据" % len(Y))return X, Ydef __getitem__(self, item): #这个函数的作用就是retuen X[item],Y[item]的值if self.mode=="semi":return self.transform(self.X[item]),self.X[item]#返回transform后的X和原始的Xelse:return self.transform(self.X[item]),self.Y[item] #加上transform是为了对图片进行函数增广def __len__(self):return len(self.X)
自定义数据集类:
food_Dataset: 自定义的数据集类,用于从指定路径读取图片及其标签(或无标签),并应用相应的变换。它支持三种模式:训练(train)、验证(val)和半监督学习(semi)。该类实现了__getitem__和__len__方法,使得它可以被PyTorch的数据加载器(DataLoader)使用。
---------------------------------------------------------------------------------------------------------------------------------
class semiDataset(Dataset):def __init__(self,no_label_loder,model,device,thres=0.99):x,y=self.get_label(no_label_loder,model,device,thres)if x==[]:self.flag=Falseelse:self.flag=Trueself.X=np.array(x) #转化成矩阵self.Y=torch.LongTensor(y)self.transform=train_transform #定义损失函数def get_label(self,no_label_loder,model,device,thres):model=model.to(device)pred_prob=[]#用一个列表存概率值labels=[]#用一个列表存对应的标签x=[]#把无标签的x存进去y=[]#把半监督学习后x对应的y存进去soft =nn.Softmaxwith torch.no_grad(): #半监督学习,对模型梯度不产生作用,因此加上with torch.no_grad()for bat_x, _ in no_label_loder: #no_label_loder返回两个值,不需要后面的,所以用_表示bat_x=bat_x.to(device)pred=model(bat_x)#预测值pred_soft=soft(pred)#转化为了概率pred_max,pred_value=pred_soft.max(1)#既可以返回最大概率值,又可以返回最大概率值下标 、1表示横着读pred_prob.extend(pred_max.cpu().numpy().tolist())#extend可以合并两个列表,append不行 对应概率的数组labels.extend(pred_value.cpu().numpy().tolist()) #对应的标签的数组for index,prob in enumerate(pred_prob):if prob>thres:x.append(no_label_loder.dataset[index][1])#取到原始数据y.append(labels[index])return x,ydef __getitem__(self, item):return self.transform(self.X[item]),self.Y[item]def __len__(self):return len(self.X)
自定义数据集类:
semiDataset: 另一个自定义数据集类,专门用于从未标记的数据中筛选出高置信度的样本及其预测标签,以便将其加入到训练集中。这个过程是通过调用模型对未标记数据进行预测来实现的。
---------------------------------------------------------------------------------------------------------------------------------
def get_semi_loader(no_label_loder,model,device,thres):semiset=semiDataset(no_label_loder,model,device,thres)if semiset.flag==False:return Noneelse:semi_loader=DataLoader(semiset,batch_size=16,shuffle=False)return semi_loader
半监督学习数据加载器:
get_semi_loader函数根据给定的无标签数据加载器、模型、设备和阈值来创建一个新的数据加载器,其中包含由模型预测并认为是可靠的样本。这允许模型从未标记的数据中学习,从而在有限的标记数据情况下提高性能。
---------------------------------------------------------------------------------------------------------------------------------
#模型框架
class myModel(nn.Module):def __init__(self,num_class):super(myModel, self).__init__()#3*224*224 -> 512*7*7 -> 拉直 -> 全连接self.conv1=nn.Conv2d(3,64,3,1,1) # -> 64*224*224 (卷积)self.bn1=nn.BatchNorm2d(64) #针对具有64个通道的二维数据的批量归一化层,目的是在训练过程中对该层输入数据进行归一化处理,以加快训练速度和提高模型性能。self.relu1=nn.ReLU() #激活函数self.pool1=nn.MaxPool2d(2) # 64*112*112 (池化)self.layer1=nn.Sequential(nn.Conv2d(64, 128, 3, 1, 1), # -> 128*112*112 (卷积)nn.BatchNorm2d(128),nn.ReLU(),nn.MaxPool2d(2) # 128*56*56)self.layer2 = nn.Sequential(nn.Conv2d(128, 256, 3, 1, 1), # -> 256*56*56 (卷积)nn.BatchNorm2d(256),nn.ReLU(),nn.MaxPool2d(2) # 256*28*28)self.layer3 = nn.Sequential(nn.Conv2d(256, 512, 3, 1, 1), # -> 512*28*28 (卷积)nn.BatchNorm2d(512),nn.ReLU(),nn.MaxPool2d(2) # 512*14*14)self.pool2=nn.MaxPool2d(2) #512*7*7self.fc1=nn.Linear(25088,1000) #拉直self.relu2=nn.ReLU()self.fc2=nn.Linear(1000,num_class)#1000->分类的类别def forward(self,x):x=self.conv1(x)x=self.bn1(x)x=self.relu1(x)x=self.pool1(x)x=self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.pool2(x)x=x.view(x.size()[0],-1) #拉直x=self.fc1(x)x=self.relu2(x)x=self.fc2(x)return x
CNN模型架构:
myModel是一个简单的卷积神经网络(CNN),设计用于分类任务。它包含了多个卷积层、批量归一化层、ReLU激活函数和最大池化层,最后通过全连接层输出分类结果。
---------------------------------------------------------------------------------------------------------------------------------
def train_val(model,train_loader,val_loader,no_label_loader,device,epochs,optimizer,loss,thres,save_path):model = model.to(device)semi_loader=Noneplt_train_loss = [] #记录所有轮次的lossplt_val_loss = []plt_train_acc = []plt_val_acc = []max_acc=0.0for epoch in range(epochs): #冲锋的号角train_loss = 0.0val_loss = 0.0semi_loss = 0.0train_acc = 0.0val_acc = 0.0semi_acc = 0.0start_time = time.time()model.train() #模型调为训练模式for batch_x, batch_y in train_loader:x, target = batch_x.to(device), batch_y.to(device)pred = model(x)train_bat_loss = loss(pred, target)train_bat_loss.backward()optimizer.step() #更新模型的作用,更新参数 之后要梯度清零,否则会积累梯度optimizer.zero_grad()train_loss += train_bat_loss.cpu().item()train_acc += np.sum(np.argmax(pred.detach().cpu().numpy(),axis=1)==target.cpu().numpy())#pred.detach().cpu().numpy()取张量数据,np.argmax(),axis=1 的意思是取一行最大的坐标,#也就是取概率最大的坐标,与标签相对比,相等就是Ture,反之Falseplt_train_loss.append(train_loss / train_loader.__len__())plt_train_acc.append(train_acc/train_loader.dataset.__len__()) #记录准确率if semi_loader!=None:for batch_x, batch_y in semi_loader:x, target = batch_x.to(device), batch_y.to(device)pred = model(x)semi_bat_loss = loss(pred, target)semi_bat_loss.backward()optimizer.step() #更新模型的作用,更新参数 之后要梯度清零,否则会积累梯度optimizer.zero_grad()semi_loss += train_bat_loss.cpu().item()semi_acc += np.sum(np.argmax(pred.detach().cpu().numpy(),axis=1)==target.cpu().numpy())#pred.detach().cpu().numpy()取张量数据,np.argmax(),axis=1 的意思是取一行最大的坐标,#也就是取概率最大的坐标,与标签相对比,相等就是Ture,反之Falseprint("半监督数据集的训练准确率为",semi_acc/semi_loader.dataset.__len__())model.eval()with torch.no_grad():for batch_x, batch_y in val_loader:x, target = batch_x.to(device), batch_y.to(device)pred = model(x)val_bat_loss = loss(pred, target)val_loss += val_bat_loss.cpu().item()val_acc += np.sum(np.argmax(pred.detach().cpu().numpy(), axis=1) == target.cpu().numpy())plt_val_loss.append(val_loss/ val_loader.dataset.__len__())plt_val_acc.append(val_acc / val_loader.dataset.__len__()) # 记录准确率if plt_val_acc[-1]>0.7:semiloader=get_semi_loader(no_label_loader,model,device,thres) #如果正确率达到0.7,就可以训练if val_acc > max_acc:torch.save(model, save_path)max_acc = val_lossprint('[%03d/%03d] %2.2f sec(s) Trainloss: %.6f |Valloss: %.6f Trainacc: %.6f | Valacc: %.6f'% \(epoch, epochs, time.time() - start_time, plt_train_loss[-1], plt_val_loss[-1],plt_train_acc[-1],plt_val_acc[-1]))plt.plot(plt_train_loss)plt.plot(plt_val_loss)plt.title("loss")plt.legend(["train", "val"])plt.show()plt.plot(plt_val_acc)plt.plot(plt_val_acc)plt.title("acc")plt.legend(["train", "val"])plt.show()
训练与验证流程 (train_val 函数)
-
初始化:将模型移动到GPU(如果可用),准备记录损失和准确率的列表。
-
循环遍历epochs:对于每个epoch:
- 执行训练阶段:计算训练损失和准确率。
- 如果存在半监督数据,则对其进行处理。
- 执行验证阶段:计算验证损失和准确率,检查是否需要保存最佳模型。
- 根据验证准确率达到阈值,更新半监督数据加载器。
- 输出当前epoch的信息,包括时间消耗、损失和准确率。
-
绘图:使用matplotlib绘制训练和验证的损失与准确率变化曲线,帮助直观了解模型的学习过程。
---------------------------------------------------------------------------------------------------------------------------------
train_path=r"D:\python_data\classify\food_classification\food-11_sample\training\labeled"
val_path=r"D:\python_data\classify\food_classification\food-11_sample\validation"
no_label_path=r"D:\python_data\classify\food_classification\food-11_sample\training\unlabeled\00"
train_set = food_Dataset(train_path,"train")
val_set = food_Dataset(val_path,"val")
no_label_set = food_Dataset(no_label_path ,"semi")
train_loader = DataLoader(train_set,batch_size=16,shuffle=True) #数据加载器
val_loader = DataLoader(val_set,batch_size=16,shuffle=True)
no_label_loader = DataLoader(no_label_set,batch_size=16,shuffle=False)#False是因为没有标签的照片不能打乱
#batch_size=4:此参数指定了每个批次(batch)中包含的数据样本数量
#为4。这意味着每次迭代过程中,DataLoader都会从train_set中取出4
#个样本组成一个批次返回给用户。选择合适的batch_size对模型训练的
#速度和性能都有影响。
#shuffle=True:在每个epoch开始前,如果设置为True,则DataLoader会将数据集中的数据顺序打乱。# model = myModel(11)from torchvision.models import resnet18
model=resnet18(pretrained=True) #pretrained=True 就是不仅用大佬的架构,还用大佬的参数 False 只用架构,不用参数
in_fetures=model.fc.in_features #提取模型分类的输出头
model.fc= nn.Linear(in_fetures,11)lr=0.001 #学习率
loss = nn.CrossEntropyLoss() #直接调用交叉熵损失
optimizer = torch.optim.AdamW(model.parameters(),lr=lr,weight_decay=1e-4) #优化器AdamW
#model.parameters(): 这个方法会返回一个生成器,包含了模型中所有可学习参数(即网络层的权重和偏置等)
# 。通过传递这个生成器给优化器,告诉优化器需要更新哪些参数。
#weight_decay=1e-4: 权重衰减系数,用于指定L2正则化的强度。L2正则化是一种防止过拟合的技术,通过对损
# 失函数添加一个与权重大小成比例的惩罚项来实现。1e-4意味着对于每个权重w,都会在损失函数中加上权重衰减有
# 助于控制模型复杂度,避免模型过度拟合训练数据。
device="cuda" if torch.cuda.is_available() else "cpu" #如果满足就是cude 否则就是CPU
save_path = "model_save/best_model.pth" #保存最好的模型
epochs=4
thres =0.1
train_val(model,train_loader,val_loader,no_label_loader,device,epochs,optimizer,loss,thres,save_path)
相关文章:
分类学习(加入半监督学习)
#随机种子固定,随机结果也固定 def seed_everything(seed):torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)torch.backends.cudnn.benchmark Falsetorch.backends.cudnn.deterministic Truerandom.seed(seed)np.random.see…...
Serilog: 强大的 .NET 日志库
Serilog 是一个功能强大的日志记录库,专为 .NET 平台设计。它提供了丰富的 API 和可插拔的输出器及格式化器,使得开发者能够轻松定制和扩展日志记录功能。在本文中,我们将探索 Serilog 的基础知识、API 使用、配置和一些常见的示例。 1. 日志…...
Matlab——添加坐标轴虚线网格的方法
第一步:在显示绘制图的窗口,点击左上角 “编辑”,然后选“坐标区属性” 第二步:点 “网格”,可以看到添加网格的方框了...
π0及π0_fast的源码解析——一个模型控制7种机械臂:对开源VLA sota之π0源码的全面分析,含我司微调π0的部分实践
前言 ChatGPT出来后的两年多,也是我疯狂写博的两年多(年初deepseek更引爆了下),比如从创业起步时的15年到后来22年之间 每年2-6篇的,干到了23年30篇、24年65篇、25年前两月18篇,成了我在大模型和具身的原始技术积累 如今一转眼已…...
TCP7680端口是什么服务
WAF上看到有好多tcp7680端口的访问信息 于是上网搜索了一下,确认TCP7680端口是Windows系统更新“传递优化”功能的服务端口,个人理解应该是Windows利用这个TCP7680端口,直接从内网已经具备更新包的主机上共享下载该升级包,无需从微…...
服务器python项目部署
角色:root, 其他用户应该也可以 1. 安装python3环境 #如果是新机器,尽量执行,避免未知报错 yum -y update python -v yum install python3 python3 -v2. 使用virtualenvwrapper 创建虚拟环境,并使用workon切换不同的虚拟环境 # 安装virtua…...
Hive-优化(语法优化篇)
列裁剪与分区裁剪 在生产环境中,会面临列很多或者数据量很大时,如果使用select * 或者不指定分区进行全列或者全表扫描时效率很低。Hive在读取数据时,可以只读取查询中所需要的列,忽视其他的列,这样做可以节省读取开销…...
C语言100天练习题【记录本】
C语言经典100题(手把手 编程) 可以在哔哩哔哩找到(url:C语言经典100题(手把手 编程)_哔哩哔哩_bilibili) 已解决的天数:一,二,五,六,八…...
记录排查服务器CPU负载过高
1.top 命令查看cpu占比过高的进程id 这里是 6 2. 查看进程中占用CPU过高的线程 id 这里是9 top -H -p 6 ps -mp 6 -o THREAD,tid,time 使用jstack 工具 产看进程的日志 需要线程id转换成16进制 jstack 6 | grep “0x9” 4.jstack 6 可以看进程的详细日志 查看日志发现是 垃圾回…...
Spring Boot 项目中 Redis 常见问题及解决方案
目录 缓存穿透缓存雪崩缓存击穿Redis 连接池耗尽Redis 序列化问题总结 1. 缓存穿透 问题描述 缓存穿透是指查询一个不存在的数据,由于缓存中没有该数据,请求会直接打到数据库上,导致数据库压力过大。 解决方案 缓存空值:即使…...
基于Spring Boot的校园失物招领系统的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
10 【HarmonyOS NEXT】 仿uv-ui组件开发之Avatar头像组件开发教程(一)
温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! 目录 第一篇:Avatar 组件基础概念与设计1. 组件概述2. 接口设计2.1 形状类型定义2.2 尺寸类型定义2.3 组件属性接口 3. 设计原则4. 使用…...
OpenHarmony 5.0.0 Release
OpenHarmony 5.0.0 Release 版本概述 OpenHarmony 5.0.0 Release版本标准系统能力持续完善。相比OpenHarmony 5.0 Beta1,Release版本做出了如下特性新增或增强: 应用框架新增更多生命周期管理能力、提供子进程相关能力,可以对应用运行时的…...
RSA的理解运用与Pycharm组装Cryptodome库
1、RSA的来源 RSA通常指基于RSA算法的密码系统,令我没想到的是,其名字的来源竟然不是某个含有特别意义的单词缩写而成(比如PHP:Hypertext Preprocessor(超文本预处理器)),而是由1977年提出该算法的三个歪果…...
Android 多用户相关
Android 多用户相关 本文主要记录下android 多用户相关的adb 命令操作. 1: 获取用户列表 命令: adb shell pm list users 输出如下: Users:UserInfo{0:机主:c13} running默认只有一个用户, id为0 ,用户状态为运行 2: 创建新用户 命令: adb shell …...
第三课:异步编程核心:Callback、Promise与Async/Await
Node.js 是一个基于事件驱动的非阻塞 I/O 模型,这使得它非常适合处理高并发的网络请求。在 Node.js 中,异步编程是一项非常重要的技能。理解和掌握异步编程的不同方式不仅能提高代码的效率,还能让你更好地应对复杂的开发任务。本文将深入探讨…...
红果短剧安卓+IOS双端源码,专业短剧开发公司
给大家拆解一下红果短剧/河马短剧,这种看光解锁视频,可以挣金币的短剧APP。给大家分享一个相似的短剧APP源码,这个系统已接入穿山甲广告、百度广告、快手广告、腾讯广告等,类似红果短剧的玩法,可以看剧赚钱,…...
C# ArrayPool
ArrayPool<T> 的作用ArrayPool<T> 的使用方式共享数组池自定义数组池 注意事项应用场景 在C#中,ArrayPool<T> 是一个非常有用的工具类,主要用于高效地管理数组的分配和回收,以减少内存分配和垃圾回收的压力。它属于 System…...
Conda 生态系统介绍
引言 Conda 是一个开源的包管理和环境管理系统,最初由 Continuum Analytics 开发,现为 Anaconda 公司维护。它在数据科学和 Python/R 生态中占据核心地位,因其能跨平台(Linux/Windows/macOS)管理依赖关系,并通过虚拟环境隔离不同项目的开发环境。Conda 的生态系统包含多…...
批量将 Word 拆分成多个文件
当一个 Word 文档太大的时候,我们通常会将一个大的 Word 文档拆分成多个小的 Word 文档,在 Office 中拆分 Word 文档是比较麻烦的,我们需要将 Word 文档的页面复制到另外一个 Word 文档中去,然后删除原 Word 文档中的内容。当然也…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
