34- PyTorch数据增强和迁移学习 (PyTorch系列) (深度学习)

news2025/7/23 22:50:02

知识要点

  •  对vgg  模型进行迁移学习
  • 定义数据路径: train_dir = os.path.join(base_dir, 'train')     # base_dir = './dataset'
  • 定义转换格式:

transform = transforms.Compose([transforms.Resize((96, 96)),  # 统一缩放
                                transforms.ToTensor(),        # 转换为tensor
                                transforms.Normalize(mean=[0.5, 0.5, 0.5],  # 正则化
                                                     std=[0.5, 0.5, 0.5])])
  • 数据转换: train_ds = torchvision.datasets.ImageFolder(train_dir, transform=transform)
  • train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size, shuffle=True, drop_last=True)   # 定义数据训练格式
  • 修改结果特征, 4分类: model.classifier[-1].out_features = 4   # 调整输出层
  • 数据位置调整: device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
  • 定义优化器: optimizer = optim.Adam(model.parameters(), lr=0.001)
  • 定义损失: loss_fn = nn.CrossEntropyLoss()
  • 梯度归零: optimizer.zero_grad()
  • loss.backward()
  • 梯度更新: optimizer.step()
  • 查看模型: model.parameters
  • 图示: plt.plot(range(1, epochs+1), train_loss, label='train_loss')
  • 图例显示: plt.legend()
  • 模型参数: model.state_dict()
  • 保存参数: torch.save(model.state_dict(), './vgg16.pth')
  • 给模型传参: new_model.load_state_dict(torch.load('./vgg16.pth'))
  • 测试数据预测:
# 测试过程
test_correct = 0
test_total = 0
new_model.eval()  # eval  评价, 评估

with torch.no_grad():
    for x, y in test_d1:
        x, y = x.to(device), y.to(device)
        y_pred = new_model(x)
        y_pred = torch.argmax(y_pred, dim=1)
        test_correct += (y_pred == y).sum().item()
        test_total += y.size(0)
        
epoch_test_acc = test_correct / test_total
print(epoch_test_acc)    # 0.9644444444444444
  • 保存最佳参数:
model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

import copy
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 没有训练前的初始化参数
best_model_weight = model.state_dict()
best_acc = 0.0
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        # 更新参数, 保存最佳参数
        best_model_weight = copy.deepcopy(model.state_dict())

# 把最好的参数加载到模型
model.load_state_dict(best_model_weight)
  • 保存完整模型: torch.save(model, './my_whole_model.pth')
  • 加载完整模型: new_model2 = torch.load('./my_whole_model.pth')

跨设备保存模型及加载:

  • model.load_state_dict(torch.load('./my_best_weight', map_location=device))
# 把刚才保存的模型映射到GPU
torch.save(model.state_dict(), './my_best_weight')

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 下载完模型后, 执行了model.to(device), 默认在CPU上
model.load_state_dict(torch.load('./my_best_weight', map_location=device))
  • 学习率衰减: step_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)  # step_lr_scheduler.step()   # from torch.optim import lr_scheduler
  • 数据加强处理:
# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])


一 天气图片分类

1.1 简介

数据四分类: Rain, sunshine, sunrise, cloudy.

1.2 导包

# vgg 
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
import torchvision
from torchvision import transforms

1.3 导入数据

import os
base_dir = './dataset'
train_dir = os.path.join(base_dir, 'train')
test_dir = os.path.join(base_dir, 'test')
  • 图片数据转换方式: 图片尺寸统一, 数据转换为tensor, 数据正则化
transform = transforms.Compose([transforms.Resize((96, 96)),  # 统一缩放
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化
                                transforms.Normalize(mean=[0.5, 0.5, 0.5],
                                                     std=[0.5, 0.5, 0.5])])
  • 图片数据导入
train_ds = torchvision.datasets.ImageFolder(train_dir, transform=train_transform)
test_ds = torchvision.datasets.ImageFolder(test_dir, transform=test_transform)

# dataloader
batch_size = 32  # batch 批次
train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size,
                                       shuffle=True, drop_last=True)
test_d1 = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

1.4 导入模型 (迁移学习)

# 加载预训练模型
model = torchvision.models.vgg16(pretrained=True)
model 

for param in model.features.parameters():
    param.requires_grad = False
  • 定义输出类别
# 修改结果特征, 4分类
model.classifier[-1].out_features = 4
model.classifier[-1]    # Linear(in_features=4096, out_features=4, bias=True)

# 另一种修改方式  # 直接替换最后一层
# model.classifier[-1] = torch.nn.Linear(model.classifier[-1], 4)
  • 数据拷贝到 GPU
# 训练  # 拷贝到GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)

1.5 定义训练

# 继续训练
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()

# 定义训练过程
def fit(epoch, model, train_loader, test_loader):
    correct = 0
    total = 0
    running_loss = 0
    
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()
            
    epoch_loss = running_loss / len(train_loader.dataset)
    epoch_acc = correct / total
    
    # 测试过程
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    test_epoch_loss = test_running_loss / len(test_loader.dataset)
    test_epoch_acc = test_correct /test_total
    
    print('epoch', epoch,
          'loss', round(epoch_loss, 3),
          'accuracy', round(epoch_acc, 3),
          'test_loss', round(test_epoch_loss, 3),
          'test_accuracy', round(test_epoch_acc, 3))
    return epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc
  • 指定训练
# 指定训练次数
epochs = 20
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc = fit(epoch, model,
                                                                 train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(test_epoch_loss)
    test_acc.append(test_epoch_acc)

model.parameters     # 查看模型结构

1.6 结果展示

plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss')
plt.legend()

plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc')
plt.legend()

二 保存模型

2.1 保存参数

  • state_dict 是一个字典, 保存了训练模型
model.state_dict()   # 保存位置

# 保存参数
path = './vgg16.pth'
torch.save(model.state_dict(), path)

2.2 恢复模型

  • 先创建模型, 然后通过模型加载参数

new_model = torchvision.models.vgg16(pretrained=False)
new_model.classifier[-1].out_features = 4

# 传参
new_model.load_state_dict(torch.load('./vgg16.pth'))
new_model.state_dict()   # 保存位置

2.3 模型预测

# 把模型拷贝到数据所在的位置(GPU/ CPU)
new_model.to(device)

# 测试过程
test_correct = 0
test_total = 0
new_model.eval()  # eval  评价, 评估

with torch.no_grad():
    for x, y in test_d1:
        x, y = x.to(device), y.to(device)
        y_pred = new_model(x)
        y_pred = torch.argmax(y_pred, dim=1)
        test_correct += (y_pred == y).sum().item()
        test_total += y.size(0)
        
epoch_test_acc = test_correct / test_total
print(epoch_test_acc)    # 0.9644444444444444

2.4 保存参数最佳的模型

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 传参
# model.load_state_dict(torch.load('./vgg16.pth'))
import copy
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# 没有训练前的初始化参数
best_model_weight = model.state_dict()
best_acc = 0.0
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
    
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        # 更新参数, 保存最佳参数
        best_model_weight = copy.deepcopy(model.state_dict())

  •  加载最佳参数模型
# 把最好的参数加载到模型
model.load_state_dict(best_model_weight)

2.5 保存完整模型和参数

  • 保存模型参数
torch.save(model, './my_whole_model.pth')
  • 加载模型及参数
new_model2 = torch.load('./my_whole_model.pth')
# 查看保存参数
new_model2.state_dict()
new_model2

2.6 跨设备的模型保存和加载

# GPU和cpu
device    # device(type='cpu')
  • 把刚才保存的模型映射到GPU 
# 把刚才保存的模型映射到GPU
torch.save(model.state_dict(), './my_best_weight')   # 保存参数

model = torchvision.models.vgg16(pretrained=False)
model.classifier[-1].out_features = 4

# 下载完模型后, 执行了model.to(device), 默认在CPU上
model.load_state_dict(torch.load('./my_best_weight', map_location=device))

三 学习率衰减

3.1 导入模型

# 加载预训练模型
model = torchvision.models.vgg16(pretrained=True)

for param in model.features.parameters():
    param.requires_grad = False

# 修改结果特征, 4分类
model.classifier[-1].out_features = 4

# 拷贝到GPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)

# 继续训练
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()

3.2 学习率衰减

from torch.optim import lr_scheduler

# 学习率衰减
step_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
  • 模型训练
# 定义训练过程
def fit(epoch, model, train_loader, test_loader):
    correct = 0
    total = 0
    running_loss = 0
    
    for x, y in train_loader:
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_fn(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()
            
    # 衰减学习率
    step_lr_scheduler.step()
    epoch_loss = running_loss / len(train_loader.dataset)
    epoch_acc = correct / total
    
    # 测试过程
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    with torch.no_grad():
        for x, y in test_loader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    test_epoch_loss = test_running_loss / len(test_loader.dataset)
    test_epoch_acc = test_correct /test_total
    
    print('epoch', epoch,
          'loss', round(epoch_loss, 3),
          'accuracy', round(epoch_acc, 3),
          'test_loss', round(test_epoch_loss, 3),
          'test_accuracy', round(test_epoch_acc, 3))
    return epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc
# 指定训练次数
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []

for epoch in range(epochs):
    epoch_loss, epoch_acc, test_epoch_loss, test_epoch_acc = fit(epoch, model, train_d1, test_d1)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    
    test_loss.append(test_epoch_loss)
    test_acc.append(test_epoch_acc)

四  数据增强

4.1 数据输入

数据增强

  • transforms.RandomCrop     # 随机位置裁剪
  • transforms.RandomRotation     # 随机旋转
  • transforms.RandomHorizontalFlip     # 水平翻转
  • transforms.RandomVerticalFlip     # 垂直翻转
  • transforms.ColorJitter(brightness)      # 亮度
  • transforms.ColorJitter(contrast)       # 对比度
  • transforms.ColorJitter(saturation)       # 饱和度
  • transforms.ColorJitter(hue)        # 色调
  • transforms.RandomGrayscale      # 随机灰度化
import os
base_dir = './dataset'
train_dir = os.path.join(base_dir, 'train')
test_dir = os.path.join(base_dir, 'test')
# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化   # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])
train_ds = torchvision.datasets.ImageFolder(train_dir, transform=train_transform)
test_ds = torchvision.datasets.ImageFolder(test_dir, transform=test_transform)

# dataloader
batch_size = 32  # batch 批次
train_d1 = torch.utils.data.DataLoader(train_ds, batch_size=batch_size,
                                       shuffle=True, drop_last=True)
test_d1 = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)

4.2 减弱数据增强

# 数据增强只会加载在训练数据上, 预测数据不调整
train_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.RandomCrop(192),     # 随机裁剪部分
                                transforms.RandomHorizontalFlip(),  # 水平翻转
                                transforms.RandomVerticalFlip(),   # 垂直翻转
                                transforms.RandomRotation(0.4),     #随机旋转
                                # transforms.ColorJitter(brightness=0.5),  # 亮度调整
                                # transforms.ColorJitter(contrast=0.5),    # 对比度调整
                                
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化    # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

test_transform = transforms.Compose([transforms.Resize((224, 224)),  # 统一缩放到224, 224
                                transforms.ToTensor(),        # 转换为tensor
                                # 正则化    # 数值大小调整
                                transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])

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

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

相关文章

如何查找你的IP地址?通过IP地址能直接定位到你家!

我们ip地址分为A、B、C、D、E共5类,每一类地址范围不同,从A到Eip地址范围依次递减,其中哦,D和E是保留地址,我们用不了。A、B、C3类地址很多都被美国这样的西方国家分走了,而留给我们的就剩有限的地址了&…

记一次接口远程调用异常排查链路 Remote peer closed connection before all data could be read

前言: 异常信息: java.io.IOException: UT000128: Remote peer closed connection before all data could be read 在九月份-十月初一直都被这个问题困扰~ 排查链路 第一次、二次、三次排查该问题: 当时看到”Remote peer c…

支持在局域网使用的项目管理系统有哪些?5款软件对比

一、选择私有部署的原因以及该方案的优点有很多可能的原因导致人们更倾向于使用私有部署的企业管理软件,其中一些原因可能包括:1.数据安全性要求:一些企业管理软件包含敏感的商业数据和隐私信息,为了保护这些信息不被未经授权的第…

MyBatisPlus中的条件构造器Wrapper

引言为什么要了解Wrapper?Wrapper解决的了什么问题?一、Wrapper:条件构造抽象类,用来解决单表操作出现的一些复杂问题,例如排序,和模糊查询等等结构图文字解释AbstractWrapper : 用于查询条件封装&#xff…

java设计模式学习

一、设计模式7大原则1.单一职责原则 (Single Responsibility Principle) 在类级别和方法级别进行职责规划,专人专事2.开放-关闭原则 (Open-Closed Principle) 增加接口功能时,尽可能不要修改原有代码3.里氏替换原则 (Liskov Substitution Principle) 子类…

华为HCIE学习之Openstack keystone组件

文章目录一、keystone对象模型二、使用token的好处Token的实现模式1、UUID Token,每次验证需要访问keystone服务端2、PKI Token 验证,在客户端即可完成 发放公钥 私钥解密3、RBAC三、policy.json权限实验一、keystone对象模型 二、使用token的好处 1、token缓存在客…

什么是数字化?企业如何实现数字化?

随着社会的发展与时代的进步,以生产为核心的企业也在进行不断的创新,而新一代信息技术的应用深化,制造业迎来了数字化转型新机遇。数字化转型近些年更多的被提及,越来越多的企业想通过数字化的转型,降低企业运营成本&a…

《Ansible变量篇:ansible中事实变量facts》

一、简介 facts组件是ansible用于采集被管理机器设备信息的一个功能, 采集的机器设备信息主要包含IP地址,操作系统,以太网设备,mac地址,时间/日期相关数据,硬件信息等。 ansible有一个模块叫setup,用于获取远程主机的相关信息,并可以将这些信息作为变量在playbook里进行调用,而…

【python】剑指offer代码大集合

剑指 Offer(第 2 版) https://leetcode.cn/problem-list/xb9nqhhg/ 剑指 Offer 03. 数组中重复的数字 https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/ # 法1:哈希表(Set) class Solution:def findRepeatNumber(self, nums: [

CentOS8基础篇12:使用RPM管理telnet-server软件包

一、RPM包管理工具简介 RedHat软件包管理工具(RedHat Package Manager,RPM) RPM软件包工具常用于软件包的安装、查询、更新升级、校验、卸载以及生成.rpm格式的软件包等操作。 RPM软件包工具只能管理后缀是.rpm的软件包。软件包的命名格式: 软件名称…

java 实现pgsql数据库免密备份 Windows版本

阐述下背景: 最近公司项目中有个功能模块,需要使用java实现pgsql数据库整库的数据备份,没有pgsql使用经验的我,在网上寻找了好多大神的帖子,也没发现适合自己当前场景的解决方案,但是我把大神们的帖子按照自…

某开源远程办公软件安装配置说明

******是开源软件,只需要简单的配置,就可以在企业搭建SSL VPN,满足日常远程办公的需求。本篇文档为在windows服务器安装搭建openvpn记录,仅供参考。 拓扑说明 使用虚拟机进行测试,主机操作系统Windows 10和m0n0。模拟…

【Java|golang】1247. 交换字符使得字符串相同

有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。 交换只能发生在两个不同的字符串之间…

JavaEE简单示例——MyBatis的缓存机制

简单介绍: 缓存机制的存在,是为了当我们在执行重复的SQL代码的时候,不需要重新向数据库进行访问,而是将之前查询的结果存放在内存当中,从而减少我们重复的获取数据库连接进行查询时候消耗的资源,是一种加快…

内容产品项目作品 || 项目背景及需求分析(一)

一、项目背景介绍 如果让大家来做一个没接触过的产品,思路: 先了解产品所在的行业,多看看第三方的行业研究的文章了解产品的主要竞品,这样做产品设计的时候不会乱搞 常见的内容产品形态:图文、音视频、直播等 二、…

走!来学习配置基于IP子网划分VLAN

划分VLAN的方式有:基于接口、基于MAC地址、基于子网、基于协议、基于策略(MAC地址、IP地址、接口) 基于IP子网划分VLAN经常适用于对安全需求不高、对移动性和简易管理需求较高的场景中。比如,一台PC配置多个IP地址分别访问不同网段…

Traefik v2.9-IngressRoute

文章目录简介资源交付创建CRD和RBAC创建ConfigMap创建Deployment创建Service创建traefik-dashboard-ingressroute简介 The Kubernetes Ingress Controller, The Custom Resource Way. In early versions, Traefik supported Kubernetes only through the Kubernetes Ingress …

Android SurfaceTexture说明

what 1. SurfaceTexture用来捕获视频流中的图像帧,视频流可以是相机预览或者是视频解码数据。 里边承接图像数据的也是GraphicBuffer, GLConsumer 作为其BufferQueue的消费方,取得数据后可以通过eglImage挂到opengles texture 里边对其做纹理采样。 ho…

学习笔记三:容器,镜像相关操作,并部署nginx

这里写目录标题镜像相关命令从dockerhub查找镜像容器相关操作以交互式方式启动并进入容器以守护进程方式启动容器查看正在运行的容器通过docker部署nginx服务在docker里安装nginx创建静态页面访问docker里的nginx服务流量走向:镜像相关命令 从dockerhub查找镜像 d…

mTip 输入法状态跟踪提示 ,可以更改热键等

ImTip ( 输入法状态跟踪提示 )最新版本是 v4.4 :免费开源,仅 715 KB。单文件绿色软件,无任何外部依赖,兼容 XP,Vista,Win7,Win8,Win10,Win11 …… 等所有流行桌面操作系统。源代码: …