当前位置:   article > 正文

【PyTorch】深度学习实践之RNN高级篇—实现分类_深度学习实现数据分类

深度学习实现数据分类

1. RNN分类器

数据集:
[图片]

数据集里有人名和对应的国家,我们需要训练一个模型,输入一个新的名字,模型能预测出这个名字是基于哪种语言的(18种不同的语言,18分类)。

[图片]

在自然语言处理中,通常的方式:

  • 先把词或字变成一个one-hot向量,one-hot向量维度高,而且过于稀疏,所以一般来说先通过嵌入层(embed)把one-hot向量转化成低维的稠密向量。
  • 然后经过RNN层,隐层的输出不一定和最终要求的目标一致,所以要用一个线性层把输出映射成和我们的要求一致。
    在上面分类器中,要求输出一个大的分类(名字属于哪一个分类),所以对于最上面部分的输出是没有要求的,也就是说并不要求所有隐藏的输出做线性的变换,而且并不知道输出的结果是什么,所以为了解决这一个问题,网络是可以变得更加简单的。
    [图片]

只需要输出最终的隐藏状态,然后最终的隐藏状态接一个线性层,然后分成18个类别。这样可以实现名字分类的任务。本节主要学习的就是处理自然语言过程的方法和流程。

整体的使用模型结构:
*[图片]
比如,Maclean这个名字,我们其实得到的是一个序列M a c l e a n,每一个字符其实就是x1,x2,x3,x4。依次类推,所以看上去我们只是名字一个字段,实际上它是一个序列,而且还有问题就是序列的长短是不一样的,所以我们还要思考序列长度不一致的问题。

[图片]

模型处理过程:

[图片]

2. 分类器实现

主体代码:

if __name__ == '__main__':
    # N_CHARS:序列的字符数 HIDDEN_SIZE:隐藏层尺寸 N_COUNTRY:国家的类别数 N_LAYES:GRU的层数
    classifier = RNNClassication(N_CHARS,HIDDEN_SIZE,N_COUNTRY,N_LAYES)
    # 使用GPU
    if USE_GPU:
        device = torch.device("cuda:0")
        model.to(device)
    # 优化器和损失函数
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(),lr = 0.001)

    # 计时
    start = time.time()
    print("Trainginng for {} epochs...".format(N_EPOCHS))
    acc_list = []
    for epoch in range(1,N_EPOCHS):
        # 训练
        trainModel()
        # 测试
        acc = testModel()
        acc_list.append(acc)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
# 计时模块
def time_since(since):
    s = time.time() - since
    m = math.floor(s/60)
    s -= m*60
    return "{} {}".format(m,s)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
# 绘图模块
epoch = np.arange(1,len(acc_list)+1,1)
acc_list = np.array(acc_list)
plt.plot(epoch,acc_list)
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.grid()
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

准备数据

  • 名字处理
    [图片]
  • 字符串先转变成序列,转成字符列表,列表里面的每一个数就是名字里面的每一个字符。
  • 再做词典,用ASCII表,ASCII表是128个字符,我们把字典长度设置成128,求每一个字符对应的ASCII值,拼成我们想要的序列。上图中的最右表中每一个数并不是一个数字,而是一个one-hot向量。例如77,就是一个128维的向量,第77个数的值为1,其他的值都是0。对于Embedding(嵌入层)来说,只要告诉嵌入层第几个维度是1就行了,所以只需要把ASCII值放在这就行了。

数据对齐,使得数据的长度一致,找出最长的,然后其余的补0。做完填充之后,可以保证构成一个张量。
[图片]

  • 国家处理
    将国家转变成一个分类索引
    [图片]
# 准备数据集
class NameDataset(Dataset):
    def __init__(self,is_train_set=True):
        filename = 'names_train.csv.gz' if is_train_set else 'names_test.csv.gz'
        with gzip.open(filename,'rt') as f:          # 使用gzip读取gz文件
            reader = csv.reader(f)                   # 使用csv读取里面内容
            rows = list(reader)                      # 存到列表中,每一个都是元组(名字,国家)
        self.names = [row[0] for row in rows]       # 将名字存到列表中
        self.len = len(self.name)                    # 记录长度
        self.countries = [row[1] for row in rows]    # 将国家存到列表中
        self.countries_list = list(sorted(set(self.countries)))  # 去重 排序 再存到列表
        self.countries_dict = self.getCountryDict()              # 设置一个字典进行查找国家
        self.countries_num = len(self.countries_list)            # 国家的类别数

    def __getitem__(self, item):
        return self.names[item],self.countries_dict[self.countries[item]]  # 字典,key是国家名,value是index

    def __len__(self):
        return self.len

    def getCountryDict(self):  # 构造国家的查询字典
        country_dict = dict()
        for idx,country_name in enumerate(self.countries_list,0):
            country_dict[country_name] = idx
        return country_dict

    def idx2country(self,index): # 根据索引返回国家的字符串
        return self.countries_list[index]

    def getCountriesNum(self):   # 返回国家的数量
        return self.countries_num
  • 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

注意:上述代码读取数据集为什么不用Numpy?因为读取数据集有很多种方式,如果是pickle/HDFS/HD5类型的数据,要用相应的包。

trainset = NameDataset(is_train_set=True)
trainloader = DataLoader(dataset=trainset,batch_size=BATCH_SIZE,shuffle=True)
testset = NameDataset(is_train_set=False)
testloader = DataLoader(dataset=testset,batch_size=BATCH_SIZE,shuffle=False)

N_COUNTRY = trainset.getCountriesNum()  # 决定模型最终输出的维度大小
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

准备模型

GRU相关的参数:hidden_size和n_layers:
[图片]

Embedding层的输入、输出维度:
[图片]

GRU的输入、输出维度:
[图片]

其中,bidrectional是双向循环神经网络

# 模型
class RNNClassication(nn.Module):
    def __init__(self,input_size,hidden_size,output_size,n_layers=1,bidirectional = True):
        super(RNNClassication, self).__init__()
        self.hidden_size = hidden_size   # GRU layer
        self.n_layers = n_layers         # GRU layer
        self.n_directions = 2 if bidirectional else 1 #What is the Bi-Direction RNN/LSTM/GRU?
        # The input of Embedding Layer with shape:
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/235417
推荐阅读
相关标签