赞
踩
换行
print("我爱你",end="\n")
print("12345677")
上述两种方法都可以输出换行;
print("我爱你"+"\n")
上述方法则为输出换行后空一行
空格
以下两种方法都可以
print("hello"+" "+"world")
print("hello"
" "
"world")
打印更改里面的内容 print('{}正在学习{}课程'.format(self.name,course))
多行
ctrl+"/"
单行
shift+“#”
去注释
ctrl+"/"
torch.manual_seed(1)
是为了设置CPU的的随机数固定,使得紧跟着的rand()函数生成的值是固定的随机
torch.manual_seed(1)
print(torch.rand(5))
print(torch.rand(5))
上述结果为
tensor([0.7576, 0.2793, 0.4031, 0.7347, 0.0293])
tensor([0.7999, 0.3971, 0.7544, 0.5695, 0.4388])
并没有固定随机数
torch.manual_seed(1)
print(torch.rand(5))
torch.manual_seed(1)
print(torch.rand(5))
上述结果为
tensor([0.7576, 0.2793, 0.4031, 0.7347, 0.0293])
tensor([0.7576, 0.2793, 0.4031, 0.7347, 0.0293])
有固定随机数
在这里使用
torch.manual_seed(1)
是 为了保证每次的实验结果一致,实验输入为随机数,因此需要保证每次随机数都一样
当一个完整的数据集通过了神经网络一次并且返回了一次-----epoch
由于完成一个epoch训练的周期较长(数据量大),一次性输入所有数据计算机无法负荷,所以将其分成多个batches。
在神经网络中传递完整的数据集一次是不够的,而且我们需要将完整的数据集在同样的神经网络中传递多次。我们使用的是有限的数据集,并且我们使用一个迭代过程即梯度下降,优化学习过程和图示。因此仅仅更新权重一次或者说使用一个 epoch 是不够的。
随着 epoch 数量增加,神经网络中的权重的更新次数也增加,曲线从欠拟合变得过拟合。
对于不同的数据集来说,最佳的epoch是不同的。但是,epoch的大小和数据集的多样化程度有关,多样化程度越强,epoch也应该越大。
Batch是每次输入网络进行训练的批次,而batchsize是每个batch中训练样本的数量。
batchsize大小的选择也是非常重要的,为了在内存容量和内存效率之间取得最佳平衡,最优化网络模型的性能和速度。
其中蓝色为所有数据一起输入进行训练,也就是只有一个batch,batch内包含所有训练样本;绿色为minibatch,即将所有数据分成若干个batches,每个batch内包含一小部分训练样本;红色为随机训练,即每个batch内只有一个样本。
蓝色全数据效果更好,当数据量较小,计算机内存可以负载的时候,可以采用这种训练方式;绿色的mini分批次训练精度略有损失;而红色的随机训练,难以达到收敛状态。
如果数据集比较小我们就采用全数据集。全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。
注:对于大的数据集我们不能使用全批次,因为会得到更差的结果。
iterations就是完成一次epoch所需的batch个数。
假设我们有12800个训练样本,分成100个batches,那么batchsize就是128。将所有的数据输入网络,训练完成一个epoch,需要经过100次iterations。
(1)batchsize:批大小。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;
(2)iteration:1个iteration等于使用batchsize个样本训练一次;
(3)epoch:1个epoch等于使用训练集中的全部样本训练一次;
datasets.MNIST是Pytorch的内置函数torchvision.datasets.MNIST,通过这个可以导入数据集。
root="./mnist/"# 训练数据保存路径
train=True# True为下载训练数据集,False为下载测试数据集
transform=torchvision.transforms.ToTensor(), # 数据范围已从(0-255)压缩到(0,1)
download=False, # 是否需要下载
#测试集
test_data = torchvision.datasets.MNIST(root="./mnist/", train=False)
torchvision.transforms.ToTensor
将X.image或者shape()为(X,Y,Z)的numpy.ndarray转换为[Z,X,Y]的取值范围是[0,1.0]的torch.FloadTensor(长张量)形式,并不是仅仅将图像转化成张量的形式。
在其他情况下,将返回张量而不进行缩放。
简单来说就是把PIL.Image或ndarray从 (H x W x C)形状转换为 (C x H x W) 的tensor。
如果
①转换前numpy.ndarray的dtype = np.uint8
②转换前的PIL.Image是L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1 格式
还会将数值从 [0, 255] 归一化到[0,1]
函数
可以用来传变量或者是列表类型,即一整个列表
def func(name):#定义函数
print ('--->',name)
username ='admin'
func(username)#把username传过去,只传一个变量
def func (names):#传列表类型
for name in names:
print(name)
name_list = ['aa','bb','cc']
func(name_list)#传列表类型
方法
class Phone:
#魔术方法之一,称作魔术方法 __名字__()
def __init__(self):#init 初始的,初始化
print('___________init')
def call(self):#self是不断发生改变的
print('------->call')
print('价格:',self.price) #不能保证每个self都存在price
p = Phone()
此时出的编译结果为
不需要调用,只要对应对象和类,就可以执行语句。详细解释如下:
p= Phone()
①找有没有一块空间是Phone
②利用phone类,向内存申请一块和phone一样的空间
③去phone中去找有没有__init__,没有则执行将开辟的内存给了对象名:p
④如果有__init___,则会进入init方法执行里面的动作,再将内存地址赋值给对象p
以下结果会报错:
print(Phone.price)#把price放在每一个对象里面,不在单独的类里
【is a base class 父类 基类】
使用父类的原因:
类层层继承
类里面重复的代码,每一个类都有相同的动作(冗余代码)
特点:
1.如果类中不定义__init__,调用父类super class的__init__
2.如果类继承父类也需要定义自己的__init__,就需要在当前类的__init__调用一下父类__init__
3.如何调用父类 init:
super().init(参数)
super(类名,对象).init(参数)
4.如果父类有eat(),子类也定义一个eat方法,默认搜索的原则:先找当前类,当前类没有再去找父类【override:重写(覆盖)】
父类提供的方法不能满足子类的需求,就需要在子类中定义一个同名的方法,这种方法:重写
5.子类的方法中也可以调用父类方法:super().方法名(参数)
class Person:##父类 def __init__(self,name,age): self.name = name self.age = age def eat(self): print(self.name + "正在吃饭……") def run(self): print(self.name + "正在跑步……") class Student(Person):##子类 # super().__init__() # super() 父类对象 # def __init__(self): # print('---------->student的init') # # 如何调用父类__init__ # super().__init__()#super() 父类对象 def __init__(self,name,age,clazz): super().__init__(name,age) self.clazz=clazz def study(self,course): print('{}正在学习{}课程'.format(self.name,course)) #打印更改里面的内容 #如果父类与子类相同方法,那么就运行子类 ##如果父类无参,子类有参,但是也优先找子类【按照方法名去找】 def eat(self,food): super().eat() print(self.name+"正在吃。。。喜欢吃:"+food) class Employee(Person):##子类 def __init__(self,name,age,salary,manager): super().__init__(name, age) self.salary = salary self.manager = manager class Doctor(Person):##子类 def __init__(self, name, age, patients): super(Doctor,self).__init__(name,age)#多了一个判断,与super()一样,判断后面的类型是不是前面的对象的 self.patients = patients s= Student('jack',18,3) # s.run() s.study('math') s.eat('满汉全席') e = Employee('lily',18,1000,'king') # e.run() lists =['zhangsan','lisi','wangwu','zhaoliu'] d = Doctor('tom',18,lists) # d.run()
初始化CNN网络–继承module【一个网络父类】
class CNN(nn.Module):
def __init__(self):
继承_init__功能
super(CNN, self).__init__() # 继承__init__功能
我们可以利用nn.Sequential()
自定义自己的网络层。
torch.nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中。
使用方式:
①一个有序的容器,神经网络模块将按照在传入构造器的顺序依次被添加到计算图中执行,
②以神经网络模块为元素的有序字典(OrderedDict)也可以作为传入参数。
③也可以利用add_module函数将特定的神经网络模块插入到计算图中。
官方给出案例(上面所提的方式1 和 方式2的列子):
一种自动命名,一种指定名字。
# Sequential使用实例 model = nn.Sequential( nn.Conv2d(1,20,5), nn.ReLU(), nn.Conv2d(20,64,5), nn.ReLU() ) # Sequential with OrderedDict使用实例 model = nn.Sequential(OrderedDict([ ('conv1', nn.Conv2d(1,20,5)), ('relu1', nn.ReLU()), ('conv2', nn.Conv2d(20,64,5)), ('relu2', nn.ReLU()) ]))
第一层卷积
self.conv1 = nn.Sequential(
# 输入[1,28,28]
nn.Conv2d(
in_channels=1, # 输入图片的高度
out_channels=16, # 输出图片的高度
kernel_size=5, # 5x5的卷积核,相当于过滤器
stride=1, # 卷积核在图上滑动,每隔一个扫一次
padding=2, # 给图外边补上0
),
# 经过卷积层 输出[16,28,28] 传入池化层
nn.ReLU(),
nn.MaxPool2d(kernel_size=2) # 经过池化 输出[16,14,14] 传入下一个卷积
)
## 第二层卷积
self.conv2 = nn.Sequential(
nn.Conv2d(
in_channels=16, # 同上
out_channels=32,
kernel_size=5,
stride=1,
padding=2
),
# 经过卷积 输出[32, 14, 14] 传入池化层
nn.ReLU(),
nn.MaxPool2d(kernel_size=2) # 经过池化 输出[32,7,7] 传入输出层
)
池化层是几个当中选一个,与下采样很类似。
从28–14—7,池化层的size为2
PyTorch的nn.Linear()是用于设置网络中的全连接层的,需要注意在二维图像处理的任务中,全连接层的输入与输出一般都设置为二维张量,形状通常为[batch_size, size],不同于卷积层要求输入输出是四维张量。其用法与形参说明如下:
in_features指的是输入的二维张量的大小,即输入的[batch_size, size]中的size。
out_features指的是输出的二维张量的大小,即输出的二维张量的形状为[batch_size,output_size],当然,它也代表了该全连接层的神经元个数。
从输入输出的张量的shape角度来理解,相当于一个输入为[batch_size, in_features]的张量变换成了[batch_size, out_features]的输出张量。
self.output = nn.Linear(in_features=32*7*7, out_features=10)
in_features由输入张量的形状决定,out_features则决定了输出张量的形状
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x) # [batch, 32,7,7]
x = x.view(x.size(0), -1) # 保留batch, 将后面的乘到一起 [batch, 32*7*7]
output = self.output(x) # 输出[50,10]
return output
view()函数的功能根reshape类似,用来转换size大小。x = x.view(batchsize, -1)中batchsize指转换后有几行,而-1指在不告诉函数有多少列的情况下,根据原tensor数据和batchsize自动分配列数。
# 定义优化器和损失函数
optimizer = torch.optim.Adam(cnn.parameters(), lr=learning_rate)
loss_function = nn.CrossEntropyLoss()
torch.unsqueeze()这个函数主要是对数据维度进行扩充。第二个参数为0,数据为行方向扩,为1,数据为列方向扩,再大错误。
将数据形式由(2000, 28, 28) 转化为 (2000, 1, 28, 28),且范围为[0,1]
test_x = torch.unsqueeze(test_data.data, dim=1).type(torch.FloatTensor)[:2000] / 255.
此代码为1,数据列方向扩
以下为示例
import torch
a = torch.tensor([1,2,3,4])
b = torch.unsqueeze(a,0)
print('b.size(): ',b.size())
print('b: ',b)
c = torch.unsqueeze(a,1)
print('c.size(): ',c.size())
print('c: ',c)
#为了节约时间只取测试数据集前2000个
test_y = test_data.test_labels[:2000]
dataset:输入的数据类型,这里是原始数据的输入。
batch_size:(数据类型 int)
批训练数据量的大小,根据具体情况设置即可(默认:1)。PyTorch训练模型时调用数据不是一行一行进行的(这样太没效率),而是一捆一捆来的。这里就是定义每次喂给神经网络多少行数据,如果设置成1,那就是一行一行进行(个人偏好,PyTorch默认设置是1)。每次是随机读取大小为batch_size。如果dataset中的数据个数不是batch_size的整数倍,这最后一次把剩余的数据全部输出。若想把剩下的不足batch size个的数据丢弃,则将drop_last设置为True,会将多出来不足一个batch的数据丢弃。
shuffle:(数据类型 bool)
洗牌。默认设置为False。在每次迭代训练时是否将数据洗牌,默认设置是False。将输入数据的顺序打乱,是为了使数据更有独立性,但如果数据是有序列特征的,就不要设置成True了。
batch_sampler:(数据类型 Sampler)
批量采样,默认设置为None。但每次返回的是一批数据的索引(注意:不是数据)。其和batch_size、shuffle 、sampler and drop_last参数是不兼容的。我想,应该是每次输入网络的数据是随机采样模式,这样能使数据更具有独立性质。所以,它和一捆一捆按顺序输入,数据洗牌,数据采样,等模式是不兼容的。
sampler:(数据类型 Sampler)
采样,默认设置为None。根据定义的策略从数据集中采样输入。如果定义采样规则,则洗牌(shuffle)设置必须为False。
num_workers:(数据类型 Int)
工作者数量,默认是0。使用多少个子进程来导入数据。设置为0,就是使用主进程来导入数据。注意:这个数字必须是大于等于0的,负数估计会出错。
pin_memory:(数据类型 bool)
内存寄存,默认为False。在数据返回前,是否将数据复制到CUDA内存中。
drop_last:(数据类型 bool)
丢弃最后数据,默认为False。设置了 batch_size 的数目后,最后一批数据未必是设置的数目,有可能会小些。这时你是否需要丢弃这批数据。
timeout:(数据类型 numeric)
超时,默认为0。是用来设置数据读取的超时时间的,但超过这个时间还没读取到数据的话就会报错。 所以,数值必须大于等于0。
train_loader = Data.DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True, num_workers=3)
for epoch in range(epoches):
print("进行第{}个epoch".format(epoch))
predict = torch.max(outputs.data, 1)[1]
其中 output 为模型的输出,该函数主要用来求 tensor 的最大值。
torch.max(input:tensor, dim:index)
该函数有两个输入:
inputs: tensor,第一个参数为一个张量
dim: index,第二个参数为一个整数[-2-1],dim=0表示计算每列的最大值,dim=1表示每行的最大值
pred_y = torch.max(test_output, 1)[1].data.numpy()
.numpy()
把tensor变成numpy
为什么要把numpy转为tensor呢?因为tensor是专门为GPU加速设计的矩阵,而numpy却不行。其实就相当于一个为GPU设计的数据结构。
numpy.squeeze()函数
语法:numpy.squeeze(a,axis = None)
1)a表示输入的数组;
2)axis用于指定需要删除的维度,但是指定的维度必须为单维度,否则将会报错;
3)axis的取值可为None 或 int 或 tuple of ints, 可选。若axis为空,则删除所有单维度的条目;
4)返回值:数组
5) 不会修改原数组;
作用:从数组的形状中删除单维度条目,即把shape中为1的维度去掉;我们可以利用squeeze()函数将表示向量的数组转换为秩为1的数组
enumerate的用法
enumerate()用于可迭代\可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标.
for i, data in enumerate(trainloader, 0):
#data里面包含图像数据(inputs)(tensor类型的)和标签(labels)(tensor类型)。
inputs, labels = data
上面代码的0表示从索引从0开始,假如为1的话,那索引就从1开始。
传统的训练函数,一个batch是这么训练的:【本CNN使用此训练方式】
①获取loss:输入图像和标签【batch_y
】,通过infer计算得到预测值,计算损失函数;
②optimizer.zero_grad()
清空过往梯度;
③loss.backward()
反向传播,计算当前梯度;
④optimizer.step()
根据梯度更新网络参数
简单的说就是进来一个batch的数据,计算一次梯度,更新一次网络,使用梯度累加是这么写的:
①获取loss:输入图像和标签,通过infer计算得到预测值,计算损失函数;
②loss.backward()
反向传播,计算当前梯度;
③多次循环步骤1-2,不清空梯度,使梯度累加在已有梯度上;
④梯度累加了一定次数后,先optimizer.step()
根据累计的梯度更新网络参数,然后optimizer.zero_grad()
清空过往梯度,为下一波梯度累加做准备;
**batch_x
**开始训练的值,从训练集里取出来的50个,每放进去50个训练后输出一次if step % 50 == 0:
# 开始训练
for epoch in range(epoches):
print("进行第{}个epoch".format(epoch))
for step, (batch_x, batch_y) in enumerate(train_loader):
output = cnn(batch_x) # batch_x=[50,1,28,28]
# output = output[0]
loss = loss_function(output, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if step % 50 == 0:
test_output = cnn(test_x) # [10000 ,10]
pred_y = torch.max(test_output, 1)[1].data.numpy()
# accuracy = sum(pred_y==test_y)/test_y.size(0)
accuracy = ((pred_y == test_y.data.numpy()).astype(int).sum()) / float(test_y.size(0))
print('Epoch: ', epoch, '| train loss: %.4f' % loss.data.numpy(), '| test accuracy: %.2f' % accuracy)
float()
函数用于将整数和字符串转换成浮点数。
.size(0)
中的0表示第0维度的数据数量.size(1)
同理
astype(int)
就是转化为整型数据,True和False转化为整型数据是0和1
.astype(bool)
作为布尔类型,也就是true or false
准确率是所有数据对的和/数据集y第0维度的数据数量
accuracy = ((pred_y == test_y.data.numpy()).astype(int).sum()) / float(test_y.size(0))
“”"
作者:Troublemaker
功能:
版本:
日期:2020/4/5 19:57
脚本:cnn.py
“”"
import torch import torch.nn as nn import torch.utils.data as Data import torchvision import matplotlib.pyplot as plt torch.manual_seed(1) # 设置超参数 epoches = 2 batch_size = 50 learning_rate = 0.001 # 搭建CNN class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() # 继承__init__功能 ## 第一层卷积 self.conv1 = nn.Sequential( # 输入[1,28,28] nn.Conv2d( in_channels=1, # 输入图片的高度 out_channels=16, # 输出图片的高度 kernel_size=5, # 5x5的卷积核,相当于过滤器 stride=1, # 卷积核在图上滑动,每隔一个扫一次 padding=2, # 给图外边补上0 ), # 经过卷积层 输出[16,28,28] 传入池化层 nn.ReLU(), nn.MaxPool2d(kernel_size=2) # 经过池化 输出[16,14,14] 传入下一个卷积 ) ## 第二层卷积 self.conv2 = nn.Sequential( nn.Conv2d( in_channels=16, # 同上 out_channels=32, kernel_size=5, stride=1, padding=2 ), # 经过卷积 输出[32, 14, 14] 传入池化层 nn.ReLU(), nn.MaxPool2d(kernel_size=2) # 经过池化 输出[32,7,7] 传入输出层 ) ## 输出层 self.output = nn.Linear(in_features=32*7*7, out_features=10) def forward(self, x): x = self.conv1(x) x = self.conv2(x) # [batch, 32,7,7] x = x.view(x.size(0), -1) # 保留batch, 将后面的乘到一起 [batch, 32*7*7] output = self.output(x) # 输出[50,10] return output # 下载MNist数据集 train_data = torchvision.datasets.MNIST( root="./mnist/", # 训练数据保存路径 train=True, transform=torchvision.transforms.ToTensor(), # 数据范围已从(0-255)压缩到(0,1) download=True, # 是否需要下载 ) # print(train_data.train_data.size()) # [60000,28,28] # print(train_data.train_labels.size()) # [60000] # plt.imshow(train_data.train_data[0].numpy()) # plt.show() test_data = torchvision.datasets.MNIST(root="./mnist/", train=False) print(test_data.test_data.size()) # [10000, 28, 28] # print(test_data.test_labels.size()) # [10000, 28, 28] test_x = torch.unsqueeze(test_data.test_data, dim=1).type(torch.FloatTensor)[:2000]/255 test_y = test_data.test_labels[:2000] # 装入Loader中 train_loader = Data.DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True, num_workers=3) def main(): # cnn 实例化 cnn = CNN() print(cnn) # 定义优化器和损失函数 optimizer = torch.optim.Adam(cnn.parameters(), lr=learning_rate) loss_function = nn.CrossEntropyLoss() # 开始训练 for epoch in range(epoches): print("进行第{}个epoch".format(epoch)) for step, (batch_x, batch_y) in enumerate(train_loader): output = cnn(batch_x) # batch_x=[50,1,28,28] # output = output[0] loss = loss_function(output, batch_y) optimizer.zero_grad() loss.backward() optimizer.step() if step % 50 == 0: test_output = cnn(test_x) # [10000 ,10] pred_y = torch.max(test_output, 1)[1].data.numpy() # accuracy = sum(pred_y==test_y)/test_y.size(0) accuracy = ((pred_y == test_y.data.numpy()).astype(int).sum()) / float(test_y.size(0)) print('Epoch: ', epoch, '| train loss: %.4f' % loss.data.numpy(), '| test accuracy: %.2f' % accuracy) test_output = cnn(test_x[:10]) pred_y = torch.max(test_output, 1)[1].data.numpy().squeeze() print(pred_y) print(test_y[:10]) if __name__ == "__main__": main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。