Thursday 14 May 2020

Darknet/YOLO optimized for Jetson


This post contains details of some of the memory adaptation of Darknet/YOLO for Jetson Nano, making possible train/inference higher resolutions.

As on the source code link above, the memory optimizations are:
- Use of Jetson Nano Unified memory (inference and training)
- Mixed precision training (Paper, implementation, implementation, NVidia)

The implementation of mixed precision is for memory optimization only. We will not get faster implementation because Jetson Nano does not have TensorCores, and Maxwell architecture does not have faster execution for FP16. See report below.

Currently, this supports YOLOv3 only. No v4, nor v2, nor tinies.
It probably works on Maxwell Jetsons and may work on Xavier. Will not work on dGPUs because of the adaptations for Unified Memory.


DataSet
Since Jetson Nano is extremely slow compared with latest dGPUs, I have tested only with Cat/Dog of COCO datasets.
It takes app. 11 days to train 320x320, app. 14.5 days to train 416x416.

More details on how to compile, etc are here.

Unified memory
Darknet has the same data on both CPU and GPU memories. This is understandable if you use dGPUs.
However, Jetson shares the same DRAM for both CPU and GPU, and we don't have to store twice the same data.
So, I adapted Darknet to alloc memory only once.

Mixed Precision and loss scale
For mix between FP16 and 32 on forward/backward/updates, I referenced the TensorFlow version of this link.
There are some proposals for dynamic loss scale (here and here).
However, due to the characteristics of Darknet/YOLOv3 behavior, I decided to implement my own.
The loss scale reduction by half rule is the same as on the links above (Reduce if NaN or Inf in dW, i.e. weights_updates on convolutional layers). However the links above doubles the loss if there's no NaN nor Inf for 1000 or 2000 iterations.

Some analysis of YOLOv3 behaviour:

The chart below shows the values of max magnitude of weight_updates among all conv layers, as well as the loss for FP32 mode.
This is an example. The values will vary if you change training parameters, or even on other training with same parameters due to the many random selections (Ex: selection of images, random generation of augmentation numbers), but the format is the same.
It starts at high value and the peak is 165,055 which will be infinite for FP16 (Max: 65,504), and we would like to set the loss scale for 0.25 in this case.
Then goes down on the first few hundreds of iterations by a factor of app. 2^10.
So, it's better to double the loss scale quickly instead of on every 1000 or 2000 iterations to avoid loss of precision during the conversion, and I decided to update the scale based on the max weight_updates of the following:
    max magnitude of current iteration / max magnitude of all iterations so far
This rule applies until the burn_in which is set to 1000 by default on the cfg file. After the burn_in, it will be doubled on every 1000 iterations (configurable) as on the links.
It could be based on the loss (less computational cost), but it gets stable before the weight_updates on the example of this chart (see avg_loss and weight_updates/256 values).



Another interesting fact is from where the max weight_updates comes from.
Below are the values of max magnitude on every conv layer. As can be noted the max magnitude varies a lot among layers, and the last conv layer is the highest on initial interactions. During this time, the max magnitude among layers varies more than a factor of 2^10.



Resizing data augmentation
Darknet/YOLOv3 implements data augmentation such as adjustment of color as well as crop, flip and resize of images.
The resize is from 1/1.4 to 1.4 of the width/height (multiple of 32 and other maths).
For 320x320, the resize varies from 256x256 to 480x480.
The resizing is adjusted randomically on every 10 interactions, but for the first 10, to initialize the memory allocation to max, darknet/YOLOv3 uses the maximum resize (480x480 in this case).
For maximum resize, the required memory usage and processing time are the highest.

Memory usage evaluation method

I have investigated the following ways to check Tegra (Jetson) system memory usage:
* tegrastats command (can output memory usage on specified interval to a log file)
* jtop command (same information as tegrastat, but no output to logfile)
* cudaMemGetInfo (c code)
* /usr/bin/time -v  (Maximum resident set size)

I decided to use tegrastats because this can log values at fixed interval (I have set to 5 seconds)
Also, cudaMemGetInfo, /usr/bin/time and tegrastats output different values.

Results for Jetson Nano:

Below are some experimental results.
The memory usage are RAM + SWAP reported by tegrastats, meaning that other processes (default processes set on Jetson Nano) memory usage are also included.
As above, Darknet/YOLOv3 uses maximum memory for maximum resize, and the first 10 iterations are set to maximum resize.
So, during the first 10 iterations, it is expected that the memory usage is app. the maximum.
However, sometimes during the training, the memory usage further increases possibly by other processes.
Due to this, there are two possibilities to Darknet being killed by out of memory:
1) During the initial memory allocation
2) After some time, due to memory usage increase by other processes.

For example, the chart below are the memory usage during trainig on 320x320 for FP32 and Mixed Precision.
FP32 finishes first as below.
Memory usage (RAM+SWAP) for first 10 iterations are app 3800MB (FP32) and 3200MB(mix).
However, during the training time, memory usage increases as on the charts below, and needs further investigations on the reasons.

Also,I have configured my Nano with default SWAP (2GB) as well as to use headless mode.



Training results

configuration Original YOLOv3 This adaptation
yolov3 320x320 OK OK
yolov3 416x416 killed after app 100 iterations(1 attempt only) OK
yolov3 544x544 killed on start killed after app 300 iterations(1 attempt only)
yolov3 tiny Depends on w/h Not implemented
yolov2 Depends on w/h Not implemented

Timing analysis
For 320x320 training, the timing to finish one iteration on 480x480 resize is:
  FP32 : 186 secs
  Mix : 272 secs 
The following is a summary of the profiling by the following command:
  nvprof --print-gpu-trace --log-file log.txt ./darknet detector train ...
I've run the training for 3 iterations, and the data below is from the 2nd iteration.
For FP32, the total GPU time is app. the same as 186 secs above.
However, for Mix, the total GPU time is 232 sec, less than the 272 secs above (40 secs difference).
On the other hand, if my analysis is correct, as bellow, the biggest difference between Mix and FP32 is the processing of the convolutions (FP16 takes 47 secs more).
So, the GPU time difference is on convolutions, while I still need to find 40 secs of difference.

mAP@0.5 results for cat/dog

w x h mode best mAP
320x320 2 classes (FP32) 66.4%
320x320 2 classes (Mixed Precision) 68.0%
416x416 2 classes (Mixed Precision) 73.3%


NOTE: trained for 5000 epochs and selected the best mAP weight (stored every 100 iterations)
Is should be stated that the mAP varies on every training, even if we don't change the settings.
So, the above numbers does not necessary means that Mixed Precision algorithm is always better than FP32.

Sunday 22 September 2019

Shapes (Circle, Triangle, Square, Star) dataset generator

I have created a python script to generate shapes , for deep learning.

The code is on gitlab here.

It can:



  • Generate circle, triangle, square and or star
  • Single or multiple shapes per image
  • 1 or 3 color channels
  • Can define color range for each of shape as well as background
  • Can further use gradient color patterns
  • Can generate full shapes or outline
  • Supports rotation
  • Can set size scales
  • Supports annotation for darknet/yolo and Pascal VOC formats




  • Set output path



  • Here an example with Pascal VOC annotation:
    Left: generated image, Center: Pascal VOC objects, Right: Pascal VOC classes

    Head, Shoulders, Knees

    Tuesday 4 December 2018

    Raspberry PI上でのIchigoJamのGPIO

    数カ月前からIchigoJamで電子工作をはじめました。

    IchigoJamのハード1台、Raspberry PI数台持っているので RPIでもIchigoJamを動作させました。

    RPI zero
    で電子工作をする際、GPIOピン名が簡単に分かるようにしました(A4用pdf, ods libreoffice):



    初代Raspberry PI(2012)
    IchigoJamはRPIの全てのGPIO 40ピンを使いますが、初代 RPIには26ピンしかないです。

       対応ピンを探しましたが見つからなかったので一部確認しました。おそらくピン1-26そのまま使えて、27-40は使えないです。すなわち、OUTピンは7-11は使えるて、1-6は使えないですね。



    Friday 29 June 2018

    H-IIAロケット39号機打ち上げを見てきました

      2018年6月12日に H-IIA ロケット 39号機の打ち上げを種子島で見てきました。
      最初は何も分からず、沢山調べて行きましたので、その経験を記載します。

      最初はちょっとだけ調べ、レンタカー、宿、交通手段の確保が困難とわかりました。
    JAXAが打ち上げを発表した日には、既にJAXA担当者が車、宿や船/飛行機を予約しているので、予約が困難とか。
      39号機の場合、発表は4月13日でした。

      ===
      まず、これまでロケットの打ち上げに興味がなく、Youtube等で見るだけで満足でした。
      しかし、子供がロケットに興味を持つようになり、種子島に行きたい、行きたい言い始めました。数ヶ月もこの状態が続いたので、GW中に調べたら、6月11日(当初予定)にH-2Aが立ち上がるとのこと。この時点で何も知らなく、調べ始めると予約するには既に遅いってことが分かりました。諦めず、頑張ると:
      ➤レンタカーは最初の数社は空きがなし。でも、なんとか一社見つかりました。
      ➤宿は西之表にありましたが、ここは発射場所から遠く。。発射場所から近い南種子町はキャンセル待ちのみだったけど、なんと、GW明けに予約できました!
      ➤飛行機は全て満席でした。当日の鹿児島➞種子島の高速船も満席でしたが、前日のを予約しました。

      これで予約は全てなんとかなりましたが、もう一つの心配は天候です。
      実際、今回は一日延期になりました。
      過去の延期に関してはここで助かりました。が、ここには最近のはないため、jaxaの過去に年間のプレスリリースもみました。
      今回はさらに直前に台風が通過しました、影響はなさそうでした。
      なお、天気に関して参考にしたのは下記です。
      ➤Jaxa の天気予報。Jaxaが参考にしている予報なので、ここは見ることですね。
      ➤気象庁の週間天気予報信頼度もあります。注意点です:Yahoo、Goo、エキサイト、livedoor等は、気象庁の予報を使っています!。ただし、信頼度は記載してません!
      ➤日本気象協会の10日の予報
      なお、発射当日は晴れとなっていましたが、風が強く、雲も沢山でていました。発射後、2分間はロケットが見れましたが、その後雲に隠れました。

      ===
      感想:家族はテレビでみるよりずっとよかったとのことです。とにかく音がすごいです。
      ここでなんと、種子島原人さん(鹿児島MBCで放送)と、鹿児島のkkb、にインタビューされました!種子島に行って、二つのテレビ局で放送されるとは!下記が種子島原人さんのYouTubeです。




      ===
      種子島に行くことは滅多にないので、他の観光もしました。
      以下が簡単な写真等です。

      6月9日にさんふらわーフェリーで大阪から鹿児島へ。翌日に行きたかったけど、台風の影響で翌日はでないかもとのこと。
      6月10日、鹿児島につき、桜島が噴火中でした。この日、高速船で種子島に行きましたが雨のため何もできず。。
        以下、バスからの桜島の噴火です。

      11日には、海岸の景色をみてから千座の岩屋へ。千座の岩屋は思ったより大きく、迷路のようでした。その次に予約していた種子島宇宙センターへ。
     


      12日が打ち上げの日です。打ち上げまでは公園で過ごし、それからマングローブへ。
     


       13日は、まず突然現れた海へ(犬城海岸)。ここは波がなく、おだやかで、されに誰も泳いでいない貸切です。次に増田宇宙通信所へ。宿で頂いた種子島の筍の写真ものせています。この日は天気がよかったので、夜に宿の近くの公園に行き、星空を見てきました。あかりが少ないため、大阪よりもずっと綺麗です。この季節の北斗七星も良く見えました。


     

      14日の朝、西之表のスーパでBBQの買い物をして、浦田海水浴場へ。ただ、途中で地元のお野菜を売っている場所が沢山あり、スーパでの買い物はちょっと失敗。。海水浴場に行ったけど、天気が悪く、途中で雨。。幸いBBQは美味しくいただけました。宿に戻り、この日も島の筍をいただきました。


      15日の朝は西之表の展望台へ。次に高速船で鹿児島へ行き、さらにここから大阪へのフェリーへ。夜景はフェリーからの写真です。夜の始めはくもりでしたが、朝3:30は晴れていて、大阪では見れない天の川が美しかったです。




    Thursday 3 May 2018

    鷹狩り

    風が強い日の写真です。





    Saturday 20 January 2018

    私の教え方

    4/ 5歳 にギターを教える
           興味を持つ
           ギターの選定
           私の教え方


      
     私は20代の約10年間ギターを引いていました。最初は二年ほど教室に通いましたが、正直すごく上手ではないです。
      しかし、プロのコーチが良い選手ではないのと同様に、自分で子供に教えることにしました。
    ー最低限の理論は知っています。
    ー独学で引けるようになった超有名人が多数います。
    ー一方、先生に教えてもらっても上手にならなかった方もいます。すなわち、先生がいたから引けるようになると限りません。

      また、子供が音楽のプロになることは期待していません。世の中にはすごく上手な子供もいますが、この子達は毎日数時間練習をしていると推定しています。
      うちの子はそこまでしません。趣味を沢山持っているのか、一日に沢山のことをしたがるのでギターにあまり時間を使いません。エニアグラムではタイプ7の性格です。

      ギターを購入する前に、以前のエレキで教えようとした時の失敗もあり、どのように教えるのかを学習する必要がありました。
      また、人間には個人差があります。その子に合った方法を探す必要があります。
      うちの子は、あまり言うことを聞く子ではありません。。。ほとんどの時、超初心者であっても自分の方法でやりたがります。
      自分の方法があまり良くない、または飽きた時にやっと話を聞いてくれます。それまでに怒らず待つか、何か他の方法を探して注目するしかなかったです。

      まず、小さい子のため知らないことが多く、一度に教える内容を極端に少なくすることにしました。ここでは、分割統治法、すなわちある内容をより小さいのに分割して教えます。

      例えば両手の指の動きを同時に教えることは非常に難しいとわかりましたので、先に右を教えて、次に左を教えました。
      ネットでも教える方法を調べました。例えばお稽古を面白くする怒らないことです。後者は重要です。子供に怒ったら、怒られた理由で興味を無くし引く気を失います。子供の学習が進まない場合、先生の問題です。先生が工夫することです。
      ただ、残念ながら、面白いネタは飽きるので長く続かないです。定期的に何か探さないとだめですが、ヒントは沢山見つかりました(ここここ)が、同等の日本語のは見つからなかったです。
      私には実験のようでした。ある方法を試しては、効果があれば続け、なければ他を探す。。
      個人差もあり、ある方法が全員に効果的と限らないです。

      音楽には子供が好きな動揺を使いました。一方練習中に子供は音楽しか引きたがらなかったです。
      例えば練習だけのために工夫されたコードの順には消極的でした。

     教えるのが簡単だった音楽は次です。理由は繰り返す部分が沢山あり、フレッツ1〜3のみを使うからです。
      Twinkle Twinkle Little Star, ABC, 雨だれぽったん(低音のドとソ)、Happy Birthday
      コードの場合、かえるの合唱、海メリーさんの羊、英語では Head Shoulders knees and toes,  Wheels on the busです。これらは主に C/GやDを使い、それほど早く左手を動かさないからです。



    ⇑C/Gは省略版です。

    最初の一年に行ったことは次の通りです。
    1) まず、両手を同時に使うのは非常に複雑だとわかりましたので、右手からはじめました。
    子供が好きな音楽を歌いながら、そのリズムに合わせて右手だけを動かして。はい、弦は押さないままです。 

    2) 6つの弦があることを理解頂けるために、一つづつの弦を引いたり、低・高音の違いを理解するために6弦と1弦だけを繰り返したり。または、背中を向いて、低・高音を引いてどっちなのかを聞いたり

    3) それでも、右手の指毎を使うのが難しいとわかりました。このため、初めてから一週間後にピックを使うことにしましたが、最初にピックなしでちょっと慣れたのか、使ってくれませんでした。
     が、以下のようにピックにお好みのシールを貼ると気が変わりました。


    4) 日程管理を楽しくするために、ギターの絵の印鑑を作りました。そしてギターを練習した日に、カレンダーに印鑑を押すようにしました。
      これは私が仕事で多忙になるまで数ヶ月続きました。多忙になってから、練習は休日になりました。

    5)二週間経った頃、Jingle Bellの最初6つの単音(弦1の0を六回)を試せるようになりました。

    6) もっと楽しくするために、エレキギターのエフェクターとアームを見せました。この音が面白く、暫くはこれが楽しみの一つでした。

    7)一ヶ月半後、弦1だけで Happy Birthdayの練習をはじめました。これです。

    --3-3-5-3-8-7--3-3-5-3-10-8--3-3-15-12-8-7--13-13-12-8-10-8--
      ここでも、一段階づつ進みました。最初は私が左手でフレッツを押して、子供が右手で弦を引く。はぃ、二人で一つのギター。
     次に、子供が三番目のフレッツを人差し指で押して引いて、他のフレットは私が押していました。ここで初めて、子供が左手を使いました。もう1つの進歩。
     ただ、他のフレッツの位置を暗記できないため、ギターにシールを貼りました。そして、シール付きの位置を覚え、やっと一人で引けるようになりました(全部人差し指だけど)!
    1


    8) 3月の半ば、ギタータブを教えても良いと思い始めました。。。
      幼い子にバイオリンを、楽譜なしで教える鈴木先生方式がありますが、、試しにタブで教えることにしました。
      まず、、実は子供にはひらがな、ローマ字と数字を、遊び感覚(家庭教育)で3歳になる頃から教えていました。
      しかし、タブを初めて教えようとしたら、ギターの弦と、タブ上の弦の関係を理解して頂けなかったです。
    確かに、下記のように、4歳(当時)の子にはわかりにくいかも。頭の中で元に戻せなかったのか。。

      どう理解頂けるのかを考えた結果、弦に「色」をつけることにしました。
      最初は1弦のみからはじめました。これを赤にして、Happy Birthdayからはじめました。
      より楽しくするために、タブに例えばお誕生日ケーキ等の絵を追加しても良いです。
      

      タブを探す時、絵を見て探すのも早くなります。
      また、タブの色とギターの弦を対応するため、ギター側にも色のシールをつけました。次の図には全ての弦に色を付けているけど、進捗と共に追加していきました。


      自作のギタータブは以下からダウンロードできます(クリックで拡大)。






    雨だれ ポッタン


    あまだれ ぽったん(低音のみ。簡単!)

    月(繰り返す部分が多いです)
    でたでた月がまるいまるい まんまるい 盆のような月が

    チューリップ
    さいた さいた チューリップの花が


    ゆきのペンキやさん
    ゆきのペンキやさんはおそらから ちらちら



    春の小川
    春の小川は、さらさら行くよ。


    とんぼのめがね
    とんぼのめがねは水いろめがね


    Twinkle Twinkle Little Star


    ABC song




    9) そろそろ、左手の他の指も教えたい時期がきました。
      ただ、人差し指で慣れちゃって、それで十分と思い込んだ子を説得するのに時間がかかりました。
      さらに、自分が引きたい曲しか引かず。。
      なんとかなりはじめたのが、適切な音楽を見つけてからです:子供が知っていた Twinkle Twinkle Little StarとABC。
      両曲ともフレッツ1/2/3しか使わないため、フレッツと指に 1/2/3のシールを貼って、フレッツ毎に別の指を使うようにと言いました。
      指にシールを貼ったのが面白いのか、ここからなんとか全の指を使いはじめました。


    10) 5月にギターのストラップを買いました。これも新しい物を貰ったのか、立って引くようにもなりました。

    11) 次に、コードを教えても良い時期がきました。
    はじめに分かったことは、手が小さいためCやGは引けないことです。。。
      この図では、Cをしようとしたけど、人差し指を弦2におくと、薬指が弦5に届かないく、Cができないです。。。





      幸い、ここを見つけて、C/Gの省略版を教えてことにしました。

      C/Gのみの簡単な曲からはじめましたけど、最初の2〜3ヶ月は全曲を一つのコードだけで引いていたり。。
     実はうちの子、まだ幼いけど自分の弱い部分をあまり見せたくない性格です。このため、長い間、何故一つのコードだけで引こうとしていたのか分らず、ある日突き止めたらやっと指が痛いとのことでした。
      この時、弦をシルク&スティールに替ました。それから指が慣れるまで多少の時間がかかりましたが、やっとC/Gを繰り返して「メーリさんの羊」を引くようになりました。

      また、結果的に良くない方法を使いました。この頃、映像と一緒に引こうとしました。
      楽しい曲の映像を編集して、コードを入れました。音楽の映像が流れているとともに、どのコードを使えばよいのかがも表示されるようにしました。
      最初は子供も好きな音楽と一緒に引けるて楽しくしていましたが、結局最初のコードしか使わなく。。。
      結局、見ることが楽しいだけと気が付き、この方法を止めて、やっと全コードを引くようになりました。
      映像を使って効果がある子もいるかもしれないけど、うちの子には2ヶ月程の無駄でした。。

      これからは、最初の頃のようにもう少し頻繁に練習をする方法を考えようと思います。また、より面白くて簡単な音楽を探したいです。