0%

配置过程

Step1 配置 CUDA

  • 首先,不确定本机是否已安装的情况下,可前往默认目录 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\ 下查看,若已安装则有对应版本的 CUDA:

  • 若尚未安装,进入 https://developer.nvidia.com/cuda-downloads,选取合适配置安装。此处以 Win11 系统为例:

  • 安装完成后,再配置系统环境变量:

  • win+R 呼出控制台,键入 nvcc --version nvcc -V 指令(两者择一即可):

  • 显示版本号及相关内容,说明配置成功

Step2 配置 CuDDN

  • 前往 https://developer.nvidia.com/rdp/cudnn-archive 下载

  • 解压下载得到的压缩包,将得到的三个文件夹 binincludelib 分别覆盖至 Step1 中所述 CUDA 根目录,如默认位置 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v版本号

Step3 配置 Pytorch

  • 前往 https://pytorch.org/get-started/locally/ 官网,可通过点选得到合适的安装命令

  • 注意到这里给的源默认为 -c pytorch,为提高下载速度可换用国内源:

国内镜像 位置
清华源 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
中科大源 https://pypi.mirrors.ustc.edu.cn/simple
豆瓣源 https://pypi.douban.com/simple
  • 这里采用清华源,输入安装指令:

1
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
  • 如上图所示,此时键入 y 以继续进行 (proceed)。耐心等待,直至安装完成

  • 新建一个 python 程序,简单验证下 pytorch 是否工作正常:

1
2
3
4
import torch

print("Torch version {}".format(torch.__version__))
print("CUDA is available: {}".format(torch.cuda.is_available()))

小结

  • CUDA(Compute Unified Device Architecture),统一计算设备架构

    • def 是使 GPU 能够解决复杂计算问题的通用并行计算架构
    • 与显驱的关系:显卡驱动用于识别计算机的 GPU 硬件并调用其资源;而 CUDA 是在此基础上的框架,用于进行一系列复杂的并行计算
  • cuDNN

    • def 深度神经网络库,是针对深度卷积神经网络的加速库
    • 强调性能、易用性和低内存开销
  • pytorch

    • def cuDNN 加速框架之一,是一个基于 Torch 的开源 Python 机器学习库
    • 包含张量计算和自动求导系统的深度神经网络两大重要功能

外观模式

案例

​ 使用外观模式模拟《Java 设计模式》教材 187 页第 5 题

外观

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 外观类:主板
*
* @author Vincent
*/
public class MainFrame {

/**
* Definition: 内存 CPU 硬盘 操作系统
*/
private Memory memory;
private CPU cpu;
private HardDisk disk;
private OS os;

/**
* Constructor
*/
public MainFrame() {
this.memory = new Memory();
this.cpu = new CPU();
this.disk = new HardDisk();
this.os = new OS();
}

/**
* 按下主机的开机按钮
*/
public void on() {
memory.check();
cpu.run();
disk.read();
os.load();
}
}

子系统类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* 子系统类:内存
*
* @author Vincent
*/
public class Memory {

public Memory() {
System.out.println("内存已被调用");
}

/**
* 内存自检
*/
public void check() {
System.out.println("正在自检内存!");
}
}

/**
* 子系统类:CPU
*
* @author Vincent
*/
public class CPU {

public CPU() {
System.out.println("CPU已被调用");
}

/**
* 运行CPU
*/
public void run() {
System.out.println("正在运行CPU!");
}
}

/**
* 子系统类:硬盘
*
* @author Vincent
*/
public class HardDisk {
public HardDisk() {
System.out.println("硬盘已被调用");
}

/**
* 读取硬盘
*/
public void read() {
System.out.println("正在读取硬盘!");
}
}

/**
* 子系统类:操作系统
*
* @author Vincent
*/
public class OS {
public OS() {
System.out.println("操作系统已被调用!");
}

public void load() {
System.out.println("正在载入操作系统!");
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 客户端类
*
* @author Vincent
*/
public class Client {
public static void main(String[] args) {
MainFrame mainFrame = new MainFrame();
try {
mainFrame.on();
} catch (Exception e) {
e.toString();
}
}
}

小结

角色

  • Facade(外观角色)

    在客户端中调用它的方法,以知道相关子系统的功能和责任;一般情况下,可以将客户端中发来的请求委派到相应的子系统,传递给对应的子系统对象处理

  • SubSystem(子系统角色)

    每个子系统是一个类的集合,用于实现子系统的功能,可被客户端或外观角色调用

特点

​ 对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,大大降低应用程序的复杂度,提高了程序的可维护性

优点

  • 对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使子系统更为易用

  • 实现了子系统与客户端之间的松耦合关系,使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可

  • 一个子系统的修改对其他子系统无任何影响,且子系统内部变化不会影响到外观对象

缺点

  • 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性

  • 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则

适用环境

  • 要为访问一系列复杂的子系统提供一个简单入口

  • 客户端程序与多个子系统之间存在很大的依赖性

  • 在层次化结构中,可以使用外观模式的定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度

桥接模式

案例

​ 使用桥接模式模拟《Java 设计模式》教材 136 页图 10-4 所表达问题

抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 抽象类:抽象图像类
* @author Vincent
*/
public abstract class Image {
protected ImageImp imp;

/**
* 注入实现类接口对象
* @param imp
*/
public void setImageImp(ImageImp imp) {
this.imp = imp;
}

/**
* 模拟解析文件
* @param fileName
*/
public abstract void parseFile(String fileName);
}

扩充抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* 扩充抽象类:BMP格式图像类
* @author Vincent
*/
public class BMPImage extends Image {

/**
* 模拟解析BMP文件并获得一个像素矩阵对象m
* @param fileName
*/
@Override
public void parseFile(String fileName) {
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName+",格式为BMP.");
}
}

/**
* 扩充抽象类:GIF格式图像类
* @author Vincent
*/
public class GIFImage extends Image {

/**
* 模拟解析GIF文件并获得一个像素矩阵对象m
* @param fileName
*/
@Override
public void parseFile(String fileName) {
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName+",格式为GIF.");
}
}

/**
* 扩充抽象类:JPG格式图像类
* @author Vincent
*/
public class JPGImage extends Image {

/**
* 模拟解析JPG文件并获得一个像素矩阵对象m
* @param fileName
*/
@Override
public void parseFile(String fileName) {
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName+",格式为JPG.");
}
}

/**
* 扩充抽象类:PNG格式图像类
* @author Vincent
*/
public class PNGImage extends Image {

/**
* 模拟解析PNG文件并获得一个像素矩阵对象m
* @param fileName
*/
@Override
public void parseFile(String fileName) {
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName+",格式为PNG.");
}
}

实现类接口

1
2
3
4
5
6
7
8
9
10
11
/**
* 实现类接口:抽象操作系统实现类
* @author Vincent
*/
public interface ImageImp {
/**
* 显示像素矩阵m
* @param m
*/
public void doPaint(Matrix m);
}

具体实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 具体实现类:Linux操作系统实现类
* @author Vincent
*/
public class LinuxImp implements ImageImp {
/**
* 调用Linux操作系统的绘制函数绘制像素矩阵
* @param m
*/
@Override
public void doPaint(Matrix m) {
System.out.println("在Linux操作系统中显示图像:");
}
}

/**
* 具体实现类:Unix操作系统实现类
* @author Vincent
*/
public class UnixImp implements ImageImp {
@Override
public void doPaint(Matrix m) {
System.out.println("在Unix操作系统中显示图像:");
}
}

/**
* 具体实现类:Windows操作系统实现类
* @author Vincent
*/
public class WindowsImp implements ImageImp {

/**
* 调用Windows操作系统的绘制函数绘制像素矩阵
* @param m
*/
@Override
public void doPaint(Matrix m) {
System.out.println("在Windows操作系统中显示图像:");
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 客户端类
* @author Vincent
*/
public class Client {
public static void main(String[] args) {
Image image;
ImageImp imp;
image = (Image) XMLUtil.getBean("image");
imp = (ImageImp) XMLUtil.getBean("os");
image.setImageImp(imp);
image.parseFile("小龙女");
}
}

小结

角色

  • Abstraction(抽象类)

​ 定义抽象类的接口,通常是抽象类而不是接口,其中定义了一个实现类接口类型的对象并可以维护该对象

  • RefinedAbstraction(扩充抽象类)

​ 扩充由抽象类定义的接口,调用在实现类接口定义的业务方法

  • Implementor(实现类接口)

​ 定义实现类的接口,不一定要与抽象类的接口完全一致。一般仅提供基本操作,而将具体实现交给子类

  • ConcreteImplementor(具体实现类)

​ 具体实现了实现类接口,在不同的具体实现类中提供了不同的实现

特点

​ 用组合关系代替继承关系,降低了抽象和实现这两个可变维度的耦合度

优点

  • 分离了抽象接口及其实现部分

  • 可以取代多层继承方案,极大地减少了子类的个数

  • 提高了系统的可扩展性,在两个变化维度中任意扩展一个维度而无需修改原有系统,符合开闭原则

缺点

  • 增加了系统理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程

  • 正确识别出系统中两个独立变化的维度并不是一件容易的事情

适用环境

  • 需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系

  • 抽象部分和实现部分可以以继承的方式独立扩展而互不影响

  • 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展

  • 不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统

容器组件

  • 视图容器
  • 基础内容
  • 表单组件
  • 导航组件
  • 其他:媒体组件、地图组件、画布组件、开放能力和无障碍访问

视图容器

视图容器 | 微信开放文档 (qq.com)

视图 view

  • def 普通视图区域,用于实现页面的布局效果

    • 类比:h5 中的块级元素 div
1
2
3
4
5
6
<!--pages/list/list.wxml-->
<view class="container1">
<view>A</view>
<view>B</view>
<view>C</view>
</view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* pages/list/list.wxss */
.container1 view {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
}

.container1 view:nth-child(1) {
background-color: lightgreen;
}
.container1 view:nth-child(2) {
background-color: lightblue;
}
.container1 view:nth-child(3) {
background-color: lightpink;
}

.container1 {
display: flex;
justify-content: space-around;
}

滚动视图 scroll-view

  • def 可拖动的视图区域,用于实现滚动列表效果

1
2
3
4
5
<scroll-view class="container2" scroll-y>
<view>A</view>
<view>B</view>
<view>C</view>
</scroll-view>
常用属性 说明
scroll-x、scroll-y(boolean) 指定滚动的方向
scroll-top 设置竖向滚动条位置
scroll-left 设置横向滚动条位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.container2 view {
width: 100px;
height: 100px;
text-align: center;
line-height: 80px;
}

.container2 view:nth-child(1) {
background-color: lightgreen;
}
.container2 view:nth-child(2) {
background-color: lightblue;
}
.container2 view:nth-child(3) {
background-color: lightpink;
}

.container2 {
border: 1px solid red;
width: 100px;
height: 120px;
}

滑块视图容器 swiper&swiper-item

  • def 可左右滑动的视图区域,用于实现轮播图效果

  • 注:内部只可放置 swiper-item;在放置其他类型组件时,其行为是未定义的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--pages/swiper/swiper.wxml-->
<!-- 轮播图的结构 -->
<swiper class="swiper-container1" indicator-dots indicator-color="lightpink" indicator-active-color="lightblue" autoplay interval="2000" circular>
<!-- 第1个轮播图 -->
<swiper-item>
<view class="item">A</view>
</swiper-item>
<!-- 第2个轮播图 -->
<swiper-item>
<view class="item">B</view>
</swiper-item>
<!-- 第3个轮播图 -->
<swiper-item>
<view class="item">C</view>
</swiper-item>
</swiper>
常用属性 说明
indicator-dots(boolean) 是否显示面板指示点
indicator-color 当前选中的指示点颜色
indicator-active-color 当前选中的指示点颜色
autoplay(boolean) 是否自动切换
interval 自动切换时间间隔
circular(boolean) 是否采用衔接滑动
1
2
3
4
5
6
7
8
9
10
/* pages/swiper/swiper.wxss */
.swiper-container1 {
height:150px;
}

.item {
height: 100%;
line-height: 100px;
text-align: center;
}

基础内容

文本组件 text

  • def 用于展现文本

    • 类比 h5 中的 span 标签
1
2
3
4
5
<!--pages/text/text.wxml-->
<view>
<!-- 支持长按选中效果,只能选用text内容组件 -->
<text selectable>1234567890</text>
</view>
常用属性 说明
selectable(boolean) 文本是否可选 (已废弃)
user-select(boolean) 文本是否可选,该属性会使文本节点显示为 inline-block

富文本组件 rich-text

  • def 用于展现富文本

1
<rich-text nodes="<h1 style='color:red;'>标题</h1>"></rich-text>
常用属性 说明
nodes 节点列表 /h5 String

表单组件

按钮组件 button

  • def 响应鼠标事件以提交表单

1
2
3
4
5
6
7
8
9
10
<!--pages/button/button.wxml-->
<!-- 通过type属性指定按钮的颜色类型 -->
<button>按钮</button>
<button type="primary" class="primary-button">主色调按钮</button>
<button type="default" class="default-button">默认按钮</button>
<button type="warn" class="warn-button">警告按钮</button>
<!-- 通过size指定按钮的大小 -->
<button size="mini">小尺寸按钮</button>
<!-- 通过plain指定镂空按钮 -->
<button plain>镂空按钮</button>
常用属性 说明
size 按钮大小
type 按钮样式类型
plain(boolean) 按钮是否镂空,背景色透明
1
2
3
4
/* pages/button/button.wxss */
.primary-button {
text-align: center;
}

媒体组件

图片组件 image

  • def 用于展示图片,支持 JPG、PNG、SVG、WEBP、GIF 等格式

常用属性 说明
scaleToFill 缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
aspectFit 缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
aspectFill 缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
widthFix 缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
heightFix 缩放模式,高度不变,宽度自动变化,保持原图宽高比不变

适配器模式

案例

​ 在现有基础上,如何扩展使其能够发出救护车灯光和声音

​ 救护车灯光和声音类已经存在,灯光类类名:AmbulanceLamp,发光方法名:lighting ();声音类类名:AmbulanceSound,发声方法名:sounding ()

目标抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 目标抽象类:汽车控制类
* @author Vincent
*/
public abstract class CarController {
public void move() {
System.out.println("玩具汽车移动!");
}

/**
* 发出声音
*/
public abstract void phonate();

/**
* 灯光闪烁
*/
public abstract void twinkle();
}

适配器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* 适配器类:警车适配器
* @author Vincent
*/
public class PoliceCarAdapter extends CarController {
/**
* 定义适配者PoliceSound对象、PoliceLamp对象
*/
private PoliceSound sound;
private PoliceLamp lamp;

public PoliceCarAdapter() {
sound = new PoliceSound();
lamp = new PoliceLamp();
}

/**
* 调用适配者类PoliceSound的方法,发出警笛声音
*/
@Override
public void phonate() {
sound.alarmSound();
}

/**
* 调用适配者类PoliceLamp的方法,呈现警灯闪烁
*/
@Override
public void twinkle() {
lamp.alarmLamp();
}
}

/**
* 适配器类:救护车适配器
*
* @author Vincent
*/
public class AmbulanceCarAdapter extends CarController {
/**
* 定义适配者AmbulanceSound对象、AmbulanceLamp对象
*/
private AmbulanceSound sound;
private AmbulanceLamp lamp;

public AmbulanceCarAdapter() {
sound = new AmbulanceSound();
lamp = new AmbulanceLamp();
}

/**
* 调用适配者类AmbulanceSound的方法,发出救护车声音
*/
@Override
public void phonate() {
sound.sounding();
}

/**
* 调用适配者类AmbulanceLamp的方法,呈现救护车灯闪烁
*/
@Override
public void twinkle() {
lamp.lighting();
}
}

适配者类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 适配者类:警灯类
* @author Vincent
*/
public class PoliceLamp {
public void alarmLamp() {
System.out.println("呈现警灯闪烁!");
}
}

/**
* 适配者类:警笛类
* @author Vincent
*/
public class PoliceSound {
public void alarmSound() {
System.out.println("发出警笛声音!");
}
}

/**
* 适配者类:救护车灯类
* @author Vincent
*/
public class AmbulanceLamp {
public void lighting() {
System.out.println("呈现救护车灯闪烁!");
}
}

/**
* 适配者类:救护车声音类
* @author Vincent
*/
public class AmbulanceSound {
public void sounding() {
System.out.println("发出救护车声音!");
}
}

客户端

1
2
3
4
5
6
7
8
9
public class Client {
public static void main(String[] args) {
CarController car ;
car = (CarController)XMLUtil.getBean();
car.move();
car.phonate();
car.twinkle();
}
}

小结

角色

  • Target(目标抽象类)

​ 定义客户所需的接口,可以是抽象类或接口、具体类

  • Adapter(适配器类)

​ 作为转换器来调用另一个接口,从而对目标抽象类和适配者

  • Adaptee(适配者类)

​ 定义了一个已经存在的接口,这个接口需要适配,一般是一个具体类,包含客户希望使用的业务方法

特点

​ 分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高

优点

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构

  • 增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用

  • 灵活性和扩展性非常好

  • 类适配器模式置换一些适配者的方法很方便;对象适配器模式可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类。

缺点

  • 类适配器模式

    • 一次最多只能适配一个适配者类,不能同时适配多个适配者
    • 适配者类不能为最终类
    • 目标抽象类只能为接口而不能为类
  • 对象适配器模式

    • 在适配器中置换适配者类的某些方法时比较麻烦

适用环境

  • 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码

  • 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作