整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          textCNN論文與原理-短文本分類(基于pytorch)

          前文已經(jīng)介紹了TextCNN的基本原理,如果還不熟悉的建議看看原理:【深度學(xué)習(xí)】textCNN論文與原理[1]及一個簡單的基于pytorch的圖像分類案例:【深度學(xué)習(xí)】卷積神經(jīng)網(wǎng)絡(luò)-圖片分類案例(pytorch實現(xiàn))[2]。 現(xiàn)在介紹一下如何使用textcnn進行文本分類,該部分內(nèi)容參考了:Pytorch-textCNN(不調(diào)用torchtext與調(diào)用torchtext)[3]。當然原文寫的也挺好的,不過感覺不夠工程化。現(xiàn)在我們就來看看如何使用pytorch和cnn來進行文本分類吧。

          1 實驗語料介紹與預(yù)處理

          本文進行的任務(wù)本質(zhì)是一個情感二分類的任務(wù),語料內(nèi)容為英文,其格式如下:

          一行文本即實際的一個樣本,樣本數(shù)據(jù)分別在neg.txt和pos.txt文件中。在進行數(shù)據(jù)預(yù)處理之前,先介紹一下本任務(wù)可能用到的一些參數(shù),這些參數(shù)我放在了一個config.py的文件中,內(nèi)容如下:

          #!/usr/bin/python
          # -*- coding: UTF-8 -*-
          """
          @author: juzipi
          @file: config.py
          @time:2020/12/06
          @description: 配置文件
          """
          LARGE_SENTENCE_SIZE = 50  # 句子最大長度
          BATCH_SIZE = 128          # 語料批次大小
          LEARNING_RATE = 1e-3      # 學(xué)習(xí)率大小
          EMBEDDING_SIZE = 200      # 詞向量維度
          KERNEL_LIST = [3, 4, 5]   # 卷積核長度
          FILTER_NUM = 100          # 每種卷積核輸出通道數(shù)
          DROPOUT = 0.5             # dropout概率
          EPOCH = 20                # 訓(xùn)練輪次
          

          下面就是數(shù)據(jù)預(yù)處理過程啦,先把代碼堆上來:

          import numpy as np
          from collections import Counter
          import random
          import torch
          from sklearn.model_selection import train_test_split
          import config
          
          random.seed(1000)
          np.random.seed(1000)
          torch.manual_seed(1000)
          
          
          def read_data(filename):
              """
              數(shù)據(jù)讀取
              :param filename: 文件路徑
              :return: 數(shù)據(jù)讀取內(nèi)容(整個文檔的字符串)
              """
              with open(filename, "r", encoding="utf8") as reader:
                  content = reader.read()
              return content
          
          
          def get_attrs():
              """
              獲取語料相關(guān)參數(shù)
              :return: vob_size, pos_text, neg_text, total_text, index2word, word2index
              """
              pos_text, neg_text = read_data("corpus/pos.txt"), read_data("corpus/neg.txt")
              total_text = pos_text + '\n' + neg_text
          
              text = total_text.split()
              vocab = [w for w, f in Counter(text).most_common() if f > 1]
              vocab = ['<pad>', '<unk>'] + vocab
          
              index2word = {i: word for i, word in enumerate(vocab)}
              word2index = {word: i for i, word in enumerate(vocab)}
          
              return len(word2index), pos_text, neg_text, total_text, index2word, word2index
          
          
          def convert_text2index(sentence, word2index, max_length=config.LARGE_SENTENCE_SIZE):
              """
              將語料轉(zhuǎn)成數(shù)字化數(shù)據(jù)
              :param sentence: 單條文本
              :param word2index: 詞語-索引的字典
              :param max_length: text_cnn需要的文本最大長度
              :return: 對語句進行截斷和填充的數(shù)字化后的結(jié)果
              """
              unk_id = word2index['<unk>']
              pad_id = word2index['<pad>']
              # 對句子進行數(shù)字化轉(zhuǎn)換,對于未在詞典中出現(xiàn)過的詞用unk的index填充
              indexes = [word2index.get(word, unk_id) for word in sentence.split()]
              if len(indexes) < max_length:
                  indexes.extend([pad_id] * (max_length - len(indexes)))
              else:
                  indexes = indexes[:max_length]
              return indexes
          
          
          def number_sentence(pos_text, neg_text, word2index):
              """
              語句數(shù)字化處理
              :param pos_text: 正例全部文本
              :param neg_text: 負例全部文本
              :param word2index: 詞到數(shù)字的字典
              :return: 經(jīng)過訓(xùn)練集和測試集劃分的結(jié)果X_train, X_test, y_train, y_test
              """
              pos_indexes = [convert_text2index(sentence, word2index) for sentence in pos_text.split('\n')]
              neg_indexes = [convert_text2index(sentence, word2index) for sentence in neg_text.split('\n')]
          
              # 為了方便處理,轉(zhuǎn)化為numpy格式
              pos_indexes = np.array(pos_indexes)
              neg_indexes = np.array(neg_indexes)
          
              total_indexes = np.concatenate((pos_indexes, neg_indexes), axis=0)
          
              pos_targets = np.ones((pos_indexes.shape[0]))  # 正例設(shè)置為1
              neg_targets = np.zeros((neg_indexes.shape[0]))  # 負例設(shè)置為0
          
              total_targets = np.concatenate((pos_targets, neg_targets), axis=0).reshape(-1, 1)
          
              return train_test_split(total_indexes, total_targets, test_size=0.2)
          
          
          def get_batch(x, y, batch_size=config.BATCH_SIZE, shuffle=True):
              """
              構(gòu)建迭代器,獲取批次數(shù)據(jù)
              :param x: 需要劃分全部特征數(shù)據(jù)的數(shù)據(jù)集
              :param y: 需要劃分全部標簽數(shù)據(jù)的數(shù)據(jù)集
              :param batch_size: 批次大小
              :param shuffle: 是否打亂
              :return: 以迭代器的方式返回數(shù)據(jù)
              """
              assert x.shape[0] == y.shape[0], "error shape!"
              if shuffle:
                  # 該函數(shù)是對[0, x.shape[0])進行隨機排序
                  shuffled_index = np.random.permutation(range(x.shape[0]))
                  # 使用隨機排序后的索引獲取新的數(shù)據(jù)集結(jié)果
                  x = x[shuffled_index]
                  y = y[shuffled_index]
          
              n_batches = int(x.shape[0] / batch_size)  # 統(tǒng)計共幾個完整的batch
              for i in range(n_batches - 1):
                  x_batch = x[i*batch_size: (i + 1)*batch_size]
                  y_batch = y[i*batch_size: (i + 1)*batch_size]
                  yield x_batch, y_batch
          

          其中各個函數(shù)怎么使用以及相關(guān)參數(shù)已經(jīng)在函數(shù)的說明中了,這里再贅述就耽誤觀眾姥爺?shù)臅r間了,哈哈。這些代碼我放在了一個dataloader.py的python文件中了,相信你會合理的使用它,如果有啥不明白的可以留言交流哦。

          2 textcnn模型構(gòu)建

          我依然先把代碼堆出來,不是網(wǎng)傳那么一句話嘛:“talk is cheap, show me code”,客官,代碼來咯:

          #!/usr/bin/python
          # -*- coding: UTF-8 -*-
          """
          @author: juzipi
          @file: model.py
          @time:2020/12/06
          @description:
          """
          import numpy as np
          import torch
          from torch import nn, optim
          import matplotlib.pyplot as plt
          import config
          import dataloader
          import utils
          
          
          class TextCNN(nn.Module):
              # output_size為輸出類別(2個類別,0和1),三種kernel,size分別是3,4,5,每種kernel有100個
              def __init__(self, vocab_size, embedding_dim, output_size, filter_num=100, kernel_list=(3, 4, 5), dropout=0.5):
                  super(TextCNN, self).__init__()
                  self.embedding = nn.Embedding(vocab_size, embedding_dim)
                  # 1表示channel_num,filter_num即輸出數(shù)據(jù)通道數(shù),卷積核大小為(kernel, embedding_dim)
                  self.convs = nn.ModuleList([
                      nn.Sequential(nn.Conv2d(1, filter_num, (kernel, embedding_dim)),
                                    nn.LeakyReLU(),
                                    nn.MaxPool2d((config.LARGE_SENTENCE_SIZE - kernel + 1, 1)))
                      for kernel in kernel_list
                  ])
                  self.fc = nn.Linear(filter_num * len(kernel_list), output_size)
                  self.dropout = nn.Dropout(dropout)
          
              def forward(self, x):
                  x = self.embedding(x)  # [128, 50, 200] (batch, seq_len, embedding_dim)
                  x = x.unsqueeze(1)     # [128, 1, 50, 200] 即(batch, channel_num, seq_len, embedding_dim)
                  out = [conv(x) for conv in self.convs]
                  out = torch.cat(out, dim=1)   # [128, 300, 1, 1],各通道的數(shù)據(jù)拼接在一起
                  out = out.view(x.size(0), -1)  # 展平
                  out = self.dropout(out)        # 構(gòu)建dropout層
                  logits = self.fc(out)          # 結(jié)果輸出[128, 2]
                  return logits
          
          
          # 數(shù)據(jù)獲取
          VOB_SIZE, pos_text, neg_text, total_text, index2word, word2index = dataloader.get_attrs()
          # 數(shù)據(jù)處理
          X_train, X_test, y_train, y_test = dataloader.number_sentence(pos_text, neg_text, word2index)
          # 模型構(gòu)建
          cnn = TextCNN(VOB_SIZE, config.EMBEDDING_SIZE, 2)
          # print(cnn)
          # 優(yōu)化器選擇
          optimizer = optim.Adam(cnn.parameters(), lr=config.LEARNING_RATE)
          # 損失函數(shù)選擇
          criterion = nn.CrossEntropyLoss()
          
          
          def train(model, opt, loss_function):
              """
              訓(xùn)練函數(shù)
              :param model: 模型
              :param opt: 優(yōu)化器
              :param loss_function: 使用的損失函數(shù)
              :return: 該輪訓(xùn)練模型的損失值
              """
              avg_acc = []
              model.train()  # 模型處于訓(xùn)練模式
              # 批次訓(xùn)練
              for x_batch, y_batch in dataloader.get_batch(X_train, y_train):
                  x_batch = torch.LongTensor(x_batch)  # 需要是Long類型
                  y_batch = torch.tensor(y_batch).long()
                  y_batch = y_batch.squeeze()  # 數(shù)據(jù)壓縮到1維
                  pred = model(x_batch)        # 模型預(yù)測
                  # 獲取批次預(yù)測結(jié)果最大值,max返回最大值和最大索引(已經(jīng)默認索引為0的為負類,1為為正類)
                  acc = utils.binary_acc(torch.max(pred, dim=1)[1], y_batch)
                  avg_acc.append(acc)  # 記錄該批次正確率
                  # 使用損失函數(shù)計算損失值,預(yù)測值要放在前
                  loss = loss_function(pred, y_batch)
                  # 清楚之前的梯度值
                  opt.zero_grad()
                  # 反向傳播
                  loss.backward()
                  # 參數(shù)更新
                  opt.step()
              # 所有批次數(shù)據(jù)的正確率計算
              avg_acc = np.array(avg_acc).mean()
              return avg_acc
          
          
          def evaluate(model):
              """
              模型評估
              :param model: 使用的模型
              :return: 返回當前訓(xùn)練的模型在測試集上的結(jié)果
              """
              avg_acc = []
              model.eval()  # 打開模型評估狀態(tài)
              with torch.no_grad():
                  for x_batch, y_batch in dataloader.get_batch(X_test, y_test):
                      x_batch = torch.LongTensor(x_batch)
                      y_batch = torch.tensor(y_batch).long().squeeze()
                      pred = model(x_batch)
                      acc = utils.binary_acc(torch.max(pred, dim=1)[1], y_batch)
                      avg_acc.append(acc)
              avg_acc = np.array(avg_acc).mean()
              return avg_acc
          
          
          # 記錄模型訓(xùn)練過程中模型在訓(xùn)練集和測試集上模型預(yù)測正確率表現(xiàn)
          cnn_train_acc, cnn_test_acc = [], []
          # 模型迭代訓(xùn)練
          for epoch in range(config.EPOCH):
              # 模型訓(xùn)練
              train_acc = train(cnn, optimizer, criterion)
              print('epoch={},訓(xùn)練準確率={}'.format(epoch, train_acc))
              # 模型測試
              test_acc = evaluate(cnn)
              print("epoch={},測試準確率={}".format(epoch, test_acc))
              cnn_train_acc.append(train_acc)
              cnn_test_acc.append(test_acc)
          
          
          # 模型訓(xùn)練過程結(jié)果展示
          plt.plot(cnn_train_acc)
          plt.plot(cnn_test_acc)
          
          plt.ylim(ymin=0.5, ymax=1.01)
          plt.title("The accuracy of textCNN model")
          plt.legend(["train", 'test'])
          plt.show()

          多說無益程序都在這,相關(guān)原理已經(jīng)介紹了,各位讀者慢慢品嘗,有事call me。 對了,程序最后運行的結(jié)果如下:

          模型分類結(jié)果

          3 結(jié)果的一個簡要分析

          其中隨著模型的訓(xùn)練,模型倒是在訓(xùn)練集上效果倒好(畢竟模型在訓(xùn)練集上調(diào)整參數(shù)嘛),測試集上的結(jié)果也慢慢上升最后還略有下降,可見開始過擬合咯。本任務(wù)沒有使用一些預(yù)訓(xùn)練的詞向量以及語料介紹,總體也就1萬多條,在測試集達到了這個效果也是差強人意了。主要想說明如何使用pytorch構(gòu)建textcnn模型,實際中的任務(wù)可能更復(fù)雜,對語料的處理也更麻煩(數(shù)據(jù)決定模型的上限嘛)。或許看完這個文章后,你對損失函數(shù)、優(yōu)化器、數(shù)據(jù)批次處理等還有一些未解之謎和改進的期待,我盡力在工作之余書寫相關(guān)文章以饗讀者,敬請關(guān)注哦。打條廣告,想及時看到最新個人原創(chuàng)文章記得關(guān)注“AIAS編程有道”公眾號哦,我在那里等你。至于本文的全部代碼和語料,我都上傳到github上了:https://github.com/Htring/NLP_Applications

          TML 文本格式化實例

          文本格式化

          此例演示如何在一個 HTML 文件中對文本進行格式化

          標簽 描述

          <b> 定義粗體文本。

          <big> 定義大號字。

          <em> 定義著重文字。

          <i> 定義斜體字。

          <small> 定義小號字。

          <strong>定義加重語氣。

          <sub> 定義下標字。

          <sup> 定義上標字。

          <ins> 定義插入字。

          <del> 定義刪除字。

          <html>
          <body>
          <b>This text is bold</b>
          <br />
          <strong>This text is strong</strong>
          <br />
          <big>This text is big</big>
          <br />
          <em>This text is emphasized</em>
          <br />
          <i>This text is italic</i>
          <br />
          <small>This text is small</small>
          <br />
          This text contains
          <sub>subscript</sub>
          <br />
          This text contains
          <sup>superscript</sup>
          </body>
          </html>
          

          HTML 文本格式化實例

          覽器的兼容性越來越好,移動端基本是清一色的webkit,經(jīng)常會用到css的不同尺寸/長度單位,這里做個整理。

          概覽

          絕對單位

          • px : Pixel 像素

          • pt : Points 磅

          • pc : Picas 派卡

          • in : Inches 英寸

          • mm : Millimeter 毫米

          • cm : Centimeter 厘米

          • q : Quarter millimeters 1/4毫米

          相對單位

          • % : 百分比

          • em : Element meter 根據(jù)文檔字體計算尺寸

          • rem : Root element meter 根據(jù)根文檔( body/html )字體計算尺寸

          • ex : 文檔字符“x”的高度

          • ch : 文檔數(shù)字“0”的的寬度

          • vh : View height 可視范圍高度

          • vw : View width 可視范圍寬度

          • vmin : View min 可視范圍的寬度或高度中較小的那個尺寸

          • vmax : View max 可視范圍的寬度或高度中較大的那個尺寸

          運算

          • calc : 四則運算

          實例:

          h1 { width: calc(100% - 10px + 2rem)

          單位比例

          1in = 2.54cm = 25.4 mm = 101.6q = 72pt = 6pc = 96px

          詳細

          絕對單位

          px - Pixel 像素

          像素 px 相對于設(shè)備顯示器屏幕分辨率而言。

          div { font-size: 12px }
          p { text-indent: 24px }

          pt Points 磅

          1 pt = 1/72 英寸

          div { font-size: 10pt }
          p { height: 100pt }

          pc Picas 派卡

          十二點活字(印刷中使用的),相當于我國新四號鉛字的尺寸。

          div { font-size: 10pc }
          p { height: 10pc }

          in Inches 英寸

          div { font-size: 10in }
          p { height: 10in }

          mm Millimeter 毫米

          div { font-size: 10mm }
          p { height: 10mm }

          cm Centimeter 厘米

          div { font-size: 10cm }
          p { height: 10cm }

          q Quarter millimeters 1/4毫米

          div { font-size: 20q }
          p { height: 100q }

          相對單位

          % 百分比

          相對于父元素寬度

          <body>

          em Element meter 根據(jù)文檔計算尺寸

          相對于當前文檔對象內(nèi)文本的字體尺寸而言,若未指定字體大小則繼承自上級元素,以此類推,直至 body,若 body 未指定則為瀏覽器默認大小。

          <body>

          rem Root element meter 根據(jù)根文檔( body/html )字體計算尺寸

          相對于根文檔對象( body/html )內(nèi)文本的字體尺寸而言,若未指定字體大小則繼承為瀏覽器默認字體大小。

          ex 文檔字符“x”的高度

          相對于字符“x”的高度,通常為字體高度的一半,若未指定字體尺寸,則相對于瀏覽器的默認字體尺寸。

          至于為啥是x,我TM也不知道。

          ch 文檔數(shù)字“0”的的寬度

          同上,相對于數(shù)字“0”的寬度。

          一張圖解釋:

          vh View height / vw View Width - 可視范圍

          相對于可視范圍的高度和寬度,可視范圍被均分為 100 單位的 vh/vw;可視范圍是指屏幕可見范圍,不是父元素的,百分比是相對于包含它的最近的父元素的高度和寬度。

          假設(shè)設(shè)備可視范圍為高度 900px,寬度 750px,則, 1 vh = 900px/100 = 9px,1vw = 750px/100 = 7.5px

          vmin / vmax 可視范圍的寬度或高度中較小/較大的那個尺寸

          假設(shè)瀏覽器的寬度設(shè)置為 1200px,高度設(shè)置為 800px, 則 1vmax = 1200/100px = 12px, 1vmin = 800/100px = 8px

          如果寬度設(shè)置為 600px,高度設(shè)置為 1080px, 則 1vmin = 6px, 1vmax = 10.8px

          假設(shè)需要讓一個元素始終在屏幕上可見:

          .box {

          假設(shè)需要讓這個元素始終鋪滿整個視口的可見區(qū)域:

          .box {

          總結(jié)

          em、rem 是實際生產(chǎn)中我們最常用到的單位,可以使用其配合媒體查詢改變 body 字體大小來實現(xiàn)響應(yīng)式的設(shè)計,vh、vw、vmin、vmax也可以很方便地幫助我們控制響應(yīng)尺寸,但實際的可控性可能不如前者,具體按照我們的業(yè)務(wù)需求去實踐吧!


          主站蜘蛛池模板: 97se色综合一区二区二区| 午夜精品一区二区三区在线视| 在线精品视频一区二区| 国产福利电影一区二区三区,亚洲国模精品一区 | 亚洲日本一区二区三区| 夜色福利一区二区三区| 国产一区二区三区在线观看精品| 久久国产视频一区| 精品国产伦一区二区三区在线观看| 天码av无码一区二区三区四区 | 亚洲日韩激情无码一区| 亚洲av不卡一区二区三区| 久久精品国产一区二区| 亚洲伦理一区二区| 国产伦精品一区二区三区精品| 亚洲AV无码一区二区三区人| 99久久精品费精品国产一区二区| 国产一区二区在线观看视频| 国产一区二区在线|播放| 综合一区自拍亚洲综合图区| 亚洲AV无码一区东京热| 精品熟人妻一区二区三区四区不卡| 亚洲乱码日产一区三区| 久久一区二区三区免费播放| 国产精品一区二区久久精品涩爱| 精品一区二区三区免费| 日本在线视频一区二区三区| 亚洲一区二区三区精品视频| 99久久无码一区人妻a黑| 亚洲一区二区三区精品视频| 91大神在线精品视频一区| 精品国产aⅴ无码一区二区| 中文字幕无码不卡一区二区三区| 国产福利酱国产一区二区| 免费无码一区二区三区蜜桃大| 国产福利电影一区二区三区,免费久久久久久久精 | 激情久久av一区av二区av三区| 国产一区三区二区中文在线| 曰韩精品无码一区二区三区| 精品一区二区久久| 中文字幕一区二区三区免费视频|