2月第2週の振り返り

2月第2週(2/3-2/9)

ASP.NET Core MVC

C#におけるasync/awaitの仕組みについて理解を試みた。

async修飾子のついたメソッドは基本的にTask(返される値がない)またはTask<最終的に返される値の型>を返すこととされ、またメソッド内でawaitの記述が可能となる。

awaitは別スレッドで実行されているTask/Task<T>の処理が終わるまでメインスレッドはその先に進まないでおくという挙動を示す。これを「待つ」と表現するとブロッキングのそれと混同しかねないので避けるべきだと思った。

非同期とは呼び出し元に戻ってきたときにまだ「最終的に期待する結果(Taskならば処理の完遂、Task<T>ならばreturn T)」が得られていないことを意味する。いつその結果が得られるかは処理の内容による。そうすると最終結果を利用してさらに何かを行いたい時に支障が生じる。そこで結果を利用する処理を行う前にawaitを行うと、最終的に期待する結果が得られたことを保証できる。

よくある無意味なawaitは以下のようなものである。

public async Task<int> DoHeavyCalc(int a, int b){
    // この間I/Oや通信、重い計算などが行われる。仮に5秒かかるとする
    return a+b;
}
int calcResult1 = await DoHeavyCalc(3, 5);
int calcResult2 = await DoHeavyCalc(7,12);
// 時間がかかるだろうから他の軽い処理をここでしておく
System.Console.WriteLine($"calcResult1 is {calcResult1}, calcResult2 is {calcResult2}");

このコードでは

  1. 別スレッドでDoHeavyCalc(3, 5)を実行させ、その最終結果が得られるまで先に進まないでおく
  2. 次に別スレッドでDoHeavyCalc(7, 12)を実行させ、その最終結果が得られるまで先に進まないでおく
  3. 他の軽い処理を行う
  4. 2つのintを踏まえてコンソール出力を行う

ので最低10秒かかる。これでは(メインスレッドが固まることがないとはいえ)逐次実行しているのと変わらない。いよいよ処理が完了している必要があるというタイミングになるまでawaitをするべきではなく、従ってこう書く。

Task<int> task1 = DoHeavyCalc(3, 5);
Task<int> task2 = DoHeavyCalc(7, 12);
// 時間がかかるだろうから他の軽い処理をここでしておく
int calcResult1 = await task1;
int calcResult2 = await task2;
// またはint[] calcResults = await Task.WhenAll(task1, task2);
System.Console.WriteLine($"calcResult1 is {calcResult1}, calcResult2 is {calcResult2}");

この場合、

  1. 別スレッドでtask1の実行が開始され、呼び出し元に直ちに戻る
  2. 別スレッドでtask2の実行が開始され、呼び出し元に直ちに戻る
  3. 他の軽い処理を行う
  4. task1の処理が終わるまで先に進まないでおく(1の時点から5秒経つまでこのフェーズ)
  5. task2の処理が終わるまで先に進まないでおく(1と2はほぼ同時に開始しているのでこのフェーズは一瞬)
  6. 2つのintを踏まえてコンソール出力を行う

となり、所要時間は約5秒となる。

元々並列プログラミングのMPI通信関数を扱うべく非同期概念を理解しようと努めていたので、あまり混乱なくC#のasync/awaitを用いることができた。

来週はSignalRを利用したリアルタイム通信について学んでいきたい。

1月第5週・2月第1週の振り返り

1月第5週・2月第1週(1/27-2/2)

並列プログラミング

ようやくMPIを用いた並列計算によるLU分解法の完全実装に成功し、無事レポートとして提出することができた。来学期以降も同じ課題が出るはずなので実際のコードは示さないが、アルゴリズムの意図を流れに沿って示すことで理解の一助になればと思う。以下で各プロセスは計算するを分担している。

  1. LUP分解(PA=LU)
    • Doolittle法を使うので、Lの対角成分は1と仮定する
    • 左上からL, Uを交互に一列/一行ずつ確定していきたい
    • そのためループはk = 0, 1, ... (N-1)で回す
      • A[k][k]が担当範囲に含まれるプロセスは、A[k][k]とそれより下の要素の中で絶対値が大きいものを探し、Aおよび列ベクトルbのk行とlargest_abs_row行を入れ替える(部分ピボット選択)。得られた最大の対角要素で列を割り、Lのk列目を得る。Lのk列目情報をlargest_abs_rowの情報とともに他のプロセスに送信する。そのLと既に確定した自分のUを使ってk+1行/列以降の未確定範囲全体に減算を行う(k=0のときUの0行目は自明である)。Uのk+1行目が確定する
      • 担当範囲が現在のkよりも左にあるプロセスは、既に自分が担当すべき範囲のL/Uを求め終わっているので、情報の受信後行入れ替えだけを行う
      • 担当範囲が現在のkよりも右にあるプロセスは、受信したLと既に確定した自分のUを使ってk+1行/列以降の未確定範囲全体に減算を行う(k=0のときUの0行目は自明である)。Uのk+1行目が確定する
    • 結果として各プロセスは自分の担当範囲におけるLとUが確定した状態になる
  2. L(Ux)=Lc=Pbからcを求める
    • 列ベクトルcもプロセス間で分担して求める
    • (まず左端のプロセスが上から順に担当範囲のcを確定する)
    • 以下を繰り返す
      • 確定されようとしているcの行が担当範囲にまだ達していないプロセスは何もしない
      • 自分の担当するcが既に確定したプロセス群は自分の知るLとcを使って、下のほうのcを右側のプロセスが求められるよう、左隣から受け取った「引くべき値の部分和」にL*cを足して右隣のプロセスに渡す(リレーする)
      • 当該ループで確定することになっているcを担当するプロセスは左隣のプロセスから「引くべき部分和」を受け取り、Pbから引いてcを確定させていく
  3. Ux=cからxを求める
    • Lc=Pb同様だが方向が逆転し、またxの確定のためにはUで割る必要がある

とこのようになる。とはいえ既存のコードを言葉で表現するとこうだという話であり、この表現からコードに起こすのは難しいかもしれない。

一つ言えるのは、手書きで変数の動きを追うのであれば6x6行列を3プロセスで分担するケースを考えるべきだということである。上述したようにプロセスは担当範囲の値確定前・確定中・確定後の3種類に分けられ、また各プロセスが1行/1列しか担当しない場合は担当範囲ので値を確定させる順番が考慮から抜けてしまうからである。そして具体的な値ではなく成分をそのまま u_{02}, l_{10}のように扱うことでプログラム中で使うべき添え字が明確になるだろう。

ASP.NET Core MVC

ようやく今期の科目を完遂したので来週からはWebアプリケーションの続きをやっていく。

1月第4週の振り返り

1月第4週(1/20-26)

並列プログラミング

取り組んでいるのはPEごとにメモリが分散している&リモートでバッチ実行されるプログラムであり、デバッガで変数の動きを確認することができない。printfデバッグはその時の当該PEの状態はわかるものの通信が正しく行われているかは確認できない。

そこで4x4行列を2PE/4PEで解いた際の処理を頭で模倣して、ループごとに全PEの状態を紙に書きだす机上デバッグをしたところ、計算機がどのようにタスクを処理しているのかが理解でき、ようやくLU分解法全体の並列処理が完成したと考えられるようになった。

断言できないのは、肝心のOakforest-PACSが現在月末処理中でジョブを実行してくれないからである。とはいえもはや無限ループに悩まされてはおらず、またLU分解部分までは今週頭の稼働期間中に正しい結果が出ていることが確認できたので恐らく正しかろうと思われ、あとはLc=b, Ux=cの代入だけなのでレポートとして出せそうである。

机上デバッグの結果、非人間的な処理方法をhuman-readableな概念で記述できるようになったので、コードそのものは公開できないにせよコメントと抽象化した処理内容を学習の成果として公開する予定である。

1月第3週の振り返り

1月第3週(1/13-1/19)

並列プログラミング

自分で一から書いたコードがMPI_Barrierに到達しないで永久ループしているようで何が原因か見当もつかず困っている。レポート課題として提出できるよう試験終了後に集中的に取り組みたい。

メディアプログラミング

顔検出で用いられるHaar-like特徴量の白黒パターンのことがずっと分からないままだったが、ようやく理解の糸口をつかめた。様々なサイズで領域を指定して白黒パターン群を領域に適用し、白部分と黒部分の輝度差をとって、その領域における輝度差の特徴が「顔」「not 顔」のいずれに類似するかということを機械学習によって決定するものであるようだ。白黒パターンは「鼻の側面は陰になり、鼻梁と隣接する頬は明るい」「黒目は白目より暗い」といったことを踏まえてそれを検出できるよう設計されていると理解した。

ASP.NET Core MVC

MVCにおけるViewModelの意義を理解した。POSTリクエストには任意のフィールドを含めることができるので、Modelを直接Viewに渡してしまうとCreate/Updateの操作において変更を想定していないフィールドが名前さえ一致していれば書き換えられてしまう。アノテーションを使ってバインドするフォームデータを制約することもできるが、文字列による指定でありIDEを前提としないとフィールド名の変更に追従できないことが考えられる。また複数のModelをViewに渡したいときや、Viewのフォームでは姓名を別の欄に入力するが実際にDBに保存するのはフルネーム(仮定の話。実際そのような設計がよいかは分からない)であるときなど、Model側がViewに配慮して新しいフィールドを追加するべきではない。

そこでViewModelというViewへの便宜を図った存在に必要最小限のフィールドを設定し、Modelの一部を詰めて表示する。POSTリクエストはViewにバインドされたViewModelで受け取り、必要な分だけControllerの中でModelに移し替える。これによりフォーマッティングのModelからの分離と、Modelに対して行える変更の制限とを実現できる。

Dependency Injectionは名前が直感的な理解を妨げているように思われた。各クラスにおいて必要な(Dependency)別クラスのインスタンスを、利用側のクラスが内部で生成するのではなく、コンストラクタが呼び出される段階で引数として外部から与えられる(Inject)ようにする。クラスのオンデマンド外部供給とでも呼ぶべきだろう。

この時別クラスそのもの(具象クラス)ではなくそのクラスが持つメソッドを定義したインターフェースを引数の型に指定することで、実運用時に具象クラスを渡せるのはもちろんながら、インターフェースを実装してさえいればモックも許容されるので、開発段階で別クラスの実装完了を待ったり、それが自分の期待通りに動くことを確認したりせずとも、「もし別クラスが自分の期待する(または仕様書にある)通りの挙動を示しさえすればこのクラスは正しく動作できるか」を確認できる(=単体テストが実行できる)という恩恵があるわけだ。

1月第2週の振り返り

1月第2週(1/6-1/12)

法医学

法医学において画像診断は死因判定と生体診察の両方に用いられるが、特に宗教的理由から解剖が忌避される地域において死後画像診断が積極的に導入されている。PMI: postmortem (cross-sectional) imagingと呼称される。

非破壊検査であるため、解剖では骨の破損状況や内容物が失われてしまうもの(骨折・腐敗遺体の脳内出血・空気塞栓・緊張性気胸など)や小型の異物を発見することに向く。一方で軟骨の損傷については発見が難しい。また外傷と病気の両方が考えられるものについて鑑別が不可能である(クモ膜下出血・動脈解離など)。

メディアプログラミング

今回は画像処理について。

昔映画館で流行ったような気がする赤青メガネであるが、赤-シアンのペアになっている。光のRGBのうちRを透過する赤フィルムと、G+Bを透過するシアンフィルムを用意することで、Rチャンネルの輝度配列とG+Bチャンネルの輝度配列を合成した画像を左右の目で分けて受けることができる。RとG+Bをずらして合成することで、左右の目で受け取る輝度情報に視差を生じさせ、そのずらす量に応じて距離が異なっているように知覚させる。そのため「目の前に飛び出して見える」ものは左右の視差が大きい=RとG+Bの像の位置が大きく異なる部分で、遠くに見えるものはその逆である。

撮像素子は光電効果を利用して光の強さを測定する。デジタルカメラでは、Bayer配列と呼ばれる並びのR/G/Bカラーフィルタを通すことで、各画素はRGBいずれかの単一波長の光の強さを測定し、他色の輝度情報を周辺の画素による測定結果から補間することで、各画素に当たっていたであろう光の成分を再現する。

RGBは光の波長ごとの強度を表現しているが、人間の色覚と合致するわけではない。写真の中で日陰に次のような色で画素に表現された物体があるとき、日向にある物体と似た色をしているのはどちらかという問いに対し、ピクセルから直接取得できるRGBでは#0000ff◆◆#00009bユークリッド距離が#0000ff◆◆#6400ffのそれと等しいため、判断できない。しかし環境光による色変化を補正しようとする作用が働き(色の恒常性)、ヒトは通常前者を日向にある物体と似た色だと認識する。そこで人間の色覚に適合するよう、照らされ具合(照度)とは独立に色合いを表現する方法への需要が生じる。

HSV色空間は、物体が反射する光の主波長(色相:Hue)・主波長成分への偏り(飽和度/彩度:Saturation)・主波長成分の分光反射率(明度:Value)によって色を表現するものであり、人間の色覚と親和的であるとされる。

ASP.NET Core MVC

https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/ に沿ってWebアプリケーションの設計を学んでいる。チュートリアルASP.NET Core 2に準拠しており最新のLTS版である3.1ではないので記述を変える必要があるところもあったが、概ね順調に進み今週は/ef-mvc/introまで終えた。

モデルの定義の中で関連するデータへのアクセスを容易にするためのナビゲーションプロパティにList<T>ではなく抽象型であるICollection<T>を使うことで、DBから条件を満たすデータを取り出そうという時にList<T>.FindAll()のような不適切な操作(条件を満たしていれば順番は不問であるのに、不要なList<T>化を行ってしまう)による取得を防止することができる。他方DBに格納する時は、仮に新規データをList<他モデル>ではなくDictionary<string, 他モデル>という形で扱っていたとしてもICollectionにキャストすれば受け入れられる。Values.ToList()の必要はない。

この「データ取得操作の規律性」・「データ登録操作の利便性」が、具象クラスではなくインタフェースによる定義を行う根拠なのだろうと思う。

ナビゲーションプロパティについて、 Microsoft.EntityFrameworkCore.ProxiesをNuGetで導入してoptions.UseLazyLoadingProxies()することでLazy Loadingがデフォルトになる(同時にすべてのナビゲーションプロパティにvirtual修飾子が必要となる)。

このLazy LoadingとEager Loadingのコンセプトについて混乱していたが、どうもEF Core 3では以下のようであると認識するに至った(正確性の保証はできない)。

  1. 既定でナビゲーションプロパティは読み込まれず、アクセスするとnullになる
  2. entity.Collection/Reference(e => e.NavProp).Load()をするとそのエンティティについてのみナビゲーションプロパティが読み込まれる(Explicit Loading)
  3. Model.Include(e => e.NavProp)をするとOUTER JOINが行われ、全件について当該ナビゲーションプロパティにアクセス可能になる(Eager Loading)
  4. options.UseLazyLoadingProxies()をするとナビゲーションプロパティへの参照が入った時点で自動的に.Load()する(Lazy Loading)

しかしLazy Loadingは当該ナビゲーションプロパティへの参照が行われるたびその一件についてのみ取得するので、1+Nクエリ問題を引き起こすことがある。

生成されたSQL文はEF Core 3では何もせずともログとして流れているが、warning扱いでVisual Studioの出力には出てこない。確認できるようにするためにはappsettings.Development.jsonで"Microsoft.EntityFrameworkCore.Database.Command": "Information"をLogLevelの中に追加すればよい(以下を参考にした)。

devadjust.exblog.jp

年末年始の振り返り

年末年始(12/30-1/5)

 

Azure for Studentsのサブスクリプションが期限を迎えるというアラートを受けて、かつて授業の最終課題として作ったWebアプリケーションの再構築に取り組む計画を立てた。

離散フーリエ変換を必要とするものだが、不規則な間隔でサンプリングされ、また当時取得できたデータでは欲しい周波数がナイキスト周波数を超えてしまっていた。今はサンプリング周波数が向上しているらしいので、これもかつては諦めていたOAuth越しのデータ取得によって新しいデータを利用して、必要であれば補間し、計算量を落とすためにFFT可能にしたい、さらにかつて不要としていたRDBの読み書きも実装したいと理想を追求すればきりがないが、それでも最低限の機能しかそろわない。

大規模な開発ではないので必要性が薄いが、初歩的なテストによって機能の保証も行うようにしたいところだ。

12月第4週の振り返り

12月第4週(12/23-12/29)

年の暮れにあまり目にしたい話題ではないと思うので法医学は折りたたんである。

並列プログラミング

汎用的なLU分解をするにあたってはピボット=対角要素の適切な選択が必要となることは前回のコードの中で示したが、本来LU分解は一回きりのAx=bを満たすxを求めるのではなく任意の b_{i}に対応する解ベクトルx_{i}を効率よく求めるためのものである。そのため一度分解した後はピボット選択の結果を置換行列(permutation matrix)Pとして保持しておき、次からは左から掛けて PAx=Pb\\ LUx=Pb\\ Lc=Pb\\ Ux=cとしてbの行を入れ替えておかなければならない。 \begin{pmatrix}1&0&0\\0&0&1\\0&1&0\end{pmatrix}\begin{pmatrix}b_{1}\\b_{2}\\b_{3}\end{pmatrix}=\begin{pmatrix}b_{1}\\b_{3}\\b_{2}\end{pmatrix}といった演算が本当だが、積を求めるのは明らかに不要だし、置換行列は各行に非零要素を1つしか持たない疎行列なのでメモリも無駄である。「置換前の行列の各行は置換の結果どの行に行けばいいのか」を行数分保持した一次元配列としておけば足りるように思う(結果的に、疎行列の座標リスト=Coordinate方式になる)。

法医学
クリックで展開

医師法では妊娠12週以上の死産児を検案し異常があると認めたときは所轄警察署に届け出なければならないと定められている。胎児の殺害=堕胎罪となりうる可能性もあるため12週未満であっても届け出るのが無難である。

(嬰児が医療行為の介在があっても未だ生育可能でない)妊娠22週未満の時期に母体保護法に基づき母体保護指定医が行う人工妊娠中絶に関しては、堕胎罪にあたらない。

法医診断にあたっては生活能力の有無(流産・堕胎・殺人の判断材料)が重要となる。妊娠週数に応じた身長・体重・胎盤重量の計算式にあてはめて推定する。また呼吸開始により現れる所見(肺の辺縁が丸みを帯びる・泡沫の漏出・肺浮揚)を確認して生産か死産かを判断する。

予期せず分娩が起きることを墜落分娩と呼び、生産児であれば窒息ないし頭部外傷が主要な死因である。

0歳児の事故死のほとんどは窒息であり、行動範囲が広がる1~4歳では交通事故・溺水が多くを占める。

腋窩、側胸部、上腕・大腿内側などの損傷は転倒によって生じることは少なく、他為が疑われる。特異性が極めて高いのが二重条痕である。

乳児の頭部が揺らされる・つかまり立ち中の転倒などにより頭蓋内出血と眼底出血が生じ、昏睡・呼吸不全・死亡に至ることがある。

今年を終えるにあたって

やや短いながらも、これが2019年最後の復習記事となる。来年も精進していきたい。