2018年12月7日金曜日

UbuntuでWiFiが認識しなかった時の対処法

HPのノートPCを買ったのですが、いざLubuntuに入れ替えるとワイヤレスカードを認識してくれず、WiFiがまったく使えませんでした。 LANコネクタもないモデルだったので使い物にならなくなってしまった。 ググるとHPのノートPCでハマってる人が山のように出てきますね…今後はHPのノートPCはもう少し注意しよう。 とりあえず解決はできたので、同じ事が起きた時にどのように対処すれば良いかまとめておきます。


ワイヤレスカードが認識しない場合、まずは使用しているワイヤレスカードが何かを調べない事にはドライバを入れようがありません。 Ubuntuでは以下のコマンドで調べられます。様々なハードウェア情報が表示されますが、重要なのはNetwork controllerのところ。
$ lspci
:
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)
03:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8821CE 802.11ac PCIe Wireless Network Adapter
:


今回はRTL8821CEを使っているとの事ですが、購入時点ではワイヤレスカードまで調べる事はできないので仕方ありません。 私はLubuntuを使いたいのでLinuxドライバがないか探しました。 見つからなかったらどうしようかと思いましたが、今回は運良く(?)同じワイヤレスカードでハマっている人がたくさん居て情報もたくさんあった上、ドライバを提供してくださっている方が居ました。 感謝しつつこれを使わせて頂きます。


ただこのドライバは内部でDKMSを使っているとの事です。 標準のLubuntuではDKMSが入っていませんから、再びここで困りました。 別環境でdebを作ってインストールしようと思ったら、入れたばかりのLubuntuにはgccすら入っておらず、なんか面倒そうな気配を感じました。 この辺りで諦めの境地に入ってきて、一番安いUSB有線LANアダプタをポチり購入しました。やはりapt-getが使えないと地獄なんだよなあ…。 こういう時のために最低1個はUSB有線LANアダプタは常備しておいたほうが良いかも知れません。 たとえば私は CableCreation のアダプタ を購入しました。

購入したUSB有線アダプタは認識してくれたので、とりあえず有線ならインターネットは使えるようになりました。 ここも認識してくれなかったら手動で依存性解決地獄を乗り越えるしかなかったので、助かった。 まずは速攻でDKMSを入れましょう。
sudo apt-get install dkms

DKMSをインストールした後は、先程のドライバをUSBメモリで送り、Githubの解説に従いつつインストール。 再起動後にきちんとWiFiネットワークに接続できました。


ノートPCが壊れて今回は色々な事をやったのですが、どのマシンでも今までで一番インストールに苦労した気がする。 HDMIが認識しなかったり、GPUの設定でコケまくったりしてました。 何となくの印象ですが、Windows用のドライバしか作らない事でコストカットしてないかなあ。 運用はLinuxじゃないと辛いのだから、そういうの本当に困るし、ハードウェアで躓くのはキツイです。

PlaidML/ROCmは対応ハードに注意

私が普段使ってるDeep LearningのライブラリはKerasなのですが、 今のKerasではGPU処理にCUDAを用いているので、NVIDIAのGPUにしか対応していません。 他のライブラリでも差はあれど今のところは似たような傾向があります。

しかし最近はOpenCLというGPUを含む異種混在環境での標準規格が推進されており、 CUDAは廃れてこちらが主流になるのではないかと思っています。 既にOpenCLに対応したDeep Learning用のライブラリとしてPlaidMLが出てきており、 これを使えばIntel/AMDのGPUも使えるようになってきている。


そんな訳でそろそろ面白いんじゃないかと思って手を出してみたのですが…、甘かった。

私はAMD Radeon Vega 8 Graphicsを動かそうと試してみたのですが、認識しませんでした。 詳しい事はこちらに書きましたが、AMDに関しては購入前からCPU/GPUをきちんと選ばないと動かない事が多そうです。 NVIDIAに関しては純粋に価格帯が高めなので、まともな構成を組もうとすると10万円を軽く超える。 もう少し安く買えたらDeep Learnin専用ノートPCにしようと思ったのですが、まだまだパンピーには早かったようだ…。

PlaidML以外にもドライバ周りからDeep Learningまで総合的にサポートする基盤としてROCmというのもあります。 ただこれも現状では同様にAPUへの対応は弱いし、GPUへの対応も限定的です。 AMD Ryzen 5 2500U / AMD Radeon Vega 8 Graphicsはやはり非対応だったので、これも今回は使えませんでした。 どれも意外と採用条件が厳しいですね。


発展途上だし動かないものは仕方ないのですが、AMDGPU-Pro DriverのせいでOSを何回再インストールしたかわかりません。 AMDのドライバには懲りたので、私はもっと要件の厳しくないライブラリが欲しいです。 でもそれはドライバとの戦いであって、当分は解決されような気もします。 NVIDIAのGPUの価格帯が落ち着いてきたらDeep Learning用マシンを購入したいとは思っているのですが、ドライバ周りも含めて面倒そうな今にわざわざ買う必要はない気もして、ノートPCはひとまずCPUベースで行こうと思いました。 早く廉価なモデルでも気軽にGPGPUできる時代になって欲しいなあ。

LinuxのAPU/GPU周辺は闇

久々にAMDのノートPCを買って気付いたのですが、最近のLinuxのAPU/GPU周りってめちゃくちゃ難しいんですね。 一番クリティカルな部分は、ノートPCでよく使われるAPUはLinuxがサポートしてないところ。

APUへの対応がないと、CPU性能がかなり落ちてしまう。 じゃあAMD APUはLinuxだとただの駄目な子なの?となってしまうのだけど、解決する手段はない事もない。 APUを認識させるためのドライバを用意すれば良いのです。


ただしここで最初の闇です。AMDは純正のAMDGPU-PRO DriverはLinuxに対応していない事が非常に多い。 私はAMD Ryzen 5 2500U / AMD Radeon Vega 8 Graphicsが搭載されたHPのノートPCをLinux化しようとしたのですが、Linuxドライバは非対応でした。

非対応のものにドライバを適用しようとしても、すぐに画面が表示されなくなったり、OSが起動しなくなったりします (闇)。 特に18.04はサポートしてないので間違って入れるとOSが起動しなくなる。 といってサポートのある16.04にしたからといって動く訳でもなく、私は起動後にブラックスクリーンで停止するので、利用は諦めました。


純正ドライバが駄目でもまだ手はあります。それはMesaなどのオープンドライバを利用してハードを認識させる方法です。 Mesaは依存関係が多いので手動インストールは辛そうだけど、PPA経由のapt-getでもインストールできる (下)
sudo add-apt-repository ppa:ubuntu-x-swat/updates
sudo apt update

AMDGPU-Pro Driverでも認識してくれないAMD Ryzen 5 2500UのAPU部分が認識され、mnist_cnn.py の実行時間が10%ほど性能改善していました。 ただもう1つ購入したDELL PCと比較すると、WindowsではCPUスコアに2倍も差がある上に結構なスペック差があるのに (下)、Linuxでの実行時間は25%くらいしか改善してないんですよねえ。 あまり性能を発揮できていないような気はしなくもない (闇)。



今回は運良くAPU部分がほんの少しでも改善できて良かったですが、AMDは購入前に徹底的に調べないと買うの怖いなあと思いました。

低価格PCのコスパが悪くなってる

久々にノートPCが死んで新しいノートPCを買ったのですが、 今って小さくてスペックが良くて安いノートPCがまったくないんですね。 4-5年前に Acer Aspire V5-171-H54C/S が4万円くらいで買えたのに、今5万円以内の小さなノートPCでこれよりスペックが良いものは1つもない。 特にCPUが酷い。 低価格路線のノートPCは下手すれば10年前のノートPCより処理速度が遅いものが普通になってて、全体的に2倍くらい割高の印象があり驚きました。

昔は4-6万円に最もコスパの良いPCが揃っていた気がするのですが、今は6-8万円にそれが移動している。 コスト増加の影響で低価格路線のコスパが悪くなり、今まで若干高めだったところのコスパが良くなったと考えるべきなのか。 それともメモリ/CPU/GPUが割高になっているせいでコスパが最悪になっていると考えるべきなのか。 組立は海外だから後者だとは思うのだけど、いずれにしても良くない傾向です。


メモリ/CPU/GPUが高過ぎて今は高いものを買う気はしないのですが、ノートPCが壊れてしまった以上は買わないといけない。 今回は処理用と作業用で、2台に分けて安物ノートPCを買おうと思っていました。 私は Acer Aspire V5-171-H54C/S と同スペックがあれば作業には困らないので、 そのスペックだけは抑えつつあとは安さだけを追求してDELLの直販モデルを作業用PCとして購入してみました。 キャンペーン中でぴったり4万円なのは良かったけど、到着まで10日待つのは辛かった。何も設定せずベンチマークした結果が以下。



Windowsだと既にIMEの反応が若干悪い気がする…。 不要なサービスを徹底的に切れば2倍は体感性能上げられると思いますが、設定量が多過ぎるので私は速攻でLubuntuに替えました。 なにしろLubuntuは初期状態でのメモリ使用量は300MBもありませんからね。 Lubuntuに替えてからは、普段の作業は非常に快適ですが、Deep LearningやDB処理するとメモリが足りなくて死ぬのが玉に瑕。

2018年12月2日日曜日

Chrome拡張でコピペ禁止を禁止

結構大きなサイトでなぜかコピペが禁止されていて辛みがあり、Chrome拡張でコピペ禁止を禁止する事にしました。 よほど重要なサイトならともかく「なぜここで?」というところはたまにある。

コピペ禁止は例えば以下のような実装パターンがあるけど、JavaScript/CSSの両方を弄らないと対処できない。 以下の4例以外にマウス/タッチイベントをキャプチャするみたいな方法もありそうだけど、実装は見た事がないし作るのは面倒そうなので割愛した。


JavaScriptによるコピペ禁止例

:

JavaScriptによる選択禁止例

:

CSSによる選択禁止例

:

JavaScriptによるキーボード禁止例

:


Chrome拡張での対応は、以前紹介した Minimal User CSS & JavaScript なChrome拡張を作った を拡張する事を前提として話を進める。 ただし "run_at": "document_start" で実行しないといけない点だけは注意して欲しい (参考)。

user.jsに以下を書き加える。
// コピペの禁止を禁止
document.addEventListener('cut', event => event.stopImmediatePropagation(), true);
document.addEventListener('copy', event => event.stopImmediatePropagation(), true);
document.addEventListener('paste', event => event.stopImmediatePropagation(), true);
// 選択の禁止を禁止 (user.cssも変更が必要)
document.addEventListener('selectstart', event => event.stopImmediatePropagation(), true);
// キーボード/マウス/タッチイベントの変更を禁止
// document.addEventListener('keydown', event => event.stopImmediatePropagation(), true);
// document.addEventListener('mousedown', event => event.stopImmediatePropagation(), true);
// document.addEventListener('dragstart', event => event.stopImmediatePropagation(), true);
// document.addEventListener('touchstart', event => event.stopImmediatePropagation(), true);
// document.addEventListener('touchmove', event => event.stopImmediatePropagation(), true);
キーボード/マウス/タッチイベントの変更禁止はリッチUIサイトでは不都合が生じる可能性がある。 普段はこれらをOFFにしておいて、いざ面倒なサイトに遭遇した時だけONにしたほうが良いかも知れない。 逆にサイト管理者がユーザに多少の不都合があったとしてもコピペを禁止したい場合、この辺を弄ると良いと思われる。
その他の指定に関しては常時ONにしておいても良いと思う。 選択の禁止はゲームサイトだと問題になる事はあるかもだけど、せいぜいそれくらいだろう。


user.cssは以下のようにする。
* {
  user-select: auto !important;
  user-drag: auto !important;
}

user-select/user-dragプロパティにはブラウザ特有の値として、-moz-, -webkit-, -khtml-, -ms- などの追加プロパティがある。 様々なブラウザの利用を考えると一番最初に書いたコピペ禁止の実装例のようにすべて指定する必要がある。 ソースを見るのが面倒な人のために書き出すと、以下のように値を指定するべきだ。
-webkit-user-select: text !important;
-webkit-user-drag: auto !important;
:
ただuser-select/user-dragさえ指定しておけばChrome拡張ではきちんと動作する事を確認しているし、 ブラウザ毎に動作が微妙に異なる部分をわざわざ指定するのは面倒なだけだ。 最も簡単な指定さえしておけば (たぶん) 十分だろう。

Chrome拡張で強力なポップアップブロックを作ってみた (3)

HTTPヘッダのContent-Security-Policy (CSP)でもポップアップブロックができる事を知ったので、 その機能を使ってポップアップブロックを作ってみました。 以前作ったもの (下) とほとんど同じ機能がHTTPヘッダでも実現できるんですね。
最低限必要なディレクトリ構造は以下。 以前作ったものに書き加えても良いです。
usercssjs/
  manifest.json
  background.js

manifest.jsonはこんな感じにします。 permissionsとbackgroundが重要で、その他は適当です。
{
  "name": "Minimal User CSS & JavaScript",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": "Minimal User CSS & JavaScript",
  "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
  "background": {
    "scripts": ["background.js"]
  }
}

background.jsはこんな感じにします。CSPにある程度の権限を与えつつ、不要な項目を削除します。 使いたい機能を指定可能なオプションと照らし合わてONにすれば良いです。 ポップアップを防ぎたい場合はallow-popups関連を停止すれば十分ですが、allow-same-originも停止させてみました。
chrome.webRequest.onHeadersReceived.addListener(
  function(details) {
    var headers = details.responseHeaders;
    var csp = {
      name: "content-security-policy",
      value: "sandbox allow-scripts allow-forms allow-presentati
on allow-orientation-lock allow-pointer-lock allow-top-navigation"
    };
    headers.push(csp);
    return {responseHeaders: headers}
  }, {
    urls: ["*://www.hoge.com/*"]
  },
  ["blocking", "responseHeaders"]
);

あとはこの拡張を読み込むだけです。chrome://extensions にアクセスし、上部に表示されている「デベロッパーモード」をONにします。 そして「パッケージ化されていない拡張機能を読み込む...」を押して、usercssjsディレクトリを選択すれば完了です。 普通の拡張のようにパッケージ化していないので、Chrome拡張のファイルを編集後に設定をリロードする事ができます。結構便利。


URLを "<all_urls>" にすればすべてのサイトに適用できますが、やはり不都合が出てきます。 なので以前作ったものと使い勝手は変わらないと思う。 ただDOMを編集するよりはこちらのほうが処理が早そうだし、URLを若干だけどパターンマッチしやすくなっている利点はあるかも。

Chrome拡張でContent-Security-Policyを取得できなくなったかも

HTTPヘッダーのContent-Security-Policy (CSP) でsandboxを設定するはたまに行われる。 これをChrome拡張で編集すると色々とページの動作を変えられて、嬉しい事がある。 指定可能なオプションはこことか見やすい

ただ以前はCSPをChrome拡張で取得できたのだけど、たぶんChrome 70からCSPがヘッダー情報として取得できなくなっていた (編集はできる)。 Chrome拡張はたまに細かい動作が変わったりして「???」となる事があるんだけど、今回もその類かも知れない。

以下は動かなくなったものだけど、これは動かないよというのも大切な事なのでメモを残しておく。 以下のサンプルくらいなら、コンテキストメニューを弄るなど、サイト側に影響を与えない別の方法で機能を提供すれば良いとも思う。
chrome.webRequest.onHeadersReceived.addListener(
  function(info) {
    var headers = info.responseHeaders;
    for (var i=headers.length-1; i>=0; --i) {
      var header = headers[i].name.toLowerCase();
      if (header == 'x-content-security-policy' || header == 'content-security-policy') {
        var values = headers[i].value.split(/ *; */);
        for (var j=0; j<values.length; j++) {
          if (values[j].startsWith('sandbox')) {
            values[j] += ' allow-modals';
            headers[i].value = values.join(';');
            break;
          }
        }
        break;
      }
    }
    return {responseHeaders: headers};
  }, {
    urls: ["<all_urls>"]
  },
  ["blocking", "responseHeaders"]
);

上記のようにwebRequestを弄るようなものはmanifest.jsonに以下の記述を加えないと動かない。 さすがにその間違いはしてない。
"permissions": ["webRequest", "webRequestBlocking", "<all_urls>"],
"background": {
  "scripts": ["background.js"]
},

今は駄目でも、気付いたら動くようになってるかも知れない。そういう事もよくある。 ただ直近数日で色々な機能が豪快に挙動が変わったみたいだ。