Beispiel #1
0
def create_vocab_text():
    TEXT = torchtext.data.Field(sequential=True,
                                tokenize=tokenizer_with_preprocessing,
                                use_vocab=True,
                                lower=False,
                                include_lengths=True,
                                batch_first=True,
                                fix_length=max_length,
                                init_token="[CLS]",
                                eos_token="[SEP]",
                                pad_token='[PAD]',
                                unk_token='[UNK]')
    LABEL = torchtext.data.Field(sequential=False, use_vocab=False)
    train_val_ds, test_ds = torchtext.data.TabularDataset.splits(
        path=DATA_PATH,
        train='train_dumy.csv',
        test='test_dumy.csv',
        format='csv',
        fields=[('Text', TEXT), ('Label', LABEL)])
    vocab_bert, ids_to_tokens_bert = load_vocab(vocab_file=VOCAB_FILE)
    TEXT.build_vocab(train_val_ds, min_freq=1)
    TEXT.vocab.stoi = vocab_bert
    pickle_dump(TEXT, PKL_FILE)

    return TEXT
    def __init__(self,
                 data_dir=r'./',
                 bert_dir=r'./pytorch_advanced/nlp_sentiment_bert/'):
        self.data_dir = data_dir
        self.bert_dir = bert_dir
        self.tokenizer_bert = BertTokenizer(
            vocab_file=self.bert_dir + "vocab/bert-base-uncased-vocab.txt",
            do_lower_case=True)
        self.vocab_bert, self.ids_to_tokens_bert = load_vocab(
            vocab_file=self.bert_dir + "vocab/bert-base-uncased-vocab.txt")

        config = get_config(file_path=self.bert_dir +
                            "weights/bert_config.json")
        self.net_bert = BertModel(config)
        self.net_bert = set_learned_params(self.net_bert,
                                           weights_path=self.bert_dir +
                                           "weights/pytorch_model.bin")
Beispiel #3
0
def get_chABSA_DataLoaders_and_TEXT(max_length=256, batch_size=32):
    """IMDbのDataLoaderとTEXTオブジェクトを取得する。 """
    def preprocessing_text(text):

        # 半角・全角の統一
        text = mojimoji.han_to_zen(text)
        # 改行、半角スペース、全角スペースを削除
        text = re.sub('\r', '', text)
        text = re.sub('\n', '', text)
        text = re.sub(' ', '', text)
        text = re.sub(' ', '', text)
        # 数字文字の一律「0」化
        text = re.sub(r'[0-9 0-9]+', '0', text)  # 数字

        # カンマ、ピリオド以外の記号をスペースに置換
        for p in string.punctuation:
            if (p == ".") or (p == ","):
                continue
            else:
                text = text.replace(p, " ")
        # ピリオドなどの前後にはスペースを入れておく
        text = text.replace(".", " . ")
        text = text.replace(",", " , ")
        return text

    # 前処理と単語分割をまとめた関数を定義
    # 単語分割の関数を渡すので、tokenizer_bertではなく、tokenizer_bert.tokenizeを渡す点に注意
    def tokenizer_with_preprocessing(text, tokenizer=tokenizer_bert.tokenize):
        text = preprocessing_text(text)
        ret = tokenizer(text)  # tokenizer_bert
        return ret

    # データを読み込んだときに、読み込んだ内容に対して行う処理を定義します
    max_length = 256
    TEXT = torchtext.data.Field(sequential=True,
                                tokenize=tokenizer_with_preprocessing,
                                use_vocab=True,
                                lower=False,
                                include_lengths=True,
                                batch_first=True,
                                fix_length=max_length,
                                init_token="[CLS]",
                                eos_token="[SEP]",
                                pad_token='[PAD]',
                                unk_token='[UNK]')
    LABEL = torchtext.data.Field(sequential=False, use_vocab=False)

    # フォルダ「data」から各tsvファイルを読み込みます
    train_ds, val_ds = torchtext.data.TabularDataset.splits(path='./data/',
                                                            train='train.tsv',
                                                            test='test.tsv',
                                                            format='tsv',
                                                            fields=[('Text',
                                                                     TEXT),
                                                                    ('Label',
                                                                     LABEL)])

    # torchtextで日本語ベクトルとして日本語学習済みモデルを読み込む
    #japanese_fastText_vectors = Vectors(name='./data/model.vec')

    # ベクトル化したバージョンのボキャブラリーを作成します
    #TEXT.build_vocab(train_ds, vectors=japanese_fastText_vectors, min_freq=5)

    # DataLoaderを作成します(torchtextの文脈では単純にiteraterと呼ばれています)
    train_dl = torchtext.data.Iterator(train_ds,
                                       batch_size=batch_size,
                                       train=True)

    val_dl = torchtext.data.Iterator(val_ds,
                                     batch_size=batch_size,
                                     train=False,
                                     sort=False)

    vocab_bert, ids_to_tokens_bert = load_vocab(vocab_file="./vocab/vocab.txt")
    TEXT.build_vocab(train_ds, min_freq=1)
    TEXT.vocab.stoi = vocab_bert

    return train_dl, val_dl, TEXT
Beispiel #4
0
 def _load_vocab(self, vocab_file):
     vocab, ids_to_tokens = load_vocab(vocab_file)
     return vocab, ids_to_tokens
Beispiel #5
0
def DataLoader(max_length=256, batch_size=32):
    """IMDbのDataLoaderとTEXTオブジェクトを取得する。 """
    # 乱数のシードを設定
    torch.manual_seed(0)
    np.random.seed(0)
    random.seed(0)
    # 単語分割用のTokenizerを用意
    tokenizer_bert = BertTokenizer(vocab_file=VOCAB_FILE, do_lower_case=False)

    def preprocessing_text(text):
        # 半角・全角の統一
        text = mojimoji.han_to_zen(text)
        # 改行、半角スペース、全角スペースを削除
        text = re.sub('\r', '', text)
        text = re.sub('\n', '', text)
        text = re.sub(' ', '', text)
        text = re.sub(' ', '', text)
        text = re.sub("\"", '', text)
        # 数字文字の一律「0」化
        text = re.sub(r'[0-9 0-9]+', '0', text)  # 数字

        # カンマ、ピリオド以外の記号をスペースに置換
        for p in string.punctuation:
            if (p == ".") or (p == ","):
                continue
            else:
                text = text.replace(p, " ")
            return text

    # 前処理と単語分割をまとめた関数を定義
    # 単語分割の関数を渡すので、tokenizer_bertではなく、tokenizer_bert.tokenizeを渡す点に注意
    def tokenizer_with_preprocessing(text, tokenizer=tokenizer_bert.tokenize):
        text = preprocessing_text(text)
        ret = tokenizer(text)  # tokenizer_bert
        return ret

    # データを読み込んだときに、読み込んだ内容に対して行う処理を定義します
    max_length = 256
    TEXT = torchtext.data.Field(sequential=True,
                                tokenize=tokenizer_with_preprocessing,
                                use_vocab=True,
                                lower=False,
                                include_lengths=True,
                                batch_first=True,
                                fix_length=max_length,
                                init_token="[CLS]",
                                eos_token="[SEP]",
                                pad_token='[PAD]',
                                unk_token='[UNK]')
    LABEL = torchtext.data.Field(sequential=False, use_vocab=False)

    # フォルダ「data」から各csvファイルを読み込みます
    # BERT用で処理するので、10分弱時間がかかります
    train_val_ds, test_ds = torchtext.data.TabularDataset.splits(
        path=DATA_PATH,
        train='train.csv',
        test='test.csv',
        format='csv',
        fields=[('Text', TEXT), ('Label', LABEL)])

    vocab_bert, ids_to_tokens_bert = load_vocab(vocab_file=VOCAB_FILE)
    TEXT.build_vocab(train_val_ds, min_freq=1)
    TEXT.vocab.stoi = vocab_bert

    batch_size = 32  # BERTでは16、32あたりを使用する
    train_dl = torchtext.data.Iterator(train_val_ds,
                                       batch_size=batch_size,
                                       train=True)
    val_dl = torchtext.data.Iterator(test_ds,
                                     batch_size=batch_size,
                                     train=False,
                                     sort=False)
    # 辞書オブジェクトにまとめる
    dataloaders_dict = {"train": train_dl, "val": val_dl}
    return train_dl, val_dl, TEXT, dataloaders_dict
def main():
    # define output dataframe
    sample = pd.read_csv("./data/sample_submission.csv")
    # データを読み込んだときに、読み込んだ内容に対して行う処理を定義します
    max_length = 256

    TEXT = torchtext.data.Field(sequential=True,
                                tokenize=tokenizer_with_preprocessing,
                                use_vocab=True,
                                lower=True,
                                include_lengths=True,
                                batch_first=True,
                                fix_length=max_length,
                                init_token="[CLS]",
                                eos_token="[SEP]",
                                pad_token='[PAD]',
                                unk_token='[UNK]')

    LABEL1 = torchtext.data.Field(sequential=False, use_vocab=False)
    LABEL2 = torchtext.data.Field(sequential=False, use_vocab=False)
    LABEL3 = torchtext.data.Field(sequential=False, use_vocab=False)
    LABEL4 = torchtext.data.Field(sequential=False, use_vocab=False)
    LABEL5 = torchtext.data.Field(sequential=False, use_vocab=False)
    LABEL6 = torchtext.data.Field(sequential=False, use_vocab=False)

    # (注釈):各引数を再確認
    # sequential: データの長さが可変か?文章は長さがいろいろなのでTrue.ラベルはFalse
    # tokenize: 文章を読み込んだときに、前処理や単語分割をするための関数を定義
    # use_vocab:単語をボキャブラリーに追加するかどうか
    # lower:アルファベットがあったときに小文字に変換するかどうか
    # include_length: 文章の単語数のデータを保持するか
    # batch_first:ミニバッチの次元を先頭に用意するかどうか
    # fix_length:全部の文章を指定した長さと同じになるように、paddingします
    # init_token, eos_token, pad_token, unk_token:文頭、文末、padding、未知語に対して、どんな単語を与えるかを指定

    # フォルダ「data」から各tsvファイルを読み込みます
    # BERT用で処理するので、10分弱時間がかかります
    temp_path = preprocessing.reformat_csv_header(path="./data",
                                                  train_file="train.csv",
                                                  test_file="test.csv")

    print("temp path {}".format(temp_path))
    print("text {}".format(vars(TEXT)))

    train_val_ds, test_ds = torchtext.data.TabularDataset.splits(
        path=temp_path,
        train='train.csv',
        test='test.csv',
        format='csv',
        fields=[('Text', TEXT), ('toxic', LABEL1), ('severe_toxic', LABEL2),
                ('obscene', LABEL3), ('threat', LABEL4), ('insult', LABEL5),
                ('identity_hate', LABEL6)])

    # torchtext.data.Datasetのsplit関数で訓練データとvalidationデータを分ける
    train_ds, val_ds = train_val_ds.split(split_ratio=0.8,
                                          random_state=random.seed(2395))

    # BERTはBERTが持つ全単語でBertEmbeddingモジュールを作成しているので、ボキャブラリーとしては全単語を使用します
    # そのため訓練データからボキャブラリーは作成しません

    vocab_bert, ids_to_tokens_bert = load_vocab(
        vocab_file="./weights/bert-base-uncased-vocab.txt")

    # このまま、TEXT.vocab.stoi= vocab_bert (stoiはstring_to_IDで、単語からIDへの辞書)としたいですが、
    # 一度bulild_vocabを実行しないとTEXTオブジェクトがvocabのメンバ変数をもってくれないです。
    # ('Field' object has no attribute 'vocab' というエラーをはきます)

    # 1度適当にbuild_vocabでボキャブラリーを作成してから、BERTのボキャブラリーを上書きします
    TEXT.build_vocab(train_ds, min_freq=1)
    TEXT.vocab.stoi = vocab_bert

    # DataLoaderを作成します(torchtextの文脈では単純にiteraterと呼ばれています)
    batch_size = 16  # BERTでは16、32あたりを使用する

    train_dl = torchtext.data.Iterator(train_ds,
                                       batch_size=batch_size,
                                       train=True)

    val_dl = torchtext.data.Iterator(val_ds,
                                     batch_size=batch_size,
                                     train=False,
                                     sort=False)

    test_dl = torchtext.data.Iterator(test_ds,
                                      batch_size=batch_size,
                                      train=False,
                                      sort=False)

    # 辞書オブジェクトにまとめる
    dataloaders_dict = {"train": train_dl, "val": val_dl}

    print(vars(train_ds[0]))
    print(vars(test_ds[0]))

    # モデル設定のJOSNファイルをオブジェクト変数として読み込みます
    config = get_config(file_path="./weights/bert_config.json")

    # BERTモデルを作成します
    net_bert = BertModel(config)

    # BERTモデルに学習済みパラメータセットします
    net_bert = set_learned_params(net_bert,
                                  weights_path="./weights/pytorch_model.bin")

    for label in [
            'toxic', 'severe_toxic', 'obscene', 'threat', 'insult',
            'identity_hate'
    ]:
        # モデル構築
        net = BertTraining(net_bert)

        # 訓練モードに設定
        net.train()

        print('done setup network')

        # 勾配計算を最後のBertLayerモジュールと追加した分類アダプターのみ実行

        # 1. まず全部を、勾配計算Falseにしてしまう
        for name, param in net.named_parameters():
            param.requires_grad = False

        # 2. 最後のBertLayerモジュールを勾配計算ありに変更
        for name, param in net.bert.encoder.layer[-1].named_parameters():
            param.requires_grad = True

        # 3. 識別器を勾配計算ありに変更
        for name, param in net.cls.named_parameters():
            param.requires_grad = True

        # 最適化手法の設定

        # BERTの元の部分はファインチューニング
        optimizer = optim.Adam(
            [{
                'params': net.bert.encoder.layer[-1].parameters(),
                'lr': 5e-5
            }, {
                'params': net.cls.parameters(),
                'lr': 5e-5
            }],
            betas=(0.9, 0.999))

        # 損失関数の設定
        criterion = nn.CrossEntropyLoss()
        # nn.LogSoftmax()を計算してからnn.NLLLoss(negative log likelihood loss)を計算

        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        # 学習・検証を実行する。1epochに20分ほどかかります
        num_epochs = 2
        net_trained = train_model(net,
                                  dataloaders_dict,
                                  criterion,
                                  optimizer,
                                  num_epochs=num_epochs,
                                  label=label,
                                  device=device)

        # 学習したネットワークパラメータを保存します
        save_path = './weights/bert_fine_tuning_weights.pth'
        torch.save(net_trained.state_dict(), save_path)

        # テストデータ
        net_trained.eval()  # モデルを検証モードに
        net_trained.to(device)  # GPUが使えるならGPUへ送る

        predicts = []

        for batch in tqdm(test_dl):  # testデータのDataLoader
            # batchはTextとLableの辞書オブジェクト
            # GPUが使えるならGPUにデータを送る
            inputs = batch.Text[0].to(device)  # 文章

            # 順伝搬(forward)計算
            with torch.set_grad_enabled(False):
                # BertForIMDbに入力
                outputs = net_trained(inputs,
                                      token_type_ids=None,
                                      attention_mask=None,
                                      output_all_encoded_layers=False,
                                      attention_show_flg=False)

                _, preds = torch.max(outputs, 1)  # ラベルを予測

                preds = preds.cpu()
                preds = preds.numpy().tolist()

                predicts += preds

        sample[label] = predicts

    # save predictions
    if not os.path.exists("./submission"):
        os.mkdir("./submission")
    sample.to_csv("./submission/submission_Bert_{}_{}ep.csv".format(
        datetime.datetime.now().date(), num_epochs),
                  index=False)
Beispiel #7
0
 def _load_vocab(self, vocab_file):
     _v, _i2t = load_vocab(vocab_file)
     return _v, _i2t