AI_ML_DL’s diary

人工知能、機械学習、ディープラーニングの日記

Kaggle散歩(January 2021)

Kaggle散歩(January 2021)

1月7日に、Riiidコンペが終了する。:1月8日追記:Riiidコンペは393位だった。72時間くらいの間に100チームくらいに追い越された。これがKaggleだ!

その後は、

HuBMAP - Hacking the Kidney
Identify glomeruli in human kidney tissue images

を考えている。

このテーマから、Discussionとnotebookの全ての関連情報(引用文献、引用コードを含む)に目を通すことによって知識を増やし、研究者レベルのコード開発を目指していきたいと思っている。

1月は、前処理、モデル構築と訓練、予測とsubmissionデータの作成、の順にベースモデルを作成する予定である。

 

1月1日(金)

Riiid AIEd Challenge, 3,221 teams, 7 days to go

private LB scoreが見えてしまうというトラブルがあったようだ。

公平を期するために、各人の昨年のある時点までの投稿データのうち、private LBスコアが最も高いものについて、private LB scoreを見ることができるようになっている。

"To retrieve your team’s score as of 2020-12-29 16:00:48 UTC, please visit this link."

こういうことは、メールで参加者に伝えられるのではなく、Discussionをチェックして、自分で気づかないとわからない。

必要な情報は、コンペサイトの中(Discussion)で適切に表示されるので、参加者の責任で取得する、というのが、Kaggleのルールになっている。

 

1月2日(土)

Riiid AIEd Challenge, 3,238 teams, 6 days to go

featureの選択にしても、LGBMのチューニングにしても、もう限界のようだ。

それでもまだ終わっていないので、何か手段を講じてスコアを上げたいものだ。 

 

Discussion

Most Votesでsortして、順にみていこう。

最初はKaggleのstaffによるメッセージである。

SAINT+: A Transformer-based model for correctness prediction

SAINT+はRiiidの研究者によって開発されたtransformerベースのプログラムで、論文へのリンクが張られている。このコンペに参加した当初は自分で文献調査して同じ論文を見つけて、”しめしめ”と思ったのだが、その時すでにDiscussionでKaggleのスタッフから紹介されていたようである。

さらに、トピックには、コメント(Comments)がつく。Kagglerたちが、トピックオーサー(ここではKaggleスタッフの1人)に対して質問したり、関連情報を交換したり、Kagglerどうしで、当該トピックスに関連した議論をする。

GitHubにSAINTとSAKTのコード例が公開されているとか、コンペサイト内にそれらしいコードが公開されているとか、コードにデータを入力するためにfeatureをベクトル化する方法を聞くとか、transformerモデルのコーディングの基礎が紹介されているサイトを紹介する、などのやりとりがある。SAINTやSAKTなどのNNと、LGBMとの比較。データ量が多いので、データハンドリング方法の工夫が必要だとか。コーディングに長けた人が、テストデータに対するハンドリング方法のコード例を具体的に示すこともある。

次は、kaggle staffによる新規参加者に対するlectureや注意事項の説明である。内容は省略するが、Kaggle内における遵守事項は重要である。

次は、kaggle staffによる、private scoreの情報が漏れたことへの対応に関するものである。kaggle staffが熟慮して決められた方法を受け入れるべきだと思う。が、しかし、金メダルレベル、賞金レベルの人達にとっては、公開される情報の質と量は非常に重要であり、真に公平な解決方法はないのかもしれない。

あとは、kaggel staffによるwelcome message、 課題提供者の挨拶、kaggle staffによるチーム結成の案内などがある。

次から、参加者からのトピックスである。

最初は、投票数256(upvote)、コメントや返信が40件ほどある。2か月前の投稿で、課題解決の参考になる情報である。課題解決のヒントになる情報で、特に、上記のSAINTの情報を調べると、GBM系よりもNN系が良さそうに思うだろうが、LGBMモデルベースでpublic LB=0.789を得ている、と記されている。

こういう情報は、締切日が近くなると、公開することに問題があると考えられなくもないが(他にこの種の情報が公開されていない場合)、締め切りまでにまだ2か月あるので、多くの人に有用だと考えて公開することにした、と書かれている。これ以外にも非常に本質的で有用な情報が含まれていて、全体のレベルを上げるのに貢献している優れた内容の投稿だと思う。

いまごろ読んでも遅いのかもしれないが、理解が深まってきた今だからこそ理解できる内容もたくさんある。

これ以上は書いてもきりがないので、書かないが、チューニングの合間に読み進めていきたいと思う。

 

1月3日(日)

  • Riiid AIEd Challenge
  • , 3,258 teams
  • , 5 days to go

なかなかスコアが上がらず、順位が下がっていく。このままだと、あと2日くらいでメダル圏外に放り出されそうだ。

min_data_in_leaf、SAKTとLGBMの比率、などの最適値を探索中。

アンサンブルの比率について:公開コードで、0.771と0.772くらいのアンサンブルで0.782になるというのがあって驚いたが、1.4%程度の増大である。小さくはないが驚くほどでもない変化幅である。

 

HuBMAP:

締切が当初の2月初旬から3月下旬に変更された。

実質、今日から参加。

Your challenge is to detect functional tissue units (FTUs) across different tissue preparation pipelines. An FTU is defined as a “three-dimensional block of cells centered around a capillary, such that each cell in this block is within diffusion distance from any other cell in the same block” (de Bono, 2013). The goal of this competition is the implementation of a successful and robust glomeruli FTU detector.:Descriptionより

あなたの課題は、さまざまな組織準備パイプライン全体で機能組織ユニット(FTU)を検出することです。 FTUは、「毛細血管を中心とするセルの3次元ブロックであり、このブロック内の各セルが同じブロック内の他のセルから拡散距離内にある」と定義されています(de Bono、2013)。 この競争の目標は、成功した堅牢な糸球体FTU検出器の実装です。:グーグル翻訳

The focus of HuBMAP is understanding the intrinsic intra-, inter-, and extra- cellular biomolecular distribution in human tissue. HuBMAP will focus on fresh, fixed, or frozen healthy human tissue using in situ and dissociative techniques that have high-spatial resolution.

The HubMAP Data Portal aims to be an open map of the human body at the cellular level. These tools and maps are openly available, to accelerate understanding of the relationships between cell and tissue organization and function and human health.

HuBMAPの焦点は、ヒト組織における固有の細胞内、細胞間、および細胞外の生体分子分布を理解することです。 HuBMAPは、高い空間分解能を持つin situおよび解離技術を使用して、新鮮な、固定された、または凍結された健康なヒト組織に焦点を当てます。

HubMAPデータポータルは、細胞レベルでの人体のオープンマップを目指しています。 これらのツールとマップは公開されており、細胞と組織の組織と機能および人間の健康との関係の理解を促進します。:グーグル翻訳

 

1月4日(月)

Riiid AIEd Challenge, 3,285 teams, 4 days to go ,286th

順位の後退速度の速さには勝てないが、ほんの少し前進した(283th)。

しかし、22:30現在、290thまで下がった。

 

InnovationDigi(HuBMAP - Hacking the Kidney
Identify glomeruli in human kidney tissue images
), 766 teams, 3 months to go

課題提供者からのメッセージと情報:

We are very much looking forward to the innovative solutions teams will generate to identify glomeruli in images of human kidney tissue.

私たちは、人間の腎臓組織の画像から糸球体glomeruliを特定するためにチームが生成する革新的なソリューションを非常に楽しみにしています。

提供されるデータ:

The kidney images and their segmentation masks, both of anatomical structures and glomeruli, were generated by HuBMAP’s tissue mapping center at Vanderbilt University (TMC-VU) team at the BIOmolecular Multimodal Imaging Center (BIOMIC). The glomeruli masks were further improved to provide a "gold standard" by the Indiana University team through a combination of manual and machine learning efforts. Any annotations of glomeruli that were considered incorrect, ambiguous, or originating from damaged portions of the images were removed.

解剖学的構造と糸球体の両方の腎臓画像とそのセグメンテーションマスクは、BIOmolecule Multimodal Imaging Center(BIOMIC)のヴァンダービルト大学(TMC-VU)チームにあるHuBMAPの組織マッピングセンターによって生成されました。 糸球体マスクはさらに改良され、手動学習と機械学習の組み合わせを通じて、インディアナ大学チームによって「ゴールドスタンダード」を提供しました。 不正確、曖昧、または画像の損傷部分に由来すると見なされた糸球体の注釈はすべて削除されました。

先行研究:5件の論文が紹介されている。

f:id:AI_ML_DL:20210104111238p:plain

感想:目的物以外の検出、分野の固有評価方法の援用などが使えそう。解析ソフトは既製品で、GitHubにある。

"This Github page explains how to use the output of ilastik classification in segmentation .tiff files and obtain disease scores per glomeruli."「このGithubページでは、セグメンテーション.tiffファイルでilastik分類の出力を使用して、糸球体ごとの疾患スコアを取得する方法について説明します。グーグル翻訳」

この"ilastik classification"について調べてみた。

"Leverage machine learning algorithms to easily segment, classify, track and count your cells or other experimental data. Most operations are interactive, even on large datasets: you just draw the labels and immediately see the result. No machine learning expertise required."

機械学習アルゴリズムを活用して、細胞やその他の実験データを簡単にセグメント化、分類、追跡、カウントします。 大規模なデータセットであっても、ほとんどの操作はインタラクティブです。ラベルを描画するだけで、すぐに結果が表示されます。 機械学習の専門知識は必要ありません。グーグル翻訳」

既製品なので、コンペで使うものではない。

NotebooksとDiscussionにおいて"ilastik"で検索したが何も出てこない。

次は2つめの論文:

Glomerulus Classification and Detection Based on Convolutional Neural Networks
Jaime Gallego, Anibal Pedraza, Samuel Lopez, Georg Steiner, Lucia Gonzalez, Arvydas Laurinavicius and Gloria Bueno

In this paper we propose two methods devoted to: Glomerulus classification and Glomerulus detection. In the Glomerulus classification proposal (Method I), we study the viability of the CNN to achieve a correct Glomerulus classification into Glomerulus/non-Glomerulus classes. In the Glomerulus detection method (Method II), we use the CNN configuration that gave the best results and performance for Glomerulus classification (Method I) to achieve the Glomeruli detection in a WSI. In this proposal, we present a method suitable for PAS samples belonging to different laboratories, thanks to color normalization process used in the data augmentation step. Our method uses a sliding
window with overlapping to perform the detection, and utilizes a majority vote decision for each pixel to reduce false positive detections. With this proposal, we achieve a detection score of 93.7%, which improves upon the results obtained in reference methods.

「 この論文では、糸球体分類と糸球体検出の2つの方法を提案します。 糸球体分類提案(方法I)では、CNNの実行可能性を調査して、糸球体/非糸球体クラスへの正しい糸球体分類を実現します。 糸球体検出法(方法II)では、糸球体分類(方法I)で最高の結果とパフォーマンスを提供するCNN構成を使用して、WSI(Whole Slide Images)で糸球体検出を実現します。 この提案では、データ拡張ステップで使用される色の正規化プロセスのおかげで、さまざまな研究所に属するPAS(Periodic Acid Schiff)サンプルに適した方法を提示します。 私たちの方法は、オーバーラップのあるスライディングウィンドウを使用して検出を実行し、各ピクセルの多数決を利用して誤検出を減らします。 この提案により、93.7%の検出スコアを達成し、参照方法で得られた結果を改善します。グーグル翻訳」

論文はこのくらいにしておこう。自分が良い結果を得て論文にしようとするときには、先行研究を引用しながら自分の研究のどこが先行研究と異なっているかを説明するために用いる。今の自分のレベルと3月末の締め切り日を考えると、新しい評価方法を考案し良い結果を得て論文にまとめることになるとは考えにくい。

課題提供者からの情報のもっと重要な部分に移ろう。

(How to Convert Polygon Masks to Pixel Masks)と(How to Perform Run-Length Encoding)である。多角形で与えられたマスクをピクセルマスクに変換するコードと、検出領域を報告する書式の説明である。

データを眺めてみよう。

とりあえず、論文の画像。

f:id:AI_ML_DL:20210104235805p:plain

f:id:AI_ML_DL:20210104235936p:plain

f:id:AI_ML_DL:20210105000050p:plain

f:id:AI_ML_DL:20210105000152p:plain

f:id:AI_ML_DL:20210105000259p:plain

f:id:AI_ML_DL:20210105000353p:plain

f:id:AI_ML_DL:20210105000434p:plain

f:id:AI_ML_DL:20210105000525p:plain

f:id:AI_ML_DL:20210105000609p:plain

f:id:AI_ML_DL:20210105000709p:plain

f:id:AI_ML_DL:20210105000752p:plain

f:id:AI_ML_DL:20210105000959p:plain


f:id:AI_ML_DL:20210105000905p:plain

f:id:AI_ML_DL:20210105001129p:plain

f:id:AI_ML_DL:20210105001627p:plain

f:id:AI_ML_DL:20210105001736p:plain

以上は主催者がDiscussionで紹介されている5件の論文から転載したものである。

 

1月5日(火)

Riiid AIEd Challenge, 3,312 teams, 3 days to go:301th(9:12)

進展なし。

 

1月6日(水)

Riiid AIEd Challenge, 3,344 teams, 2 days to go:327th

チューニング中!

夜中に、メダル圏外に放出されました。

あと1日ある。さらに離されるか、それとも・・・。

 

HuBMAP, 783 teams, 3 months to go

ベースモデルを作成しようとしている。

edaとbaselineをキーワードに、公開コードから、自分でハンドリングできそうなコードを探しているのだが、なかなか見つけられない。

チューニングの立場から見ると、チューニングしやすいコードは、スコアに関係しているコードがどれであるか、がわかりやすく、理解しやすく、かつ、パラメータだけでなく、コードの変更も容易であるということになる。目の前のコードがどこまであてはまるかは、見る側のコード理解力、コード構成能力による。

いわゆるベースラインコードと呼ばれるものは、初級レベルの人にも理解しやすいということに加えて、前処理も、訓練/予測モデルも教科書的であり、必要最小限の機能をもつだけであることが多い。

ゼロから作るのは難しく、ベースラインとなるコードから始めるということであれば、これまでと同じように、チューニングしやすいコードを探すことから始めるのがよさそうであるということになる。

これまでと変えたいと思っているのは、フォークしたコードは、理解できる範囲でチューニングするのではなく、隅々まで理解して、あらゆる箇所に手を加えることができるようになることである。

1つのモデルを選定した。そのモデルの作成者は、機械学習ディープラーニングの中級であると自称している。Kaggleのcompetition, notebook, およびdiscussionのexpertである。

前処理が約110行、訓練が約30行、予測も約30行で、その他が約120行である。

順に理解していこう。

前処理は3種類あり、1つは、マスクの処理で、Run-Length Encodingに関する処理のための関数:rle_encode, rle_decodeなど、もう1つは、画像の分割、最後に、画像とマスクのデータセットの作成である。

 

1月7日(木)

 Riiid AIEd Challenge, 3,366 teams, a day to go:350th

メダル圏外に放出された。

完敗です。

チューニングメインの戦いはこれを最後にする。

最後にちょっと面白い現象を見ることができた。

フォークしたとき、feature_fractionの値は、0.52に設定されていた。意味が分からずそのまま使っていたが、12月29日に、先が見えなくなって、意味も分からず、0.75と0.25を試してみたら、0.25の場合にpublic LBが上がった。といっても数値は変わらず順位が少し上がっただけである。翌日、0.20を試してみたら、さらに、順位が少し上がった。それ以降0.2がベストだと思い込んでそのまま使っていた。今日、もうすることがなくなって、試しに、feature_fractionを外してみた(デフォルトは1.0)。そうすると、収束後のfeature_importanceの分布が0.2の場合とは全く違うものになった。0.2の場合は、40近くのfeatureを使っていても、ほぼ全てのfeatureがそれなりに寄与していたのだが、デフォルトの1.0では、20個を超えたくらいから寄与が非常に小さくなった。寄与率の減衰率が明らかに大きくなったのである。0.2に設定すると、ランダムに選ばれた2割のfeatureで最適化しようとするから、もともと重要でないfeatureでも無理に使われていたのかもしれない。さらに、0.2では、計算の都度、val_AUCがかなりばらついたし、feature_importanceもval_AUCと同様、計算するたびに、明らかに分布が異なっていたように思う。本質的ではないところで時間を無駄にしたような気がする。上位にいくためには、こんなチューニングよりは、アンサンブルの片割れのSAKTのチューニング、もしくは、SAKTのSAINTとの置き換えに時間を使ったほうが良かったのではないかと思う。

 

HuBMAP:796 teams, 3 months to go

Run-Length Encodingについては、コンペの課題提供グループから、説明図付きでコードが提供されている。

f:id:AI_ML_DL:20210105000905p:plain

これはglomerulusとマスクの画像の例である。このマスクは、glomerulusの領域を正しく表現しているのだろうか。

もっと詳細な評価をしている論文はないのか。

f:id:AI_ML_DL:20210107100256p:plain

この論文では、 glomerular lesions(糸球体の病変)まで検出している。

f:id:AI_ML_DL:20210107101640p:plain

The convolutional neural networks implemented in this paper consist of U-Net, DenseNet, LSTM-GCNet, and 2D V-Net. All of these architectures receive images
with labels, and output the corresponding predictions. UNet [33], consists of several contracting paths to capture context and symmetric expanding paths which enable
precise segmentation and location.

このホワイトペーパーで実装されている畳み込みニューラルネットワークは、U-Net、DenseNet、LSTM-GCNet、および2DV-Netで構成されています。 これらのアーキテクチャはすべて、ラベル付きの画像を受け取り、対応する予測を出力します。 UNet [33]は、コンテキストをキャプチャするためのいくつかの縮小パスと、正確なセグメンテーションとロケーションを可能にする対称的な拡張パスで構成されています。(グーグル翻訳)

画像解析には、U-Net、DenseNet、LSTM-GCNet、および2DV-Netを用いていると書かれており、最初の段階である糸球体の検出とセグメンテーションには、U-Netが用いられている。

もう1つの論文を見よう。

f:id:AI_ML_DL:20210107112013p:plain

この論文の解析対象は、糸球体の内部に存在するスパイク状の構造である。

f:id:AI_ML_DL:20210107112139p:plain

f:id:AI_ML_DL:20210107112535p:plain

U-Netでセグメンテーションを行い、その内部にあるスパイク構造をResNetで検出・分類している。コンペの課題は、この図では、前処理段階に相当する。

セグメンテーションの正確さが問われているが、正確さの評価は Dice coefficient、
f:id:AI_ML_DL:20210107114325p:plain

すなわち、正しいマスクと予測したマスクとの重なり度合いで評価される。

train_dataのマスクと、test_dataのマスクのグレードは同じであると仮定すると、train_dataのマスクを用いて訓練するのが最良だと思うが、どうなんだろう。

Run-Length Encodingについて考えているうちに、検出しようとしている糸球体の形状の詳細と対応するマスクの形状との関係が気になって、以上の論文を調べてみた。

コンペの画像とマスクの位置関係を見ていると、マスクは糸球体そのものだけでなく、糸球体を覆っている境界層、および境界層と糸球体の隙間も含んでいるように見える。

ウイキペディアの模式図はつぎのように描かれている。

f:id:AI_ML_DL:20210107090551p:plain

Bowman's capsuleは、自分が見た範囲(上記論文およびコンペの画像数枚)では、この模式図ほどは厚くないようであるが、コンペのマスクが、総じてこのカプセルを含んでいるように見える。マスクは提供されたまま使うべきかどうか。マスクのサイズや形状を変えたらどうなるのか気になるので、変えられるようにしよう。

*1月8日追記:2か月前にマスクの正確さについてユーザーから問題提起され、スタッフが対応したことがdiscussionに残されている。その後、private_test_dataにおいても不具合が見つかり、その対応のために、コンペ期間が3月下旬まで延長されることになったということのようである。

主催者が用意している情報をもう一度最初からチェックする。

discussionのタイトル:Welcome to the HuBMAP: Hacking the Kidney Competition!

最初のnotebookのタイトル:Dataset Details

Normal glomeruli typically range from 100-350 μm in diameter with a roughly spherical shape (Kannan, 2019)30155-X/abstract). 

f:id:AI_ML_DL:20210107135300p:plain

図3は、PASで染色されたヒト腎臓組織のサブセクションからの糸球体を含む光学顕微鏡画像です。 細胞の遺伝物質(核酸で構成される染色体)を含む、細胞ごとに1つの核(球形)は、PAS染色画像で濃い青紫色に染色されます。 PAS染色組織のマゼンタ染色領域は、染色された多糖類です。グーグル翻訳

f:id:AI_ML_DL:20210107150934p:plain

Figure 3: Glomerulus within PAS Stain Kidney Image

次は、Polygon to Pixel Mask Conversionのnotebookから学ぼう。

学ぶだけでは前進できない。

さあ、新しく、自分のnotebookを立ち上げよう。
 

1月8日(金)

  • Riiid AIEd Challenge
  • 3,399 teams, 
  • 2 hours to go:393th 

結果:目標としていた銀メダル以上に届かなかった。

成果:LightGBMに対する理解が増した。

反省:

1.feature engineeringの技術習得が進まなかった。

2.AI Educationへの興味が続かず、当該分野の本質を理解できなかった。(プログラミングやチューニングは手段であり、メダル取得、賞金取得などは目標ではあっても目的ではない。目的はAIの技術開発に寄与することであり、それを実現するためには、コンペの課題をもっと深く理解し、AIをどう使えばこれまでと違うレベルのことができるようになるのかを考え続ける状態を維持しなければならなかったと思う。目標に集中するあまり、目的を見失っていたということになる。当該コンペの開催期間中は当該コンペの課題に集中しなければ何も得られずにおわってしまうということ。期間が短いので、より集中力を高めて取り組まないと身に付かないのだろうと思う。)

3.Riiidコンペが終了する前に次のコンペに取り掛かったのはまずかった。1月3日、Riiidのドラフト計算とcommitの待ち時間に、次のコンペをどれにしようかと考え、on goingのコンペを調べているうちに、HuBMAPに入り込み、お手本になりそうなコードをフォークしてsubmitまでしてしまった。Riiidモデルの見直しやfeature選択の見直しなどやるべきことがあったはずなのに、メダル圏内残留を諦めたようになってしまった。コンペの最後の3日間に集中できなかったことは、反省、反省、反省。

感想:

ちょっと調べたら、すでに商品化されていること、商品化のベースとなっていると推測されるレベルの高い予測モデルが論文発表されていることなどがわかった。それにもかかわらず賞金までつけてKaggleに課題を出したということは、トップレベルのKagglerへの挑戦(状)であって、自分の出る幕ではないと感じた。だからこそ自分の取り組み方を変えなければと思いながら取り組み始めたが、公開コードのチューニングから抜け出せず、途中であきらめようとしたが、それでも何かを学ばねばという思いで取り組んでいた。しかしながら、結局は、チューニングのどつぼにはまってしまったということだ。また、終盤に集中を切らした理由の1つは、銀のレベルまで上がる可能性がなくなったことである。次のレベルに上がるには銀以上が必要だから。

 

HuBMAP:805 teams, 3 months to go:624th(仮)

notebookの立ち上げ:今日は枠組みを作ろう。

1.notebookのタイトル

・公開コードからキーワードを拾ってみると、(PyTorch or Fastai or Keras or TF)、(EffUNet or ResUNet or PraNet or RetinaNet or FPN or Double UNet or ...)、(GPU or TPU)、・・・

2.構成:概要説明、import、configuration、前処理(preprocess)、augmentation(PyTorch :albumentations) 、モデル(model)、訓練(train)、予測(inference)、TTA、後処理(postprocess)、submitファイルの作成など。

・公開コードから、どのようにパーツを配置しているのかを学ぼう。

・1つ1つのセルに、どれだけのコードを入れるのか。1セル、1機能とか。

・注釈は、どの位置に、どのように入れるのか。マークダウンセルを使う。コードセルの先頭に書く。クラスや関数の直前に書く。

・わかりやすいコードの書き方、改造しやすいコードの書き方。

 

1月11日(月)

HuBMAP

さあ、自分のnotebookを作ろう。

HuBMAPのコンペサイトで、New Notebookをクリックし、Notebookを選択し、Createをクリックすると、notebookが立ち上がる。

notebookのタイトルは、"notebook84f8ff2dab"のように、自動的に割り当てられる。そのタイトルのまま使うのは不便なので、コードの内容を表すタイトルに変更する。

*notebookのタイトル変更:仮に、"HuBMAP TF/Keras UNet"としておこう。

notebookには、コンペのDatasetがデフォルトで付属する。

Notebookを説明しているセルが1つデフォルトで付属する。

そのセルは、実行すると、pandasとnumpyとosをimportし、Datasetのディレクト名やファイル名を表示する。ファイル名の拡張子は、csvの他に、tiffjsonがある。

 

1月12日(火)

HuBMAP:839 teams, 2 months to go

自分のnotebookを作ろうとしている。

そのnotebookのタイトルを仮に"HuBMAP TF/Keras UNet"としたのは、HuBMAPのコンペで、プログラムをTF/Kerasで記述し、UNetを使って、glomeruli FTU(functional tissue units )を検出しようと考えている、ということである。

notebookを立ち上げた時にデフォルトで付いていたセルはそのまま使う。これを1番目のセルとする。1番目のセルは手を加えずにそのまま使うことにする。

2番目のセルをどうしようか迷っている。よくあるパターンは、モジュールとかパッケージをimportすることである。

プログラムを作る順番を、迷う必要はない。セルの追加・削除、順番の入れ替えなどは、いつでも、容易にできるので、1セル1機能の考え方で、とにかく必要なセルを作っていこう。

ようやく、train.csvを読み込んでtableを表示した。8つの画像のidとマスクの位置情報(RLE encoded segmentation masks)が含まれている。

まずは、画像とマスクを表示してみよう。

画像を読み込んで表示してみた。ファイルサイズが大きいので、適切なタイミングで消去しなければ、メモリーオーバーになって、プログラムは途中で停止してしまう。

 

1月13日(水)

HuBMAP:849 teams, 2 months to go (Mar 26)

今日は、マスクデータの操作方法を学ぶ。

Paulo Pinto氏により公開された、Severstal: Steel Defect Detectionのコンペにおける"mask2rle"と"rle2mask"のコードが、このコンペの公開コードで引用されている。

"mask2rle"のコードは、実質6行、"rle2mask"のコードは、実質9行である。

rle2maskには、shape=(1600, 256)というように画像サイズが指定されていて、違和感を感じたが、これは、Severstal: Steel Defect Detectionコンペのsteel試験片の画像サイズに対応しているので、目的とする画像サイズに合わせればよいということがわかる。

理解しておくべき主なキーワードは、"T", "flatten", "concatenate", "where", "join", "split"である。 

Notebooks Grandmasterのiafoss氏も同様なコードを使っており、扱いにくい大きな画像を短冊状に切り出して使いやすくした画像のデータセットを公開されているので、iafoss氏のコードも見ておく。iafoss氏の関数のネーミングは、"mask2enc" と "enc2mask" となっている。

この2つの関数 "mask2enc"  と "enc2mask" を使うことにして、先へ進む。

 

1月14日(木)

HuBMAP

いろいろなコードを見ていると、目移りして、現在位置がわからなくなった。

自分のnotebookは、1週間経っても、まだ、"train/0486052bb.tiff"を表示しただけである。

1月6日に、trainとinferenceを含む公開コードの1つを選んで、それに倣って、自前のコードを構築するつもりだったが、2,3日の中断の間にそのことから離れてしまっていた。その公開コードにもどろう。

そのコードは、train+inferenceであり、submitしてpubliv LBも得られているので、学ぶには適切だと思ったが、入力データが3つあって(input(3))、PreTrain coco weightsと、PyTorch pretrained modelsが含まれている。こういうデータセットは有用だが、最初からこれを使ってしまうと、それに縛られて次の展開が難しくなるかもしれないので、入力データが、コンペのデータセットのみ(input(1))のコードを探した。そうすると、version1がそれに該当し、かつ、そのコードは公開コードのコピーではないことがわかったので、version1をお手本にして次に進もう。

version1はtrainまでだが、そのtrainの結果を見ると、1エポックに約40分かかっており、かつ、train BCEは順調に下がっているが、valid BCEは1度下がっただけで反転、すなわち3エポック目でoverfittingになっている。

モデルは、torchvision.models.segmentation.fcn_resnet50(True)を使っている。

PyTorchのドキュメンテーションを見ると、Semantic Segmentationとして、FCN ResNetとDeepLabV3 ResNetの2種類がある。

notebookのタイトルからは、EffUNet, ResUNet, PraNet, RetinaNet, FPN, Double UNet, Unet++などのモデルが使われていることがわかった。

それぞれの特徴を調べてみようと思って文献を検索してみた。特徴を調べると書いたが、本音は、糸球体の領域を正しく検出できるモデルはどれかを知りたいということである。しかし、糸球体をDNNで調べる最終的な目的は、糸球体の病態を調べることにあるからだろうと思うのだが、今回のコンペのように糸球体の領域をいかに正確に切り出すことができるか、ということについて、種々のモデルを比較した論文は見つけられなかった。自分でやってみて論文にまとめると面白いかもしれない。しかしながら、本当に重要なのはこれまでのどのモデルよりも正確に評価するモデルを構築することだ。

input(1)にこだわっていたが、このコードの作者は、version4(input(3))において、学習済みモデルを使用するなどの対策を講じることによって、train時間を短縮し、val_lossを低減することに成功し、かつsubmissionファイルも完成させているので、このversion4の理解を次の目標にする。

version4のセルの総数は20。セル1からセル5までは準備。

セル6は、rle_encode, rle_decode, make_grid(画像の分割)。

セル7は、全く理解できない。セル8は、・・・。セル9は画像とマスクのペアを描画して確認。

セル10とセル11は、train_dataとval_dataへの分割か?

セル12からセル17までは、get_modelからtrainまで。セル18で不要なデータを消去。

セル19は、test_dataの処理と予測とsubmissionデータの作成。

セル20は、submissionファイルの作成。

 

1月15日(金)

HuBMAP:

セル単位で理解しながら、1語づつ、1行づつ、丁寧に転記していこうと思ったが、理解が追い付かず、思うように進まないので、夕方になって、version 4の20のセルの全てをコピペした。

これをRunしたら、これまでのチューニングと、ほぼ同じことになる。

学びやすいコードを選んだ結果、PyTorchを使うことになった。notebookの名前は、TF/Keras UNetとしていたが、中身は、現時点では、PyTorch FCN ResNet50である。

FCN ResNet101、DeepLabV3 ResNet50、DeepLabV3 ResNet101などを使ってみることについては、比較的容易にできそうである。

この中では、DeepLabV3 ResNet101が最も性能が高そうだが、Kaggle kernelで動かせるかどうかわからないが、やってみればわかること。

それよりも、EfficientNetとUNetの組み合わせが良さそうなので、UNet with EfficientNet Encoderモデルを調査しよう。

 

 1月16日(土)

HuBMAP

UNet with EfficientNet Encoderを論文を見ながら組み上げる力はないので、コードを探してみる。

最初に探すべき場所は、GitHubであろう。

efficientnet unetで検索すると14件のrepositoryが出てきた。

segmentation modelを包括的に扱っているrepositoryでは、Unet, Linknet, FPN(Feature Pyramid Network), PSPNet(Pyramid Scene Parsing Network)の4種類のモデルと、VGGからEfficientNetまで10種類(サイズまでカウントすれば32種類)のbackboneの組み合わせが紹介されている。

当該コンペ内で、Unetがどのように使われているかを調べてみると、ほぼ、上記のGitHubサイトからの引用であることがわかった。

ということで、明日は、すでに誰かが作成しているデータセットがあればそれを使うこととし、もし、便利に使えるデータセットがなければ、自分でデータセットを作ってみようと思う。

最初は、網羅的なことは考えず、EfficientNetをbackboneとするUnetを、intenet offで使えるようにする。 

 

1月17日(日)

HuBMAP

インターネットに接続しておけば、次のコードで簡単にインストールできるのだが、

!pip install git+https://github.com/qubvel/segmentation_models.pytorch

これをデータセットにして、インプットデータに加えて、次のコードでインストールしようとしたが、うまくいかなかった。

!pip install ../input/qubvelsegmentationmodelspytorch -f ./ --no-index

"qubvelsegmentationmodelspytorch"は、作成したデータセットのファイル名である。

次のようなメッセージが現れて停止する。

Looking in links: ./
Processing /kaggle/input/qubvelsegmentationmodelspytorch
Requirement already satisfied: torchvision>=0.3.0 in /opt/conda/lib/python3.7/site-packages (from segmentation-models-pytorch==0.1.3) (0.8.1)
ERROR: Could not find a version that satisfies the requirement pretrainedmodels==0.7.4 (from segmentation-models-pytorch)
ERROR: No matching distribution found for pretrainedmodels==0.7.

requirements.txt は、以下の内容である。

torchvision>=0.3.0
pretrainedmodels==0.7.4
efficientnet-pytorch==0.6.3
timm==0.3.2

これらのモジュール/パッケージがインストール済みであることが前提になっているのだろう。ということだとすると、Kaggle kernelの中を把握し、それを適切にコントロールできることが必要なのだろう。 

 

1月18日(月)

HuBMAP

GitHubにあるsegmentation modelをHuBMAP用のnotebookで使えるようにするために、今日は、Kaggle の notebook について学ぼう。

 

***急用が入ったので中断 ***

 

1月20日(水)

HuBMAP: 

1月18日に調べていたnotebookのDockerについて、作業を進めよう。

KaggleのNotebookのサイトのトップページに移動する。

Notebooks
Explore and run data science and machine learning notebooks. Learn More.

トップページにある、このLearn More.をクリックすると、次のサイトに移動する。

How to Use Kaggle
Help and Documentation

ここから、Notebooks/The notebook Environment/modifying a Notebook-specific Environmentと辿れば、notebookのDockerの使い方がわかる。

自分が今使っているnotebookのセルにおいて、!pip install my-new-package(!pip install pretrainedmodels==0.7.4)を実行すれば、notebookのDocker containerに、モジュールやパッケージを、インストールすることができる。

既に存在するパッケージのバージョンを変更したい場合は、!pip install my-existing-package==X.Y.Zとすればよい。

ということで、次の3つをインストールした。

!pip install pretrainedmodels==0.7.4
!pip install efficientnet-pytorch==0.6.3
!pip install timm==0.3.2

この3つを、今使っているnotebookにインストールしておけば、インターネットを閉じて、notebookにinput dataとしてアップロードしたdatasetに格納したPyTorchのsegmentation modelsをインストールすることができることを確認した。

これで、課題を1つクリヤすることができた。

インストールしたモジュールやパッケージがnotebookのDockerに格納されているかどうかは、notebookのセルで、!pip listを実行すれば、確認することができる。

このDockerの状態が、notebookに対して別の作業をしたときにも保持されているかどうかは、まだわからない。

明日から、segmentation modelsに入っていて、notebookのDockerに格納されたであろうパッケージ内にあるモデルを読み込んで、現状のモデル "Pytorch FCN-Resnet50"と置き換えることに挑戦する。

最初に、EfficientNet-Unetを使えるようにする。

 

1月21日(木)

notebookのDockerへのパッケージの追加はうまくいったと思ったが、Run allを実行すると、追加したパッケージは削除されていた。

特定のnotebookに特定のDockerを付属させることができるようだが、再スタートするとインストールされたはずのパッケージが消えている。

Kaggleの説明文:

Modifying a Notebook-specific Environment
It is also possible to modify the Docker container associated with the current Notebook image.

Using a standard package installer
In the Notebook Editor, make sure "Internet" is enabled in the Settings pane (it will be by default if it's a new notebook).

For Python, you can run arbitrary shell commands by prepending ! to a code cell. For instance, to install a new package using pip, run !pip install my-new-package. You can also upgrade or downgrade an existing package by running !pip install my-existing-package==X.Y.Z.

!pip installを実行すれば、確かに、新たにDocker containerに、インストールしたことを!pip listによって、確認することができる。

Restart sessionで、元の木阿弥になる、インストールしたパッケージが消えてしまうのだ。

変更したDocker imageを使うのだから、Environment Preferenceの、Pin to original environmentではなく、Always use latest environmentを選んでいる。

インターネットOnで、パッケージをインストールした後、インターネットOffにして、ドラフトを走らせれば良いのではないかと思うのだが、うまくいってない。timmとかefficientnet-pytorchなども、datasetに入れて、inputdataとして読み込んでインストールできれば良いのだが、できないだろうか。

 

HuBMAP:892 teams, 2 months to go : 698th(0.827)

FCN-Resnet50のかわりに、とりあえず、DeepLabV3 Resnet50を使おうとしたら、エラーが出てしまった。うまくいかないものだ。まだ、コードの理解が足らないのだろう。torchvisionに入っているのだから、簡単だろうと思ったのだが、うまくいかない。

 

1月22日(金)

HuBMAP

Dockerにパッケージを追加してからinternet offにしてRun allにすれば計算は可能で、submitも可能(エラーは出ない)であることを確認した。

しかし、commitの結果を見ると、プログラムの最初に実行した!pip listによって、ドラフト計算中に存在していたはずのパッケージが消失していることが分かった。

internet offの条件付きのコードコンペでは、追加したいモジュール/パッケージは、全て、Datasetからインストールするしかなさそうだ。

 

よくわからなかったが、いろいろやってみて、なんとかできるようになった。

*必要なもの(pretrainedmodels==0.7.4、efficientnet-pytorch==0.6.3、timm==0.3.2)は、Datasetにして、Datasetからインストールすることができるようになった)

Datasetの作り方:

・pretrainedmodels==0.7.4をインストールするためのDataset:

Googleで検索し、ダウンロードサイトhttps://pypi.org/project/pretrainedmodels/ に行って、ファイルをダウンロードし、Kaggle のDatasetサイトの、+ New Datasetをクリックし、ダウンロードしたファイルを、フォルダーごと、Drag and drop files to uploadのスペースに移動する。データセットに名前を付けて、Createボタンをクリックすれば出来上がり。Createボタンの横にあるボタンで、PrivateかPublicかを選んでおく。

・efficientnet-pytorch==0.6.3をインストールするためのDataset:

同様にして、https://pypi.org/project/efficientnet-pytorch/ このサイトからダウンロードした。ただし、バージョンがefficientnet-pytorch 0.7.0となっていたので、Project descriptionボタンの下の、Release historyをクリックして、0.6.3を選んでダウンロードした。以下同じ。

・timm==0.3.2をインストールするためのDataset:

同様にして、https://pypi.org/project/timm/0.3.2/ このサイトからダウンロードして、同様の操作をしたが、圧縮ファイルであったためか、作成したDatasetでは、installできなかった。エラーメッセージに、setup.pyが見つからないと表示されていた。確かに、フォルダーの中を見ても、そのようなファイルが見当たらない。結局、7-zipで解凍し、setup.pyを確認してから、Datasetを作成した。

*これで、Segmentation-models-pytorch 0.1.3 を使う準備ができた。

明日は、FCN-Resnet50が使っているpretrain-coco-weights-pytorchとpytorch-pretrained-modelsの2つのDatasetがどのように使われているのかを確かめるとともに、新たなDataset:segmentation-models-pytorch013の使い方を検討する。

 

1月23日(土)

HuBMAP:896 teams, 2 months to go:

FCN-Resnet50をdeeplabv3-Resnet50に変更した。

オリジナルコードのinput Datasetに必要なデータが入っていたのでモデル名を書き換えただけで動くと思ったが、エラーが出た。データサイズが違うからダメとのこと。

model.classifier[4]とmodel.aux_classifier[4]の意味が分からずググると、GitHubでabeja-incが公開しているコードplatform-feature-image-segmentationのtrain.pyの中で使われていて、FCN-とdeeplabv3ではコードが少し異なっていて、if文で分けている。それに倣ってコードを変更することによりdeeplabv3-が使えるようになった。しかし、計算時間は3割増し、Lossの初期値は4割増しとなり、途中までは期待外れ。エポック数を増やしてみてどうなるか、調べてみる。

3エポックでは、deeplabv3の方がval_lossがかなり大きいにもかかわらずLBは同レベルだった。deeplabv3を7エポックまで増やしてcommit, submitした結果、overfittingのためLBは14/1000悪化した。FCNとの比較ではdeeplabv3が少しよさそうな感触だが、これ以上は追及しない。 

 

segmentation_models_pytorch 0.1.3:

各モデルのweightは、外部から読み込むようになっているので、internet offでは、

URLError: <urlopen error [Errno -3] Temporary failure in name resolution>

このようにエラーとなる。

ということで、Datasetを作った。といっても新たに作ったのはなく、Datasetのコピーである。元のdatasetのネーミングがわかりにくかったので、わかりやすいものにした。

internet経由でのweightの読み込みは、こんなふうになっている。

Downloading: "https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth" to /root/.cache/torch/hub/checkpoints/efficientnet-b5-b6417697.pth

Dataset(名前は、pytorch_efficientnet_pretrained_models)から読み込んだweightのデータは、同じ場所に置くことになる。そのためのコードは、勉強中のコードを参考にすると、次のようになる。(最初にこのコードを見たときは全く理解できなかった)

!mkdir -p /root/.cache/torch/hub/checkpoints/

!cp ../input/pytorch_efficientnet_pretrained_models

/efficientnet-b5-b6417697.pth /root/.cache/torch/hub/checkpoints/ 

ようやく、internet offで、efficientnetB5-Unetのモデルができた。

モデルのコードのほんの1部分を表示する。(注) インデントは表示できない。

最初の6行:effitientnetB5ベースのエンコーダ:

Unet(
(encoder): EfficientNetEncoder(
(_conv_stem): Conv2dStaticSamePadding(
3, 48, kernel_size=(3, 3), stride=(2, 2), bias=False
(static_padding): ZeroPad2d(padding=(0, 1, 0, 1), value=0.0)
)

おそらく、デコーダーの開始:

(decoder): UnetDecoder(
(center): Identity()
(blocks): ModuleList(
(0): DecoderBlock(
(conv1): Conv2dReLU(
(0): Conv2d(688, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
デコーダのブロックが0から4まで続き、最後はセグメンテーションブロック:
(segmentation_head): SegmentationHead(
(0): Conv2d(16, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): Identity()
(2): Activation(
(activation): Identity() ) ) )

次は、このefficientnetB5-Unetで解析する方法を検討しよう。

コードを作るにも、バグ出しするにも、時間がかかるだろうから、まずは、B5よりも倍以上計算速度が速い、efficientnetB0-Unetで検討することにしよう。

関係ありそうなコード

model = smp.Unet('efficientnet-b0', classes=1, aux_params=aux_params)

試しに走らせてみたらエラーになった箇所

output = model(image)['out']:TypeError: new(): invalid data type 'str'

 

1月24日(日)

HuBMAP

PyTorchでEfficientnet-Unetを用いたコードを調べた。

output = model(image)['out']ではなく、output = model(image)となっていたので、['out']を削除した。

その結果、trainまでエラーなく動き、lossも減少している。

efficientnetB0からB3にすると、B0では、train_lossとval_lossの反転が3エポック目で生じたが、B3では、5エポックでも反転しなかった。B5では、GPUのメモリーオーバーとなって計算できなかった。

順調かと思いきや、trainまでは動いたが、inferenceの次の行でエラーが発生した。

score = model(image.to(DEVICE)[None])['out'][0][0]

上記と同様に対処すればよいのだろうが、どこまで削除したらよいのだろう。

score = model(image.to(DEVICE)):これで動けばよいのだが。

動作確認中に、failed to fetchと表示されて計算停止。再度Run。

RuntimeError: Expected 4-dimensional input for 4-dimensional weight [40, 3, 3, 3], but got 3-dimensional input of size [3, 257, 257] instead

trainのときの対応と同じく、['out']のみ除去する、ということでエラーは回避できた。

 

1月25日(月)

HuBMAP

efficientnetB3-Unetの5エポックで、LB=0.740:849th相当/905 teams

3エポックでは、LB=0.280となり、心配だったが、うまく計算できているようだ。

6エポックでは、LB=0.777となった。

他の条件は全く同じで、FCN-Resnet50の場合には、3エポックでLB=0.798であった。ちょっと計算してみた、というだけでは、各モデルを正しく評価できていないかもしれない。

 

U-Netの調査

Review: U-Net (Biomedical Image Segmentation)
Sik-Ho Tsang, Nov 5, 2018·5 min read

 

f:id:AI_ML_DL:20210125112851p:plain

 

f:id:AI_ML_DL:20210125112937p:plain

 Since unpadded convolution is used, output size is smaller than input size. Instead of downsizing before network and upsampling after network, overlap tile strategy is used. Thereby, the whole image is predicted part by part as in the figure above. The yellow area in the image is predicted using the blue area. At the image boundary, image is extrapolated by mirroring.

 

f:id:AI_ML_DL:20210125113558p:plain

 Since the training set can only be annotated by experts, the training set is small. To increase the size of training set, data augmentation is done by randomly deformed the input image and output segmentation map.

GitHub:qubvel/segmentation_models.pytorch:に含まれているモデルは、9種類ある。HuBMAPの課題に対して、どれが最適かは、実際に適用しなければわからない。

Unet,  Unet++, MAnet, Linknet, FPN, PSPNet, PAN, DeepLabV3, DeepLabV3+

これらのモデルの文献を調べると、Unetが2015年、PSPNetが2016年、LinknetとDeepLabV3が2017年、Unet++とPANとDeepLabV3+が2018年、FPNは2017年の論文ではdetectionに、2018年以降にsegmentationにも用いられたようである。MAnetは2020年となっている。このように、MAnetが最も新しく、肝臓と腫瘍のsegmentationや、空撮画像のsegmentationに威力を発揮しているようである。その模式図は以下の通り。

f:id:AI_ML_DL:20210125202949p:plain

それではと意気込んでMA-Netで計算してみたが、デフォルトでは、良い結果は得られなかった。HuBMAPの課題に合わないのか、それとも、正しく使えていないのか。

 

1月26日(火)

HuBMAP

MA-Net:上に示した模式図の外観からはU-Netのバリエーションの1つと考えられる。

名称はMulti-scale Attention Netで、2つの構成要素からなる。Position-wise Attention Block (PAB) and Multi-scale Fusion Attention Block (MFAB)

それぞれ次のように説明されている。The PAB is used to model the feature interdependencies in spatial dimensions, which capture the spatial dependencies between pixels in a global view. In addition, the MFAB is to capture the channel dependencies between any feature map by multi-scale semantic feature fusion.

引用文献を示していなかった。

f:id:AI_ML_DL:20210126105630p:plain

f:id:AI_ML_DL:20210126105813p:plain

f:id:AI_ML_DL:20210126110012p:plain

f:id:AI_ML_DL:20210126110103p:plain

f:id:AI_ML_DL:20210126110150p:plain

f:id:AI_ML_DL:20210126115244p:plain

表2と表3の両方に、U-Netがある。表2のU-Netはオリジナルで、表3のU-Netは``Liver segmentation in CT images using three dimensional to two dimensional fully convolutional network"というタイトルの論文中で次のような模式図で表されている。

f:id:AI_ML_DL:20210126123337p:plain

というように、MA-Netは優れもののようだが、試しに動かしただけでは、期待した結果は得られていない。

今日は、LinknetとPSPNet(Pyramid Scene Parsing Network)を3エポック計算してcommit, submitしたが、いずれもSubmission Scoring Errorとなった。

PAN(Pyramid Attention Network)も計算してみた。計算時間は他のモデルの2倍くらいかかった。LBスコアは2エポックからoverfittingになっていたので予想通り低く、0.243であった。

encoderをefficientnetB3にし、batch_size=32で、9つのモデルの全てで計算可能か否かを調べた。その結果DeepLabV3のみ、batch_size=16にしてメモリーオーバーを回避した以外は、計算できた。1エポックあたりの計算時間は6つが12分程度だったが、PANとDeepLabV3+は約20分、DeepLabV3はbatch_size=16で24分を要した。

まだ、性能を比較できる段階には到っていない。

公開コードの様子から、efficientnetB3-UnetでLB=0.85が視界に入るぐらいになってからにしようかなと思っている。

  • Aux classification outputが次のように例示されているが、まだ使っていない。
  • 今回の課題は糸球体だけを検出するから、不要!
  • aux_params=dict(
        pooling='avg',             # one of 'avg', 'max'
        dropout=0.5,               # dropout ratio, default is None
        activation='sigmoid',      # activation function, default is None
        classes=4,                 # define number of output labels
    )
    model = smp.Unet('resnet34', classes=4, aux_params=aux_params)
    mask, label = model(x)
    mask.shape, label.shape
    # (N, 4, H, W), (N, 4)

次のようなlossが用意されているが、これもまだ使っていない。

JaccardLoss
DiceLoss
FocalLoss
LovaszLoss
SoftBCEWithLogitsLoss
SoftCrossEntropyLoss
SoftCrossEntropyLossは、Drop-in replacement for torch.nn.CrossEntropyLoss with label_smoothingとのことである。

あとは、k fold cross validationと、data augmentationをやらないといけない。

GPUは残り20分程度になってしまったので、本格的な計算はできない。

(出力層)、loss、K fold cv、augmentationなどを、GPUが使えるようになる土曜日の朝までに追加して、次のステージに進めるようにしよう。

 

1月27日(水)

HuBMAP

出力層(Aux classification output)を、良く考えずに追加しようとしたが、maskは1種類で、分類はしないから、不要!

augmentationをやってみよう。

Albumentations Documentationを見ると、目的毎に良く使われる方法や、ベースセットのようなものが、加工後の画像例とともに示されているので、適当に選んで、コピペして使うことができる。

augmentasionのセットをコピペして、計算できることをCPUで確認した。GPUが使えない(使い切った)ので3エポックぐらい計算しただけで、commit, submitまではできなかった。効果の確認やチューニングは土曜日以降になる。

loss関数、optimizer、lrについては、明日、検討してみる。


1月28日(木)

HuBMAP

lossは、順に試してみるつもりだが、2つか3つを組み合わせることで、より良い結果が得られるという報告もあり、最適解を見つけるのは容易ではなさそうだ。

Kaggleで過去のコンペのトップクラスの解法を見れば、参考になることは多いが、状況が異なっているので、そのまま適用してもうまくいかないかもしれない。

プログラム中に、全てのloss関数を書き込んでおいて、単独でも混合でも使えるようにしておこう。

optimizer, lr scheduler:

最近提案されたoptimizerに、NovoGradというのがあって、AdamやAdamWよりも高性能ということらしい。

Training Deep Networks with Stochastic Gradient Normalized by Layerwise Adaptive Second Moments, Boris Ginsburg  et al., arXiv:1905.11286v3 [cs.LG] 6 Feb 2020

In all experiments, NovoGrad performed equally or better than SGD and Adam/AdamW. NovoGrad is more robust to the initial learning rate and weight initialization than other methods. For example, NovoGrad works well without LR warm-up, while other methods require it. NovoGrad performs exceptionally well for large batch training, e.g. it outperforms other methods for ResNet-50 for all batches up to 32K. In addition, NovoGrad requires half the memory compared to Adam.

NovoGrad and all models in this paper are open sourced. 

https://github.com/jettify/pytorch-optimizer

Datasetを作って、このpytorch-optimizerを使う準備をした。

明日は、NovoGradとOneCycleLR Schedulerを使ってみよう。 

 

1月29日(金)

HuBMAP

optimizerとlr_scheduler:素人につき、検討中!

順序:

optimizer = torch.optim.AdamW( ...

scheduler = optim.lr_scheduler.OneCycleLR(optimizer, ...

for image, mask in loader:

      ................................

      output = model(image) 

      loss = loss_fn(output, mask)

      loss.backward( )

      optimizer.step( )

      scheduler.step( )

こんな感じでよいのかな。

この順に並べてみたが、計算結果は異常であった。train_lossはlr_scheduler無しの場合よりも少し大きかったが問題ないレベルだと思う。しかしval_lossが桁違いに大きかった。

pytorchのマニュアルをみるとexampleがあり、引用文献をみるとoptimizerにSGDを使い、lrは考えられないくらい大きな値(最大値)を使っている。まずは、次のexampleをそのまま使ってみよう。

Example

>>> data_loader = torch.utils.data.DataLoader(...)
>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
>>> scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, steps_per_epoch=len(data_loader), epochs=10)
>>> for epoch in range(10):
>>>     for batch in data_loader:
>>>         train_batch(...)
>>>         scheduler.step()

これでは、trainingは進まなかった。原因調査中。

Example

>>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
>>> scheduler = ReduceLROnPlateau(optimizer, 'min')
>>> for epoch in range(10):
>>>     train(...)
>>>     val_loss = validate(...)
>>>     # Note that step should be called after validate()
>>>     scheduler.step(val_loss)

Example

>>> scheduler = CosineAnnealingWarmRestarts(optimizer, T_0, T_mult)
>>> iters = len(dataloader)
>>> for epoch in range(20):
>>>     for i, sample in enumerate(dataloader):
>>>         inputs, labels = sample['inputs'], sample['labels']
>>>         optimizer.zero_grad()
>>>         outputs = net(inputs)
>>>         loss = criterion(outputs, labels)
>>>         loss.backward()
>>>         optimizer.step()
>>>         scheduler.step(epoch + i / iters)

WARNING

Prior to PyTorch 1.1.0, the learning rate scheduler was expected to be called before the optimizer’s update; 1.1.0 changed this behavior in a BC-breaking way. If you use the learning rate scheduler (calling scheduler.step()) before the optimizer’s update (calling optimizer.step()), this will skip the first value of the learning rate schedule. If you are unable to reproduce results after upgrading to PyTorch 1.1.0, please check if you are calling scheduler.step() at the wrong time.

 

1月30日(土)

HuBMAP

OneCycleLR:これを使えるようにする。

optimizer:SGD:torch.optimのマニュアルのexampleそのままで実行してみた結果、train_lossは見事に収束したが、val_lossはtrain_lossより小さい。すなわち、underfitting、のような結果である。パラメータの設定が不十分なのだと思う。

今は、submitしてスコアが計算されることの確認が重要なのでcommitした。

ところが、commit中にWarningが現れ、心配た。約4時間後、スコアは計算されていた。それはよかったのだが、なんと、LB=0.486であった。なさけない。

optimizer:AdamW:AdamWはlr_schedulerを使わない場合のデータがあるので、lr_schedulerを入れたことによるlossの変化を比較することができる。

schedulerはそのままで、lrとweight_decayはデフォルト値から始めてみた。

train_lossは減少したが、val_lossが、ありえないくらい大きな値になった。

不慣れでよくわからなかったが、lrの初期値や最大値を変更することで、設定した10エポックで収束し、かつ、lr_schedulerを使わない場合よりも30%くらい小さいval_lossが得られた。

その結果、ようやくLB=0.796(859th相当)となった。

公開コードのチューニングをしていて最も驚いたことの1つが、この、lr_scheduler.OneCycleLRである。

指定したエポック数で収束する仕組みは凄いなと思う。

efficientnetのpretrained modelには、imagenetの他に、advpropやnoisy-studentいうのがある。これらを使えるようにしたいと思う。

これは、モデルのweightに"advprop"もしくは"noisy-student"を指定してRunすれば、学習済みモデルのweightの場所を指定するメッセージが現れてプログラムが停止するので、そのメッセージに示されているURLからweightをダウンロードして、Datasetを作ればよい。

明日は、計算速度向上の方法を、"Pytorch FCN-Resnet50 in 20 minute"に学ぼう。

 

1月31日(日)

HuBMAP

昨日だけでGPUを16時間以上使い、LBスコアは0.777から0.796まで上がった。

元は同じコードで、前処理の計算時間を短縮したバージョンを別のKagglerが公開しているので、それに乗り換えてみる。train時間だけを見ると、8倍くらい速く、トータルでも3~4倍速い。

コードを解析して高速化した部分だけ移植する方法もあるが、コードの変更履歴がわからないことと、コードの理解力不足のため、乗り換える(主に、segmentation modelsパッケージの追加)という方法をとることにする。

とりあえず、trainまで動くようにした。メモリーの使用状況を見ると、前処理したデータを全部RAMに格納してから、trainを開始していることがわかった。元のコードではCPUとGPUが交互に動作していたが、高速コードでは、CPUとGPUが並列動作しているように見える。それで、全体として、処理速度が向上しているのだろう。commit, submitしてみると、LBスコアも計算された。

昨日は、LB=0.80を超えられなかったが、時間短縮できるコードに乗り換えると、時間短縮の効果に加えて、LBスコアも0.83+にアップした。

スコアアップの原因は、augmentationであることがわかった。

コード乗り換えの際に、使われているaugmentationのコードが同じものに見えたので、取り換えなかったのだが、よく見ると、新たなaugmentationコードでは、distortion(ElasticTransform, GridDistortion, OpticalDistortion)の確率がゼロになっていたのである。昨日までのコードは、変形量を大きくしすぎていたために、trainがうまく進まなかったものと思われる。

 

1月7日に終了したRiiid!コンペは残念な結果に終わった。チューニングだけでは、まぐれあるいは幸運にも恵まれないとメダルは難しい。

次のステップに進むために、GitHubを活用し、モデルの選択肢を増やし、最新の情報に接し、日々勉強を怠らず、技術と知識を積み重ねていこう。

1月は今日で終わり。来月もKaggleに集中しよう。

 

f:id:AI_ML_DL:20210101145217p:plain

style=162 iteration=500

f:id:AI_ML_DL:20210101145334p:plain

style=162 iteration=50

f:id:AI_ML_DL:20210101145458p:plain

style=162 iteration=5