MXNet Gluon のLSTMについて

f:id:touch-sp:20190723133956j:plain

>>> model = mx.gluon.rnn.LSTM(512, num_layers=1)
>>> model.initialize()
>>> input = mx.nd.random.uniform(shape=(15,10,200))
>>> h0 = mx.nd.zeros(shape=(1,10,512))
>>> c0 = mx.nd.zeros(shape=(1,10,512))
>>> out, state = model(input, [h0,c0])
>>> out.shape
(15, 10, 512)
>>> state[0].shape
(1, 10, 512)
>>> state[1].shape
(1, 10, 512)
>>> out[14]==state[0]

[[[1. 1. 1. ... 1. 1. 1.]
  [1. 1. 1. ... 1. 1. 1.]
  [1. 1. 1. ... 1. 1. 1.]
  ...
  [1. 1. 1. ... 1. 1. 1.]
  [1. 1. 1. ... 1. 1. 1.]
  [1. 1. 1. ... 1. 1. 1.]]]
<NDArray 1x10x512 @cpu(0)>

outの最後とstate[0]は当然ながら一致する。

Seq2Seq

翻訳などの文章→文章の場合にはEncoderの出力のうち「h」のみをDecoderに渡す場合と「h」「c」の両方を渡す場合が考えられる。下記参考文献(p.297)によると「h」のみを渡すことが一般的らしい。

Image Captioning

Encoderとして学習済みのResNetを使用したモデルをMXNetで書いてみた。

import mxnet as mx
from mxnet.gluon import nn, rnn, Block
from gluoncv.model_zoo import get_model

class Encoder(Block):
    def __init__(self, num_hidden):
        super(Encoder, self).__init__()

        with self.name_scope():
            self.features = get_model('ResNet50_v2', pretrained=False).features
            self.output = nn.Dense(num_hidden)
    
    def forward(self, X):
        out = self.features(X)
        out = self.output(out)
        return out


class Decoder(Block):
    def __init__(self, vocab_size, embed_size, num_hiddens):
        super(Decoder, self).__init__()

        with self.name_scope():
            self.embedding = nn.Embedding(vocab_size, embed_size)
            self.rnn = rnn.LSTM(num_hiddens, num_layers=1)
            self.dense = nn.Dense(vocab_size, flatten=False)

    def forward(self, X, features):
        X = self.embedding(X)
        X = X.swapaxes(0, 1)
        h0 = features.expand_dims(0)
        c0 = mx.nd.zeros_like(h0)
        out, state = self.rnn(X, [h0,c0])
        out = out.swapaxes(0, 1)
        out = self.dense(out)
        return out


class EncoderDecoder(Block):
    def __init__(self, vocab_size, embed_size, num_hiddens):
        super(EncoderDecoder, self).__init__()

        with self.name_scope():
            self.encoder = Encoder(num_hiddens)
            self.decoder = Decoder(vocab_size, embed_size, num_hiddens)

    def forward(self, enc_X, dec_X):
        features = self.encoder(enc_X)
        return self.decoder(dec_X, features)

あらかじめ学習済みパラメーターを保存しておく

from gluoncv.model_zoo import get_model
net = get_model('ResNet50_v2', pretrained=True)
net.features.save_parameters('features.params')

学習済み部分とそうでない部分を別々に初期化する。

import mxnet as mx
net = model.EncoderDecoder(8000, 200, 512)
net.encoder.features.load_parameters('features.params')
net.encoder.output.initialize(mx.init.Xavier())
net.decoder.initialize(mx.init.Xavier())

参考文献

ゼロから作るDeep Learning ? ―自然言語処理編

ゼロから作るDeep Learning ? ―自然言語処理編

10行で物体検出(gluoncv) GPUあり

初めに

03. Predict with pre-trained YOLO models — gluoncv 0.5.0 documentation
今回はデモのみ実行してみた

環境

Windows10 Pro 64bit
NVIDIA GeForce GTX1080
CUDA9.2
cudnn7.2.1
Python3.6.8

mxnet, gluoncvのインストール

pip install mxnet
pip install gluoncv

その他のパッケージはインストール不要

バージョンの確認(pip freeze)

certifi==2019.6.16
chardet==3.0.4
cycler==0.10.0
gluoncv==0.4.0.post0
graphviz==0.8.4
idna==2.6
kiwisolver==1.1.0
matplotlib==3.1.1
mxnet-cu92==1.4.1
numpy==1.16.4
Pillow==6.1.0
pyparsing==2.4.0
python-dateutil==2.8.0
requests==2.18.4
scipy==1.3.0
six==1.12.0
tqdm==4.32.2
urllib3==1.22

実行ファイル

from gluoncv import model_zoo, data, utils
from matplotlib import pyplot as plt

net = model_zoo.get_model('yolo3_darknet53_voc', pretrained=True)

im_fname ='person.jpg'

x, img = data.transforms.presets.yolo.load_test(im_fname, short=512)

class_IDs, scores, bounding_boxs = net(x)

ax = utils.viz.plot_bbox(img, bounding_boxs[0], scores[0],
                         class_IDs[0], class_names=net.classes)

plt.axis('off')
plt.show()

結果

f:id:touch-sp:20190717231815p:plain

GluonCVのpretrained modelについて

学習済みモデル

学習済みモデルを使うことは非常に簡単

from gluoncv.model_zoo import get_model
net = get_model('ResNet50_v2', pretrained=True)

「ImageNet」データセットを使って学習済みとのこと。

>>> len(net.classes)
1000

1000クラス?
「ImageNet」とは言っても「ILSVRC2012」データセットを使っていると思われる。
「ImageNet」と「ILSVRC2012」についてはこちらを参照させて頂いた。
starpentagon.net
「ILSVRC2012」データセットのクラスは動物が多く、人間が含まれない。

モデルの構成

「features」と「output」に分けられる。

>>> a = mx.nd.ones(shape=(1,3,244,244))
>>> out = net(a)
>>> out1 = net.features(a)
>>> out2 = net.output(out1)
>>> out==out2

[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
  1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]]
<NDArray 1x1000 @cpu(0)>

「output」部分を変更してfine-tuneを行う。

画像の前処理

画像の前処理は以下のように行う

from mxnet import image
from gluoncv.data.transforms.presets.imagenet import transform_eval
img = image.imread('COCO_train2014_000000329134.jpg')
img = transform_eval(img)

なかみは以下と同様である

from mxnet import image
from mxnet.gluon.data.vision import transforms

transform_all = transforms.Compose([
        transforms.Resize(256, keep_ratio=True),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
    ])

img = image.imread('COCO_train2014_000000329134.jpg')
img = transform_all(img)
img = pre.expand_dims(0)

ToTensor以降に「uint8」から「float32」に変わるためサイズが大きくなる。
学習する時にメモリに余裕がなければ作業を2回に分けて前半終了時点のデータをメモリにのせるのが良いのではないか?
後半はバッチ毎に毎回処理するので無駄が増えるが・・・。
すべて未処理のままメモリにのせるのも良いが画像を縮小していないのでそれはそれでサイズが大きい。
つまりは最初に画像を縮小しておけば良いのではと思う。

transform_1st = transforms.Compose([
        transforms.Resize(256, keep_ratio=True),
        transforms.CenterCrop(224),
        #transforms.ToTensor(),
        #transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
    ])

transform_2nd = transforms.Compose([
        #transforms.Resize(256, keep_ratio=True),
        #transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
    ])

ちなみにMXNetではRecordIOという形式が推奨されている。(これに関しては不勉強)

画像の縮小

いろいろ方法はあるがgluonを使用して事前学習を忠実に再現する。
JPEGで保存すると圧縮の問題かどうかわからないが後で読み込んだ時に再現出来なかったのでPNGで保存。

import os
from PIL import Image
from mxnet import image
from mxnet.gluon.data.vision import transforms

transform_1st = transforms.Compose([
        transforms.Resize(256, keep_ratio=True),
        transforms.CenterCrop(224),
        #transforms.ToTensor(),
        #transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
    ])

image_dir = 'train2014'
output_dir = 'resize_img'

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

images = os.listdir(image_dir)

num_images = len(images)

for i, filename in enumerate(images):
    name, ext = os.path.splitext(filename)
    new_name = name + '.png'
    img = image.imread(os.path.join(image_dir, filename))
    img = transform_1st(img)
    Image.fromarray(img.asnumpy()).save(os.path.join(output_dir, new_name))

    if (i+1) % 100 == 0:
        print ("[{}/{}] Resized the images and saved into '{}'.".format(i+1, num_images, output_dir))

以下個人的メモ

以下のような使い方を想定している。
まずは画像をバイナリデータとして読み込んでおく。
学習する直前にNDArrayに変換して正規化する。

transform_2nd = transforms.Compose([
        #transforms.Resize(256, keep_ratio=True),
        #transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
    ])

def image_transform(img):
    post = image.imdecode(img)
    post = transform_2nd(post)
    post = post.expand_dims(0)
    return post

with open('D:/downloads/data/resize_img/COCO_train2014_000000579156.png', 'rb') as f:
    img1 = f.read()
with open('D:/downloads/data/resize_img/COCO_train2014_000000000151.png', 'rb') as f:
    img2 = f.read()

image_list = []

image_list.append(image_transform(img1))
image_list.append(image_transform(img2))

result = mx.nd.concat(*image_list, dim=0)

WindowsでMXNet-SSDを使う(GPUあり)

環境

Windows10 Pro 64bit
NVIDIA GeForce GTX1080
CUDA9.2
cudnn7.2.1
Python3.6.8(venv使用)

必要なパッケージのインストール

pip install mxnet-cu92
pip install opencv-python
pip install matplotlib

バージョン確認(pip freeze)

certifi==2019.6.16
chardet==3.0.4
cycler==0.10.0
graphviz==0.8.4
idna==2.6
kiwisolver==1.1.0
matplotlib==3.1.1
mxnet-cu92==1.4.1
numpy==1.16.4
opencv-python==4.1.0.25
pyparsing==2.4.0
python-dateutil==2.8.0
requests==2.18.4
six==1.12.0
urllib3==1.22

MXNetのソースをダウンロード

こちら』から最新のソースコードをダウンロードして解凍

imageのダウンロード

  • 『incubator-mxnet-master/example/ssd/data/demo』フォルダ内に移動してdownload_demo_images.pyの中身を丸々書き換え。
import requests
import os

def download_image(url,filename):
    response = requests.get(url)

    with open(filename,"wb") as fout:
        fout.write(response.content)

if __name__ == "__main__":
    base_url = "https://cloud.githubusercontent.com/assets/3307514/"
    demo_list = {"20012566/cbb53c76-a27d-11e6-9aaa-91939c9a1cd5.jpg":"000001.jpg",
    "20012564/cbb43894-a27d-11e6-9619-ba792b66c4ae.jpg": "000002.jpg",
    "20012565/cbb53942-a27d-11e6-996c-125bb060a81d.jpg": "000004.jpg",
    "20012562/cbb4136e-a27d-11e6-884c-ed83c165b422.jpg": "000010.jpg",
    "20012567/cbb60336-a27d-11e6-93ff-cbc3f09f5c9e.jpg": "dog.jpg",
    "20012563/cbb41382-a27d-11e6-92a9-18dab4fd1ad3.jpg": "person.jpg",
    "20012568/cbc2d6f6-a27d-11e6-94c3-d35a9cb47609.jpg": "street.jpg"}

    for k, v in demo_list.items():

        download_image(base_url + k, v)
  • 実行
python download_demo_images.py

学習済みモデルのダウンロード

  • こちら』のサイト内から学習済みモデルをダウンロードして解凍
  • modelフォルダに中身のみコピー(jsonファイルとparamsファイル)

実行

python demo.py --gpu 0 --images ./data/demo/person.jpg

Windows上のPythonでCOCO APIを使ってみる

はじめに

こちらの記事を参照させて頂いた。
qiita.com

データのダウンロード

今回は試しに「captions_train-val2014.zip」をダウンロードする。
http://msvocds.blob.core.windows.net/annotations-1-0-3/captions_train-val2014.zip
解凍すると「annotations」フォルダのなかに「captions_train2014.json」ファイル、「captions_val2014.json」ファイルがある。

jsonファイルの読み込み

from pycocotools.coco import COCO
coco = COCO('captions_train2014.json')

読み込んだファイルのサイズを見てみる

>>> len(coco.anns)
414113
>>> len(coco.imgs)
82783

82783の画像に対して説明文が414113個。
だいたい1画像に5個の説明文ということがわかる。

一つの画像を見てみる

「57870」は適当な数字。

imgs_keys = coco.imgs.keys()

for key in imgs_keys:
    if coco.imgs[key]['id']==57870:
        print(coco.imgs[key]['flickr_url'])

http://farm4.staticflickr.com/3153/2970773875_164f0c0b83_z.jpg

http://farm4.staticflickr.com/3153/2970773875_164f0c0b83_z.jpg

説明文を見てみる

anns_keys = coco.anns.keys()

for key in anns_keys:
    if coco.anns[key]['image_id']==57870:
        print(coco.anns[key]['caption'])

このように出力される。

A restaurant has modern wooden tables and chairs.
A long restaurant table with rattan rounded back chairs.
a long table with a plant on top of it surrounded with wooden chairs
A long table with a flower arrangement in the middle for meetings
A table is adorned with wooden chairs with blue accents.

大文字から始まったりそうでなかったり。
ピリオドがあったりなかったり。

画像のファイル名を知る

画像ファイルをダウンロードしたと仮定して対応するファイル名を知るには1行でOK。

coco.loadImgs(57870)[0]['file_name']

このように出力される。

'COCO_train2014_000000057870.jpg'

最も長い説明文

>>> coco.anns[776153]['caption']
'A black and white shot shows a  bus interior with windows, hand rail,  and a woman, her
eyes closed, as she holds a bag on her lap, an empty seat, and a second, male passenger,
holding a cell and reaching under his jacket, while holding a suitcase.  '

http://farm4.staticflickr.com/3465/3203708166_dc3078e2ff_z.jpg

最も短い説明文

>>> coco.anns[27468]['caption']
'Person snowboarding down a hill.   '

http://farm8.staticflickr.com/7068/6932931159_14236c1dab_z.jpg

長い説明文を除外する

import nltk

original_token = []

for key in anns_keys:
    caption = coco.anns[key]['caption']
    tokens = nltk.tokenize.word_tokenize(caption.lower())
    if tokens[-1]=='.':
        tokens = tokens[:-1]
    if len(tokens)<=13:
        img_id = coco.anns[key]['image_id']
        a = [coco.loadImgs(img_id)[0]['file_name'], tokens]
        original_token.append(a)

文の最後のピリオドを除いて13単語以下の文章のみ抽出した。
開始文字と終了文字を足してさらにパディングで15単語に統一することを想定している。

>>> len(original_token)
375551

ほとんどの文章が残っているので、もともと説明文は一部を除いて短いことがわかる。

最後に

画像ファイル名とID化した説明文書をリストにして保存。
ついでに「id_to_char」、「char_to_id」も保存。

from pycocotools.coco import COCO
import nltk
import pickle

coco = COCO('annotations/captions_train2014.json')

anns_keys = coco.anns.keys()

original_token = []

for key in anns_keys:
    caption = coco.anns[key]['caption']
    tokens = nltk.tokenize.word_tokenize(caption.lower())
    if tokens[-1]=='.':
        tokens = tokens[:-1]
    if len(tokens)<=13:
        img_id = coco.anns[key]['image_id']
        a = [coco.loadImgs(img_id)[0]['file_name'], tokens]
        original_token.append(a)

from collections import Counter
freq = Counter()

for i in range(len(original_token)):
    freq.update(set(original_token[i][1]))

common = freq.most_common()
vocab = sorted([t for t, c in common if c>=3])
vocab.append('<pad>')
vocab.append('<start>')
vocab.append('<end>')
vocab.append('<unk>')

id_to_word = {i+1:t for i, t in enumerate(vocab)}
word_to_id = {t:i+1 for i, t in enumerate(vocab)}

original_token_id = []

for i in range(len(original_token)):
    sent = ['<start>'] + original_token[i][1] + ['<end>']
    sent_id = [word_to_id[t] if (t in word_to_id) else word_to_id['<unk>'] for t in sent]
    if(len(sent_id)<15):
        sent_id = sent_id + [word_to_id['<pad>']] * (15-len(sent_id))
    original_token_id.append([original_token[i][0], sent_id])

with open('id_to_word.pkl', 'wb') as f:
    pickle.dump(id_to_word, f)

with open('word_to_id.pkl', 'wb') as f:
    pickle.dump(word_to_id, f)

with open('filename_token.pkl', 'wb') as f:
    pickle.dump(original_token_id, f)
>>> len(word_to_id)
10593
>>> len(filename_token)
375551
>>> len(list(set([c[0] for c in filename_token])))
82775

10593単語
375551文章
82775画像

#ファイル名の拡張子をjpgからpngに変更する
import os

png_token = []

for i in range(len(filename_token)):
    name, ext = os.path.splitext(filename_token[i][0])
    new_filename = name + '.png'
    png_token.append([new_filename, filename_token[i][1]])

#ファイル名をID化する
temp_list = list(set([c[0] for c in png_token]))
id_to_image = {i+1:t for i, t in enumerate(temp_list)}
image_to_id = {t:i+1 for i, t in enumerate(temp_list)}

imageid_token = [[image_to_id[c[0]], c[1]] for c in png_token]

#pickleで保存する
with open('id_to_image.pkl', 'wb') as f:
    pickle.dump(id_to_image, f)

with open('image_to_id.pkl', 'wb') as f:
    pickle.dump(image_to_id, f)

with open('imageid_token.pkl', 'wb') as f:
    pickle.dump(imageid_token, f)

#確認
random_num = 300000
id_to_image[imageid_token[random_num][0]]
' '.join([id_to_word[c] for c in png_token[random_num][1]])

これでImage Captioningのデータ準備は終了。

Windowsで「CartoonGAN」を試してみる(GPUあり)

github.com

環境

Windows10 Pro 64bit
NVIDIA GeForce GTX1080
CUDA9.2
cudnn7.2.1
Python3.6.8(venv使用)

Pytorchの導入

今回は古いPytorchをpipで導入する

pip install http://download.pytorch.org/whl/cu92/torch-0.4.1-cp36-cp36m-win_amd64.whl
pip install torchvision==0.2.1

その他のパッケージはインストール不要

バージョン確認(pip freeze)

numpy==1.16.4
Pillow==6.1.0
six==1.12.0
torch==0.4.1
torchvision==0.2.1

コードとモデルのダウンロード

上記GitHubページからすべてのコードをZIPファイルでダウンロードして解凍する。
モデルのダウンロードのみUbuntuを使用。

sh pretrained_model/download_pth.sh

「test.py」の書き換え

60~63行目を以下のように書き換える

  • 修正前
	if opt.gpu > -1:
		input_image = Variable(input_image, volatile=True).cuda()
	else:
		input_image = Variable(input_image, volatile=True).float()
  • 修正後
	if opt.gpu > -1:
		with torch.no_grad():
			input_image = Variable(input_image).cuda()
	else:
		with torch.no_grad():
			input_image = Variable(input_image).float()

実行

my_imgフォルダを作成して画像を入れて、いよいよ実行。

python test.py --input_dir my_img --style Hosoda --gpu 0

結果

  • もと画像

f:id:touch-sp:20190629130059j:plain

  • 変換後

f:id:touch-sp:20190717222930j:plain

警告

  • 今回は無視した。
UserWarning: nn.functional.tanh is deprecated. Use torch.tanh instead.

WindowsでPyTorchの「Image Captioning」を試してみる

github.com

環境

Windows 10 Pro
GPUなし
Python 3.6.8(venv使用)

PyTorchのインストール

今回は古いPytorchをpipで導入する。
非常に簡単。

pip install http://download.pytorch.org/whl/cpu/torch-0.4.1-cp36-cp36m-win_amd64.whl
pip install torchvision==0.2.1

学習済みモデルを試すだけならそれ以外のパッケージは不要

コードとモデルのダウンロード

  • コードのダウンロード

上記GitHubページからすべてのコードをZIPファイルでダウンロードして解凍する。
使用するのは「pytorch-tutorial-master\tutorials\03-advanced」フォルダ内の「image_captioning」フォルダのみ。

  • 学習済みモデルのダウンロード

学習済みモデルはこちらのページの下のほうにある「Pretrained model」の項を参照。

  1. ZIPファイルをダウンロードして解凍する。
  2. 「image_captioning」フォルダの下に「models」フォルダと「data」フォルダを作成してそこに移動する。
  3. モデルの名前を変更する。

「encoder-5-3000.pkl」→「encoder-2-1000.ckpt」
「decoder-5-3000.pkl」→「decoder-2-1000.ckpt」

コードの書き換え

学習済みモデルを試すだけなので不要なパッケージはインストールしていない。
そのためコードの書き換えが必要。

  • build_vocab.py

1行目と5行目をコメントアウトする

#import nltk
import pickle
import argparse
from collections import Counter
#from pycocotools.coco import COCO
  • sample.py

2行目と66, 67行目をコメントアウトする

#import matplotlib.pyplot as plt
    #image = Image.open(args.image)
    #plt.imshow(np.asarray(image))

実行

python sample.py --image png/example.png

ちなみにjpegファイルも受け付ける。

結果

<start> a group of giraffes standing next to each other . <end>

学習

GitHubを忠実に再現すると以下の環境で5epoch学習するのに約4時間かかった。

Windows10 Pro 64bit
Intel(R) Core(TM) i7-7700K
RAM 32.0 GB

NVIDIA GeForce GTX1080
CUDA9.2
cudnn7.2.1

Python3.6.8