vscodeでリモート開発をするための環境

vscodeのリモート開発環境構築

  • 研究室の後輩とか向け
  • vscodeのremote development using sshを使用
  • 踏み台サーバを通る必要がある場合の.ssh/configの書き方
  • jupyterとかを使いたいときのポートフォワーディング設定
  • オススメのvscode拡張

とかを書いておく.

vscode remote developmentの導入

これを使うと,研究室のファイルなどがローカルにあるノリで作業できる.
ここの最初らへんが参考になる.

拡張機能Remote-SSHをインストール

f:id:goldfish-man:20201223173116p:plain
remote-ssh

vscodeのサイドバーの四角が4つ組み合わさったアイコンf:id:goldfish-man:20201223173805p:plainから検索

.ssh/configの設定

毎回,目的のipなどをフルで入力しても良いけれど,面倒くさいので設定すると楽
デフォルトのフォーマットは以下のような感じ.

Host alias
    HostName hostname
    User user
  • 接続ポートがデフォルトの22番以外の場合.
port <番号>
  • 踏み台を経由して接続
(Windowsの場合) ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p <踏み台のalias>
(Ubuntuの場合) ProxyCommand ssh <踏み台のalias> -W %h:%p
  • ポートフォワーディングする場合
LocalForward 127.0.0.1:8888 127.0.0.1:8888

Cisco AnyConnectが使いづらいので,代替としてOpenConnectを使う

大学のVPN

大学のVPNで色々と問題があったけれど,なんとか解決できたっぽい.
officialな方法だと使わされるAnyConnectが悪いのかはわからない.
少なくともルーティングの設定などが(そもそも出来るのかしらんけど)分かりにくいのは確か.

問題点

今回の方法で解決できるのは以下の2つの問題.

原因

  • なんでQiitaとかのサイトに繋がらないかはわからん
  • 大学側行きの通信だけ,大学側のゲートウェイに流したいけど,AnyConnectだと設定が弄れなさそう(よくわからん)

解決法(セキュリティ的に問題があったらゴメン)

  1. AnyConnectの代わりにOpenConnect使う
  2. OpenConnectの設定ファイルをいじってルーティングを設定する

以下で手順を解説していく.

手順

OpenConnectのインストール

OpenConnectは

OpenConnect is an SSL VPN client initially created to support Cisco's AnyConnect SSL VPN.

らしい.

こんな感じの画面が開きます.
自分の場合は設定済みなのでServerにTMU-VPNって出てるけど気にしないでください.

f:id:goldfish-man:20201110220651p:plain
GUI画面

OpenConnectの接続設定

File -> Profiles -> New profileから大学のGatewayを入力.
入力したら,Save&Connect押して,そもそも接続できるか試しとくと良いかも.

ルーティング設定

OpenConnectのルーティングの設定はvpnc-script.jsを弄れば良いらしい.
vpnc-script.jsはexeファイルと同じ階層にあった.
25行目のコメントを読むと-1を設定すれば上書きされなさそうなので,

// How to add the default internal route
// -1 - Do not touch default route (but do other necessary route setups)
// 0 - As interface gateway when setting properties
// 1 - As a 0.0.0.0/0 route with a lower metric than the default route
// 2 - As 0.0.0.0/1 + 128.0.0.0/1 routes (override the default route cleanly)

このコメントのすぐ下のコードの0の部分を-1に書き換える.

# 編集前
if (env("REDIRECT_GATEWAY_METHOD")) {
    var REDIRECT_GATEWAY_METHOD = env("REDIRECT_GATEWAY_METHOD");
} else {
    var REDIRECT_GATEWAY_METHOD = 0;
}


# 編集後
if (env("REDIRECT_GATEWAY_METHOD")) {
    var REDIRECT_GATEWAY_METHOD = env("REDIRECT_GATEWAY_METHOD");
} else {
    var REDIRECT_GATEWAY_METHOD = -1;
}

ぱっとみ環境変数を使った方がお行儀が良いかも.
次に-1の場合のルーティングを書き加える.
163行目以降の// Add internal network routesから始まるブロックを参考にしつつ,その下に-1のパターンを追記
IPアドレスとマスクの部分は各自置き換えてください.

// Add internal network routes
echo("Configuring Legacy IP networks:");
if (env("CISCO_SPLIT_INC")) {
    // Waiting for the interface to be configured before to add routes
    if (!waitForInterface()) {
        echo("Interface does not seem to be up.");
    }
    
    for (var i = 0 ; i < parseInt(env("CISCO_SPLIT_INC")); i++) {
        var network = env("CISCO_SPLIT_INC_" + i + "_ADDR");
        var netmask = env("CISCO_SPLIT_INC_" + i + "_MASK");
        var netmasklen = env("CISCO_SPLIT_INC_" + i + "_MASKLEN");
        exec("route add " + network + " mask " + netmask + " " + internal_gw);
    }
} else if (REDIRECT_GATEWAY_METHOD > 0) {
    // Waiting for the interface to be configured before to add routes
    if (!waitForInterface()) {
        echo("Interface does not seem to be up.");
    }
    
    if (REDIRECT_GATEWAY_METHOD == 1) {
        exec("route add 0.0.0.0 mask 0.0.0.0 " + internal_gw + " metric 1");
    } else {
        exec("route add 0.0.0.0 mask 128.0.0.0 " + internal_gw);
        exec("route add 128.0.0.0 mask 128.0.0.0 " + internal_gw);
    }
}
echo("Route configuration done.");

// --------------------------------------追記した部分--------------------------------------
if (REDIRECT_GATEWAY_METHOD == -1) {
    // Waiting for the interface to be configured before to add routes
    if (!waitForInterface()) {
        echo("Interface does not seem to be up.");
    }
    
    exec("route add 大学のIPアドレス mask 大学のマスク " + internal_gw + " metric 1");
}
// --------------------------------------追記終わり--------------------------------------

if (env("INTERNAL_IP6_ADDRESS")) {
    echo("Configuring " + env("TUNIDX") + " interface for IPv6...");
    exec("netsh interface ipv6 set address " + env("TUNIDX") + " " + env("INTERNAL_IP6_ADDRESS") + " store=active");
    echo("done.");

これで,大学行きの通信だけそっちのゲートウェイを使ってくれそう.
設定前と設定後のVPN接続時の,tracert www.youtube.comの結果とか見て,ちゃんとルーティング出来てるか確認してみてください.
(LinuxだったらtracerouteWindowsだったらtracert)

dockerの場所を移動した話

dockerの場所を移動した

dockerはデフォルトで /var/lib/docker にインストールされる.
しかし,様々な理由で(システム用の容量が少ないなど),ここのデータ容量が足りなかったので,別ストレージに移した.
色々な方法がネットに散らばっているが,下のサイトで紹介されているやり方が一番簡単で分かりやすかった.

How to move docker data directory to another location on Ubuntu - guguweb.com

手順

① dockerデーモンを止める

sudo service docker stop

/etc/docker にある daemon.json に以下の内容を追記

{ 
   "graph": "/path/to/your/docker"  
}

自分の場合は,もとからruntimeの設定があったので,

{
    "graph": "/srv/docker",
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

③ データを移動

sudo rsync -aP /var/lib/docker/ /path/to/your/docker

④ 古いディレクトリを一旦リネーム

sudo mv /var/lib/docker /var/lib/docker.old

⑤ dockerデーモンを起動

sudo service docker start

⑥ 確認 docker run hello-world とか色々回してみて問題無さそうだったら,古いdockerファイルを削除

sudo rm -rd /var/lib/docker.old/

AtCoder Beginner Contest 131感想戦

コンテストやったきりで復習しないマンなので,
blogに書くことによって強制的に復習するライフハック()を実践していく.

AtCoder Beginner Contest 131

atcoder.jp

A - Security

https://atcoder.jp/contests/abc131/tasks/abc131_a

解けた.

S = input()
ahead = S[0]
flag = False
for s in S[1:]:
    if s == ahead:
        flag = True
        break
    ahead = s
if flag:
    print("Bad")
else:
    print("Good")

B - Bite Eating

https://atcoder.jp/contests/abc131/tasks/abc131_b

解けた.
0に近い数値を引かなきゃいけないのに,単純にminで取ってしまってちょっと手間取った.

import numpy as np
N, L = map(int, input().split())
taste = [L+i for i in range(N)]
taste = np.array(taste)
print(sum(taste) - taste[np.argmin(np.abs(taste))])

C - Anti-Division

https://atcoder.jp/contests/abc131/tasks/abc131_c

解けた.
最初わかんねぇ!と思ったけど,紙に書いたらn個おきに割り切れるやつが来るので,
その数を引いて,重なってる部分を補正してやれば良いと気づけた.
でも正直もっと良い実装がありそう.

from fractions import gcd

def lcm(x, y):
    return (x * y) // gcd(x, y)

A, B, C, D = map(int, input().split())
if A%C == 0:
    wid = A
else:
    wid = (A//C + 1) * C
if wid > B:
    c_num = 0
else:
    c_num = (B-wid) // C + 1

if A%D == 0:
    wid = A
else:
    wid = (A//D + 1) * D
if wid > B:
    d_num = 0
else:
    d_num = (B-wid) // D + 1

E = lcm(C, D)
if A%E == 0:
    wid = A
else:
    wid = (A//E + 1) * E
if wid > B:
    e_num = 0
else:
    e_num = (B-wid) // E + 1

print(B - A - (c_num + d_num - e_num) + 1)

D - Megalomania

https://atcoder.jp/contests/abc131/tasks/abc131_d

やったぜ,解けた.
感覚的にCの方が難しかった気がする.
締め切り時刻と,締め切り時刻までのコストの和を比較すれば良いと気づけた.

N = int(input())
A = []
B = []
for i in range(N):
    a, b = map(int, input().split())
    A.append(a)
    B.append(b)
tmp = zip(B, A)
B, A = zip(*sorted(tmp))

total = 0
flag = False
for b, a in zip(B, A):
    total += a
    if total > b:
        flag = True
        break
if flag:
    print("No")
else:
    print("Yes")

E, F

わかんなかったorz
D問終わった時点で.40分位残ってたけど20分位椅子を温めて諦めた.
こういうの解けるようになりたいなぁ...

GitHub Desktopでauthentication failedが出た時のメモ

GitHub Desktopでpullは出来るのに,pushをしようとするとauthentication failedが出て,
push出来なかった時にどうやって解決したのかのメモ.

やったこと

  • sshで接続できるかもと思い,githubsshの設定をした
    →結果,解決せず

  • GitHub DesktopのOptionsから,Accountsタブを選びsign out,その後log in
    →治っちゃった...

どうなってるのかサッパリわからん

PythonでOpenCVを使ってHDR画像を生成する

複数のLDR画像からHDR画像を生成する

Python3でOpenCVを使って,複数のLDR画像からHDR画像を生成する.
B4ゼミでやったことのメモ書き的なの.
以下の書いたことの上位互換がOpenCVのtutorial
一応,Debevecさんの論文読んだ時のメモ

環境

  • Python 3.6.8
  • OpenCV 3.3.1
  • NumPy 1.16.2
  • 一応,Jupyterでやっています

処理

自分がやった時は,先輩にもらった3枚のLDR画像を合成した.

モジュールの読み込み

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams["font.size"] = 18

画像の読み込み

最初に,露出を変えて撮影された3枚の画像を読み込む.
後で,逆露光時間(inverce exposure time)が必要になるのでexifで確認しておく.
windowsであれば,エクスプローラーの表示タブの詳細ウィンドウから露出時間を確認する.(プロパティの詳細からでも見れます)

露出時間
露出時間

ldr1_img = cv2.imread(input_dir + "1_window_evaluative_m1EV.JPG")
ldr2_img = cv2.imread(input_dir + "2_window_evaluative_0EV.JPG")
ldr3_img = cv2.imread(input_dir + "3_window_evaluative_p1EV.JPG")
images = [ldr1_img, ldr2_img, ldr3_img]

IETs = np.asarray([1/80, 1/40, 1/20], dtype=np.float32)

CRFの予測・HDRIの生成

HDRI生成アルゴリズムはカメラ応答関数(CRF: camera response function)を使用する.
今回はDebevecのアルゴリズムを使ってCRFを予測する.

calibrate = cv2.createCalibrateDebevec()
response = calibrate.process(images, IETs)

plt.plot(response[:, 0, 0], color="blue", label="blue")
plt.plot(response[:, 0, 1], color="green", label="green")
plt.plot(response[:, 0, 2], color="red", label="red")
plt.legend();

camera response function
camera response function

merge_debevec = cv2.createMergeDebevec()
hdr_img = merge_debevec.process(images, IETs, response)

Tonemapping

HDR画像をそのまま見ても綺麗に見れない.
なので,LDRの環境でHDRの広いレンジを自然に見れるようにトーンマッピングする.
トーンマッピングも色々な方法が考えられていて,OpenCVにも複数パターン実装されている.

  • 一番単純なやつ
tonemap = cv2.createTonemap(2.2)
ldr_img = tonemap.process(hdr_img)
ldr_img = np.clip(ldr_img*255, 0, 255).astype('uint8')
  • Reinhardさんが考案したやつ(論文)
    createTonemapReinhardドキュメント
    一つ目の引数はgamma値だけど,2.2位が多くのディスプレイに合うらしい.
tonemap = cv2.createTonemapReinhard(2.0, 1.0, 0, 0)
ldr_reinhard_img = tonemap.process(hdr_img)
ldr_reinhard_img = np.clip(ldr_reinhard_img*255, 0, 255).astype('uint8')

一応,保存

cv2.imwrite(output_dir + 'ldr.png', ldr_img)
cv2.imwrite(output_dir + "ldr_reinhard.png", ldr_reinhard_img)

結果

ちょっとトーンマップのパラメータを調整した結果.

result
result

AtCoder Beginner Contest 125感想戦

コンテストやったきりで復習しないマンなので,
blogに書くことによって強制的に復習するライフハック()を実践していく.

AtCoder Beginner Contest 125

atcoder.jp

A - Biscuit Generator

https://atcoder.jp/contests/abc125/tasks/abc125_a

解けた.

A, B, T = map(int, input().split())
print(int((T+0.5)//A*B))

まあ,書かれていた通りに実装.
特に何もなかった.

B - Resale

https://atcoder.jp/contests/abc125/tasks/abc125_b

解けた.

import numpy as np
N = int(input())
V = np.array(list(map(int, input().split())))
C = np.array(list(map(int, input().split())))
ans = 0
for i in V-C:
    if(i > 0):
        ans += i
print(ans)

最初読んだ時に,何にもわからん.....DPとか要るんか????
ってなって絶望しかけた.
B問題で要るはずがないと思って考えたら,
価値-コストが正のものだけ選べばということに気づいてAC.
行列同士の引き算とかする時は,本当にNumPyが便利.

C - GCD on Blackboard

https://atcoder.jp/contests/abc125/tasks/abc125_c

解けなかった....
頭ワルワルTLE実装

from functools import reduce

def gcd(a,b):
  while b!=0:
    a,b=b,a%b
  return a

def gcd_list(numbers):
    return reduce(gcd, numbers)

N = int(input())
A = list(map(int, input().split()))

max_ans = 0
for i in range(len(A)):
    tmp = A[:i] + A[1+i:]
    ans = gcd_list(tmp)
    if max_ans < ans:
        max_ans = ans
print(max_ans)

一個を除いた場合の最大公約数なのはわかるけど,
時間を短くする方法を思いつかなかったorz
あと,AtCoderPythonのバージョンが3.4なので,
最大公約数を求めるgcdmathモジュールじゃなくて,
fractionsモジュールにあるのを初めて知った.

Twitterで観測した解法は,

  • 累積最大公約数
  • 数列のテキトーな2要素(1個目と2個目とか)の約数の和集合を取って全探索

の2種類があった気がする.
2つ目の解き方もあー,言われてみればと思ったけど,
今回は1つ目の解き方でお直しした.

def gcd(a,b):
  while b!=0:
    a,b=b,a%b
  return a


N = int(input())
A = list(map(int, input().split()))

# 累積最大公約数的な
head = []
tail = []
head.append(A[0])
tail.append(A[-1])
for i, j in zip(A[1:], A[N-2::-1]):
    head.append(gcd(head[-1], i))
    tail.append(gcd(tail[-1], j))
ans = 0
for i in range(len(head)-2):
    tmp = gcd(head[i], tail[len(tail)-1-2-i])
    if ans < tmp:
        ans = tmp
print(max(head[-1], head[-2], tail[-2], ans))

D - Flipping Signs

https://atcoder.jp/contests/abc125/tasks/abc125_d

解けた.

import numpy as np

N = int(input())
A = np.array(list(map(int, input().split())))

ans = np.zeros(1, dtype=np.uint64)
even_odd = 0
mini = 1000000000

for i in A:
    if(i < 0):
        even_odd = (even_odd + 1) % 2
    ans += abs(i)
    if(mini > abs(i)):
        mini = abs(i)
        
if(even_odd == 0):
    print(ans[0])
else:
    print((ans - (mini * 2))[0])

D問題だし,やっぱ難しいな~と思って紙に書いてたら,
あれ,これ結局マイナスを自由に移動できるから,
最終的に負の数が0か1にしかならないじゃんって気づけた.

結果

result
result