tag:crieit.net,2005:https://crieit.net/users/sgrdk/feed skybee8の投稿 - Crieit Crieitでユーザーskybee8による最近の投稿 2021-04-15T21:21:40+09:00 https://crieit.net/users/sgrdk/feed tag:crieit.net,2005:PublicArticle/16850 2021-04-15T21:19:45+09:00 2021-04-15T21:21:40+09:00 https://crieit.net/posts/KeyBERT KeyBERTでキーフレーズ抽出を試してみる <p>最近キーフレーズ抽出に興味がありいろいろと調べていたら、BERT版のキーフレーズ抽出パッケージがあったので試してみた。ちなみにキーフレーズ抽出とは、「文章からその主題を良く表現している句を抽出する技術」のこと。<br /> 環境は、Docker for Mac を想定。</p> <h1 id="環境設定"><a href="#%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A">環境設定</a></h1> <h2 id="Docker for Macのメモリ制限解放"><a href="#Docker+for+Mac%E3%81%AE%E3%83%A1%E3%83%A2%E3%83%AA%E5%88%B6%E9%99%90%E8%A7%A3%E6%94%BE">Docker for Macのメモリ制限解放</a></h2> <p>Decktopにある<code>Preference</code> -> <code>Advance</code> でMemoryの上限を調整する。KeyBERTをインストールするとPytorchをインストールしようとするが、Dockerのデフォルト設定のままだとメモリ不足でインストールに失敗する。なので、設定を変更してメモリ制限を解除する。今回は12Gに設定した。</p> <h2 id="KeyBERTのインストール"><a href="#KeyBERT%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">KeyBERTのインストール</a></h2> <pre><code class="python">pip install keybert </code></pre> <h2 id="MeCabのインストール"><a href="#MeCab%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">MeCabのインストール</a></h2> <p>KeyBERTは日本語の分かち書きに対応していないため、MeCabを利用する。</p> <pre><code class="python">pip install mecab-python3 pip install unidic-lite </code></pre> <h1 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h1> <p>今回は、Wikipediaのディズニーランドの記事を使ってみる。</p> <pre><code class="python">from keybert import KeyBERT import MeCab doc1 = """ 東京ディズニーランド(とうきょうディズニーランド、英称:Tokyo Disneyland、略称:TDL)は、 千葉県浦安市舞浜にあるディズニーリゾートを形成する日本のディズニーパーク。 年間来場者数は日本最大の約1,800万人で、世界のテーマパーク・アミューズメントパークの中でも、 フロリダ州のウォルト・ディズニー・ワールド・リゾートのマジック・キングダム、カリフォルニア州の ディズニーランド・リゾートのディズニーランド・パークに次いで世界3位の規模を誇る[1]。 オリエンタルランドがウォルト・ディズニー・カンパニーとのライセンス契約のもと運営している[3]。 """ # MeCabで分かち書き words = MeCab.Tagger("-Owakati").parse(doc1) model = KeyBERT('distilbert-base-nli-mean-tokens') print(model.extract_keywords(words, top_n = 10, keyphrase_ngram_range=(1, 1))) </code></pre> <h1 id="結果"><a href="#%E7%B5%90%E6%9E%9C">結果</a></h1> <p>キーフレーズとして「ディズニーランド」が上位に上がってくると思いきや、結果は8番目だった。</p> <pre><code>[('アミューズメント', 0.5486), ('オリエンタル', 0.534), ('ライセンス', 0.5144), ('マジック', 0.4829), ('キングダム', 0.4651), ('フロリダ', 0.4469), ('カンパニー', 0.44), ('日本', 0.4295), ('ディズニー', 0.4252), ('ランド', 0.4068)] </code></pre> <h1 id="ちょっとだけ追加検証"><a href="#%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E3%81%A0%E3%81%91%E8%BF%BD%E5%8A%A0%E6%A4%9C%E8%A8%BC">ちょっとだけ追加検証</a></h1> <p>ちなみに、下記の文章(概要の部分)を追加するとどうなるかというと。。。</p> <pre><code class="python">doc2 = """ 誘致当時の経緯から東京ディズニーシーと共に米国ディズニーグループによる直営ではなく、 日本企業の 株式会社オリエンタルランド が米国ディズニーからのライセンス契約により運営している。 なお、東京ディズニーリゾートで販売されているキャラクターの著作権や版権ビジネスはすべてウォルト・ディズニー・ジャパンが、 アトラクションやショーの企画に関しては、米国ディズニー・パークス・エクスペリエンス・プロダクツおよび米 国ディズニーの子会社であるウォルト・ディズニー・アトラクションズ・ジャパンが担当している。 """ </code></pre> <h2 id="結果2"><a href="#%E7%B5%90%E6%9E%9C2">結果2</a></h2> <p>「ディズニー」が消えてしまった。「エクスペリエンス」って1回して出てきていないんだけど。。</p> <pre><code>[('エクスペリエンス', 0.5799), ('アトラクション', 0.5603), ('アミューズメント', 0.5486), ('オリエンタル', 0.534), ('キャラクター', 0.5154), ('ライセンス', 0.5144), ('プロダクツ', 0.494), ('マジック', 0.4829), ('ジャパン', 0.4752), ('キングダム', 0.4651)] </code></pre> skybee8 tag:crieit.net,2005:PublicArticle/16819 2021-04-05T20:50:12+09:00 2021-04-05T21:17:41+09:00 https://crieit.net/posts/Tesseract-Ubuntu-Docker TesseractをUbuntu(Docker)で試してみる <p>DockerでJupyterLab環境で構築し、その中でTesseractを使って画像から文字を抽出する。</p> <h1 id="DockerでJupyter Lab環境を構築"><a href="#Docker%E3%81%A7Jupyter+Lab%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89">DockerでJupyter Lab環境を構築</a></h1> <h2 id="Dockerfileを作る"><a href="#Dockerfile%E3%82%92%E4%BD%9C%E3%82%8B">Dockerfileを作る</a></h2> <p>任意のフォルダにDockerfileという名前のファイルを作成する。</p> <pre><code class="shell">$ mkdir ~/Desktop/docker_build $ cd Desktop/docker_build/ $ touch Dockerfile </code></pre> <p>Dockerfileの中身</p> <pre><code class="docker">FROM ubuntu:latest # update RUN apt-get -y update && apt-get install -y \ sudo \ wget \ vim #install anaconda3 WORKDIR /opt # download anaconda package and install anaconda # archive -&gt; https://repo.continuum.io/archive/ RUN wget https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh && \ sh /opt/Anaconda3-2019.10-Linux-x86_64.sh -b -p /opt/anaconda3 && \ rm -f Anaconda3-2019.10-Linux-x86_64.sh # set path ENV PATH /opt/anaconda3/bin:$PATH # update pip and conda RUN pip install --upgrade pip WORKDIR / RUN mkdir /work # execute jupyterlab as a default command CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"] </code></pre> <h2 id="Dockerをビルド"><a href="#Docker%E3%82%92%E3%83%93%E3%83%AB%E3%83%89">Dockerをビルド</a></h2> <pre><code class="shell">$ docker build . Successfully built d723190a8650 </code></pre> <h2 id="Dockerを起動"><a href="#Docker%E3%82%92%E8%B5%B7%E5%8B%95">Dockerを起動</a></h2> <pre><code class="shell">$ docker run -p 8888:8888 -v ~/Desktop/ds_python:/work --name my-lab d723190a8650 </code></pre> <p>ブラウザからlocalhost:8888にアクセスしてJupyter Labに入る。</p> <h1 id="Docker上でTesseract"><a href="#Docker%E4%B8%8A%E3%81%A7Tesseract">Docker上でTesseract</a></h1> <h2 id="Tesseractインストール"><a href="#Tesseract%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Tesseractインストール</a></h2> <h3 id="ターミナル起動"><a href="#%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E8%B5%B7%E5%8B%95">ターミナル起動</a></h3> <ul> <li>workディレクトリをクリック</li> <li>File -> New -> Terminal</li> </ul> <h2 id="本体インストール"><a href="#%E6%9C%AC%E4%BD%93%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">本体インストール</a></h2> <p>インストール途中で、ロケーションとタイムゾーンを聞かれるので、Asia、Tokyoを選択</p> <pre><code class="shell">$ sudo apt-get update $ sudo apt install tesseract-ocr $ sudo apt install libtesseract-dev </code></pre> <h2 id="バージョン確認"><a href="#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%A2%BA%E8%AA%8D">バージョン確認</a></h2> <pre><code class="shell">$ tesseract -v tesseract 4.1.0-rc1-184-g497d leptonica-1.75.3 libgif 5.1.4 : libjpeg 8d (libjpeg-turbo 1.5.2) : libpng 1.6.34 : libtiff 4.0.9 : zlib 1.2.11 : libwebp 0.6.1 : libopenjp2 2.3.0 Found AVX2 Found AVX Found SSE </code></pre> <h2 id="訓練済みモジュールインストール"><a href="#%E8%A8%93%E7%B7%B4%E6%B8%88%E3%81%BF%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">訓練済みモジュールインストール</a></h2> <pre><code class="shell">sudo apt install tesseract-ocr-jpn tesseract-ocr-jpn-vert sudo apt install tesseract-ocr-script-jpan tesseract-ocr-script-jpan-vert </code></pre> <p>モジュールがインストールされたか確認</p> <pre><code class="shell">$ tesseract --list-langs List of available languages (6): Japanese Japanese_vert eng jpn jpn_vert osd </code></pre> <h1 id="Tesseract実行"><a href="#Tesseract%E5%AE%9F%E8%A1%8C">Tesseract実行</a></h1> <p>第一引数は画像の名前、第二引数はOCRの結果を出力するファイル名。デフォルトで.txt拡張子が付く。</p> <pre><code class="shell">$ tesseract image.png ocr_out -l jpn </code></pre> <h1 id="PythonでTesseract実行"><a href="#Python%E3%81%A7Tesseract%E5%AE%9F%E8%A1%8C">PythonでTesseract実行</a></h1> <h2 id="pytesseractインストール"><a href="#pytesseract%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">pytesseractインストール</a></h2> <pre><code class="shell">pip install pytesseract </code></pre> <h2 id="pytesseract実行"><a href="#pytesseract%E5%AE%9F%E8%A1%8C">pytesseract実行</a></h2> <pre><code class="python">import Image import pytesseract FILE_NAME = './image.jpg' print(pytesseract.image_to_string(Image.open(FILE_NAME), lang=('jpn')) </code></pre> <h1 id="おまけ"><a href="#%E3%81%8A%E3%81%BE%E3%81%91">おまけ</a></h1> <h2 id="OpenCVでグレースケール変換"><a href="#OpenCV%E3%81%A7%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E5%A4%89%E6%8F%9B">OpenCVでグレースケール変換</a></h2> <h3 id="OpenCVインストール"><a href="#OpenCV%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">OpenCVインストール</a></h3> <pre><code class="shell">$ pip install opencv-python $ apt-get install -y libgl1-mesa-dev </code></pre> <h3 id="グレースケール変換"><a href="#%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E5%A4%89%E6%8F%9B">グレースケール変換</a></h3> <pre><code class="python">import cv2 im = cv2.imread('./image.jpeg') im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) cv2.imwrite('./image_gray.jpeg', im_gray) print(pytesseract.image_to_string(Image.open('./image_gray.jpeg'), lang='jpn')) </code></pre> skybee8 tag:crieit.net,2005:PublicArticle/16818 2021-04-05T16:27:16+09:00 2021-04-05T16:34:35+09:00 https://crieit.net/posts/MMR-Pyspark MMRアルゴリズムをPysparkで実装する <p>レコメンド結果にMMRを適用して多様性を考慮したかった。<br /> 以下のようにPythonで実装されているコードはあったが、Pysparkで実装れているサンプルがなかったので実装してみた。</p> <p><a target="_blank" rel="nofollow noopener" href="https://yolo-kiyoshi.com/2020/05/08/post-1781/">MMR実装を参考にしたページ</a></p> <h2 id="実装コード"><a href="#%E5%AE%9F%E8%A3%85%E3%82%B3%E3%83%BC%E3%83%89">実装コード</a></h2> <h3 id="モジュールインポート"><a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88">モジュールインポート</a></h3> <pre><code class="python">from pyspark.sql import DataFrame as SDF from typing import Set, Callable, List import pyspark.sql.functions as F </code></pre> <h3 id="検索クエリとアイテムリストの類似度結果を取得する関数"><a href="#%E6%A4%9C%E7%B4%A2%E3%82%AF%E3%82%A8%E3%83%AA%E3%81%A8%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E9%A1%9E%E4%BC%BC%E5%BA%A6%E7%B5%90%E6%9E%9C%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0">検索クエリとアイテムリストの類似度結果を取得する関数</a></h3> <pre><code class="python">def sim_func(df: SDF, item_id: int, rec_item_id: int) -> float: min_score = df.filter(F.col('item_id') == item_id).groupBy().min('score').collect()[0][0] try: score = df.filter((F.col('item_id') == item_id) & (F.col('rec_item_id') == rec_item_id)).collect()[0]['score'] except: score = min_score return score </code></pre> <h3 id="選択済みアイテムがオリジナルのアイテムと同じ集合になるまでLOOP"><a href="#%E9%81%B8%E6%8A%9E%E6%B8%88%E3%81%BF%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%81%8C%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%81%AE%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%81%A8%E5%90%8C%E3%81%98%E9%9B%86%E5%90%88%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7LOOP">選択済みアイテムがオリジナルのアイテムと同じ集合になるまでLOOP</a></h3> <pre><code class="python">def mmr(df: SDF, items: Set[int], item_id: int, lambda_: float, sim_func1: Callable[[SDF, int, int], float], sim_func2: Callable[[SDF, int, int]) -> List[int]: def _argmax(keys, f): return max(keys, key=f) selected = [] while set(selected) != items: remaining = items - set(selected) mmr_score = lambda x: labmda_ * sim_func1(df, item_id, x) - (1 - lambda_) * max([sim_func2(df, x, y) for y in set(selected)-{x}] or [0]) next_selected = _argmax(remaining, mmr_score) selected.append(next_selected) return selected </code></pre> <h3 id="MMR実行"><a href="#MMR%E5%AE%9F%E8%A1%8C">MMR実行</a></h3> <pre><code class="python">mmr( df, set(list(df.filter(F.col('item_id') == 12345678).select('rec_item_id').toPandas()['rec_item_id'])), 12345678, 0.8, sim_func, sim_func ) </code></pre> skybee8