13 May 2017

pytorch基础

目录

欢迎在文章下方评论,建议用电脑看

pytorch基础

在建立一个模型时。以我的理解来看,就是分为四个部分:数据的读取,模型的构建,模型的算法训练,训练结果的保存及其可视化,最后是对模型的泛化预测。所以下面就是按照这样的5个部分来记录怎么学习pytorch的。

数据的读取

DataLoader

DataLoader 是 torch 给你用来包装你的数据的工具. 所以你要讲自己的 (numpy array 或其他) 数据形式装换成 Tensor, 然后再放进这个包装器中. 使用 DataLoader 有什么好处呢? 就是他们帮你有效地迭代数据, 举例:

举例说明:

	import torch
	import torch.utils.data as Data
	torch.manual_seed(1)    # reproducible

	BATCH_SIZE = 5      # 批训练的数据个数

	x = torch.linspace(1, 10, 10)       # x data (torch tensor)
	y = torch.linspace(10, 1, 10)       # y data (torch tensor)

	# 先转换成 torch 能识别的 Dataset
	torch_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)

	# 把 dataset 放入 DataLoader
	loader = Data.DataLoader(
		dataset=torch_dataset,      # torch TensorDataset format
		batch_size=BATCH_SIZE,      # mini batch size
		shuffle=True,               # 要不要打乱数据 (打乱比较好)
		num_workers=2,              # 多线程来读数据
	)

	for epoch in range(3):   # 训练所有!整套!数据 3 次
		for step, (batch_x, batch_y) in enumerate(loader):  # 每一步 loader 释放一小批数据用来学习
			# 假设这里就是你训练的地方...

			# 打出来一些数据
			print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
				  batch_x.numpy(), '| batch y: ', batch_y.numpy())

	"""
	Epoch:  0 | Step:  0 | batch x:  [ 6.  7.  2.  3.  1.] | batch y:  [  5.   4.   9.   8.  10.]
	Epoch:  0 | Step:  1 | batch x:  [  9.  10.   4.   8.   5.] | batch y:  [ 2.  1.  7.  3.  6.]
	Epoch:  1 | Step:  0 | batch x:  [  3.   4.   2.   9.  10.] | batch y:  [ 8.  7.  9.  2.  1.]
	Epoch:  1 | Step:  1 | batch x:  [ 1.  7.  8.  5.  6.] | batch y:  [ 10.   4.   3.   6.   5.]
	Epoch:  2 | Step:  0 | batch x:  [ 3.  9.  2.  6.  7.] | batch y:  [ 8.  2.  9.  5.  4.]
	Epoch:  2 | Step:  1 | batch x:  [ 10.   4.   8.   1.   5.] | batch y:  [  1.   7.   3.  10.   6.]
	"""

可以看出, 每步都导出了5个数据进行学习. 然后每个 epoch 的导出数据都是先打乱了以后再导出.

真正方便的还不是这点. 如果我们改变一下 BATCH_SIZE = 8, 这样我们就知道, step=0 会导出8个数据, 但是, step=1 时数据库中的数据不够 8个, 这时怎么办呢:


	BATCH_SIZE = 8      # 批训练的数据个数

	...

	for ...:
		for ...:
			...
			print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
				  batch_x.numpy(), '| batch y: ', batch_y.numpy())
	"""
	Epoch:  0 | Step:  0 | batch x:  [  6.   7.   2.   3.   1.   9.  10.   4.] | batch y:  [  5.   4.   9.   8.  10.   2.   1.   7.]
	Epoch:  0 | Step:  1 | batch x:  [ 8.  5.] | batch y:  [ 3.  6.]
	Epoch:  1 | Step:  0 | batch x:  [  3.   4.   2.   9.  10.   1.   7.   8.] | batch y:  [  8.   7.   9.   2.   1.  10.   4.   3.]
	Epoch:  1 | Step:  1 | batch x:  [ 5.  6.] | batch y:  [ 6.  5.]
	Epoch:  2 | Step:  0 | batch x:  [  3.   9.   2.   6.   7.  10.   4.   8.] | batch y:  [ 8.  2.  9.  5.  4.  1.  7.  3.]
	Epoch:  2 | Step:  1 | batch x:  [ 1.  5.] | batch y:  [ 10.   6.]
	"""

这时, 在 step=1 就只给你返回这个 epoch 中剩下的数据就好了.

模型构建

有两种方式:

	class Net(torch.nn.Module):
		def __init__(self, n_feature, n_hidden, n_output):
			super(Net, self).__init__()
			self.hidden = torch.nn.Linear(n_feature, n_hidden)
			self.predict = torch.nn.Linear(n_hidden, n_output)

		def forward(self, x):
			x = F.relu(self.hidden(x))
			x = self.predict(x)
			return x

	net1 = Net(1, 10, 1)   # 这是我们用这种方式搭建的 net1

上面就是一般的构造神经网路模型的方式,就是创建一个类,然后的,在 __init__中构建好大概的骨架,然后在forward()这个函数中选择用什么样的激活函数。

print(net1)
"""
Net (
  (hidden): Linear (1 -> 10)
  (predict): Linear (10 -> 1)
)
"""


print(cnn)  # net architecture
class CNN(nn.Module):
	def __init__(self):
		super(CNN, self).__init__()
		self.conv1 = nn.Sequential(         # input shape (1, 28, 28)
			nn.Conv2d(
				in_channels=1,              # input height
				out_channels=16,            # n_filters
				kernel_size=5,              # filter size
				stride=1,                   # filter movement/step
				padding=2,                  # if want same width and length of this image after con2d, padding=(kernel_size-1)/2 if stride=1
			),                              # output shape (16, 28, 28)
			nn.ReLU(),                      # activation
			nn.MaxPool2d(kernel_size=2),    # choose max value in 2x2 area, output shape (16, 14, 14)
		)
		self.conv2 = nn.Sequential(         # input shape (1, 28, 28)
			nn.Conv2d(16, 32, 5, 1, 2),     # output shape (32, 14, 14)
			nn.ReLU(),                      # activation
			nn.MaxPool2d(2),                # output shape (32, 7, 7)
		)
		self.out = nn.Linear(32 * 7 * 7, 10)   # fully connected layer, output 10 classes

	def forward(self, x):
		x = self.conv1(x)
		x = self.conv2(x)
		x = x.view(x.size(0), -1)           # flatten the output of conv2 to (batch_size, 32 * 7 * 7)
		output = self.out(x)
		return output


CNN (
  (conv1): Sequential (
	(0): Conv2d(1, 16, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
	(1): ReLU ()
	(2): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
  )
  (conv2): Sequential (
	(0): Conv2d(16, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
	(1): ReLU ()
	(2): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
  )
  (out): Linear (1568 -> 10)
)


我们会发现 cnn中 多显示的模型结构中,他把激励函数也一同纳入进去了, 但是 net1 中, 激励函数实际上是在 forward() 功能中才被调用的. 这也就说明了, 相比 cnn这种构造方式,output = cnn(b_x) # cnn output net1 的好处就是, 你可以根据你的个人需要更加个性化你自己的前向传播过程, 比如(RNN). 不过如果你不需要七七八八的过程, 相信 类似cnn这种构造。形式更适合你.

模型的算法训练,

一般训练模型的模板代码如下:

	optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)   # optimize all cnn parameters
	loss_func = nn.CrossEntropyLoss()                       # the target label is not one-hotted

	for epoch in range(EPOCH):
		......
		output = net(b_x)               # net output
		loss = loss_func(output, b_y)   # cross entropy loss
		optimizer.zero_grad()           # clear gradients for this training step
		loss.backward()                 # backpropagation, compute gradients
		optimizer.step()                # apply gradients

也就是选取优化器加上loss函数,然后在循环的时候计算梯度,进行反向传播等等等….

训练结果的保存及其可视化

保存模型的两种方式:

	torch.save(net1, 'net.pkl')  # 保存整个网络
	torch.save(net1.state_dict(), 'net_params.pkl')   # 只保存网络中的参数 (速度快, 占内存少)

提取模型:

  	# restore entire net1 to net2 这种方式将会提取整个神经网络, 网络大的时候可能会比较慢.
    net2 = torch.load('net.pkl')
    prediction = net2(x)

  	# 将保存的参数复制到 net3  这种方式将会提取所有的参数, 然后再放到你的新建网络中.
    net3.load_state_dict(torch.load('net_params.pkl'))
    prediction = net3(x)

Tags:
Stats:
comments


Share: