Pytorch-基於colab對中文評論使用LSTM進行情感分析

  • 之前由於在本機mac中訓練驗證碼識別,導致mac後來的使用有點卡,另外囊中羞澀,所以考慮用google的colab進行訓練
  • 關於google的colab的使用,一般包含兩個方面:
  1. google的雲盤:https://drive.google.com/
  2. colab:https://colab.research.google.com/notebooks/intro.ipynb 

 

  • 關於使用,我們只要把數據上傳到雲磁盤,然後可以在colab頁面上新建一個筆記本(jupyter風格),就可以開始操作代碼了。
  • 值得注意的是,如果需要使用GPU,則在筆記本的菜單欄裏選擇 -  代碼執行程序 - 更改運行時的類型- 選擇GPU即可。
  • 數據存儲的路徑怎麼看?一般是存儲在/content/gdrive/My Drive/ 路徑下; 下面是我讀取文件夾下的圖片數據
from google.colab import drive

def get_train(path):
    X=[]
    files=os.listdir(path)
    cnt=0
    for ele in files:
      cnt=cnt+1
      if cnt % 100==0:
        print(cnt)
      img=Image.open(path+ele)
      img_array=np.array(img)
      X.append(img_array)
    return X

# 掛在google的磁盤
drive.mount('/content/gdrive/')

# 要看下該磁盤下的目錄
# for ele in os.listdir("/content/gdrive/My Drive/data/Images"):
#   print(ele)

#找到圖片所在目錄
trainx=get_train("/content/gdrive/My Drive/data/Images/")
# 獲取圖片並且轉換
print(len(trainx))

 

  • 數據集是對酒店的中文評論數據,只有0,1兩類; 實際上有些評論是比較中性的,對於這種情況,模型可能會存在一定的誤殺
  • 模型採用雙向的LSTM,當訓練集上(train)的準確率達到0.9之後,我們就開始在驗證集(val)上計算準確率,如果在驗證集上的準確率達到0.82,那麼我就終止訓練了,並將模型進行保存。
  • 先看下結果

epoch=7的時候,訓練集上的準確率達到96.2%, 驗證集上的準確率達到82.5%

看了幾條,紅款部分是誤殺的;實際上像第一條,也不能定義爲好,數據集的質量有待提升;

 

  • 下面我就丟代碼了,因爲寫的時間比較短,所以代碼的結構不是很好,將就看看吧;
    import torchtext
    import torch
    from torchtext.vocab import  Vectors
    from torchtext import data
    import jieba
    import torch.nn as nn
    from torchtext.data import BucketIterator
    import torch.optim as optim
    import torch.nn.functional as F
    from google.colab import drive
    import os
    drive.mount('/content/gdrive/')
    # 定義分詞器,爲列處理器服務
    def cut_words(text):
        return list(jieba.cut(text))
    # 定義列的處理器
    TEXT=torchtext.data.Field(sequential=True,tokenize=cut_words,batch_first=True)
    LABEL=torchtext.data.Field(sequential=False,use_vocab=False)
    
    tv_datafields = [("label", LABEL),("review", TEXT)]
    test_datafields=[("label", None),("review", TEXT)]
    # 觀察下數據存儲的位置
    for ele in os.listdir("/content/gdrive/"):
      print(ele)
    
    # 讀取訓練和驗證集數據
    train,val=torchtext.data.TabularDataset.splits(path="/content/gdrive/My Drive/data/",train="train.csv",validation="val.csv",format="csv",skip_header=True,fields=tv_datafields)
    train_len=len(train)
    
    #vectors = Vectors(name='/content/gdrive/My Drive/data/glove.6B.300d.txt')
    
    # 構建字典
    TEXT.build_vocab(train)
    LABEL.build_vocab()
    vocab_len=TEXT.vocab.__len__()
    
    # 構建迭代器
    train_iter,val_iter=BucketIterator.splits(
        (train,val),
        batch_size=64,
        sort_key=lambda x: len(x.review),
        sort_within_batch=False,
        repeat=False
    )
    
    
    # 定義lstm模型
    class rnn(nn.Module):
    
        def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim):
            super(rnn, self).__init__()
    
            self.embedding = nn.Embedding(vocab_size, embedding_dim)
            # 這次沒有采用預訓練的詞向量,發現我自己找的是英文glove預訓練詞向量
            #self.embedding.weight.data.copy_(TEXT.vocab.vectors)
            #self.embedding.weight.requires_grad=True
            self.rnn= nn.LSTM(embedding_dim, hidden_dim,num_layers=2,batch_first=True,bidirectional=True)
            #self.fc = nn.Linear(hidden_dim, output_dim)
            self.fc=nn.Sequential(
                nn.Linear(hidden_dim*2, output_dim),
                nn.Sigmoid()
            )
        def forward(self, text):
    
            embedded = self.embedding(text)
            output,(hidden,cell)=self.rnn(embedded)
            hidden = torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim = 1)
            y=self.fc(hidden)
            return y
    
    
    model=rnn(vocab_size=vocab_len,embedding_dim=300,hidden_dim=128,output_dim=1)
    model.cuda()
    
    
    lr=0.001
    
    optimizer = optim.Adam(model.parameters(), lr=lr)
    criterion = nn.BCELoss()
    
    for i in range(20):
        model.train()
        total_loss=0
        total_accurate=0
        for batch_idx, batch in enumerate(train_iter):
            data, target = batch.review.cuda(), batch.label.cuda()
            optimizer.zero_grad()
            pred= model(data).squeeze()
            loss = criterion(pred, target.float())
            loss.backward()
            optimizer.step()
            total_loss+=loss.item()
            accurate=((pred>0.5)==target).sum().item()
            total_accurate+=accurate
            if batch_idx % 10 ==0:
              print("EPOCH:{epoch},Batch:{batch},Loss:{loss},Acc:{acc}".format(loss=loss,epoch=i,acc=accurate/64,batch=batch_idx))
        avg_acc=total_accurate/train_len
        avg_loss=total_loss/train_len
        print("\n"*3)
        print("avg_acc:{avg_acc},avg_loss:{avg_loss}".format(avg_acc=avg_acc,avg_loss=avg_loss)) 
    
        # 如果訓練集上的準確率達到95%,那麼就看下模型在驗證集上的準確率
        if avg_acc>0.95 :
          model.eval()
          val_acc=0.0
          for batch_idx, batch in enumerate(val_iter):
              data, target = batch.review.cuda(), batch.label.cuda()
              pred= model(data).squeeze()
              accurate=((pred>0.5)==target).sum().item()
              val_acc+=accurate
          print("val_avg_acc:{val_avg_acc}".format(val_avg_acc=val_acc/len(val)))
          # 如果驗證集上的準確率達到82%,那麼就看下驗證集上的預測結果,並保存模型到final.pkl中,終止循環了
          if val_acc/len(val)>0.82:
            for batch_idx, batch in enumerate(val_iter):
              data, target = batch.review.cuda(), batch.label.cuda()
              pred= model(data).squeeze()
              for i in range(len(data)):
                source=[TEXT.vocab.itos[ele] for ele in data[i] if TEXT.vocab.itos[ele]!='<pad>' and  TEXT.vocab.itos[ele]!='<unk>']
                print("真實標籤:{real_tag},預測標籤:{pred_tag},真實評論:{real_review}".format(real_tag=target[i],real_review="".join(source),pred_tag=int((pred>0.5)[i])))
              torch.save(model,"final.pkl")
            break

     

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章