CV・NLPハマりどころメモ

画像認識と自然言語処理を研究する上でうまくいかなかったことと,その対策をまとめる自分用のメモが中心.

自作データで学習したモデルを再度読み込んで2回目の学習を実行[Flair]

自作データを使って2回以上の学習を回したときにハマったのでまとめる.

筆者が自作データでNERの学習を行なったときに,1回目に学習したモデルを2回目の学習に引き継ぎたいと思った.

しかしながら,その方法は公式ドキュメントには書いていなかったので,自分で調べて解決した.

結論としては,SequenceTagger.load()を使って,1回目のモデルを読み込み,それをtaggerとして用いた.

以下,1回目に学習したモデルを2回目の学習に引き継ぐコード.

from flair.data import Corpus
from flair.embeddings import TokenEmbeddings, WordEmbeddings, StackedEmbeddings
from flair.data import Sentence
from flair.models import SequenceTagger
from flair.embeddings import (
    WordEmbeddings,
    CharacterEmbeddings,
    FlairEmbeddings,
    BertEmbeddings,
)
from flair.data import Corpus
from flair.datasets import ColumnCorpus
from typing import List
from pathlib import Path
import sys
from docopt import docopt

def loadCorpus(data_folder):
    # define columns
    columns = {0: "text", 1: "ner"}

    # init a corpus using column format, data folder and the names of the train, dev and test files
    corpus: Corpus = ColumnCorpus(
        data_folder,
        columns,
        train_file="train.tsv",
        test_file="test.tsv",
        dev_file="devel.tsv",
    )
    return corpus

# 1回目の学習

datapath = "/root/data/input/my-ner-data/"

# 1. get the corpus
corpus: Corpus = loadCorpus(datapath)
print(corpus)

# 2. what tag do we want to predict?
tag_type = "ner"

# 3. make the tag dictionary from the corpus
tag_dictionary = corpus.make_tag_dictionary(tag_type=tag_type)
print(tag_dictionary.idx2item)

# 4. initialize embeddings
embedding_objects: List[TokenEmbeddings] = []

embedding_objects.append(CharacterEmbeddings())
    
embeddings: StackedEmbeddings = StackedEmbeddings(embeddings=embedding_objects)

# 5. initialize sequence tagger
tagger: SequenceTagger = SequenceTagger(
    hidden_size=256,
    embeddings=embeddings,
    tag_dictionary=tag_dictionary,
    tag_type=tag_type,
    use_crf=True,
)

# 6. initialize trainer
from flair.trainers import ModelTrainer

resultpath = "/root/output/flair_test"

trainer: ModelTrainer = ModelTrainer(tagger, corpus)

# 7. start training
resultpath = Path(resultpath) / "tagger_results" / "char"
trainer.train(
    str(resultpath),
    learning_rate=0.1,
    mini_batch_size=32,
    max_epochs=5,
    patience=5 
)

# 2回目の学習

best_model = "/root/output/flair_test/tagger_results/char/best-model.pt"

# 1. get the corpus
corpus: Corpus = loadCorpus(datapath)
print(corpus)

# 2. what tag do we want to predict?
tag_type = "ner"

# 3. make the tag dictionary from the corpus
tag_dictionary = corpus.make_tag_dictionary(tag_type=tag_type)
print(tag_dictionary.idx2item)

# 4. initialize embeddings
embedding_objects: List[TokenEmbeddings] = []

embedding_objects.append(CharacterEmbeddings())
    
embeddings: StackedEmbeddings = StackedEmbeddings(embeddings=embedding_objects)

# 5. initialize sequence tagger
# tagger: SequenceTagger = SequenceTagger(
#     hidden_size=256,
#     embeddings=embeddings,
#     tag_dictionary=tag_dictionary,
#     tag_type=tag_type,
#     use_crf=True,
# )
    

# 2回目のtaggerは,SequenceTagger.loadで読み込んだモデルを使う.
tagger = SequenceTagger.load(best_model)

# 6. initialize trainer
from flair.trainers import ModelTrainer

resultpath = "/root/output/flair_test"

trainer: ModelTrainer = ModelTrainer(tagger, corpus)

# 7. start training
resultpath = Path(resultpath) / "tagger_results" / "char"
trainer.train(
    str(resultpath),
    learning_rate=0.1,
    mini_batch_size=32,
    max_epochs=5,
    patience=5 
)

f-stringを使ってスマートにパスを生成する[Python]

Python3.6から使えるようになったf-stringを使って,スマートにパスを生成しよう.

かっこ悪いパスの生成

from datetime import datetime

now = datetime.now().strftime("%Y%m%d%H%M%S")

dst = "/root/output/" + now + "_result/hoge.txt"
print(dst)

>> /root/output/20190910091617_result/hoge.txt

変数nowの周囲に+や余計な括弧"が混入しているため,生成されるパス名が把握しづらい.

スマートなパスの生成

from datetime import datetime

now = datetime.now().strftime("%Y%m%d%H%M%S")

dst = f"/root/output/{now}_result/hoge.txt"
print(dst)

>> /root/output/20190910091749_result/hoge.txt

f-stringを使って文字列内に変数を埋め込んでパスを生成.

パスが一続きの文字列として記述されているため,生成されるパス名が把握しやすい.

さらにスマートなパスの生成

from pathlib import Path
from datetime import datetime

now = datetime.now().strftime("%Y%m%d%H%M%S")
outdir = f"/root/output/{now}_result"
fname = "hoge.txt"

dst = Path(outdir) / fname
print(dst)

>> /root/output/20190910093057_result/hoge.txt

Pathを使って,出力先フォルダPath(outdir)と出力ファイル名fnameを連結した.

パス生成の際,出力先フォルダと出力ファイル名の間に/があるため,フォルダ名とファイル名の区別がつき,わかりやすいと思う.

pipでパッケージの最新版をインストールする[git]

git hub の最新版のコードを使いたいときのコマンド.

以下に,NLPライブラリFlairの最新版をインストールするときのコマンドを示す.

インストール前にflairがあっても,最新版に更新してくれる.

ただし,最新版は,バグやら不具合が多くて不安定なので,特に必要性が無い時には安定版を使うのが吉.

pip install git+https://github.com/zalandoresearch/flair.git

容量が一杯になってしまった時にでるエラー[AWS][EC2]

apt update を実行して以下のエラー

こんな時は,df -h で容量を調べてみよう.きっとディスクがパンパンになっているはずだ.

  Error writing to output file - write (28: No space left on device) Error writing to file - write (28: No space left on device) [IP:  80]
Get:13 http://archive.ubuntu.com/ubuntu xenial-updates Release [108 kB]
Err:13 http://archive.ubuntu.com/ubuntu xenial-updates Release
  Error writing to output file - write (28: No space left on device) Error writing to file - write (28: No space left on device) [IP:  80]
Get:14 http://archive.ubuntu.com/ubuntu xenial-backports Release [106 kB]
Err:14 http://archive.ubuntu.com/ubuntu xenial-backports Release
  Error writing to output file - write (28: No space left on device) Error writing to file - write (28: No space left on device) [IP:  80]
Reading package lists... Done
E: The repository 'http://ppa.launchpad.net/jonathonf/python-3.6/ubuntu xenial Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://security.ubuntu.com/ubuntu xenial-security Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64  Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64  Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://archive.ubuntu.com/ubuntu xenial Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://archive.ubuntu.com/ubuntu xenial-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: The repository 'http://archive.ubuntu.com/ubuntu xenial-backports Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

\cite, \citet, \citepの違いは?[Latex]

\citetと\citepでは,括弧の位置が異なる.

*を付けるとet al.で省略しない.

\citeと\citet, \citepの使い分けはまだわからない.

\citet{jon90}    --> Jones et al. (1990)
\citep{jon90}   --> (Jones et al., 1990)
\citet*{jon90}  --> Jones, Baker, and Williams (1990)
\citep*{jon90}  --> (Jones, Baker, and Williams, 1990)

\citetは一続きの文で著者名を出しながら引用するときに使うのかな.

The system is proposed by \citet{jon90} in this field.

↓

The system is proposed by Jones et al. (1990) in this field.

\citepは通常の引用の時に使うんだと思う.

In the field of biomedical, a NER corpus is available \citep{jon90}.

↓

In the field of biomedical, a NER corpus is available (Jones et al., 1990).

参考

https://www.reddit.com/r/LaTeX/comments/5g9kn1/whats_the_difference_between_cite_citep_and_citep/

章番号を参照した時に「1. 章」とドットが付く問題の解決法[Latex]

問題: \ref で参照すると不要なドットが付く

電◯情報通信学会の日本語原稿を執筆していると,章番号を\refで参照した際に,不要なドットがついてしまう.

\ref{sec:conclusion}章でまとめと今後の課題を述べる.

↓

6. 章でまとめと今後の課題を述べる.

ぐぬぬ「6章」と表示させたいのに変なドットが付いてしまう...

解決法:学会が提供するclsファイルを編集&プリアンブルを追加

まずは,学会が提供する ieicej.clsの2531行目辺りを以下のように編集する(該当部分は,Control+Fで"section"を検索して見つけても良い).

\setcounter{secnumdepth}{5}
\newcounter{section}
\newcounter{subsection}[section]
\newcounter{subsubsection}[subsection]
\newcounter{paragraph}[subsubsection]
\newcounter{subparagraph}[paragraph]
%\renewcommand{\thesection}{\@arabic\c@section.} # この行をコメントアウト
\renewcommand{\thesubsection}{\thesection.\,\@arabic\c@subsection} # \thesectionの横に "." を付ける.
\renewcommand{\thesubsubsection}{%
   \thesubsection.\,\@arabic\c@subsubsection}
\renewcommand{\theparagraph}{% (
 \@alph\c@paragraph\,)}
\renewcommand{\thesubparagraph}{% (
 \@roman\c@subparagraph\,)}

次に,main.tex(tecrep.tex)に

\usepackage{secdot}
\sectiondot{subsection}

を追加する.

以上で,ドットが付く問題が解決しているはずだ.

参考

tex 図番号,表番号の後ろに不要なピリオドが出力される - Qiita

https://oku.edu.mie-u.ac.jp/tex/mod/forum/discuss.php?d=1386

起動中のコンテナに別ターミナルからアクセス[Docker]

docker exec -it my-container /bin/bash

あるコンテナで学習を回すと,そのコンテナが結果出力で占有させてしまったので上のコマンドで, 2つ目のコンソールを立ちあげて,学習とLinuxの設定を同時に実施した.