PyTorch搭建模型流程总结
之前手动搭建的一个神经网络来实现MINIST识别问题,但是效果不好,正好课题需要使用PyTorch,也学习了一段时间,对搭建流程做一个总结,顺便看一下自己写的网络和torch相差多少~~
使用PyTorch主要需要自己实现的部分就是 定义自己的网络 以及 定义自己的训练流程,下面也会对着两点分别讲述,最终使用之前MINIST的数据集进行训练。之前手动实现的
继承Module实现自己的层
nn.Module
是一个模型构造类,我们可以继承他来实现自己想要的模型。在自己定义的新类里面只需要对Module的 __init__()
以及 forward()
两个方法进行重载即可。
在__init__()
里面主要进行网络层的定义,将自己网络中所需要的层进行初始化。首先将定义自己所需的层,感觉一般需要的层在touch里面都已经定义好了,当然这里的层也可以是我们自己定义的,比如我们实现的一个网络,也可以作为一个层加入网络中作为网络的一部分。然后对模型参数进行初始化。以Bert的源码为例:
def __init__(self, config, add_pooling_layer=True):
super().__init__(config)
self.config = config
# 首先定义了如下三层 其中每一层都是之前自定义的模型类的实例
self.embeddings = BertEmbeddings(config)
self.encoder = BertEncoder(config)
self.pooler = BertPooler(config) if add_pooling_layer else None
# 接下来对所有参数进行初始化
self.init_weights()
那么为什么将模型实例化后加入自定义的类就可以将他们联系在一起进行训练了呢?是因为模型的参数都是Parameter类,只要将模型加入Module中 或者 将Parameter加入到Module中,就会自动将其添加到模型的参数列表,就可以进行后面自动梯度的计算。
那么对于第二个方法forward()
也需要重载,在这个方法里面主要规定前面定义的层之间的计算顺序问题。因为我们在前面定义的层都是作为模型的一个参数,是没有顺序的(也可以使用Sequential
类进行更方便的实现模型,添加的顺序就是定义的顺序,但是这样不如自己实现一个类灵活)。对于计算,一般来说就可以按顺序,第一层的输出作为第二层的输入,以此计算,最后输出输出层的输出(套娃概念,不愧是我~~~)。那么还是以Bert为例,但是这里只截取重要的部分:
embedding_output = self.embeddings(
input_ids=input_ids,
position_ids=position_ids,
token_type_ids=token_type_ids,
inputs_embeds=inputs_embeds,
past_key_values_length=past_key_values_length,
)
encoder_outputs = self.encoder(
embedding_output, # 这里就是上一层的输出
attention_mask=extended_attention_mask,
head_mask=head_mask,
encoder_hidden_states=encoder_hidden_states,
encoder_attention_mask=encoder_extended_attention_mask,
past_key_values=past_key_values,
use_cache=use_cache,
output_attentions=output_attentions,
output_hidden_states=output_hidden_states,
return_dict=return_dict,
)
sequence_output = encoder_outputs[0]
pooled_output = self.pooler(sequence_output) if self.pooler is not None else None # 这里也一样
if not return_dict:
return (sequence_output, pooled_output) + encoder_outputs[1:]
return BaseModelOutputWithPoolingAndCrossAttentions(
last_hidden_state=sequence_output,
pooler_output=pooled_output,
past_key_values=encoder_outputs.past_key_values,
hidden_states=encoder_outputs.hidden_states,
attentions=encoder_outputs.attentions,
cross_attentions=encoder_outputs.cross_attentions,
)
那么我们可以定义神经网络如下:
import torch
from torch import nn
# 定义神经网络
class ANN(nn.Module):
def __init__(self, input_size, hidden_size, output_size ):
super().__init__()
self.hidden_linear = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.output_linear = nn.Linear(hidden_size, output_size)
for params in self.parameters(): # 随机初始化参数
nn.init.normal_(params,mean=0,std=