Pytorch
Package
torch
torch.nn
torch.autograd
torch.nn.functional
torch.optim
torch.utils
torchvision
第一部分查看验证和相关信息
#查看pytorch是否安装成功
import torch
print(torch.__version__)
tor.cuda.is_available()
torch.version.cuda
#查看GPU号
t=torch.tensor([1,2,3])
t
t=t.cuda()
t
输出:tensor([1,2,3]),device="cuda:GPU的符号"
第二部分张量
#index和内容
a = [1,2,3,4]
a[2]
#输出 3
a=[
[1,2,3],
[4,5,6],
[7,8,9]
]
dd[0][2]
#输出3
不适用attay或者matrix类似的定义,用n-tensor/n-array来代表多维数据。但是张量并不代表有多少个维度,如上面dd代表的是9个维度(数学意义上)。一个张量元素代表的是一个维度
张量三个基本元素:秩Rank 轴Axes 形状Shape
秩 考虑的是秩的个数,就是轴的个数。表示Array的维度,需要多少个索引来访问张良数据结构中包含的特定数据元素,比如上面a就是1,dd就是2
rank-2tensor,也是2个秩axes,也就是2维数组
轴 某个方向上索引的个数,轴考虑的是长度。轴的数量就是秩
。每个轴上面的长度,就是这个轴/一个秩下的索引个数。比如一个轴len是3,那么索引就是0 1 2,他就是3dimention(数学)。每个秩包括len(秩)维数字
dd.shape
#输出 torch.Size([3,3])
表示每个轴上有3个索引(轴的长度),一共有两个轴,即秩为2
Reshape过程
import torch
t=[
[1,2,3],
[4,5,6],
[7,8,9]
]
tt = torch.tensor(t)
tt
type(tt)
tt.shape
tt.reshape(1,9)
tt.reshape(1,9).shape
#结果 从tt开始
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
torch.Tensor
torch.Size([3, 3])
tensor([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
torch.Size([1, 9])
#注意,torch.size里面数字的乘积前后应该一致
Reshaping改变形状但是不改变底层数组
CNN和张量
通常CNN长度为
len([? , ? , ? , ? ])=4
A0 A1 A2 A3 四个轴,每个?表示轴长度
B C H W 图像的宽和长,C表示图像的channal,比如rgb是c=3。B表示batchsize多少个样本
比如[3,1,28,28] 3个图,1个channal,28*28的大小
#假设我们有3个filter,高和宽不做变化
土建[1,1,28,28]经过filter之后变成[1,3,28,28],即3个featuremap
查看设备以及张量的计算
#例子
import torch
import numpy as np
t=[
[1,2,3]
]
tt = torch.Tensor(t)
type(tt)
print(tt.dtype)
print(tt.device)
print(tt.layout)
device=torch.device("cuda:0")
device
tt.device
ttt = tt.cuda()
#结果
torch.Tensor
torch.float32
cpu
torch.strided
device(type='cuda', index=0)
device(type='cpu')
device(type='cuda',index=0)
#注意,这里面ttt+tt是不能操作的,因为在不同的设备之内
张量的创建方法
import numpy as np
import torch
data = np.array([1,2,3])
type(data)
输出 numpy.ndarray
torch.Tensor(data)
#输出 tensor([1., 2., 3.])浮点数 torch.float32 Constructor function
torch.tensor(data)
#输出 tensor([1, 2, 3], dtype=torch.int32)和np中的数据类型是一样的 torch.int32 factury function
torch.as_tensor(data)
#输出 tensor([1, 2, 3], dtype=torch.int32)和np中的数据类型是一样的 torch.int32 factury function
torch.from_numpy(data)
输出
#tensor([1, 2, 3], dtype=torch.int32)和np中的数据类型是一样的 torch.int32 factury function
get_default_dtype
#输出是 torch.float32
倾向于使用工厂函数,构造函数是默认转换为缺省值(默认值)。工厂函数根据输入函数推断出来,不使用缺省值。
扩展
torch.tensor(data,dtype = torch.float64)
tensor([1, 2, 3], dtype=torch.int64)
四个函数的区别之一:前两个将np映射到tensor然后产生一个copy改变np不改变tensor。但是后两个保留np到tensor的映射,改变np,他们的tensor数值也改变了
data = np.array([1,2,3])
data
#输出array([1,2,3])
t1=torch.Tensor(data)
t2=torch.tensor(data)
t3=torch.as_tensor(data)
t4=torch.from_numpy(data)
data[0]=0
data[1]=0
data[2]=0
print(t1)
print(t2)
#输出 tensor([1., 2., 3.])
#tensor([1, 2, 3], dtype=torch.int32)
print(t4)
print(t5)
#输出 tensor([0, 0, 0], dtype=torch.int32)
tensor([0, 0, 0], dtype=torch.int32)
专注于正确,而不专注于效率:最好的方法使用torch.tensor()和torch.as_tensor(),因为前者复制一个副本,后者可以使用任何的python数组。而另外的Tensor使用的缺省值,而from只能应用于numpy数组。
张 量的一些常用创建函数
import torch
torch.eye(2)
#建立一个对角线是1的2*2张量 浮点数
#tensor([[1., 0.],
# [0., 1.]])
torch.zeros(2,2)
#建立一个全部都是0的2*2张量 浮点数
#tensor([[0., 0.],
# [0., 0.]])
torch.ones(2,2)
#建立全部都是1的2*3张量 浮点数
#tensor([[1., 1.],
# [1., 1.]])
torch.rand(2,2)
#随机建立2*2的张量 浮点数
#tensor([[0.6214, 0.2073],
# [0.1053, 0.5916]])
Tensor的四大类操作
- Reshaping operations 重塑 塑造和直观的理解张量
- Element-wise operations 元素的操作还原和访问
- Reduction operations 裁剪
- Access operations 访问
t = torch.tensor([
[1,1,1,1],
[2,2,2,2],
[3,3,3,3]
],dtype=torch.float32)
#注意他的秩为2,第一个轴元素3,第二个轴元素4.第一个轴的元素是四个数字组成的Array,第二个轴的元素是Number(可以理解成数组的编号)
#获得他们的形状
t.size()
t.shape
#输出相同都是torch.Size([3, 4])
len(t.shape)
#输出2,通过len快速获得秩的数目
torch.tensor(t.shape).prod()
#输出12,将shape转化为张量,然后查看张量的元素,即张量的标量分量
t.numel()
#输出12 直接产生元素数目
##只要reshape之后,他们元素不变就行
#####t.reshape(1,12) 或2*6都是秩为12
#####t.reshape(2,2,3) 乘积仍是12
#例子 squeeze和unsqueeze
print(t.reshape(1,12))
print(t.reshape(1,12).shape)
#输出
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])
torch.Size([1, 12])
#增加或者减少秩
#squeeze去掉维度是1的轴
print(t.reshape(1,12).squeeze())
print(t.reshape(1,12).squeeze().shape)
#输出:
tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.])
torch.Size([12])
#unsqueeze增加维度是1的轴
print(t.reshape(1,12).squeeze().unsqueeze(dim=0))
print(t.reshape(1,12).squeeze().unsqueeze(dim=0).shape)
#输出
tensor([[1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]])
torch.Size([1, 12])
Flatten卷积层和全连接层
def flatten(t):
t=t.reshape(1,-1)
t=t.squeeze()
return t
flatten(t)
#输出tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.]) -1表示任意值:根据reshape中元素个数以及已有的信息(这里是,其中一个维度为1),来计算机自动选一个合适的维度,并赋值给-1(在这里,运行过程中是12)
##非常大的区别,平铺之后tensor(【】),但是reshape(1,12)的表示是tensor(【【】】)。后者表示秩为2,但是前者为1
#cat来拼接??????????????????????????????????????
组合和平铺
t1 = torch.tensor([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
])
t2 = torch.tensor([
[2,2,2,2],
[2,2,2,2],
[2,2,2,2],
[2,2,2,2]
])
t3=torch.tensor([
[3,3,3,3],
[3,3,3,3],
[3,3,3,3],
[3,3,3,3]
])
t=torch.stack((t1,t2,t3))
t.shape
t
#结果torch.Size([3, 4, 4])
#tensor([[[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]],
#
# [[2, 2, 2, 2],
# [2, 2, 2, 2],
# [2, 2, 2, 2],
# [2, 2, 2, 2]],
#
# [[3, 3, 3, 3],
# [3, 3, 3, 3],
# [3, 3, 3, 3],
# [3, 3, 3, 3]]])
t=t.reshape(3,1,4,4)
t
#结果
#tensor([ [ [ [1, 1, 1, 1],
# Batch Channel Height width [1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]]],
#
#
# [[[2, 2, 2, 2],
# [2, 2, 2, 2],
# [2, 2, 2, 2],
# [2, 2, 2, 2]]],
#
#
# [[[3, 3, 3, 3],
# [3, 3, 3, 3],
# [3, 3, 3, 3],
# [3, 3, 3, 3]]]])
#下标查看
t[0] #第一张照片
#输出tensor([[[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]]])
t[0][0] #第一个照片,第一个颜色
#输出tensor([[1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1],
# [1, 1, 1, 1]])
t[0][0][0] #第一个照片第一个颜色第一行
#输出tensor([1, 1, 1, 1])
t[0][0][0][0]
#输出tensor(1)
#flatten的四种操作
t.reshape(1,-1)[0]
t.reshape(-1)
t.view(t.numel())
t.flatten()
#输出为tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])
#最好的是用flatten
#选择性flatten
t.flatten(start_dim=1).shape #【?。?。?。?】从四个里面选择索引为1的,开始进行操作。跳过批次,每张照片的颜色 宽 高进行faltten
t.flatten(start_dim=1)
#输出 torch.Size([3, 16])
#tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
# [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
# [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]])
元素操作element-wise operation
t1=torch.tensor([
[1,2],
[3,4]
],dtype=torch.float32)
t2=torch.tensor([
[9,8],
[7,6]
],dtype=torch.float32)
#有两个秩,第一个秩是array,第二个秩是数字
t1[0]
#输出tensor([1., 2.])
t1[0][0]
#tensor(1.)
#### two tensor must have the same shape,calculation is avaible = the same number of axes,and the lens of axes are the same
t1 + t2
tensor([[10., 10.],
[10., 10.]])
其他的算法也都是元素操作
#四个基本张量-数字的操作(数字是0阶张量)
t1 + 2 == t1.add(2)
t1 - 2 == t1.sub(2)
t1 * 2 == t1.mul(2)
t1 / 2 == t1.div(2)
#输出为
tensor([[3., 4.],
[5., 6.]])
tensor([[-1., 0.],
[ 1., 2.]])
tensor([[2., 4.],
[6., 8.]])
tensor([[0.5000, 1.0000],
[1.5000, 2.0000]])
#对于上述过程的理解是 将2应用到新的形状t1.shape上面 成为broadcasting 广播
np.broadcast_to(2,t1.shape)
#结果array([[2, 2],
# [2, 2]])
t1 + torch.tensor(
np.broadcast_to(2,t1.shape)
,dtype=torch.float32
)
#结果是 tensor([[3., 4.],
# [5., 6.]])
#复杂点的计算1张量和2张量
t1 = torch.tensor([
[1,1],
[1,1]
],dtype=torch.float32)
t2=torch.tensor([2,4],dtype=torch.float32)
np.broadcast_to(t2.numpy(),t1.shape)
#结果array([[2., 4.],
# [2., 4.]], dtype=float32)
#逻辑运算
t=torch.tensor([
[0,5,7],
[6,0,7],
[0,8,0]
],dtype=torch.float32)
t.eq(0)
#结果tensor([[ True, False, False],
# [False, True, False],
# [ True, False, True]])
t.gt() lt() ge() le() eq() ne()代表大于 小于 大于等于 小于等于 等于 不等于
t.max(tensor) : 返回 tensor 中最大的一个数;
t.max(tt) : 返回tt和t中每个元素tensor最大的数值
t.max(tensor,dim) : 指定维上最大数,返回 tensor 和下标;
t.max(tensor1,tensor2) : 比较两个 tensor 相比较大的元素;
#一些其他基本操作
t.abs() #绝对值
t.sqrt() #平方根
t.neg() #取反
t.neg().abs() #取反之后取绝对值
张量缩减操作argmax
t=torch.tensor([
[0,1,0],
[2,0,2],
[0,3,0]
],dtype=torch.float32)
t.sum()
t.numel()
t.sum().numel()
t.sum().numel()<t.numel()
#输出
#tensor(8.)
#9
#t.sum().numel()
#True
###sum operation是一个缩减命令
t.prod()乘积
t.mean()求平均值
t.std()求标准差
#都是缩减命令
t=torch.tensor([
[1,1,1,1],
[2,2,2,2],
[3,3,3,3]
],dtype=torch.float32)
#这是一个秩为2,3*4的张量
t.sum(dim=0)
#输出 tensor([6.,6.,6.,6.,])
等价代码是
t[0] + t[1] + t[2]
t.sum(dim=1)
t[0].sum()
t[1].sum()
t[2].sum()
#输出 tensor([4.,8.,12.,])
##0是行维度,1是列维度:沿着第一个轴的是array,沿着第二个周的是number。sum(0)代表,把每个array相加得到的数值
t.max() ##tensor(5.) 最大数是4
t.argmax() ##tensor(11) 最大数值的index是11
t.flatten() ##tensor([1., 0., 0., 2., 0., 3., 3., 0., 4., 0., 0., 5.]) argmax就是平铺之后的数值
t.max(dim=0)
#torch.return_types.max(
#values=tensor([4., 3., 3., 5.]),
#indices=tensor([2, 1, 1, 2])) 注意这里max返回两种数据
t.argmax(dim=0)
#tensor([2, 1, 1, 2]) 返回index
t.max(dim=1)
#torch.return_types.max(
#values=tensor([2., 3., 5.]),
#indices=tensor([3, 1, 3]))
t.argmax(dim=1)
#tensor([3, 1, 3])
t.mean()
#输出 tensor(1.5000)
t.mean().item()
#1.5 item命令将返回的mean提取为一个独立的元素
t.mean(dim=0).tolist()
#[1.6666666269302368, 1.0, 1.0, 2.3333332538604736]返回一个list
t.mean(dim=0).numpy()
#array([1.6666666, 1. , 1. , 2.3333333], dtype=float32) 返回一个numpy array
数据集
记住:
- Who created the dataset?
- How was the dataset created?
- What transformations were used?
- What intent does the dataset have ?
- Possible unintentional consequences?
- Is the dataset biased?
- Are there ethical issues with the dataset?
项目计算的四个步骤
- Prepare the data ETL过程 extract,transform,and load 两个重要的工具Dataset and Dataload
- Build the model
- Train the model
- Analyze the model‘s results
#加载数据
import torch
import torchvision
import torchvision.transforms as transforms
train_set = torchvision.datasets.FashionMNIST(
root='D:\\22SS\\cvhci\\FashionMNIST' #数据的存储地址
,train=True #数据的使用目的,这里是训练集
,download=True #如果指定目录下面没有,那么可以下载
,transform=transforms.Compose([
transforms.ToTensor() #因为我们想用这个数据集进行训练,所以我们ToTensor来将图片像素转化为张量
])
)
train_loader = torch.utils.data.DataLoader(train_set,batch_size=10) #设定批大小为10
#数据展示
import numpy as np
import matplotlib.pyplot as plt
torch.set_printoptions(linewidth=120) #设置打印到控制台的输出的行宽
len(train_set) #查看训练集中有多少图片 60000
train_set.train_labels #数据集的标签的张量tensor([9, 0, 0, ..., 3, 0, 5]),在数据集中一共有10类
train_set.train_labels.bincount() #数据集某个标签下的频率统计,展示所有标签的对应的频率tensor([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000])
#单个图像输出
sample = next(iter(train_set)) #将train_set加入迭代器中,然后用next从头开始调用,一次next就调用一个
len(sample) #输出为2,因为数据有一个标签张量一个图像内容张量
type(sample) #这里是一个特殊的存储模式
image,label = sample #这个是将两个张量赋值给两个数值,分别是image和label。可以把他理解为解构和封装
image.shape #查看图片形状
print(label) #查看标签
plt.imshow(image.squeeze(),cmap="gray")
print("label:",label) #画出image,使用灰度图。然后写出标签
#多个图像输出
batch = next(iter(train_loader)) #输出2
############ Dataloader 作为迭代器,每次产生一个 batch 大小的数据。但是用set就是每个图为单位
len(batch) #list
type(batch)
images,labels = batch
images.shape #torch.Size([10, 1, 28, 28])
labels.shape #torch.Size([10])
grid = torchvision.utils.make_grid(images,nrow=10) #使用内置utils工具,以图片为单位,10列的形式生成网格
plt.figure(figsize=(15,15)) #每个grid大小
plt.imshow(np.transpose(grid,(1,2,0))) #np转换成生成图片需要的结构
目标指向的NN
- Extend the nn.Module base class
- Define layers as class attributes
- Implement the forward() method
使用nn.Module建立一个神经网络
class Network(nn.Module): #将普通网络转化为pytorch nn.module所有功能的网络,各种内置参数都可以使用了 (权重更新更加方便)
def __init__(self): #这里是双下划线
super(Network,self).__init__() #超参初始化
self.conv1 = nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
self.conv2 = nn.Conv2d(in_channels=6,out_channels=12,kernel_size=5)
self.fc1 = nn.Linear(in_features=12*4*4,out_features=120)
self.fc2 = nn.Linear(in_features=120,out_features=60)
self.out = nn.Linear(in_features=60,out_features=10)
def forward(self,t):
#implement the forward pass
return t
network = Network()
print(network)
#输出Network(
#(conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
#(conv2): Conv2d(6, 12, kernel_size=(5, 5), stride=(1, 1))
#(fc1): Linear(in_features=192, out_features=120, bias=True)
#(fc2): Linear(in_features=120, out_features=60, bias=True)
#(out): Linear(in_features=60, out_features=10, bias=True)
#)
network.conv1 #用这个.来识别各层网络的参数
#输出Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
network.conv1.weight
network.conv1.weight.shape
#查看某一层的权重和他的张量 torch.Size([6, 1, 5, 5]) 6个filter 1个inputchannel 5*5的核大小
network.conv2.weight.shape
#输出 torch.Size([12, 6, 5, 5]) # output12 input6表示核的深度 filter 5*5
network.conv2.weight[0].shape #torch.Size([6, 5, 5])看一个filter的张量结构
for param in network.parameters():
print(param.shape)
#输出为torch.Size([6, 1, 5, 5])
#torch.Size([6])
#torch.Size([12, 6, 5, 5])
#torch.Size([12])
#torch.Size([120, 192])
#torch.Size([120])
#torch.Size([60, 120])
#torch.Size([60])
#torch.Size([10, 60])
#torch.Size([10])
for name,param in network.named_parameters(): #\t\t是让结果对齐输出
print(name,'\t\t',param.shape)
#conv1.weight torch.Size([6, 1, 5, 5])
#conv1.bias torch.Size([6])
#conv2.weight torch.Size([12, 6, 5, 5])
#conv2.bias torch.Size([12])
#fc1.weight torch.Size([120, 192])
#fc1.bias torch.Size([120])
#fc2.weight torch.Size([60, 120])
#fc2.bias torch.Size([60])
#out.weight torch.Size([10, 60])
#out.bias torch.Size([10])
parameter是函数内部的参数,argument是函数使用者从外部给函数的数值
在cnn到fc层的时候,系统随即创建一个转换矩阵,然后进行转换。
in_features = torch.tensor([1,2,3,4],dtype = torch.float32) #这里面in_feature是定义的函数,不是nn内置参数
weight_matrix = torch.tensor([
[1,2,3,4],
[2,3,4,5],
[3,4,5,6]
],dtype = torch.float32)
weight_matrix.matmul(in_features)
#输出是 tensor([30., 40., 50.])
fc = nn.Linear(in_features=4,out_features=3)
fc(in_features)
#输出是tensor([ 0.6834, -0.7238, -0.1147], grad_fn=<AddBackward0>) #这里展示的是系统会随机生成一个矩阵来计算
fc.weight = nn.Parameter(weight_matrix) ###重点 将之前的矩阵赋值给fc层的矩阵
fc = nn.Linear(in_features=4,out_features=3)
fc(in_features)
#输出 tensor([29.5013, 40.2981, 49.9314], grad_fn=<AddBackward0>)很接近之前的值,他们不同因为增加了bias
#关闭bias之后的输出
fc.weight = nn.Parameter(weight_matrix)
fc = nn.Linear(in_features=4,out_features=3,bias=False)
fc(in_features)
#tensor([0.5870, 2.8734, 0.8371], grad_fn=<SqueezeBackward3>)
前向传播
class Network(nn.Module): #将普通网络转化为pytorch nn.module所有功能的网络,各种内置参数都可以使用了 (权重更新更加方便)
def __init__(self): #这里是双下划线
super(Network,self).__init__() #超参初始化
self.conv1 = nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
self.conv2 = nn.Conv2d(in_channels=6,out_channels=12,kernel_size=5)
self.fc1 = nn.Linear(in_features=12*4*4,out_features=120)
self.fc2 = nn.Linear(in_features=120,out_features=60)
self.out = nn.Linear(in_features=60,out_features=10)
def forward(self,t):
#implement the forward pass
#inpuyt layer
t = t
#(2 hidden conv layer)
t = self.conv1(t)
t = F.relu(t)
t = F.max_pool2d(t,kernel_size=2,stride=2)
#(3 hidden conv layer)
t = self.conv2(t)
t = F.relu(t)
t = F.max_pool2d(t,kernel_size=2,stride=2)
#4 hidden liner layer
t = t.reshape(-1,12*4*4) #(4*4是之前卷积层计算的结果)
t = self.fc1(t)
t = F.relu(t)
#5 hidden liner layer
#
t = self.fc2(t)
t = F.relu(t)
#6 output layer
t = self.out(t)
#t=F.softmax(t,dim=1)
return t
###关注他的书写顺序,conv activefunction pooling
图片预测,使用Pytorch
network = Network() ####这一步的内在内容很重要:生成一个Instance然后在之后的调用过程中改变Instance的值。如果直接用Network()那么用一次创建一次Instance。Instance的创建占用额外的内存,要避免这种使用方法。
data_loader = torch.utils.data.DataLoader(
train_set
,batch_size =10
)
batch = next(iter(data_loader)) #批次训练,单次训练见后面
images,labels = batch
images.shape
#输出 torch.Size([10, 1, 28, 28])
labels.shape
#torch.Size([10])
preds = network(images)
preds.shape
#torch.Size([10, 10])
preds
#tensor([[ 0.0844, -0.0992, -0.0125, -0.0030, -0.0452, 0.0589, -0.0883, #-0.1155, 0.0089, -0.1507],
# [ 0.0879, -0.0960, -0.0179, -0.0092, -0.0378, 0.0620, -0.0946, #-0.1235, 0.0191, -0.1485],
# [ 0.0883, -0.1031, -0.0143, -0.0102, -0.0397, 0.0586, -0.0922, #-0.1226, 0.0131, -0.1492],
# [ 0.0897, -0.1030, -0.0179, -0.0089, -0.0390, 0.0566, -0.0930, #-0.1222, 0.0157, -0.1461],
# [ 0.0877, -0.1058, -0.0149, -0.0106, -0.0444, 0.0574, -0.0943, #-0.1240, 0.0106, -0.1511],
# [ 0.0864, -0.1053, -0.0125, -0.0046, -0.0422, 0.0592, -0.0920, #-0.1201, 0.0099, -0.1519],
# [ 0.0786, -0.1043, -0.0049, -0.0073, -0.0423, 0.0721, -0.0916, #-0.1166, 0.0017, -0.1607],
# [ 0.0901, -0.1058, -0.0089, -0.0053, -0.0373, 0.0598, -0.0950, #-0.1232, 0.0181, -0.1487],
# [ 0.0840, -0.1002, -0.0178, -0.0031, -0.0400, 0.0589, -0.0870, #-0.1076, 0.0182, -0.1506],
# [ 0.0831, -0.1011, -0.0167, 0.0025, -0.0463, 0.0546, -0.0763, #-0.1048, 0.0199, -0.1472]],
# grad_fn=<AddmmBackward0>)
preds.argmax(dim=1)
#tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
labels
#tensor([9, 0, 0, 3, 0, 2, 7, 2, 5, 5])
eq = preds.argmax(dim=1).eq(labels)
preds.argmax(dim=1).eq(labels).sum()
#tensor(3)
#最后两行的等价函数
def get_num_correct(preds,labels): #计算标签的正确数目
return preds.argmax(dim=1).eq(labels).sum().item()
get_num_correct(preds,labels)
#3
#单次训练
sample = next(iter(train_set))
image,label = sample
output = network(image.unsqueeze(0)) #因为神经网络是[batch,channel,hight,weight],所以单个图片要加上一个1的batchsize。unsqueeze就是在index 0 的地方加上要给维度
print(output)
#tensor([[ 0.0844, -0.0992, -0.0125, -0.0030, -0.0452, 0.0589, -0.0883, -0.1155, 0.0089, -0.1507]],
grad_fn=<AddmmBackward0>)
训练神经网络Traning
- Get batch from the training set
- Pass batch to network
- Calculate the loss(difference between the predicted values and the true values)
- Calculate the gradient of the loss function w.r.t the network’s weights
- Update the weights using the gradients to reduce the loss
- Repeat steps 1-5 until one epoch is completed
- Repeat steps 1-6 for as many epochs required to obtain the desired level of accuracy
#####------------单批次计算
network = Network()
train_loader = torch.utils.data.DataLoader(train_set,batch_size=100) #数据加载,这里是载入图片,一百个图片是一个batch
optimizer = optim.Adam(network.parameters(),lr=0.01) #设置优化权重的方法
batch = next(iter(train_loader)) #用iter方法调用train_loader里面的一个batch数据,并且赋值给batch
images,labels = batch #图像处理的时候有两个维度,这里面我们将他分别赋值给images和labels
preds = network(images) #前向传播的images预测结果(初始预测,没有任何优化)
loss = F.cross_entropy(preds,labels) #计算loss方程
loss.backward() #反向传播梯度
optimizer.step() #进行梯度优化
#第一次反向传播的loss计算
print('loss1:',loss.item())
preds = network(images)
#在输入一次,epoch第二次的梯度
loss = F.cross_entropy(preds,labels)
print('loss2',loss.item())
正确的网络书写顺序
#####------------单批次计算
network = Network()
train_loader = torch.utils.data.DataLoader(train_set,batch_size=100) #数据加载,这里是载入图片,一百个图片是一个batch
optimizer = optim.Adam(network.parameters(),lr=0.01) #设置优化权重的方法
batch = next(iter(train_loader)) #用iter方法调用train_loader里面的一个batch数据,并且赋值给batch
images,labels = batch #图像处理的时候有两个维度,这里面我们将他分别赋值给images和labels
preds = network(images) #前向传播的images预测结果(初始预测,没有任何优化)
loss = F.cross_entropy(preds,labels) #计算loss方程
loss.backward() #反向传播梯度
optimizer.step() #进行梯度优化
#第一次反向传播的loss计算
print('loss1:',loss.item())
preds = network(images)
#在输入一次,epoch第二次的梯度
loss = F.cross_entropy(preds,labels)
print('loss2',loss.item())
Training Loop
重点神经网络是批次batch训练,每个batch包括多张图片。当我们将训练集中所有图片都训练完一次之后,这是完成一个epoch
#加载包
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
torch.set_printoptions(linewidth=120)
torch.set_grad_enabled(True)
##计算标签的正确数目
def get_num_correct(preds,labels):
return preds.argmax(dim=1).eq(labels).sum().item()
#训练网络
class Network(nn.Module):
def __init__(self):
super(Network,self).__init__()
self.conv1 = nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
self.conv2 = nn.Conv2d(in_channels=6,out_channels=12,kernel_size=5)
self.fc1 = nn.Linear(in_features=12*4*4,out_features=120)
self.fc2 = nn.Linear(in_features=120,out_features=60)
self.out = nn.Linear(in_features=60,out_features=10)
def forward(self,t):
t = t
t = self.conv1(t)
t = F.relu(t)
t = F.max_pool2d(t,kernel_size=2,stride=2)
t = self.conv2(t)
t = F.relu(t)
t = F.max_pool2d(t,kernel_size=2,stride=2)
t = t.reshape(-1,12*4*4)
t = self.fc1(t)
t = F.relu(t)
t = self.fc2(t)
t = F.relu(t)
t = self.out(t)
return t
#导入训练集
train_set = torchvision.datasets.FashionMNIST(
root='D:\\22SS\\cvhci\\FashionMNIST'
,train=True
,download=True
,transform=transforms.Compose([
transforms.ToTensor()
])
)
#----------------------------------训练一个epoch
#训练一个epoch
network = Network()
train_loader = torch.utils.data.DataLoader(train_set,batch_size=100)
optimizer = optim.Adam(network.parameters(),lr=0.01)
total_loss = 0
total_correct = 0
for batch in train_loader:
images,labels = batch
preds = network(images)
loss = F.cross_entropy(preds,labels)
optimizer.zero_grad() #每次都从0开始梯度,否则的话,他会每次都累加梯度。这并不是我们计算过程中想要的
loss.backward()
optimizer.step()
total_loss += loss.item()
total_correct += get_num_correct(preds,labels)
print('epoch:',0,'total_correct:',total_correct,'loss',total_loss)
#-----------------------------------------------训练多个epoch
#训练5个epoch
network = Network()
train_loader = torch.utils.data.DataLoader(train_set,batch_size=100)
optimizer = optim.Adam(network.parameters(),lr=0.01)
for epoch in range(5):
total_loss = 0
total_correct = 0
for batch in train_loader:
images,labels = batch
preds = network(images)
loss = F.cross_entropy(preds,labels)
optimizer.zero_grad() #每次都从0开始梯度,否则的话,他会每次都累加梯度。这并不是我们计算过程中想要的
loss.backward()
optimizer.step()
total_loss += loss.item()
total_correct += get_num_correct(preds,labels)
print('epoch:',epoch,'total_correct:',total_correct,'loss',total_loss)
Confusion matrix来分析神经网络训练结果
展示哪些类之间混淆了
关于是否进行梯度跟踪
len(train_set)
len(train_set.targets)
def get_all_preds(model,loader):
all_preds = torch.tensor([])
for batch in loader:
images,labels = batch
preds = model(images)
all_preds = torch.cat(
(all_preds,preds)
,dim=0
)
return all_preds
prediction_loader = torch.utils.data.DataLoader(train_set,batch_size=10000)
train_preds = get_all_preds(network,prediction_loader)
train_preds.shape
print(train_preds.requires_grad) #表示这个训练集需要梯度跟踪
train_preds.grad
train_preds.grad_fn
with torch.no_grad(): ###如果在局部关闭梯度跟踪
prediction_loader = torch.utils.data.DataLoader(train_set,batch_size=10000)
train_preds=get_all_preds(network,prediction_loader)
print(train_preds.requires_grad)
train_preds.grad
train_preds.grad_fn
preds_correct = get_num_correct(train_preds,train_set.targets)
print('total correct',preds_correct)
print('accuracy',preds_correct/len(train_set))
confusion matrix
train_set.targets #训练集自己的标签
train_preds.argmax(dim=1) #训练集的预测标签
stacked = torch.stack(
(
train_set.targets
,train_preds.argmax(dim=1)
)
,dim=1
)
stacked.shape
stacked
stacked[0].tolist()
j,k = stacked[0].tolist()
j
k
cmt = torch.zeros(10,10,dtype=torch.int32) #创建一个10*10的零矩阵
cmt
for p in stacked: ###在真假矩阵里面,对应的块加一
tl,pl = p.tolist()
cmt[tl,pl] = cmt[tl,pl]+1
cmt
#plotting a confusion matrix
import matplotlib.pyplot as prediction_loader
from sklearn.matrics import confusion_matrix
from resources.pltcm import plot_confusion_matrix
cm = confusion_matrix(train_set.targets,train_preds.argmax(dim=1))
print(type(cm))
cm
names = ('T-shirt/top','trouser','pullover','4','5','6','7','8','9','10')
plt.figure(figsize=(10,10))
plot_confusion_matrix(cm,names)
结果
concatenating拼接 and stacking堆叠张量
拼接是在已有的轴上拼接张量
堆叠是在原来张量的基础上扩展新的轴
unsqueeze的使用
import torch
t1 = torch.tensor([1,1,1])
t1.shape
#结果torch.Size([3])
t1.unsqueeze(dim=0)
#结果tensor([[1, 1, 1]])
t1.unsqueeze(dim=1)
tensor([[1],
[1],
[1]])
#shape
print(t1.shape)
print(t1.unsqueeze(dim=0))
print(t1.unsqueeze(dim=1))
torch.Size([3])
tensor([[1, 1, 1]])
tensor([[1],
[1],
[1]])
cat
t1=torch.tensor([1,1,1])
t2=torch.tensor([2,2,2])
t3=torch.tensor([4,3,3])
torch.cat(
(t1,t2,t3)
,dim=0
)
#tensor([1, 1, 1, 2, 2, 2, 4, 3, 3])
torch.stack(
(t1,t2,t3)
,dim=0
)
#tensor([[1, 1, 1],
# [2, 2, 2],
# [4, 3, 3]])
torch.cat(
(
t1.unsqueeze(0)
,t2.unsqueeze(0)
,t3.unsqueeze(0)
)
,dim=0
)
#输出tensor([[1, 1, 1],
# [2, 2, 2],
# [4, 3, 3]])
#在另外的维度上面,只能进行堆叠。因为本身t1,2,3没有第二个维度
torch.stack(
(t1,t2,t3)
,dim=1
)
#tensor([[1, 2, 4],
# [1, 2, 3],
# [1, 2, 3]])
Tensorboard
tensorflow的可视化工具
打开tensorboard
(cvhci) C:\Users\tengf>tensorboard --logdir=runs
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
TensorBoard 2.6.0 at http://localhost:6006/ (Press CTRL+C to quit)
###浏览器上面输入网址访问
(cvhci) C:\Users\tengf>tensorboard --version
2.6.0
#查看tensorboard版本
#额外import一个tensorboard的支持
from torch.utils.tensorboard import SummaryWriter
####将原始图像images和labels传入tensorboard并且生成一个images的网格显示图片
network = Network()
images,labels = next(iter(train_loader))
grid = torchvision.utils.make_grid(images) #后面要传给Summarywriter,去创建一组图像,
tb = SummaryWriter()
tb.add_image('images',grid) #传递标签和网格
tb.add_graph(network,images)
##在每批次for batch in train_loader中加入,传输给tensorboard每批次的信息
tb.add_scalar('Loss',total_loss,epoch)
tb.add_scalar('Number Correct',total_correct,epoch)
tb.add_scalar('Accuracy',total_correct/len(train_set),epoch)
tb.add_histogram('conv1.bias',network.conv1.bias,epoch)
tb.add_histogram('conv1.weight',network.conv1.weight,epoch)
tb.add_histogram('conv1.weight.grad',network.conv1.weight.grad,epoch)
Tensorboard重点:超参调试
如何建立多个超参,同时运行并且在tensorboard中展示
run Builder
from collections import OrderedDict
from collections import namedtuple
from itertools import product
class RunBuilder():
@staticmethod
def get_runs(params):
Run = namedtuple('Run',params.keys())
runs=[]
for v in product(*params.values()):
runs.append(Run(*v))
return runs
params = OrderedDict( #设置初始测试的各个参数
lr = [.01,.001]
,batch_size = [1000,10000]
)
runs = RunBuilder.get_runs(params) #调用runbuilder功能
runs
##结果是
#[Run(lr=0.01, batch_size=1000),
# Run(lr=0.01, batch_size=10000),
# Run(lr=0.001, batch_size=1000),
# Run(lr=0.001, batch_size=10000)]
run = runs[0]
print(run.lr,run.batch_size)
#0.01 1000
笛卡尔乘积就是两个集合x和y,乘积为(x,y)
RunManager
字典是另外一个可变的数据结构,且可存储任意类型对象,比如字符串、数字、列表等。字典是由关键字和值两部分组成,也就是 key 和 value,中间用冒号分隔。这种结构类似于新华字典,字典中每一个字都有一个对应的解释
_名字 这种表示内部定义,不能被外部引用
Num_Worker告诉程序用多少个单元去出去程序
减少从磁盘中提取数据的时间