<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>goodness.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 01 Aug 2023 00:44:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>goodness.log</title>
            <url>https://velog.velcdn.com/images/numpy_master/profile/c0086df6-851d-4694-b7c7-e47e486d446d/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. goodness.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/numpy_master" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[512 토큰 이상의 한국어 처리를 위한 
BERT+Longformer Build]]></title>
            <link>https://velog.io/@numpy_master/%EA%B8%B4-%ED%95%9C%EA%B5%AD%EC%96%B4-%EC%B2%98%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-Longformer-Build</link>
            <guid>https://velog.io/@numpy_master/%EA%B8%B4-%ED%95%9C%EA%B5%AD%EC%96%B4-%EC%B2%98%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-Longformer-Build</guid>
            <pubDate>Tue, 01 Aug 2023 00:44:17 GMT</pubDate>
            <description><![CDATA[<h2 id="작성-동기">작성 동기</h2>
<h4 id="1-한국어-데이터를-처리하기-위해-처음에-bert-모델을-고려하였다">1. 한국어 데이터를 처리하기 위해 처음에 BERT 모델을 고려하였다.</h4>
<h4 id="2-bert의-최대-토큰-수는-512토큰이고-내-데이터는-대부분-10003000-토큰-사이였다">2. BERT의 최대 토큰 수는 512토큰이고 내 데이터는 대부분 1000~3000 토큰 사이였다.</h4>
<h4 id="3-따라서-bert를-사용할-경우-512토큰-이내인-문장-혹은-문단-단위로-나눠-처리해야하는데-이-경우엔-전체-문맥을-온전히-고려할-수-없다">3. 따라서 BERT를 사용할 경우 512토큰 이내인 문장 혹은 문단 단위로 나눠 처리해야하는데 이 경우엔 전체 문맥을 온전히 고려할 수 없다.</h4>
<h4 id="4-긴-문서-처리를-위해-bert처럼-transformer-기반의-모델로-설계되고-4096-토큰까지-처리할-수-있는-longformer-모델이-있다-github-주소--httpsgithubcomallenailongformer">4. 긴 문서 처리를 위해 BERT처럼 Transformer 기반의 모델로 설계되고 4096 토큰까지 처리할 수 있는 longformer 모델이 있다. (github 주소 : <a href="https://github.com/allenai/longformer">https://github.com/allenai/longformer</a>)</h4>
<h4 id="5-하지만-한국어-처리는-지원하지-않는다">5. 하지만 한국어 처리는 지원하지 않는다.</h4>
<h4 id="6-longformer-모델을-한국어로-사전학습-시켜야-하나-했지만-github에-기존-사전학습-모델을-longformer로-build-해주는-코드를-제공하였다-httpsgithubcomallenailongformerblobmasterscriptsconvert_model_to_longipynb">6. longformer 모델을 한국어로 사전학습 시켜야 하나 했지만 github에 기존 사전학습 모델을 longformer로 build 해주는 코드를 제공하였다 !(<a href="https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb">https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb</a>)</h4>
<h4 id="7-위-코드를-응용하여-다국어한국어-포함를-지원하는-bert를-longformer로-build하면-된다">7. 위 코드를 응용하여 다국어(한국어 포함)를 지원하는 BERT를 longformer로 build하면 된다.</h4>
<h4 id="8-필자는-정리된-게시글이-딱히-없어서-해당-깃허브-issue들을-뒤적거리며-해결하였고-그-내용을-정리하여-공유하고자-한다">8. 필자는 정리된 게시글이 딱히 없어서 해당 깃허브 issue들을 뒤적거리며 해결하였고 그 내용을 정리하여 공유하고자 한다.</h4>
<h4 id="기본적으로-아래-github-issue를-참고했다">기본적으로 아래 github issue를 참고했다.</h4>
<p><a href="https://github.com/dcaled/convert_bert_to_long/blob/main/convert_bert_to_long.ipynb">https://github.com/dcaled/convert_bert_to_long/blob/main/convert_bert_to_long.ipynb</a></p>
<h2 id="가상환경-생성">가상환경 생성</h2>
<blockquote>
<p>conda create --name longformer python=3.7
conda activate longformer
git clone <a href="https://github.com/allenai/longformer.git">https://github.com/allenai/longformer.git</a>
cd longformer
pip install -r requirements.txt</p>
</blockquote>
<h4 id="아래-부터는-jupyter-notebook으로-실행한다">아래 부터는 jupyter notebook으로 실행한다.</h4>
<blockquote>
<p>%pip install transformers==3.0.2</p>
</blockquote>
<h2 id="모듈-import">모듈 import</h2>
<h4 id="bertmodel과-berttokenizerfast를-추가로-불러온다-참고로-bert-뿐만아니라-원하는-사전학습-모델을-longformer로-build할-수-있다">BertModel과 BertTokenizerFast를 추가로 불러온다. 참고로 BERT 뿐만아니라 원하는 사전학습 모델을 longformer로 build할 수 있다.</h4>
<pre><code class="language-python">import logging
import os
import math
import copy
import torch
from dataclasses import dataclass, field
from transformers import RobertaForMaskedLM, RobertaTokenizerFast, TextDataset, DataCollatorForLanguageModeling, Trainer
from transformers import TrainingArguments, HfArgumentParser
from transformers.modeling_longformer import LongformerSelfAttention
from transformers import BertModel, BertTokenizerFast
import tensorflow as tf
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)</code></pre>
<h2 id="class-정의">class 정의</h2>
<h4 id="longformer-selfattention을-bertmodel에-build하는-class-선언">longformer SelfAttention을 BERTModel에 Build하는 class 선언</h4>
<pre><code class="language-python">class BertLongSelfAttention(LongformerSelfAttention):
    def forward(
        self,
        hidden_states,
        attention_mask=None,
        head_mask=None,
        encoder_hidden_states=None,
        encoder_attention_mask=None,
        output_attentions=False,
    ):
        return super().forward(hidden_states, attention_mask=attention_mask, output_attentions=output_attentions)


class BertLong(BertModel):
    def __init__(self, config):
        super().__init__(config)
        for i, layer in enumerate(self.encoder.layer):
            # replace the `modeling_bert.BertSelfAttention` object with `LongformerSelfAttention`
            layer.attention.self = BertLongSelfAttention(config, layer_id=i)</code></pre>
<h4 id="selfencoderlayer-부분만-상속받은-모델과-맞춰주면-된다-아래-코드부터도-동일하다">self.encoder.layer 부분만 상속받은 모델과 맞춰주면 된다. 아래 코드부터도 동일하다.</h4>
<pre><code class="language-python">for i, layer in enumerate(self.encoder.layer):</code></pre>
<h2 id="build-function-정의">build function 정의</h2>
<h4 id="본인이-사용할-model과-tokenizer를-load-해준다">본인이 사용할 model과 tokenizer를 load 해준다.</h4>
<h4 id="다국어-bert-model인-bert-base-multilingual-cased를-load-하였다">다국어 BERT Model인 &#39;bert-base-multilingual-cased&#39;를 load 하였다.</h4>
<pre><code class="language-python">def create_long_model(save_model_to, attention_window, max_pos):
    model = BertModel.from_pretrained(&#39;bert-base-multilingual-cased&#39;)
    tokenizer = BertTokenizerFast.from_pretrained(&#39;bert-base-multilingual-cased&#39;, model_max_length=max_pos)
    config = model.config

    print(max_pos)
    # extend position embeddings
    tokenizer.model_max_length = max_pos
    tokenizer.init_kwargs[&#39;model_max_length&#39;] = max_pos
    current_max_pos, embed_size = model.embeddings.position_embeddings.weight.shape
    config.max_position_embeddings = max_pos

    assert max_pos &gt; current_max_pos
    # allocate a larger position embedding matrix
    new_pos_embed = model.embeddings.position_embeddings.weight.new_empty(max_pos, embed_size)
    print(new_pos_embed.shape)
    print(model.embeddings.position_embeddings)
    # copy position embeddings over and over to initialize the new position embeddings
    k = 0
    step = current_max_pos
    while k &lt; max_pos - 1:
        new_pos_embed[k:(k + step)] = model.embeddings.position_embeddings.weight
        k += step
    print(new_pos_embed.shape)
    model.embeddings.position_ids = torch.from_numpy(tf.range(new_pos_embed.shape[0], dtype=tf.int32).numpy()[tf.newaxis, :])
    model.embeddings.position_embeddings = torch.nn.Embedding.from_pretrained(new_pos_embed)

    # replace the `modeling_bert.BertSelfAttention` object with `LongformerSelfAttention`
    config.attention_window = [attention_window] * config.num_hidden_layers
    for i, layer in enumerate(model.encoder.layer):
        longformer_self_attn = LongformerSelfAttention(config, layer_id=i)
        longformer_self_attn.query = layer.attention.self.query
        longformer_self_attn.key = layer.attention.self.key
        longformer_self_attn.value = layer.attention.self.value

        longformer_self_attn.query_global = copy.deepcopy(layer.attention.self.query)
        longformer_self_attn.key_global = copy.deepcopy(layer.attention.self.key)
        longformer_self_attn.value_global = copy.deepcopy(layer.attention.self.value)

        layer.attention.self = longformer_self_attn
    print(model.embeddings.position_ids.shape)
    logger.info(f&#39;saving model to {save_model_to}&#39;)
    model.save_pretrained(save_model_to)
    tokenizer.save_pretrained(save_model_to)
    return model, tokenizer</code></pre>
<h4 id="아래-코드에서-핵심은-max_pos-4096이다">아래 코드에서 핵심은 max_pos (4096)이다.</h4>
<h4 id="나머지는-추가-사전교육을-위한-부분이다-원하면-전체-코드를-참고하기-바란다httpsgithubcomallenailongformerblobmasterscriptsconvert_model_to_longipynb">나머지는 추가 사전교육을 위한 부분이다. 원하면 전체 코드를 참고하기 바란다.(<a href="https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb">https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb</a>)</h4>
<pre><code class="language-python">@dataclass
class ModelArgs:
    attention_window: int = field(default=512, metadata={&quot;help&quot;: &quot;Size of attention window&quot;})
    max_pos: int = field(default=4096, metadata={&quot;help&quot;: &quot;Maximum position&quot;})

parser = HfArgumentParser((TrainingArguments, ModelArgs,))

training_args, model_args = parser.parse_args_into_dataclasses(look_for_args_file=False, args=[
    &#39;--output_dir&#39;, &#39;tmp&#39;,
    &#39;--warmup_steps&#39;, &#39;500&#39;,
    &#39;--learning_rate&#39;, &#39;0.00003&#39;,
    &#39;--weight_decay&#39;, &#39;0.01&#39;,
    &#39;--adam_epsilon&#39;, &#39;1e-6&#39;,
    &#39;--max_steps&#39;, &#39;3000&#39;,
    &#39;--logging_steps&#39;, &#39;500&#39;,
    &#39;--save_steps&#39;, &#39;500&#39;,
    &#39;--max_grad_norm&#39;, &#39;5.0&#39;,
    &#39;--per_gpu_eval_batch_size&#39;, &#39;8&#39;,
    &#39;--per_gpu_train_batch_size&#39;, &#39;2&#39;,  # 32GB gpu with fp32
    &#39;--gradient_accumulation_steps&#39;, &#39;32&#39;,
    &#39;--evaluate_during_training&#39;,
    &#39;--do_train&#39;,
    &#39;--do_eval&#39;,
])

# Choose GPU
import os
os.environ[&quot;CUDA_VISIBLE_DEVICES&quot;] = &quot;0&quot;</code></pre>
<h2 id="build">Build</h2>
<h4 id="마지막-코드이다-오류-없이-실행된다면-longformer-build에-성공한-것이고-bert-base-4096이라는-폴더에-build-되었을-것이다">마지막 코드이다. 오류 없이 실행된다면 longformer build에 성공한 것이고, bert-base-4096이라는 폴더에 build 되었을 것이다.</h4>
<pre><code class="language-python">model_path = f&#39;{training_args.output_dir}/bert-base-{model_args.max_pos}&#39;
if not os.path.exists(model_path):
    os.makedirs(model_path)

logger.info(f&#39;Converting bert-base into bert-base-{model_args.max_pos}&#39;)
model, tokenizer = create_long_model(
    save_model_to=model_path, attention_window=model_args.attention_window, max_pos=model_args.max_pos)</code></pre>
<h2 id="final">Final</h2>
<h4 id="build한-longformer-모델을-사용하고자-할때-아래-코드처럼-불러오면-된다">build한 longformer 모델을 사용하고자 할때 아래 코드처럼 불러오면 된다.</h4>
<pre><code class="language-python">from transformers import BertModel, BertTokenizerFast
from transformers.modeling_longformer import LongformerSelfAttention


class BertLongSelfAttention(LongformerSelfAttention):
    def forward(
        self,
        hidden_states,
        attention_mask=None,
        head_mask=None,
        encoder_hidden_states=None,
        encoder_attention_mask=None,
        output_attentions=False,
    ):
        return super().forward(hidden_states, attention_mask=attention_mask, output_attentions=output_attentions)


class BertLong(BertModel):
    def __init__(self, config):
        super().__init__(config)
        for i, layer in enumerate(self.encoder.layer):
            # replace the `modeling_bert.BertSelfAttention` object with `LongformerSelfAttention`
            layer.attention.self = BertLongSelfAttention(config, layer_id=i)

model = BertLong.from_pretrained(&#39;bert-base-4096/&#39;)
tokenizer = BertTokenizerFast.from_pretrained(&#39;bert-base-4096/&#39;)</code></pre>
]]></description>
        </item>
    </channel>
</rss>