わかりやすいパターン認識(第2版)の書評

本書は1998年に発売された『わかりやすいパターン認識』の改訂版であり,全体を通して統計的パターン認識の基礎が「わかりやすい」筆致でまとめられている。本書は全9章から構成されている。パターン認識の考え方(第1章)から始まり,識別関数の学習・評価・設計法(第2~4章),特徴抽出・次元削減(第5~7章)など,統計的パターン認識の分野における基礎的かつ重要な話題が精選されている。第8章では期待損失学習,第9章ではベイズ決定則と学習アルゴリズムの関係など,高度な話題にも触れられている。「統計的パターン認識ベイズ決定則を土台とする一学問」というフレーズには、改訂前から強い感銘を受けた。

改訂前後の大きな違いは,各章に数値計算・実験例や演習問題が数多く追加されていることである。例えば第2章には,パーセプトロンの学習過程が具体的な数値例とともに説明されており,第3章には3層ニューラルネットの実験例などが追加されている。演習問題では,具体的な数値例を与えて学習アルゴリズムの動作を確認させるものや,本文中の数式を具体的に導出させるものがある。詳細な解答例を載せたPDFが出版社のサポートページで公開されているのがありがたい。著者らの知見やノウハウを述べたCoffee Breakの欄にも加筆修正がされており,深層学習についても触れられている。「むすび」には,旧版以降に出版された参考書がコメントつきで紹介されており,初学者への良き指針となるだろう。

旧版は近年の深層学習・機械学習ブーム以前に発行されているが,本改訂で新たな章を割いて取り入れた話題はない。ただし深層学習を理解する上で重要な,「浅い」ニューラルネットであるパーセプトロンや3層ニューラルネット誤差逆伝播法などに多くの紙面を割いて説明しており,本書発行の主旨を考えれば欠点にはあたらない。本書で取り上げられるトピックは技術の進展を経ても陳腐化しないものばかりが精選されているのである。

パターン認識に関心を持つ各位に本書の一読を広く薦めたい。

現在開いているページのewwバッファを複製する

ewwを起動中、以下の関数を実行する。
すると、現在のページのURLを引き継いで新しくewwバッファが作成される。

(defun eww-duplicate-buffer ()
  "Duplicate current eww buffer."
  (interactive)
  (let ((url (plist-get eww-data :url)))
    (with-current-buffer (clone-buffer)
      (eww (if (consp url) (car url) url)))))

リージョンをクオートやブラケットで囲う(Emacsのselected.elを利用)

以下の記事を参考に、リージョンを{クオートやブラケット}で囲うelispをselectedを使って書いてみたということ。

リージョンを選択し、クオートやブラケットの記号を一つ押すだけで、リージョン全体が囲えるので便利である。

selected.elはMELPAからインストール可能。もしくは以下からダウンロード。

コードはこんな感じ。オリジナルの記事ではバッククオートがなかったため、新たに追加してみた。応用すれば、ブレースなど他の記号でも実現できるだろう。

(defun region-to-single-quote ()
  (interactive)
  (quote-formater "'%s'" "^\\(\"\\).*" ".*\\(\"\\)$"))
(defun region-to-double-quote ()
  (interactive)
  (quote-formater "\"%s\"" "^\\('\\).*" ".*\\('\\)$"))
(defun region-to-back-quote ()
  (interactive)
  (quote-formater "`%s`" "^\\('\\).*" ".*\\('\\)$"))
(defun region-to-bracket ()
  (interactive)
  (quote-formater "\(%s\)" "^\\(\\[\\).*" ".*\\(\\]\\)$"))
(defun region-to-square-bracket ()
  (interactive)
  (quote-formater "\[%s\]" "^\\(\(\\).*" ".*\\(\)\\)$"))
(defun region-to-brace ()
  (interactive)
  (quote-formater "\%s\]" "^\\(\(\\).*" ".*\\(\)\\)$"))
(defun quote-formater (quote-format re-prefix re-suffix)
  (if mark-active
      (let* ((region-text (buffer-substring-no-properties
                           (region-beginning) (region-end)))
             (replace-func
              (lambda (re target-text)
                (replace-regexp-in-string re "" target-text nil nil 1)))
             (text (funcall replace-func re-suffix
                            (funcall replace-func re-prefix region-text))))
        (delete-region (region-beginning) (region-end))
        (insert (format quote-format text)))
    (error "Not Region selection")))

(when (require 'selected nil t)
  ;; リージョンをシングルクオートで囲う
  (define-key selected-keymap (kbd "\'") #'region-to-single-quote)

  ;; リージョンをダブルクオートで囲う
  (define-key selected-keymap (kbd "\"") #'region-to-double-quote)

  ;; リージョンバッククオートで囲う
  (define-key selected-keymap (kbd "\`") #'region-to-back-quote)

  ;; リージョンをブラケット(カッコ)で囲う
  (define-key selected-keymap (kbd "(") #'region-to-bracket)

  ;; リージョンをカギカッコで囲う
  (define-key selected-keymap (kbd "[") #'region-to-square-bracket))

リージョンで囲った文字列を対象にgoogle翻訳を呼び出す(Emacs)

以下の記事では、「selected」という、リージョンで囲われた文字列を対象に様々な関数を1キーストロークで発動できるパッケージの紹介がされている。

同記事では対象の文字列に対してgoogle検索を呼び出す方法も紹介されているが、ここではgoogle翻訳を呼び出すのが目的である。

MELPAよりgoogle-translateというパッケージをインストールした上で、以下の関数を定義する。

;; https://solist.work/blog/posts/google-translate/
;; https://w.atwiki.jp/ntemacs/pages/86.html
;; http://emacs.rubikitch.com/google-translate/
;; で紹介されていた関数をアレンジ
(defvar google-translate--english-chars "[:ascii:]’“”–")
(defvar google-translate--target-text "")
(defun google-translate-auto ()
  "Automatically recognize and translate Japanese and English."
  (interactive)
  (cond ((use-region-p)
         (setq google-translate--target-text
               (replace-regexp-in-string
                "\\([^\n]\\)\n\\([^\n]\\)" "\\1 \\2"
                (replace-regexp-in-string
                 "^\s*\\(.*?\\)\s*$" "\\1"
                 (funcall region-extract-function nil))))
         (deactivate-mark)
         (when (fboundp 'cua-cancel)
           (cua-cancel)))
         (t
          (setq google-translate--target-text
                (read-string "Google Translate: "))))
  (if (string-match
       (format "\\`[%s]+\\'" google-translate--english-chars)
       google-translate--target-text)
      (google-translate-translate "en" "ja" google-translate--target-text)
    (google-translate-translate "ja" "en" google-translate--target-text)))

この関数のミソは、google翻訳にかける前に「改行」を削除していることである。また日本語と英語を自動判別する機能もついているので、便利に使えるだろう。

そして以下の設定を書く。

(when (require 'selected nil t)
  (define-key selected-keymap (kbd "t") #'google-translate-auto)
  (selected-global-mode 1))

すると、リージョンに文字列が囲われた状態で、t を押下すればgoogle translateからの翻訳結果が帰ってくる(*Google Translate*バッファ)。

ewwを使っていたら「error in process filter: Invalid image type ‘svg’」というエラーが出たとき

ewwでリンク先のページに飛んだ時、表題のエラーに出会うことがある。 これはEmacssvgをサポートする形でコンパイルされていないから、ということ。 しかしeww(というかshr)はsvgが使える前提で一部の関数が実装されているのが問題。

当面、以下の関数を再定義して、しのぐことにする。 オリジナルの関数からの変更点は、(memq 'svg image-types)を関数後部あたりに入れたこと。

(defun shr-parse-image-data ()
  (let ((data (buffer-substring (point) (point-max)))
        (content-type
         (save-excursion
           (save-restriction
             (narrow-to-region (point-min) (point))
             (let ((content-type (mail-fetch-field "content-type")))
               (and content-type
                    ;; Remove any comments in the type string.
                    (intern (replace-regexp-in-string ";.*" "" content-type)
                            obarray)))))))
    ;; SVG images may contain references to further images that we may
    ;; want to block.  So special-case these by parsing the XML data
    ;; and remove anything that looks like a blocked bit.
    (when (and shr-blocked-images
               (eq content-type 'image/svg+xml))
      (setq data
            ;; Note that libxml2 doesn't parse everything perfectly,
            ;; so glitches may occur during this transformation.  And
            ;; encode as utf-8: There may be text (and other elements)
            ;; that are non-ASCII.
            (shr-dom-to-xml
             (libxml-parse-xml-region (point) (point-max)) 'utf-8)))
    ;; SVG images often do not have a specified foreground/background
    ;; color, so wrap them in styles.
    (when (and (display-images-p)
               (eq content-type 'image/svg+xml)
               (memq 'svg image-types)) ;; ←SVGが含まれていないときにnil
      (setq data (svg--wrap-svg data)))
    (list data content-type)))

第2弾:Waveデータに対するLSB置換法に基づくステガノグラフィ by Python (バグ修正済)

表題の通り。

今回も外部パッケージの力を借りてLSB置換法に基づくステガノグラフィを試してみた。
参考にしたのは以下のリポジトリである(Steganography/stego_lsb)。

トルエンディアン環境で正常に動作するよう、バグを修正したPythonコードを以下に置いた。
https://gist.github.com/tam17aki/fa084a9e698ffd255791750b923cdc8c

下記の内容が書かれたテキストファイルをまるごと、waveデータに埋め込んでみた(utf-8)。

A01	あらゆる 現実を すべて 自分の ほうへ ねじ曲げたのだ。
A02	一週間ばかり ニューヨークを 取材した。
A03	テレビゲームや パソコンで ゲームを して 遊ぶ。
A04	物価の 変動を 考慮して 給付水準を 決める 必要がある。
A05	救急車が 十分に 動けず 救助作業が 遅れている。
A06	言論の 自由は 一歩 譲れば 百歩も 千歩も 攻めこまれる。
A07	会場の 周辺には 原宿駅や 代々木駅も あるし ちょっと 歩けば 新宿御苑駅も ある。
A08	老人ホームの 場合は 健康器具や ひざ掛けだ。
A09	ちょっと 遅い 昼食を とるため ファミリーレストランに 入ったのです。
A10	嬉しいはずが ゆっくり 寝ても いられない。

出典:http://research.nii.ac.jp/src/ATR503.html

結果は次の通り。元の音声(host.wav)とメッセージが埋め込まれた音声(stego_lsb.wav) (初回はロードが入り冒頭の音が欠けるので再生は2回目以降)。
メッセージが埋め込まれることによる音質の劣化は確認できないので、優れた手法のように思える。しかしながら、この手法は「攻撃」に弱いのが欠点である。