GPT-2の汎用日本語モデルが
いつの間にか公開されていたので、
これにサクっとファインチューニングを施すやつ。
いわゆるフェイク何某にもなりかねないので
一応注意の上、参考程度にしてください。
つまるところ……ある程度、最初から日本語を学習させたBOTに
途中から特定の人物のTwitterから抽出した特徴を転移学習させて
手っ取り早くその人っぽいBOTを作ろう!というやつ。
今回は、これを最小ステップ(TwitterのIDを指定するくらいの作業)で実現したい。
えぇ、そらもう。
流行りに乗っかりますよ。
#必要そうなものを入れる
!git clone https://github.com/tanreinama/gpt2-japanese
まずは環境構築。
GPT-2日本語モデルを環境にダウンロードして展開。
ついでにファインチューニング用の
データセット作成用エンコーダとそれ用のディレクトリを作ります。
例によってTweepyで特定Twitterの投稿を収集。
APIキーなどは適当に用意してください。
収集したツイートからURLやらリツイートを取り沿いて
処理ディレクトリに放り込み、エンコードしてハイ終了。
# 転移学習させる
なんか付属のファインチューニングコードが
使いにくかったので少しいじったものが上記。
500エポックで止まる省エネ仕様です。
学習結果はこちらで出力。
5文章くらいがつらつらと出てきます。
後は煮るなり焼くなり、以下宜しく。
いつの間にか公開されていたので、
これにサクっとファインチューニングを施すやつ。
いわゆるフェイク何某にもなりかねないので
一応注意の上、参考程度にしてください。
つまるところ……ある程度、最初から日本語を学習させたBOTに
途中から特定の人物のTwitterから抽出した特徴を転移学習させて
手っ取り早くその人っぽいBOTを作ろう!というやつ。
今回は、これを最小ステップ(TwitterのIDを指定するくらいの作業)で実現したい。
えぇ、そらもう。
流行りに乗っかりますよ。
#必要そうなものを入れる
!git clone https://github.com/tanreinama/gpt2-japanese
!git clone https://github.com/tanreinama/Japanese-BPEEncoder.git
%cd gpt2-japanese
!pip uninstall tensorflow -y
!pip install -r requirements.txt
!wget https://www.nama.ne.jp/models/gpt2ja-small.tar.bz2
!tar xvfj gpt2ja-small.tar.bz2
!mkdir srcdataset
まずは環境構築。
GPT-2日本語モデルを環境にダウンロードして展開。
ついでにファインチューニング用の
データセット作成用エンコーダとそれ用のディレクトリを作ります。
# 転移学習させるTwitterID
tw_id="hibiki_linasha"
# Tweepy用にAPIキーを入れる
CONSUMER_KEY = '*********'
CONSUMER_SECRET = '*********'
ACCESS_TOKEN = '*********'
ACCESS_TOKEN_SECRET = '*********'
# 以下処理
import tweepy
import pandas as pd
import datetime
import re
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
api = tweepy.API(auth)
def get_tweets():
tweet_data = []
for tweet in tweepy.Cursor(api.user_timeline,screen_name =
tw_id,exclude_replies = True).items():
tw_id,exclude_replies = True).items():
tweet_data.append(tweet.text.replace('\n',''))
df = pd.DataFrame(tweet_data)
df.to_csv("rawtweet.txt", sep=",")
df = pd.read_csv("rawtweet.txt")
df = df.replace("https(:\/\/[-_\.!~*\'()a-zA-Z0-9;\/?:\@&=\+$,%#]+)", "" ,regex=True)
df = df.replace("@YouTubeより", "" ,regex=True)
df = df[~df['0'].str.contains('RT', na = False)]
df.to_csv("/content/gpt2-japanese/srcdataset/dataset.txt", index=False, sep=",")
print("Complete.")
get_tweets()
get_tweets()
!python /content/Japanese-BPEEncoder/encode_bpe.py
--src_dir /content/gpt2-japanese/srcdataset --dst_file finetune
--src_dir /content/gpt2-japanese/srcdataset --dst_file finetune
例によってTweepyで特定Twitterの投稿を収集。
APIキーなどは適当に用意してください。
収集したツイートからURLやらリツイートを取り沿いて
処理ディレクトリに放り込み、エンコードしてハイ終了。
# 転移学習させる
import json
import os
import numpy as np
import tensorflow.compat.v1 as tf
import time
import tqdm
from copy import copy
from encode_bpe import BPEEncoder_ja
import model
if int(tf.__version__[0]) > 1:
from model import HParams as HParams
else:
from tensorflow.contrib.training import HParams
CHECKPOINT_DIR = 'checkpoint'
SAMPLE_DIR = 'samples'
dataset = 'finetune.npz'
base_model = 'gpt2ja-small'
batch_size = 1
optim = "adam"
learning_rate = 5
warmup_steps = 0
run_name = "gpr2ja-finetune_run12-small"
save_every = 1000
gpu = "0"
def maketree(path):
try:
os.makedirs(path)
except:
pass
with open('ja-bpe.txt') as f:
bpe = f.read().split('\n')
with open('emoji.json') as f:
emoji = json.loads(f.read())
enc = BPEEncoder_ja(bpe, emoji)
n_vocab = len(enc)
def main():
if 'small' in base_model:
hparams = HParams(**{
"n_vocab": n_vocab,
"n_ctx": 1024,
"n_embd": 768,
"n_head": 12,
"n_layer": 12
})
elif 'medium' in base_model:
hparams = HParams(**{
"n_vocab": n_vocab,
"n_ctx": 1024,
"n_embd": 1024,
"n_head": 16,
"n_layer": 24
})
elif 'large' in base_model:
hparams = HParams(**{
"n_vocab": n_vocab,
"n_ctx": 1024,
"n_embd": 1280,
"n_head": 20,
"n_layer": 36
})
else:
raise ValueError('invalid model name.')
config = tf.ConfigProto()
if int(gpu) >= 0:
config.gpu_options.allow_growth = True
config.gpu_options.visible_device_list = gpu
with tf.Session(config=config,graph=tf.Graph()) as sess:
context = tf.placeholder(tf.int32, [None, None])
output = model.model(hparams=hparams, X=context,
past=None, reuse=tf.AUTO_REUSE)
past=None, reuse=tf.AUTO_REUSE)
loss = tf.reduce_mean(
tf.nn.sparse_softmax_cross_entropy_with_logits(
labels=context[:, 1:], logits=output['logits'][:, :-1]))
saver = tf.train.Saver()
ckpt = tf.train.latest_checkpoint(base_model)
saver.restore(sess, ckpt)
train_vars = tf.trainable_variables()
global_step = tf.Variable(0, trainable=False)
if warmup_steps > 0:
learning_rate = tf.compat.v1.train.polynomial_decay(
learning_rate=1e-10,
end_learning_rate=learning_rate,
global_step=global_step,
decay_steps=warmup_steps
)
else:
learning_rate = 5
if optim=='adam':
opt = tf.train.AdamOptimizer(learning_rate=learning_rate,
beta1=0.9,
beta2=0.98,
epsilon=1e-7)
elif optim=='adagrad':
opt = tf.train.AdagradOptimizer(learning_rate=learning_rate)
elif optim=='sgd':
opt = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
else:
raise ValueError('invalid optimizer name.')
train_vars = tf.trainable_variables()
opt_grads = tf.gradients(loss, train_vars)
opt_grads = list(zip(opt_grads, train_vars))
opt_apply = opt.apply_gradients(opt_grads)
summaries = tf.summary.scalar('loss', loss)
summary_log = tf.summary.FileWriter(
os.path.join(CHECKPOINT_DIR, run_name))
saver = tf.train.Saver(
var_list=train_vars,
max_to_keep=5,
keep_checkpoint_every_n_hours=2)
sess.run(tf.global_variables_initializer())
ckpt = tf.train.latest_checkpoint(base_model)
saver.restore(sess, ckpt)
print('Loading checkpoint', ckpt)
print('Loading dataset...')
global_chunks = []
with np.load(dataset) as npz:
for inditem, item in enumerate(npz.files):
token_chunk = npz[item]
current_token = []
for ind in range(0,len(token_chunk)):
current_token.append(np.uint16(token_chunk[ind]))
if len(current_token) == hparams.n_ctx:
global_chunks.append(current_token)
current_token = []
global_chunk_index = np.random.permutation(len(global_chunks))
global_chunk_step = 0
print('Training...')
def sample_feature():
nonlocal global_chunks,global_chunk_index,global_chunk_step
p_input_ids = []
for b in range(batch_size):
idx = global_chunk_index[global_chunk_step]
global_chunk_step += 1
if global_chunk_step >= len(global_chunk_index):
global_chunk_step = 0
global_chunk_index = np.random.permutation(len(global_chunks))
sampled_token = global_chunks[idx]
ids = copy(global_chunks[idx])
p_input_ids.append(ids)
return {context:p_input_ids}
counter = 1
counter_path = os.path.join(CHECKPOINT_DIR, run_name, 'counter')
if os.path.exists(counter_path):
with open(counter_path, 'r') as fp:
counter = int(fp.read()) + 1
maketree(os.path.join(CHECKPOINT_DIR, run_name))
def save():
maketree(os.path.join(CHECKPOINT_DIR, run_name))
print(
'Saving',
os.path.join(CHECKPOINT_DIR, run_name,
'model-{}').format(counter))
saver.save(
sess,
os.path.join(CHECKPOINT_DIR, run_name, 'model'),
global_step=counter)
with open(counter_path, 'w') as fp:
fp.write(str(counter) + '\n')
avg_loss = (0.0, 0.0)
start_time = time.time()
try:
for i in range(500):
if counter % save_every == 0:
save()
(_, v_loss, v_summary) = sess.run(
(opt_apply, loss, summaries),
feed_dict=sample_feature())
summary_log.add_summary(v_summary, counter)
avg_loss = (avg_loss[0] * 0.99 + v_loss,
avg_loss[1] * 0.99 + 1.0)
print(
'[{counter} | {time:2.2f}] loss={loss:2.2f} avg={avg:2.2f}'
.format(
counter=counter,
time=time.time() - start_time,
loss=v_loss,
avg=avg_loss[0] / avg_loss[1]))
counter = counter+1
if warmup_steps > 0:
global_step = global_step+1
save()
except KeyboardInterrupt:
print('interrupted')
save()
if __name__ == '__main__':
main()
なんか付属のファインチューニングコードが
使いにくかったので少しいじったものが上記。
500エポックで止まる省エネ仕様です。
#例文出力
!python gpt2-generate.py --model
/content/gpt2-japanese/checkpoint/gpr2ja-finetune_run12-small/
--num_generate 5
/content/gpt2-japanese/checkpoint/gpr2ja-finetune_run12-small/
--num_generate 5
学習結果はこちらで出力。
5文章くらいがつらつらと出てきます。
後は煮るなり焼くなり、以下宜しく。
コメント