机器学习(9.2-9.8)pytorch学习(二)

news2024/9/21 2:39:57

文章目录

    • 摘要
    • Abstract
  • 1 torch 和 torchvision
    • 1.1 查看CIFAR10数据集内容
    • 1.2 Dataloader的使用
  • 2 神经网络的构建
    • 2.1 神经网络的基本骨架
    • 2.2 卷积层原理
      • 2.2.1 卷积基本原理
      • 2.2.2 padding
    • 2.3 构建一个卷积神经网络
    • 2.4 池化层
    • 2.5 非线性激活
      • 2.5.1 RELU的使用
      • 2.5.2 Sigmoid的使用
    • 2.6 线性层及其他层
      • 2.6.1 线性层
      • 2.6.2 其他层
    • 2.7 搭建小实战和Sequential 的使用
      • 2.7.1 小实战
      • 2.7.2 Sequentia的使用
    • 总结

摘要

在前段时间,入门学习了有关pytorch的相关安装和简单入门使用后,这周补充学习了pytorch中的数据集CIFAR10的使用并以此为数据集进行神经网络构建的相关学习,学会了通过调用pytorch中的有关卷积、池化、非线性、线性等包训练图片。

Abstract

After learning the installation and simple use of pytorch, I learned the use of data set CIFAR10 in pytorch this week and learned the construction of neural network based on it. I learned to train pictures by calling packages in pytorch about convolution, pooling, nonlinear, linear, etc.

1 torch 和 torchvision

torch 和 torchvision 是 PyTorch 深度学习框架提供的两个重要库:

  1. torch: torch 库是 PyTorch 的核心库,提供了张量操作、神经网络构建、自动微分等功能。主要功能包括:
  • 张量操作:提供了张量(多维数组)的创建、操作和运算,支持 GPU 加速计算。
  • 神经网络构建:包括各种类型的神经网络层、激活函数和优化器,方便用户构建和训练神经网络模型。
  • 自动微分:PyTorch 的自动微分引擎可以自动计算张量的梯度,支持反向传播算法进行模型训练。
  1. torchvision: torchvision 库是 PyTorch 的计算机视觉库,提供了一系列用于图像处理和计算机视觉任务的工具和数据集。主要功能包括:
  • 数据加载:提供了常用的图像数据集(如 ImageNet、CIFAR-10 等)的加载和预处理功能
  • 图像变换:包括各种图像变换操作,如裁剪、缩放、旋转等,用于数据增强和预处理。
  • 模型库:包含了一些经典的计算机视觉模型(如 ResNet、AlexNet 等),方便用户进行图像分类、目标检测等任务。

torch 提供了深度学习框架的核心功能,而 torchvision 则是专注于图像处理和计算机视觉任务的扩展库。这两个库结合起来可以帮助用户更轻松地构建和训练深度学习模型,并在计算机视觉任务中取得良好的表现。

1.1 查看CIFAR10数据集内容

torchvison.datasets.CIFAR10

import torchvision

train_set = torchvision.datasets.CIFAR10(root="./dataset2", train=True, transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset2", train=False, transform=dataset_transform, download=True)

# 查看第一个数据
print(test_set[0])
# 输出为(<PIL.Image.Image image mode=RGB size=32x32 at 0x20CC5155A60>, 3)可知第一个为img,第二个为标签的target
# 查看测试集中有什么类型的图片
print(test_set.classes)     # ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
img, target = test_set[0]   # 分别获得图片和target
print(img)      # <PIL.Image.Image image mode=RGB size=32x32 at 0x20CC5155AF0>
print(target)   # 3
print(test_set.classes[target]) # cat 即classes[3]
img.show()

Tensorboard查看内容

import torchvision
from torch.utils.tensorboard import SummaryWriter

dataset_transform = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])
train_set = torchvision.datasets.CIFAR10(root="./dataset2", train=True, transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset2", train=False, transform=dataset_transform, download=True)

writer = SummaryWriter("P10")
for i in range(10):
    img, target = test_set[i]
    writer.add_image("test_set", img, i)

writer.close()

tensorboard --logdir=“P10”

在这里插入图片描述

1.2 Dataloader的使用

dataset 相当于有一副扑克牌,dataloader 则是从这副扑克牌中拿牌,设定一次拿几张牌等

查看dataloader的用法
torch.utils.data.DataLoader

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

test_data = torchvision.datasets.CIFAR10("./dataset2", train=False, transform=torchvision.transforms.ToTensor())
test_loader =  DataLoader(test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=False)


writer = SummaryWriter("dataloader")

step = 0
for data in test_loader:
    imgs, targets = data
    writer.add_images("test_data_drop_last", imgs, step)
    step = step+1

writer.close()

batch_size表示每次取多少个数据
shuffle 表示每一次取这么完整的数据时候打乱
drop_last 表示最后一个step若取不到batch_size大小的数据时,是否舍弃

for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        writer.add_images("Epoch:{}".format(epoch), imgs, step)
        step = step+1

2 神经网络的构建

torch.nn(neural network)

2.1 神经网络的基本骨架

torch.nn.module

import torch
from torch import nn

class Cc(nn.Module):
    # 继承父类的初始化
    def __init__(self):
        super(Cc, self).__init__()

    #重写forward函数
    def forward(self, input):
        output = input + 1
        return output

cxc = Cc()
x = torch.tensor(1.0)
output = cxc(x)
print(output)

2.2 卷积层原理

2.2.1 卷积基本原理

在这里插入图片描述

卷积运算包括输入图像和卷积核,设定步长stride

  1. 卷积核在输入图像上向右滑动stride格,到达边界后再向下滑动stride格
  2. 重复操作1至,图片的纵向最边界

在这里插入图片描述

代码示例:

import torch
import torch.nn.functional as F

input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])

kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])

print(input.shape)      # torch.Size([5, 5])
print(kernel.shape)     # torch.Size([3, 3])
# 要求的输入格式为
# input– input tensor of shape(minibatch,in_channels,iH,iW)
input = torch.reshape(input, (1, 1, 5, 5))
kernel = torch.reshape(kernel, (1, 1, 3, 3))

print(input.shape)      # torch.Size([1, 1, 5, 5])
print(kernel.shape)     # torch.Size([1, 1, 3, 3])

output = F.conv2d(input, kernel, stride=1)          # tensor([[[[10, 12, 12],
print(output)                                       #           [18, 16, 16],
                                                    #           [13,  9,  3]]]])

output = F.conv2d(input, kernel, stride=2)          # tensor([[[[10, 12],
print(output)                                       #           [13,  3]]]])

2.2.2 padding

在这里插入图片描述

在这里插入图片描述

代码实现:

import torch
import torch.nn.functional as F

input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])

kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])

output = F.conv2d(input, kernel, stride=1, padding=1)   # tensor([[[[ 1,  3,  4, 10,  8],
print(output)                                           #           [ 5, 10, 12, 12,  6],
                                                        #           [ 7, 18, 16, 16,  8],
                                                        #           [11, 13,  9,  3,  4],
                                                        #           [14, 13,  9,  7,  4]]]])

2.3 构建一个卷积神经网络

卷积结果计算公式:

长度: H 2 = H 1 − F H + 2 P S + 1 长度:H_2=\frac{H_1-F_H+2P}{S}+1 长度:H2=SH1FH+2P+1

宽度: W 2 = W 1 − F W + 2 P S + 1 宽度:W_2=\frac{W_1-F_W+2P}{S}+1 宽度:W2=SW1FW+2P+1

其中,H1和W1表示输入的高度宽度;H1和W2表示输出特征图的高度宽度;F表示卷积核的长和宽的大小,S表示滑动窗口的步长,P表示边界填充的(填了几圈0)

官方给出的计算公式(加上了dilation的属性参与计算)
在这里插入图片描述

关于dilation属性:控制点之间的距离,默认是1,如果大于1,则该运算又称为扩张卷积运算。

在这里插入图片描述

import torch
import torch.nn as nn
import torchvision
from torch.utils.data import DataLoader
from torch.nn import Conv2d
# 创建数据
from torch.utils.tensorboard import SummaryWriter

test_data = torchvision.datasets.CIFAR10("dataset2", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=True)
# 设置batch_size
data_loader = DataLoader(test_data, batch_size=64)

# 构建神经网络
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)

    def forward(self, x):
        x = self.conv1(x)
        return x

# 初始化该神经网络
cnn = CNN()
print(cnn)

writer = SummaryWriter("data_conv2d")

step = 0
for data in data_loader:
    imgs, targets = data
    output = cnn(imgs)
    print(imgs.shape)   # torch.Size([64, 3, 32, 32])
    print(output.shape) # torch.Size([64, 6, 30, 30])
    writer.add_images("input", imgs, step)
    # 6channel的图片无法进行显示 将[64, 6, 30, 30]->[64, 3, 30, 30]
    output = torch.reshape(output, (-1, 3, 30, 30))
    writer.add_images("output", output, step)
    step = step+1

writer.close()

在这里插入图片描述

2.4 池化层

作用: 保留输入的特征,并减少数据量

在这里插入图片描述

import torch
import torchvision
from torch.nn import MaxPool2d
import torch.nn as nn
input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]], dtype=torch.float32)
input = torch.reshape(input, (-1, 1, 5, 5))

class MaxPool(nn.Module):
    def __init__(self):
        super(MaxPool, self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)

    def forward(self, input):
        output = self.maxpool1(input)
        return output

mp = MaxPool()
output = mp(input)

# tensor([[[[2., 3.],
#           [5., 1.]]]])
print(output)

以图片集为例:

import torch
import torchvision
from torch.nn import MaxPool2d
import torch.nn as nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 初始化数据集
dataset = torchvision.datasets.CIFAR10("dataset2", train=False, transform=torchvision.transforms.ToTensor())
data_loader = DataLoader(dataset, batch_size=64,)

class MaxPool(nn.Module):
    def __init__(self):
        super(MaxPool, self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)

    def forward(self, input):
        output = self.maxpool1(input)
        return output
        
mp = MaxPool()
writer = SummaryWriter("maxPool")
step = 0
for data in data_loader:
    imgs, target = data
    output = mp(imgs)
    writer.add_images("input", imgs, step)
    writer.add_images("maxpool", output, step)
    step = step+1

writer.close()

在这里插入图片描述

2.5 非线性激活

作用: 为神经网络引入非线性限制

2.5.1 RELU的使用

RELU

对于Relu,输入小于0的数,被截为0,对于大于0的数,取原数值
在这里插入图片描述

关于inplace参数:

  1. 若为true,则输入变量的值也会被替换
  2. 若为false,则输入变量的值保持不变,将函数处理的值给新变量,优点是能够保存初始数据

在这里插入图片描述

import torch
import torch.nn as nn
from torch.nn import ReLU
input = torch.tensor([[1, -0.5],
                      [-1, 3]])
print(input)

class NonLinear(nn.Module):
    def __init__(self):
        super(NonLinear, self).__init__()
        self.relu1 = ReLU()

    def forward(self,input):
        output = self.relu1(input)
        return output

non = NonLinear()
output = non(input)
print(output)

在这里插入图片描述

2.5.2 Sigmoid的使用

Sigmoid

import torchvision
from torch.nn import Sigmoid
import torch.nn as nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("dataset2", train=False, transform=torchvision.transforms.ToTensor())
data_loader = DataLoader(dataset, batch_size=64)

class NonLinear(nn.Module):
    def __init__(self):
        super(NonLinear, self).__init__()
        self.sigmoid = Sigmoid()

    def forward(self, input):
        output = self.sigmoid(input)
        return output

writer = SummaryWriter("data_sigmoid")

non = NonLinear()
step = 0
for data in data_loader:
    imgs, target = data
    writer.add_images("input", imgs, global_step=step)
    output = non(imgs)
    writer.add_images("img_sigmoid", output, step)
    step +=1

writer.close()

在这里插入图片描述

2.6 线性层及其他层

2.6.1 线性层

在这里插入图片描述

作用: 对输入数据进行线性变换和仿射变换,将输入数据映射到输出数据空间,使用较多

import torch
import torchvision
import torch.nn as nn
from torch.utils.data import  DataLoader
from torch.nn import Flatten, Linear

dataset = torchvision.datasets.CIFAR10("dataset2", train=False, transform=torchvision.transforms.ToTensor())
data_loader = DataLoader(dataset, batch_size=64, drop_last=True)

class Li(nn.Module):
    def __init__(self):
        super(Li, self).__init__()
        self.linear1 = Linear(196608, 10)

    def forward(self,x):
        output = self.linear1(x)
        return  output

l = Li()

for data in data_loader:
    imgs, target = data
    print(imgs.shape)
    output = torch.flatten(imgs)
    print(output.shape)
    output = l(output)
    print(output.shape)

在这里插入图片描述

关于Linear(196608, 10)钟196608的计算

  1. 由output = torch.reshape(imgs,(1,1,1,-1)) 结合64332*32计算得到
  2. 通过output = torch.flatten(imgs) 将多维度展平

注:torch.reshape() 功能更强大

2.6.2 其他层

在这里插入图片描述

2.7 搭建小实战和Sequential 的使用

2.7.1 小实战

在这里插入图片描述

  1. 首先计算出每次进行卷积时的padding填充了几圈

在这里插入图片描述
2. 代码实现

import torch
import torch.nn as nn
from torch.nn import Conv2d, MaxPool2d, Linear, Flatten

class conv(nn.Module):
    def __init__(self):
        super(conv, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=32, kernel_size= 5, stride=1, padding=2)
        self.maxPool1 = MaxPool2d(kernel_size=2)
        self.conv2 = Conv2d(32, 32, 5, padding=2)
        self.maxPool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2)
        self.maxPool3 = MaxPool2d(2)
        self.flatten1 = Flatten()
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxPool1(x)
        x = self.conv2(x)
        x = self.maxPool2(x)
        x = self.conv3(x)
        x = self.maxPool3(x)
        x = self.flatten1(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x

cc = conv()
input = torch.ones((64, 3, 32, 32))
output = cc(input)
print(output.shape) # torch.Size([64, 10])

2.7.2 Sequentia的使用

torch.nn.Sequentia

import torch
import torch.nn as nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential

class seq(nn.Module):
    def __init__(self):
        super(seq, self).__init__()
        self.model = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )
    def forward(self,x):
        x = self.model(x)
        return x

s = seq()

input = torch.ones((64, 3, 32, 32))
print(input.shape)  # torch.Size([64, 3, 32, 32])
output = s(input)
print(output.shape) # torch.Size([64, 10])

总结

通过学习pytorch的一些简单的入门使用,提高了自己的代码能力,不过对于pytorch的学习和使用,还要多看官方文档和自己的深入理解

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

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

相关文章

【开源免费】基于SpringBoot+Vue.J大学生租房平台(JAVA毕业设计)

本文项目编号 T 019 &#xff0c;文末自助获取源码 \color{red}{T019&#xff0c;文末自助获取源码} T019&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

java基础概念21-权限修饰符、代码块

一、权限修饰符 1-1、作用 权限修饰符&#xff0c;是用来控制一个成员能够被访问的范围的。 可以修饰&#xff1a;成员变量&#xff0c;方法&#xff0c;构造方法&#xff0c;内部类。 1-2、权限修饰符的分类 二、代码块 局部代码块构造代码块静态代码块 2-1、局部代码块 …

【C++ Primer Plus习题】12.5

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include <cstdlib> #in…

Linux-【组管理、权限管理、定时任务调度】

目录 前言 Linux组基本介绍 文件/目录 所有者 查看文件 所有者 修改文件所有者 文件/目录 所在组 修改文件/目录 所在组 其它组 改变用户所在组 权限的基本介绍 rwx权限 rwx作用到文件 rwx作用到目录 修改权限 第一种方式&#xff1a;、-、变更权限 第二种方式…

Java进阶13讲__第11讲

配置文件 日志 1. Properties属性文件 1.1 特点、作用 都只能是键值对键不能重复文件后缀一般是.properties结尾的 1.2 读取 package cn.hdc.oop10.properties;import java.io.FileNotFoundException; import java.io.FileReader; import java.util.Properties; import j…

「iOS」折叠cell

iOS学习 前言简单的折叠cell效果原理 稍作修改总结 前言 在暑期仿写中&#xff0c;3G share项目里我们简单的使用了折叠cell。现在写一篇博客来总结该方法。 简单的折叠cell 效果 先看效果&#xff1a; 原理 将cell的高度设置为一个单元格的高度。创建一个按钮&#xff0…

【C++】作用域指针、智能指针、共享指针、弱指针

十、智能指针、共享指针 从上篇文章 【C】如何用C创建对象&#xff0c;理解作用域、堆栈、内存分配-CSDN博客 中我们知道&#xff0c;你的对象是创建在栈上还是在堆上&#xff0c;最大的区别就是对象的作用域不一样。所以在C中&#xff0c;一旦程序进入另外一个作用域&#xf…

【xinference】(19):在L40设备上通过Xinference框架,快速部署CogVideoX-5b模型,可以生成6秒视频,速度比409D快一点

1&#xff0c;关于Xinference Xorbits Inference (Xinference) 是一个开源平台&#xff0c;用于简化各种 AI 模型的运行和集成。借助 Xinference&#xff0c;您可以使用任何开源 LLM、嵌入模型和多模态模型在云端或本地环境中运行推理&#xff0c;并创建强大的 AI 应用。 htt…

鸿蒙开发笔记_电商严选01_登录页面(静态页面)

由于上班较忙,抽空闲暇时间,快速更新中。。。 效果图 登录页面(静态页面) import CommonConstants from ./CommonConstants;/*** 登录页面*/ // 输入文本框,的自定义样式扩展 // @Extend装饰器表示继承、扩展的意思。这里代表:自定义样式扩展 @Extend(TextInput) functio…

Qt使用小技巧之按钮动态变化

前言 最近写小demo中无意发现的&#xff0c;是想实现当鼠标悬停到按钮上面的时候&#xff0c;按钮实现动态变化&#xff0c;让人知道鼠标经过了按钮&#xff0c;效果如下 hoverDynamicPushButton 正文 首先是将按钮的边框给去掉&#xff0c;然后设置下它的悬停伪状态就行了 格…

linux日常使用命令总结

一、文件复制 在 Linux 中&#xff0c;复制文件是一个常见的操作&#xff0c;通常使用 cp 命令来完成。cp 命令提供了丰富的选项来满足不同的需求。下面是使用 cp 命令复制文件的一些基本用法和示例。 基本用法 cp 命令的基本语法如下&#xff1a; cp [选项] 源文件 目标文…

京东获得JD商品详情 API 返回值说明||京东商品详情数据采集API接口详解

item_get-获得JD商品详情 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheStri…

了解分布式事务与本地事物基本概念

一、本地事物 1、事物的基本性质 数据库事物的几个特性&#xff1a;原子性、一致性、隔离性、持久性&#xff0c;简称ACID&#xff1b; 原子性&#xff1a;一系列的操作整体不可拆分&#xff0c;要么全成功&#xff0c;要么同时失败。 一致性&#xff1a;数据在事物的前后&am…

SpringMVC上

SpringMVC介绍 MVC模型 MVC全称Model View Controller&#xff0c;是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分&#xff1a; Model&#xff08;模型&#xff09;&#xff1a;指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用…

Typora教程

1 TyporaChina https://typorachina.com/guide/

【C语言必学知识点七】坚决不允许你还不知道C/C++程序如何对内存进行分区!!!

动态内存管理——详细解读C/C程序中的内存分区 导读一、C/C程序中的内存分区二、常见的动态内存的错误2.1 内存开辟失败后对空指针进行解引用2.2 对已开辟好的空间进行越界访问2.3 free不是有动态函数开辟的空间2.4 free动态内存开辟空间的一部分2.4.1 free函数的底层逻辑 2.5 …

【HarmonyOS】- 内存优化

文章目录 知识回顾前言源码分析1. onMemoryLevel2. 使用LRUCache优化ArkTS内存原理介绍3. 使用生命周期管理优化ArkTS内存4. 使用purgeable优化C++内存拓展知识1. Purgeable Memory总结知识回顾 前言 当应用程序占用过多内存时,系统可能会频繁进行内存回收和重新分配,导致应…

Excel文档的读取【2】

读取了工作簿对象后&#xff0c;下一步就是读取指定的工作表。每个工作簿中&#xff0c;都包含一个或多个工作表。每个工作表&#xff0c;都有一个名称。阿珍收到的Excel文件&#xff0c;由两个工作表组成&#xff0c;分别为“销售商品”和“销售订单数据”。 使用print输出…

基于移动互联网的校内物业报修管理系统设计与实现(论文+源码)_kaic

基于移动互联网的校内物业报修管理系统设计与实现 摘  要 校园后勤服务对于学校的发展至关重要&#xff0c;它不仅是学校管理的基石&#xff0c;也是实现教育目标的关键因素&#xff0c;为学生提供优质的生活环境。如果学校能够提供出色的后勤保障&#xff0c;让师生无需担心…

【生日视频制作】保时捷车主提车交车仪式感AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程保时捷车主提车交车仪式感AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】保时捷车主提车交车仪式感AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤&#xff1a; 下载AE模板 安装AE软件 把AE模板导入…