excel 97-2003(xls)作成のたvbaマクロを excel 2016 で実行したら、
実行エラー '3706': プロバイダーが見つかりません。正しくインストールされていない可能性があります。
というエラー。
どうやら、win10では、「Microsoft.Jet.OLEDB.4.0」が利用できないらしく、 「Microsoft.ACE.OLEDB.12.0」への置き換えが必要らしい。
iisサーバでは、logファイルの先頭がコメントになっており、 出力項目は、そちらに記載されています。
$ head -4 u_ex190906.log #Software: Microsoft Internet Information Services 7.5 #Version: 1.0 #Date: 2019-09-06 00:00:00 #Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
Fields | 内容 |
---|---|
date | 日付 |
time | 時刻 |
s-ip | サーバIP |
cs-method | メソッド |
cs-uri-stem | URL (PATH) |
cs-uri-query | URL QUERY (PARAMEMTER) |
s-port | サーバポート |
cs-username | ユーザ名 |
c-ip | ユーザIP |
cs(User-Agent) | ユーザエージェント |
sc-status | HTTPレスポンスコード |
sc-substatus | HTTPレスポンスコード・サブ? |
sc-win32-status | WINDOWS終了コード |
time-taken | 処理時間 |
参考url
SQL::Statement を installする際、 Text::Soundex という初めて見る perl module を見かけた。
https://metacpan.org/pod/Text::Soundex
上記 url の DESCRIPTION によれば、
Soundex is a phonetic algorithm for indexing names by sound, as pronounced in English.
らしく、Soundex アルゴリズムについては、次のurlが参考になります。
が、 SQL::Statement は、Text::Soundex を何の為に利用しているんでしょうね?
そこまでは調べていません。
先日のエントリに関連しますが、 centos8 / rhel8 で openldap-servers がリポジトリから削除され、 yum install できなくなりました。
これにより、OpenAM + OpenLDAP 構築において yum install openldap-servers が利用できなくなった為、 OpenAM用 OpenLDAP from source code の build 手順を記載しておきます。
wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.48.tgz tar -xvf openldap-2.4.48.tgz cd openldap-2.4.48.tgz
less README : REQUIRED SOFTWARE : Base system (libraries and tools): Standard C compiler (required) Cyrus SASL 2.1.21+ (recommended) OpenSSL 0.9.7+ (recommended) Reentrant POSIX REGEX software (required) : SLAPD: BDB and HDB backends require Oracle Berkeley DB 4.4 - 4.8, or 5.0 - 5.1. It is highly recommended to apply the patches from Oracle for a given release.
↑の為、Cyrus SASL , OpenSSL , Berkeley DB を install。
$ wget https://github.com/cyrusimap/cyrus-sasl/releases/download/cyrus-sasl-2.1.27/cyrus-sasl-2.1.27.tar.gz $ tar -xvf cyrus-sasl-2.1.27.tar.gz $ cd cyrus-sasl-2.1.27 $ ./configure --prefix=/usr/local/cyrus_sasl $ make $ make check $ sudo make install $ wget https://www.openssl.org/source/openssl-1.1.1d.tar.gz $ tar -xvf openssl-1.1.1d.tar.gz $ cd openssl-1.1.1d $ ./config --prefix=/usr/local/openssl_1_1_1 $ make $ make test $ sudo make install $ wget https://download.oracle.com/berkeley-db/db-5.1.29.tar.gz $ tar -xvf db-5.1.29.tar.gz $ cd db-5.1.29 $ cd db-5.1.29/build_unix $ ../dist/configure --prefix=/usr/local/BerkeleyDB.5.1 $ make $ sudo make install
まず、先程、installした Cyrus SASL , OpenSSL , Berkeley DB の場所を OpenLDAPが把握できるよう、環境変数を設定。
$ export CPPFLAGS="-I/usr/local/BerkeleyDB.5.1/include -I/usr/local/cyrus_sasl/include -I/usr/local/openssl_1_1_1/include" $ export LDFLAGS="-L/usr/local/BerkeleyDB.5.1/lib -L/usr/local/cyrus_sasl/lib -L/usr/local/openssl_1_1_1/lib" $ export LD_LIBRARY_PATH="/usr/local/BerkeleyDB.5.1/lib:/usr/local/cyrus_sasl/lib:/usr/local/openssl_1_1_1/lib"
$ ./configure --prefix=/usr/local/openldap \ --enable-cleartext=yes \ --enable-crypt=yes \ --enable-rwm=yes \ --enable-overlays=yes \ --enable-modules=yes \ --enable-monitor=yes \ --enable-memberof=mod \ --enable-syncprov=mod \ --enable-unique=mod \ --enable-ppolicy=mod \ --enable-collect=mod \ --with-tls=openssl \ --with-cyrus-sasl $ make depend $ make $ make test $ sudo make install
$ sudo groupadd ldap $ sudo useradd -g ldap ldap $ cd /usr/local/openldap # slapd.conf は、後程、初期設定(slapd.d作成)の為に編集します $ sudo chown root.ldap etc/openldap/slapd.conf $ sudo chmod 644 etc/openldap/slapd.conf # var 以下には、openldap のデータが保存されます $ sudo chown ldap.ldap -R var $ sudo cp -p var/openldap-data/DB_CONFIG.example var/openldap-data/DB_CONFIG $ sudo vi var/openldap-data/DB_CONFIG # Berkeley DB の cache size 変更 org) set_cachesize 0 268435456 1 new) set_cachesize 0 805306368 1 # Berkeley DB への更新が発生後、削除可能であれば削除 set_flags DB_LOG_AUTOREMOVE
$ sudo vi /etc/rsyslog.conf ↓追加 #openldap slapd log local4.* /var/log/slapd/slapd.log $ sudo systemctl restart rsyslog
OpenLDAPの設定は、以前からある slapd.conf でなく slapd.d が推奨されており、 今回は、slapd.conf を slapd.d 用の初期データとして利用します。
# 暗号化されたパスワードを表示させます。 $ /usr/local/openldap/sbin/slappasswd New password: Re-enter new password: {SSHA}cwqMnl8H6x8nxa3jphm3+LbOoUUvHkit ↑この文字列は後から利用する為、メモしておくように $ cd /usr/local/openldap/ $ sudo vi etc/openldap/slapd.conf # 後程、slaptest コマンドにより slapd.conf → slapd.d を自動作成しますが # olcDatabase={1}monitor.ldif , olcDatabase={2}bdb.ldif にある {1}{2}等の # 連番は 「database ~」の記載順になっています。 ↓追加 > include /usr/local/openldap/etc/openldap/schema/cosine.schema > include /usr/local/openldap/etc/openldap/schema/inetorgperson.schema > include /usr/local/openldap/etc/openldap/schema/nis.schema > include /usr/local/openldap/etc/openldap/schema/ppolicy.schema ↓追加 > modulepath /usr/local/openldap/libexec/openldap > # moduleload memberof.la > moduleload syncprov.la > moduleload unique.la > moduleload ppolicy.la > moduleload auditlog.la ↓追加 ( 動的更新である OLC(On-Line Configuration) を利用する為 ) > database config > rootdn cn=admin,cn=config > access to * > by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage > by * break ↓追加 ( monitor 閲覧は manager のみ) > database monitor > access to * > by dn.exact="cn=Manager,dc=sso,dc=xmart-helm,dc=com" read > by * none ↓変更や削除 < database mdb > database bdb < maxsize 1073741824 < suffix "dc=my-domain,dc=com" > suffix "dc=sso,dc=xmart-helm,dc=com" < rootdn "cn=Manager,dc=my-domain,dc=com" > rootdn "cn=Manager,dc=sso,dc=xmart-helm,dc=com" < rootpw secret > rootpw {SSHA}cwqMnl8H6x8nxa3jphm3+LbOoUUvHkit # slapd.conf の書式check $ sudo /usr/local/openldap/sbin/slaptest -u \ -f /usr/local/openldap/etc/openldap/slapd.conf config file testing succeeded # slapd.conf による起動test $ sudo tail -f /var/log/slapd/slapd.log $ sudo /usr/local/openldap/libexec/slapd \ -u ldap -f /usr/local/openldap/etc/openldap/slapd.conf $ ps -ef | less $ sudo kill $SLAPD_PROC_NO # 上記までに問題ないことが確認できた為、slapd.conf をベースに slapd.d を作成 $ sudo mkdir /usr/local/openldap/etc/openldap/slapd.d $ sudo chown ldap.ldap /usr/local/openldap/etc/openldap/slapd.d $ sudo -u ldap /usr/local/openldap/sbin/slaptest \ -f /usr/local/openldap/etc/openldap/slapd.conf \ -F /usr/local/openldap/etc/openldap/slapd.d # ↑こちらが自動生成 ↓こちらが作成されたslapd.dのtest $ sudo /usr/local/openldap/sbin/slaptest -u \ -F /usr/local/openldap/etc/openldap/slapd.d config file testing succeeded # slapd.d 作成により、こちらを参照するはずですが # 念の為、slapd.conf , slapd.ldif を退避 # ( slapd.ldif の利用のされ方は理解していません ) $ sudo mv /usr/local/openldap/etc/openldap/slapd.conf \ /usr/local/openldap/etc/openldap/slapd.conf.20191101 $ sudo rm /usr/local/openldap/etc/openldap/slapd.ldif # slapd.d による起動test $ sudo tail -f /var/log/slapd/slapd.log $ sudo /usr/local/openldap/libexec/slapd \ -u ldap -F /usr/local/openldap/etc/openldap/slapd.d $ ps -ef | less $ sudo kill $SLAPD_PROC_NO
以下は、「入門LDAP/OpenLDAPディレクトリサービス導入・運用ガイド第3版」に 記載の起動scriptを参考にしています。
$ cd /lib/systemd/system $ sudo vi slapd.service [Unit] Description=OpenLDAP Server Daemon After=syslog.target network.target [Service] Type=forking PIDFile=/usr/local/openldap/var/run/slapd.pid #「-h」は待受アドレスの指定. # ldap:/// -> ldap port(389). ldapi:/// -> UnixDomainSocket ExecStart=/usr/local/openldap/libexec/slapd -u ldap -h "ldap:/// ldapi:///" ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill -TERM $MAINPID [Install] WantedBy=multi-user.target $ sudo systemctl enable slapd.service $ sudo systemctl start slapd.service
https://github.com/hiroyuki-sato/openldap-schemas-for-openam
上記urlにある「cn={99}openam.ldif」を投入します。
私の手元環境において、実際には「cn={99}openam.ldif」を少々、変更し 独自カラム追加等を行っています。
$ sudo /usr/local/openldap/bin/ldapmodify \ -Y EXTERNAL -H ldapi:// -D cn=config \ -f cn={99}openam.ldif
schemaが完成すれば、データストア作成 を行い、完了です。
$ vi 2_CREATE_DATA_STORE.ldif dn: dc=sso,dc=xmart-helm,dc=com objectclass: dcObject objectclass: organization o: xmart-helm dc: sso dn: cn=Manager,dc=sso,dc=xmart-helm,dc=com objectclass: organizationalRole cn: Manager dn: ou=People,dc=sso,dc=xmart-helm,dc=com objectClass: organizationalUnit ou: People dn: ou=Groups,dc=sso,dc=xmart-helm,dc=com objectClass: organizationalUnit ou: Groups dn: cn=sidNext,dc=sso,dc=xmart-helm,dc=com cn: sidNext uidNumber: 1 objectClass: uidNext dn: cn=defaultpolicy,dc=sso,dc=xmart-helm,dc=com objectClass: top objectClass: device objectClass: pwdPolicyChecker objectClass: pwdPolicy cn: defaultpolicy pwdAttribute: userPassword dn: cn=HelpDesk,dc=sso,dc=xmart-helm,dc=com objectclass: organizationalRole cn: HelpDesk dn: cn=HelpDesk,cn=HelpDesk,dc=sso,dc=xmart-helm,dc=com objectClass: person cn: HelpDesk sn: HelpDesk userPassword: {SSHA}cwqMnl8H6x8nxa3jphm3+LbOoUUvHkit $ /usr/local/openldap/bin/ldapadd -x -w sasa24ki \ -D cn=Manager,dc=sso,dc=xmart-helm,dc=com \ -f /home/end0tknr/tmp/LDAP/2_CREATE_DATA_STORE.ldif # 上記の確認 $ /usr/local/openldap/bin/ldapsearch -x -b "dc=sso,dc=xmart-helm,dc=com" \ "(objectclass=*)"
「はて?」と思ったら、 openldap-servers は SSLv3に伴う脆弱性(POODLE)の影響で、 非推奨となり、centos8 標準のリポジトリから外れたみたい。
$ sudo yum install openldap-servers [sudo] password for end0tknr: Last metadata expiration check: 0:07:11 ago on Sat 02 Nov 2019 08:16:08 PM JST. No match for argument: openldap-servers Error: Unable to find a match
描画だけの graphviz でなく、 部分構造探索や(フィンガープリントによる)類似性判定を利用したかったので、お試し。
試してみたものの、化学式以外のグラフ構造を描くことができなかった為、 今後、しばらくは使用しない気がします。
普段であれば、source から build (compile)しますが、 軽いインターネット検索による情報からでは上手くいかず、今回は anaconda を利用。
※「Anaconda3-2019.10-Linux-x86_64.sh」が最新でしたが、 私の環境であるcentos8では、インストーラであるこの.shが動作しなかったので 以下のverを利用しています。
※ また、anacondaのインストーラにより .bashrcに環境変数設定等が追記されます
$ wget https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh $ chmod 755 Anaconda3-2019.07-Linux-x86_64.sh $ ./Anaconda3-2019.10-Linux-x86_64.sh : PREFIX=/home/end0tknr/anaconda3 $ cat ~/.bashrc : __conda_setup="$('/home/end0tknr/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)" if [ $? -eq 0 ]; then eval "$__conda_setup" else if [ -f "/home/end0tknr/anaconda3/etc/profile.d/conda.sh" ]; then . "/home/end0tknr/anaconda3/etc/profile.d/conda.sh" else export PATH="/home/end0tknr/anaconda3/bin:$PATH" fi fi unset __conda_setup # <<< conda initialize <<<
## rdkit のchannel から my-rdkit-env という名称の環境を作成し ## rdkit を install $ conda create -c rdkit -n my-rdkit-env rdkit ## my-rdkit-env 環境を起動 $ conda activate my-rdkit-env ## my-rdkit-env 環境を停止 $ conda deactivate ## anaconda install 以降、linux へのlogin時に condaが起動する為 ## 以下のコマンドにより、これを 有効化/無効化 $ conda config --set changeps1 False $ conda config --set changeps1 True
以下のscriptで化学構造式をpngファイルに描画できます。
#!/home/end0tknr/anaconda3/bin/python3 # -*- coding: utf-8 -*- from rdkit import Chem from rdkit.Chem import Draw def main(): save_image_to_file() def save_image_to_file(): mol_0 = Chem.MolFromSmiles("O=C(N)c1ccc[nH0]c1") Draw.MolToFile(mol_0,'mol_0_image.png') mol_1 = Chem.MolFromSmiles("[LDK]") # mol_1 = Chem.MolFromSmiles("O=C") if mol_1 == None: print("invalid mol code") return Draw.MolToFile(mol_1,'mol_1_image.png') if __name__ == '__main__': main()
メモ。 次のurlにまとめられている通り。
「-fPIC」は、Position-Independent Code の略で、shared object作成時のoption。
PIC でcompileされた場合、メインメモリのどこに配置されても、絶対アドレスに関わらず、正しく実行できる。
GitHub - miyamotok0105/pytorch_handbook: pytorch_handbook
上記urlの6章を写経。
deep learning による画像生成とは、GAN を使用しているらしい。
GANの学習不安定を改善する為、その後、DCGANやLSGANが現れたそうですが、 今回、STL-10データを使用し、LSGAN による画像生成を実施。
#!/usr/local/python3/bin/python3 # -*- coding: utf-8 -*- import os # ↓ $ sudo /usr/local/python3/bin/pip install google.colab from google.colab import drive import random import numpy as np # import torch import torch.nn as nn import torch.optim as optim import torch.utils.data import torchvision.datasets as dset import torchvision.transforms as transforms import torchvision.utils as vutils from PIL import Image # 本src内にcopyしました # from net import weights_init, Generator, Discriminator # import matplotlib.pyplot as plt import matplotlib matplotlib.use('Agg') import matplotlib.pylab as plt # google colaboratory なら google drive を mount 可 gdrive_mount_point = None gdrive_path = None #gdrive_mount_point = '/content/gdrive' #gdrive_path = \ # '/content/gdrive/My Drive/Colab Notebooks/pytorch_handbook/chapter6/' workers = 2 batch_size=50 nz = 100 nch_g = 64 nch_d = 64 n_epoch = 200 lr = 0.0002 beta1 = 0.5 outf = './result_lsgan' # LSGANにより作成された画像の保存先 display_interval = 100 device = 'cuda' if torch.cuda.is_available() else 'cpu' def main(): print("DEVICE:", device) avoid_Imabe_colab_bug() mount_and_cd_gdrive() make_output_dir() random.seed(0) # 乱数seed固定 (目的は理解していません) np.random.seed(0) torch.manual_seed(0) (dataloader) = load_train_and_test_data() (netG,netD) = make_generator_and_discriminator() # 贋作生成器と識別器 (optimizerG,optimizerD) = make_optimizer(netG,netD) # optimizer criterion = nn.MSELoss() # 損失関数は平均二乗誤差損失 # 確認用の固定したノイズ fixed_noise = torch.randn(batch_size, nz, 1, 1, device=device) # LSGAN の学習が 1 epoch 進む毎に画像fileを自動保存します train_lsgan(dataloader,netG,netD,optimizerD,optimizerG,criterion,fixed_noise) def make_optimizer(netG,netD): optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999), weight_decay=1e-5) optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999), weight_decay=1e-5) return optimizerG,optimizerD def train_lsgan(dataloader,netG,netD,optimizerD,optimizerG,criterion,fixed_noise): # 学習のループ for epoch in range(n_epoch): for itr, data in enumerate(dataloader): real_image = data[0].to(device) # 元画像 sample_size = real_image.size(0) # 画像枚数 # 正規分布からノイズを生成 noise = torch.randn(sample_size, nz, 1, 1, device=device) # 元画像に対する識別信号の目標値「1」 real_target = torch.full((sample_size,), 1., device=device) # 贋作画像に対する識別信号の目標値「0」 fake_target = torch.full((sample_size,), 0., device=device) ############################ # 識別器Dの更新 ########################### netD.zero_grad() # 勾配の初期化 output = netD(real_image) # 識別器Dで元画像に対する識別信号を出力 # 元画像に対する識別信号の損失値 errD_real = criterion(output, real_target) D_x = output.mean().item() fake_image = netG(noise) # 生成器Gでノイズから贋作画像を生成 # 識別器Dで元画像に対する識別信号を出力 output = netD(fake_image.detach()) # 贋作画像に対する識別信号の損失値 errD_fake = criterion(output, fake_target) D_G_z1 = output.mean().item() errD = errD_real + errD_fake # 識別器Dの全体の損失 errD.backward() # 誤差逆伝播 optimizerD.step() # Dのパラメーターを更新 ############################ # 生成器Gの更新 ########################### netG.zero_grad() # 勾配の初期化 # 更新した識別器Dで改めて贋作画像に対する識別信号を出力 output = netD(fake_image) # 生成器Gの損失値。Dに贋作画像を元画像と誤認させたいため目標値は「1」 errG = criterion(output, real_target) errG.backward() # 誤差逆伝播 D_G_z2 = output.mean().item() optimizerG.step() # Gのパラメータを更新 if itr % display_interval == 0: print('[{}/{}][{}/{}] Loss_D: {:.3f} Loss_G: {:.3f} D(x): {:.3f} D(G(z)): {:.3f}/{:.3f}' .format(epoch + 1, n_epoch, itr + 1, len(dataloader), errD.item(), errG.item(), D_x, D_G_z1, D_G_z2)) if epoch == 0 and itr == 0: # 初回に元画像を保存する vutils.save_image(real_image, '{}/real_samples.png'.format(outf), normalize=True, nrow=10) ############################ # 確認用画像の生成 ############################ # 1エポック終了ごとに確認用の贋作画像を生成する fake_image = netG(fixed_noise) vutils.save_image(fake_image.detach(), '{}/fake_samples_epoch_{:03d}.png'.format(outf, epoch + 1), normalize=True, nrow=10) ############################ # モデルの保存 ############################ if (epoch + 1) % 50 == 0: # 50エポックごとにモデルを保存する torch.save(netG.state_dict(), '{}/netG_epoch_{}.pth'.format(outf, epoch + 1)) torch.save(netD.state_dict(), '{}/netD_epoch_{}.pth'.format(outf, epoch + 1)) def make_generator_and_discriminator(): # 生成器G。ランダムベクトルから贋作画像を生成する netG = Generator(nz=nz, nch_g=nch_g).to(device) netG.apply(weights_init) # weights_init関数で初期化 # print(netG) # 識別器D。画像が、元画像か贋作画像かを識別する netD = Discriminator(nch_d=nch_d).to(device) netD.apply(weights_init) # print(netD) return netG, netD def load_train_and_test_data(): # STL-10のtrain & test data (stl10_binary.tar.gz 2.5GB)を download & read trainset = dset.STL10(root='./dataset/stl10_root', download=True, # labalを使用しない為 # labelなしを混在した'train+unlabeled'を使用 split='train+unlabeled', transform=transforms.Compose([ transforms.RandomResizedCrop(64, scale=(88/96, 1.0), ratio=(1., 1.)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness=0.05, contrast=0.05, saturation=0.05, hue=0.05), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ])) testset = dset.STL10(root='./dataset/stl10_root', download=True, split='test', transform=transforms.Compose([ transforms.RandomResizedCrop(64, scale=(88/96, 1.0), ratio=(1., 1.)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness=0.05, contrast=0.05, saturation=0.05, hue=0.05), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ])) # STL-10の train dataとtest dataを合わせ訓練データとする dataset = trainset + testset # 訓練データをセットしたデータローダを作成 dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=int(workers)) return dataloader def make_output_dir(): try: os.makedirs(outf, exist_ok=True) except OSError as error: print(error) pass # colab固有のerror回避の為らしい def avoid_Imabe_colab_bug(): Image.register_extension = register_extension Image.register_extensions = register_extensions def register_extension(id, extension): Image.EXTENSION[extension.lower()] = id.upper() def register_extensions(id, extensions): for extension in extensions: register_extension(id, extension) def mount_and_cd_gdrive(): if gdrive_mount_point: drive.mount(gdrive_mount_point) os.chdir(gdrive_path) print(os.getcwd()) def weights_init(m): """ ニューラルネットワークの重みを初期化する。 作成したインスタンスに対しapplyメソッドで適用する :param m: ニューラルネットワークを構成する層 """ classname = m.__class__.__name__ if classname.find('Conv') != -1: # 畳み込み層の場合 m.weight.data.normal_(0.0, 0.02) m.bias.data.fill_(0) elif classname.find('Linear') != -1: # 全結合層の場合 m.weight.data.normal_(0.0, 0.02) m.bias.data.fill_(0) elif classname.find('BatchNorm') != -1: # バッチノーマライゼーションの場合 m.weight.data.normal_(1.0, 0.02) m.bias.data.fill_(0) class Generator(nn.Module): """ 生成器Gのクラス """ def __init__(self, nz=100, nch_g=64, nch=3): """ :param nz: 入力ベクトルzの次元 :param nch_g: 最終層の入力チャネル数 :param nch: 出力画像のチャネル数 """ super(Generator, self).__init__() # ニューラルネットワークの構造を定義する self.layers = nn.ModuleDict({ 'layer0': nn.Sequential( nn.ConvTranspose2d(nz, nch_g * 8, 4, 1, 0), # 転置畳み込み nn.BatchNorm2d(nch_g * 8), # バッチノーマライゼーション nn.ReLU() # 正規化線形関数 ), # (B, nz, 1, 1) -> (B, nch_g*8, 4, 4) 'layer1': nn.Sequential( nn.ConvTranspose2d(nch_g * 8, nch_g * 4, 4, 2, 1), nn.BatchNorm2d(nch_g * 4), nn.ReLU() ), # (B, nch_g*8, 4, 4) -> (B, nch_g*4, 8, 8) 'layer2': nn.Sequential( nn.ConvTranspose2d(nch_g * 4, nch_g * 2, 4, 2, 1), nn.BatchNorm2d(nch_g * 2), nn.ReLU() ), # (B, nch_g*4, 8, 8) -> (B, nch_g*2, 16, 16) 'layer3': nn.Sequential( nn.ConvTranspose2d(nch_g * 2, nch_g, 4, 2, 1), nn.BatchNorm2d(nch_g), nn.ReLU() ), # (B, nch_g*2, 16, 16) -> (B, nch_g, 32, 32) 'layer4': nn.Sequential( nn.ConvTranspose2d(nch_g, nch, 4, 2, 1), nn.Tanh() ) # (B, nch_g, 32, 32) -> (B, nch, 64, 64) }) def forward(self, z): """ 順方向の演算 :param z: 入力ベクトル :return: 生成画像 """ for layer in self.layers.values(): # self.layersの各層で演算を行う z = layer(z) return z class Discriminator(nn.Module): """ 識別器Dのクラス """ def __init__(self, nch=3, nch_d=64): """ :param nch: 入力画像のチャネル数 :param nch_d: 先頭層の出力チャネル数 """ super(Discriminator, self).__init__() # ニューラルネットワークの構造を定義する self.layers = nn.ModuleDict({ 'layer0': nn.Sequential( nn.Conv2d(nch, nch_d, 4, 2, 1), # 畳み込み nn.LeakyReLU(negative_slope=0.2) # leaky ReLU関数 ), # (B, nch, 64, 64) -> (B, nch_d, 32, 32) 'layer1': nn.Sequential( nn.Conv2d(nch_d, nch_d * 2, 4, 2, 1), nn.BatchNorm2d(nch_d * 2), nn.LeakyReLU(negative_slope=0.2) ), # (B, nch_d, 32, 32) -> (B, nch_d*2, 16, 16) 'layer2': nn.Sequential( nn.Conv2d(nch_d * 2, nch_d * 4, 4, 2, 1), nn.BatchNorm2d(nch_d * 4), nn.LeakyReLU(negative_slope=0.2) ), # (B, nch_d*2, 16, 16) -> (B, nch_d*4, 8, 8) 'layer3': nn.Sequential( nn.Conv2d(nch_d * 4, nch_d * 8, 4, 2, 1), nn.BatchNorm2d(nch_d * 8), nn.LeakyReLU(negative_slope=0.2) ), # (B, nch_d*4, 8, 8) -> (B, nch_g*8, 4, 4) 'layer4': nn.Conv2d(nch_d * 8, 1, 4, 1, 0) # (B, nch_d*8, 4, 4) -> (B, 1, 1, 1) }) def forward(self, x): """ 順方向の演算 :param x: 元画像あるいは贋作画像 :return: 識別信号 """ for layer in self.layers.values(): # self.layersの各層で演算を行う x = layer(x) return x.squeeze() # Tensorの形状を(B)に変更して戻り値とする if __name__ == '__main__': main()
↑こちらを実行すると、以下の画像ファイルが生成されます。
google colab の gpu付環境で、6時間程、学習させ、80epochの時点で停止させました。 80epochの学習程度では、まだまだといった印象です。
サンプル画像
1epoch後の画像
81epoch後の画像
$ ./foo_6_1.py Traceback (most recent call last): File "./foo_6_1.py", line 7, in <module> from google.colab import drive File "/usr/local/python3/lib/python3.7/site-packages/google/colab/__init__.py", line 25, in <module> from google.colab import auth File "/usr/local/python3/lib/python3.7/site-packages/google/colab/auth.py", line 26, in <module> import sqlite3 as _sqlite3 # pylint: disable=g-bad-import-order File "/usr/local/python3/lib/python3.7/sqlite3/__init__.py", line 23, in <module> from sqlite3.dbapi2 import * File "/usr/local/python3/lib/python3.7/sqlite3/dbapi2.py", line 27, in <module> from _sqlite3 import * ModuleNotFoundError: No module named '_sqlite3'
というエラーが発生。
どうやら、「yum install sqlite-devel」と、python の再installが必要らしい。
$ yum install sqlite-devel # ↓次に既にinstall済のpython moduleの一覧作成 $ sudo /usr/local/python3/bin/pip freeze > requirements.txt # ↓「--enable-loadable-sqlite-extensions」を追加し、python本体の再install $ ./configure --prefix=/usr/local/python3 \ --enable-loadable-sqlite-extensions \ --enable-optimizations $ make $ sudo make install # ↓先程の requirements.txt で python module群も再install $ sudo /usr/local/python3/bin/pip install -r requirements.txt
上記により「ModuleNotFoundError: No module named '_sqlite3'」は解消されました。
ただ、以下のような warning が発生するようになりました。 まぁ、warning ですので、今後、気が向いたら調べます。
$ ./foo_6_1.py /usr/local/python3/lib/python3.7/site-packages/IPython/utils/traitlets.py:5: UserWarning: IPython.utils.traitlets has moved to a top-level traitlets package. warn("IPython.utils.traitlets has moved to a top-level traitlets package.")
https://colab.research.google.com って スゴい
from google.colab import drive drive.mount('/content/gdrive')
google colaboratory for python で↑このように実行後、 ↓こちらのurlへブラウザでアクセスし、そこで表示された 「authorization code」をgoogle colaboratory へ入力するだけ
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=ないしょ Enter your authorization code: ·········· Mounted at /content/gdrive
独自データセットを CNN(AlexNet) で画像分類 - end0tknr's kipple - 新web写経開発 の続きとして 前回エントリの内容を、「CNN(AlexNet) + 転移学習」で実施。
転移学習とは、学習済のモデルを再利用するもので、 今回の場合、CNN(AlexNet) の最終のみ、重みを更新する学習を行っています。
#!/usr/local/python3/bin/python3 # -*- coding: utf-8 -*- import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler from torch.autograd import Variable import numpy as np import torchvision from torchvision import datasets, models, transforms # import matplotlib.pyplot as plt import matplotlib matplotlib.use('Agg') import matplotlib.pylab as plt from PIL import Image import time import os import cv2 from PIL import Image device = 'cuda' if torch.cuda.is_available() else 'cpu' num_epochs = 50 def main(): print("DEVICE:", device) #画像の前処理を定義 data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } #画像とラベルを読み込む data_dir = 'hymenoptera_data' image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']} train_loader = torch.utils.data.DataLoader(image_datasets['train'], batch_size=5, shuffle=True, num_workers=4) test_loader = torch.utils.data.DataLoader(image_datasets['val'], batch_size=5, shuffle=False, num_workers=4) dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes net = models.alexnet(pretrained=True) # 学習済み重みを利用するAlexNet net = net.to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4) # ネットワークのパラメータを凍結 for param in net.parameters(): param.requires_grad = False # backward時に重みを更新させない net = net.to(device) # 最終層を2クラス用(アリ,ハチ)に変更. # 変更することで、最終層はbackward時に重みが更新される num_ftrs = net.classifier[6].in_features net.classifier[6] = nn.Linear(num_ftrs, 2).to(device) # 最適化関数. # lr_schedulerは学習率を変更する為のものらしいが、理解していません criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4) lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1) train_loss_list = [] train_acc_list = [] val_loss_list = [] val_acc_list = [] for epoch in range(num_epochs): train_loss = 0 train_acc = 0 val_loss = 0 val_acc = 0 #train net.train() for i, (images, labels) in enumerate(train_loader): images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = net(images) loss = criterion(outputs, labels) train_loss += loss.item() train_acc += (outputs.max(1)[1] == labels).sum().item() loss.backward() optimizer.step() avg_train_loss = train_loss / len(train_loader.dataset) avg_train_acc = train_acc / len(train_loader.dataset) #val net.eval() with torch.no_grad(): for images, labels in test_loader: images = images.to(device) labels = labels.to(device) outputs = net(images) loss = criterion(outputs, labels) val_loss += loss.item() val_acc += (outputs.max(1)[1] == labels).sum().item() avg_val_loss = val_loss / len(test_loader.dataset) avg_val_acc = val_acc / len(test_loader.dataset) output_str_format = ', '.join(['Epoch [{}/{}]','Loss: {loss:.4f}', 'val_loss: {val_loss:.4f}','val_acc: {val_acc:.4f}', 'lr:{learning_rate}']) print(output_str_format.format(epoch+1, num_epochs, i+1, loss=avg_train_loss, val_loss=avg_val_loss, val_acc=avg_val_acc, learning_rate=optimizer.param_groups[0]["lr"])) #学習率調整 lr_scheduler.step() train_loss_list.append(avg_train_loss) train_acc_list.append(avg_train_acc) val_loss_list.append(avg_val_loss) val_acc_list.append(avg_val_acc) output_to_file(train_loss_list,train_acc_list,val_loss_list,val_acc_list) def output_to_file(train_loss_list,train_acc_list,val_loss_list,val_acc_list): plt.figure() plt.plot(range(num_epochs), train_loss_list, color='blue', linestyle='-', label='train_loss') plt.plot(range(num_epochs), val_loss_list, color='green', linestyle='--', label='val_loss') # plt.ylim([0,0.04]) plt.legend() plt.xlabel('epoch') plt.ylabel('loss') plt.title('Training and validation loss') plt.grid() plt.savefig( 'test_4_1.png' ) plt.figure() plt.plot(range(num_epochs), train_acc_list, color='blue', linestyle='-', label='train_acc') plt.plot(range(num_epochs), val_acc_list, color='green', linestyle='--', label='val_acc') plt.ylim([0,1]) plt.legend() plt.xlabel('epoch') plt.ylabel('acc') plt.title('Training and validation accuracy') plt.grid() plt.savefig( 'test_4_2.png' ) if __name__ == '__main__': main()
↑こう書くと、↓こう出力されます。
DEVICE: cuda Epoch [1/50], Loss: 0.8953, val_loss: 1.2442, val_acc: 0.8366, lr:0.01 : Epoch [20/50], Loss: 0.0634, val_loss: 1.4746, val_acc: 0.8954, lr:0.001 Epoch [21/50], Loss: 0.2592, val_loss: 1.4652, val_acc: 0.8954, lr:0.00010000000000000002 : Epoch [30/50], Loss: 0.2551, val_loss: 1.4208, val_acc: 0.8889, lr:0.00010000000000000002 Epoch [31/50], Loss: 0.2619, val_loss: 1.4198, val_acc: 0.8889, lr:1.0000000000000003e-05 : Epoch [50/50], Loss: 0.2745, val_loss: 1.4169, val_acc: 0.8889, lr:1.0000000000000002e-06
GitHub - miyamotok0105/pytorch_handbook: pytorch_handbook
先日の CNN(AlexNet) エントリの続きで、やはり上記urlの写経。
前回は、CIFAR-10 https://www.cs.toronto.edu/~kriz/cifar.html というバイナリ?で用意されたデータを使用しましたが、 今回は、 https://download.pytorch.org/tutorial/hymenoptera_data.zip にある アリとハチの画像を分類します。
画像のサンプルは以下。
#!/usr/local/python3/bin/python3 # -*- coding: utf-8 -*- import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler from torch.autograd import Variable import numpy as np import torchvision from torchvision import datasets, models, transforms # import matplotlib.pyplot as plt import matplotlib matplotlib.use('Agg') import matplotlib.pylab as plt from PIL import Image import time import os import cv2 from PIL import Image DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu' root = 'hymenoptera_data' num_classes = 2 TRAIN_NUM_EPOCHS = 500 fc_size = 9216 def main(): print("DEVICE:", DEVICE) (data_transforms, to_tensor_transforms) = get_pre_process() # 定義したDatasetとDataLoaderを使います。 custom_train_dataset = CustomDataset(root, data_transforms["train"], train=True) train_loader = torch.utils.data.DataLoader(dataset=custom_train_dataset, batch_size=5, shuffle=True) custom_test_dataset = CustomDataset(root, data_transforms["val"]) test_loader = torch.utils.data.DataLoader(dataset=custom_test_dataset, batch_size=5, shuffle=False) # for i, (images, labels) in enumerate(train_loader): # print(images.size()) # print(images[0].size()) # print(labels[0].item()) # #ここに訓練などの処理をきます。 # break global fc_size # batch_size=10, channel=3, size=224x224 fc_size = get_fc_size( torch.FloatTensor(10, 3, 224, 224) ) print("fc_size:",fc_size) net = AlexNet(num_classes, fc_size).to(DEVICE) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4) (train_loss_list, train_acc_list, val_loss_list, val_acc_list) = \ train_epochs(train_loader, test_loader, net, criterion, optimizer) output_to_file(train_loss_list,train_acc_list,val_loss_list,val_acc_list) def train_epochs(train_loader, test_loader, net, criterion, optimizer): train_loss_list = [] train_acc_list = [] val_loss_list = [] val_acc_list = [] for epoch in range(TRAIN_NUM_EPOCHS): train_loss = 0 train_acc = 0 val_loss = 0 val_acc = 0 #train net.train() for i, (images, labels) in enumerate(train_loader): images, labels = images.to(DEVICE), labels.to(DEVICE) optimizer.zero_grad() outputs = net(images) loss = criterion(outputs, labels) train_loss += loss.item() train_acc += (outputs.max(1)[1] == labels).sum().item() loss.backward() optimizer.step() avg_train_loss = train_loss / len(train_loader.dataset) avg_train_acc = train_acc / len(train_loader.dataset) #val net.eval() with torch.no_grad(): for images, labels in test_loader: images = images.to(DEVICE) labels = labels.to(DEVICE) outputs = net(images) loss = criterion(outputs, labels) val_loss += loss.item() val_acc += (outputs.max(1)[1] == labels).sum().item() avg_val_loss = val_loss / len(test_loader.dataset) avg_val_acc = val_acc / len(test_loader.dataset) output_str_format = ', '.join(['Epoch [{}/{}]','Loss: {loss:.4f}', 'val_loss: {val_loss:.4f}','val_acc: {val_acc:.4f}']) print (output_str_format.format(epoch+1, TRAIN_NUM_EPOCHS, i+1, loss=avg_train_loss, val_loss=avg_val_loss, val_acc=avg_val_acc)) train_loss_list.append(avg_train_loss) train_acc_list.append(avg_train_acc) val_loss_list.append(avg_val_loss) val_acc_list.append(avg_val_acc) return train_loss_list, train_acc_list, val_loss_list, val_acc_list def show_img(img): npimg = img.numpy() # ↓この行は理解できていません # plt.imshow(np.transpose(npimg, (1,2,0)), interpolation='nearest') def get_pre_process(): #画像の前処理 data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), # re-size transforms.RandomHorizontalFlip(), # 反転 transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) #正規化 ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]), } #正規化をしない前処理 to_tensor_transforms = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor() ]) return data_transforms , to_tensor_transforms def get_nn_features(): features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(64, 192, kernel_size=5, padding=2), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(192, 384, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ) return features def get_fc_size( size_check ): features = get_nn_features() #バッチサイズ10, 6×6のフィルターが256枚 #10バッチは残して、6×6×256を1次元に落とす=>6×6×256=9216 print("size1:",features(size_check).size()) #バッチ10の値を軸にして残りの次元を1次元へ落とした場合の #Tensorの形状をチェックすると9216。 print("size2:",features(size_check).view(size_check.size(0), -1).size()) #fc_sizeを全結合の形状として保持 global fc_size fc_size = features(size_check).view(size_check.size(0), -1).size()[1] print("size3:",fc_size) return fc_size def output_to_file(train_loss_list,train_acc_list,val_loss_list,val_acc_list): plt.figure() plt.plot(range(TRAIN_NUM_EPOCHS), train_loss_list, color='blue', linestyle='-', label='train_loss') plt.plot(range(TRAIN_NUM_EPOCHS), val_loss_list, color='green', linestyle='--', label='val_loss') # plt.ylim([0,0.04]) plt.legend() plt.xlabel('epoch') plt.ylabel('loss') plt.title('Training and validation loss') plt.grid() plt.savefig( 'test_4_1.png' ) plt.figure() plt.plot(range(TRAIN_NUM_EPOCHS), train_acc_list, color='blue', linestyle='-', label='train_acc') plt.plot(range(TRAIN_NUM_EPOCHS), val_acc_list, color='green', linestyle='--', label='val_acc') plt.ylim([0,1]) plt.legend() plt.xlabel('epoch') plt.ylabel('acc') plt.title('Training and validation accuracy') plt.grid() plt.savefig( 'test_4_2.png' ) class CustomDataset(torch.utils.data.Dataset): classes = ['ant', 'bee'] def __init__(self, root, transform=None, train=True): self.transform = transform # 指定する場合、前処理クラスを受取り self.images = [] # 画像とlabelの保持用 self.labels = [] # 訓練と検証で、読込むpathを取得 if train == True: root_ants_path = os.path.join(root, 'train', 'ants') root_bees_path = os.path.join(root, 'train', 'bees') else: root_ants_path = os.path.join(root, 'val', 'ants') root_bees_path = os.path.join(root, 'val', 'bees') ant_images = os.listdir(root_ants_path) # アリの画像一覧を取得 ant_labels = [0] * len(ant_images) # アリをlabel=0に指定 bee_images = os.listdir(root_bees_path) # ハチの画像一覧を取得 bee_labels = [1] * len(bee_images) # ハチをlabel=1に指定 # listのmerge for image, label in zip(ant_images, ant_labels): self.images.append(os.path.join(root_ants_path, image)) self.labels.append(label) for image, label in zip(bee_images, bee_labels): self.images.append(os.path.join(root_bees_path, image)) self.labels.append(label) def __getitem__(self, index): image = self.images[index] # indexを元に画像のpathとlabel取得 label = self.labels[index] with open(image, 'rb') as f: # pathから画像読込み image = Image.open(f) image = image.convert('RGB') if self.transform is not None: # 前処理がある場合は入れる image = self.transform(image) return image, label def __len__(self): # ここにはデータ数を指定します。 return len(self.images) class AlexNet(nn.Module): def __init__(self, num_classes, fc_size): super(AlexNet, self).__init__() self.features = get_nn_features() self.classifier = nn.Sequential( nn.Dropout(p=0.5), nn.Linear(fc_size, 4096), #fc_sizeで計算した形状を指定 nn.ReLU(inplace=True), nn.Dropout(p=0.5), nn.Linear(4096, 4096), nn.ReLU(inplace=True), nn.Linear(4096, num_classes) ) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x if __name__ == '__main__': main()
↑こう書くと、↓こう出力されます。
手元のcent os 8 でも実行しましたが、GPUがなく時間がかかる為、 google colaboratory でも実行しています。
$ wget https://download.pytorch.org/tutorial/hymenoptera_data.zip $ unzip hymenoptera_data.zip $ ./foo.py DEVICE: cuda size1: torch.Size([10, 256, 6, 6]) size2: torch.Size([10, 9216]) size3: 9216 fc_size: 9216 Epoch [1/500], Loss: 0.1392, val_loss: 0.1386, val_acc: 0.5061 Epoch [2/500], Loss: 0.1394, val_loss: 0.1386, val_acc: 0.5061 : Epoch [500/500], Loss: 0.0758, val_loss: 0.0612, val_acc: 0.8653
事前の 「$ sudo /usr/local/python3/bin/pip install opencv-python」だけでは、不足らしい。
$ ./foo_4_2.py Traceback (most recent call last): File "./foo_4_2.py", line 21, in <module> import cv2 File "/usr/local/python3/lib/python3.7/site-packages/cv2/__init__.py", line 3, in <module> from .cv2 import * ImportError: libSM.so.6: cannot open shared object file: No such file or directory
とエラーとなった為、以下のように「yum search libSM」で検索し、
$ yum search libSM CentOS-8 - AppStream 189 kB/s | 6.0 MB 00:32 CentOS-8 - Base 910 kB/s | 7.9 MB 00:08 CentOS-8 - Extras 587 B/s | 2.1 kB 00:03 ============================= Name Exactly Matched: libSM ============================= libSM.i686 : X.Org X11 SM runtime library libSM.x86_64 : X.Org X11 SM runtime library libSM.i686 : X.Org X11 SM runtime library libSM.x86_64 : X.Org X11 SM runtime library ============================ Name & Summary Matched: libSM ============================ libsmbios.i686 : Libsmbios C/C++ shared libraries libsmbios.x86_64 : Libsmbios C/C++ shared libraries ================================= Name Matched: libSM ================================= libsmi.i686 : A library to access SMI MIB information libsmi.x86_64 : A library to access SMI MIB information libSM-devel.i686 : X.Org X11 SM development package libSM-devel.x86_64 : X.Org X11 SM development package libsmartcols.x86_64 : Formatting library for ls-like programs. libsmbclient.x86_64 : The SMB client library libsmartcols.i686 : Formatting library for ls-like programs. libsmartcols.x86_64 : Formatting library for ls-like programs. libsmbclient.i686 : The SMB client library libsmbclient.x86_64 : The SMB client library libsmartcols-devel.i686 : Formatting library for ls-like programs. libsmartcols-devel.x86_64 : Formatting library for ls-like programs.
以下のようにinstallし、完了
$ sudo yum install libSM.x86_64
3次元データも1次元に変換し、全結合層への入力データとする為、 3次元データが持つ形状を無視してしまう
3次元データを受け、畳込み(≒フィルタ)演算し、3次元を出力する為、形状を保つ. また、プーリングとは縦横の空間を小さくする演算.
pytorch for pythonによる CIFAR10 に対する画像分類 - end0tknr's kipple - 新web写経開発
上記urlにある先日のエントリはMLPによるものですが、 これをAlexNetで実装すると以下の通り。
#!/usr/local/python3/bin/python3 # -*- coding: utf-8 -*- import torch import torchvision import torch.nn as nn import torch.optim as optim import torch.nn.functional as F import torchvision.transforms as transforms import numpy as np # from matplotlib import pyplot as plt import matplotlib matplotlib.use('Agg') import matplotlib.pylab as plt NUM_CLASSES = 10 # CIFAR10データは、10種類のdata DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu' DATA_DIR = './data/' IMG_SIZE_AND_CHANNEL = 0 TRAIN_NUM_EPOCHS = 30 # 学習回数 #TRAIN_NUM_EPOCHS = 50 # 学習回数 def main(): (train_loader, test_loader) = get_train_test_data() print("train_loader: ", train_loader) print("test_loader: ", test_loader) net = AlexNet(NUM_CLASSES).to(DEVICE) # net = MLPNet().to(DEVICE) (criterion, optimizer) = get_net_criterion_optimizer(net) (train_loss_list, train_acc_list, val_loss_list, val_acc_list) = \ train(train_loader, test_loader, net, criterion, optimizer) output_to_file(train_loss_list, train_acc_list, val_loss_list, val_acc_list) # torch.save(net.state_dict(), 'net.ckpt') # net2 = MLPNet().to(device) # net2.load_state_dict(torch.load('net.ckpt')) # net2.eval() # with torch.no_grad(): # total = 0 # test_acc = 0 # for images, labels in test_loader: # images, labels = images.view(-1, 32*32*3).to(device), labels.to(device) # outputs = net2(images) # test_acc += (outputs.max(1)[1] == labels).sum().item() # total += labels.size(0) # print('精度: {} %'.format(100 * test_acc / total)) def get_train_test_data(): # CIFAR10とは、ラベル付済の5万枚の訓練画像と1万枚のテスト画像のデータセットで # 以下で、STEP1) www.cs.toronto.edu から自動的にダウンロード & 解凍します # STEP2) 画像と正解ラベルのペアを返却 が行われます train_dataset = torchvision.datasets.CIFAR10(root=DATA_DIR, train=True, transform=transforms.ToTensor(), download=True) test_dataset = torchvision.datasets.CIFAR10(root=DATA_DIR, train=False, transform=transforms.ToTensor(), download=True) # 試しに1つの訓練用データの内容を見ると、3チャネル , 32x32size だと分かります image, label = train_dataset[0] # print( image.size() ) # print(label) global IMG_SIZE_AND_CHANNEL IMG_SIZE_AND_CHANNEL = image.size()[0] * image.size()[1] * image.size()[2] # DataLoader() は、batch_size分だけ、画像と正解ラベルを返します train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True, num_workers=2) test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False, num_workers=2) return train_loader, test_loader # MLP ネットワークの定義 # (多層パーセプトロン, 入力層,隠れ層,出力層が全結合である最も単純なdeep learning) class MLPNet (nn.Module): def __init__(self): super(MLPNet, self).__init__() # 32x32size & 3チャネル, 隠れ層のunit数は、600 self.fc1 = nn.Linear(IMG_SIZE_AND_CHANNEL, 600) self.fc2 = nn.Linear(600, 600) self.fc3 = nn.Linear(600, NUM_CLASSES) self.dropout1 = nn.Dropout2d(0.2) self.dropout2 = nn.Dropout2d(0.2) def forward(self, x): x = F.relu(self.fc1(x)) x = self.dropout1(x) x = F.relu(self.fc2(x)) x = self.dropout2(x) return F.relu(self.fc3(x)) class AlexNet(nn.Module): def __init__(self, num_classes): super(AlexNet, self).__init__() self.features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=5), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(64, 192, kernel_size=5, padding=2), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(192, 384, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=2, stride=2), ) self.classifier = nn.Linear(256, num_classes) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x def get_net_criterion_optimizer(net): criterion = nn.CrossEntropyLoss() # 以下のparameterの妥当性は理解していません optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4) return criterion, optimizer def train(train_loader, test_loader, net, criterion, optimizer): #最後にlossとaccuracyのグラフを出力する為 train_loss_list = [] train_acc_list = [] val_loss_list = [] val_acc_list = [] for epoch in range(TRAIN_NUM_EPOCHS): #エポックごとに初期化 train_loss = 0 train_acc = 0 val_loss = 0 val_acc = 0 net.train() #訓練モードへ切り替え #ミニバッチで分割し読込み for i, (images, labels) in enumerate(train_loader): # AlexNetの場合、view()での1次元化変換を行わない images, labels = images.to(DEVICE), labels.to(DEVICE) # #viewで縦横32x32 & 3channelのimgを1次元に変換し、toでDEVICEに転送 # images, labels = \ # images.view(-1,IMG_SIZE_AND_CHANNEL).to(DEVICE),labels.to(DEVICE) optimizer.zero_grad() # 勾配をリセット outputs = net(images) # 順伝播の計算 loss = criterion(outputs, labels) #lossの計算 train_loss += loss.item() #lossのミニバッチ分を溜め込む #accuracyをミニバッチ分を溜め込む #正解ラベル(labels)と予測値のtop1(outputs.max(1))が一致時、1が返る train_acc += (outputs.max(1)[1] == labels).sum().item() #逆伝播の計算 loss.backward() #重みの更新 optimizer.step() #平均lossと平均accuracyを計算 avg_train_loss = train_loss / len(train_loader.dataset) avg_train_acc = train_acc / len(train_loader.dataset) net.eval() #評価モードへ切り替え #評価するときに必要のない計算が走らないようtorch.no_gradを使用 with torch.no_grad(): for images, labels in test_loader: # AlexNetの場合、view()での1次元化変換を行わない images, labels = images.to(DEVICE), labels.to(DEVICE) # images, labels = \ # images.view(-1,IMG_SIZE_AND_CHANNEL).to(DEVICE),labels.to(DEVICE) outputs = net(images) loss = criterion(outputs, labels) val_loss += loss.item() val_acc += (outputs.max(1)[1] == labels).sum().item() avg_val_loss = val_loss / len(test_loader.dataset) avg_val_acc = val_acc / len(test_loader.dataset) # 訓練データのlossと検証データのlossとaccuracyをログ出力. print ("Epoch [{}/{}], Loss: {loss:.4f},val_loss: {val_loss:.4f},val_acc: {val_acc:.4f}" .format(epoch+1, TRAIN_NUM_EPOCHS, i+1, loss=avg_train_loss, val_loss=avg_val_loss, val_acc=avg_val_acc)) train_loss_list.append(avg_train_loss) train_acc_list.append(avg_train_acc) val_loss_list.append(avg_val_loss) val_acc_list.append(avg_val_acc) return train_loss_list,train_acc_list,val_loss_list,val_acc_list def output_to_file(train_loss_list,train_acc_list,val_loss_list,val_acc_list): plt.figure() plt.plot(range(TRAIN_NUM_EPOCHS), train_loss_list, color='blue', linestyle='-', label='train_loss') plt.plot(range(TRAIN_NUM_EPOCHS), val_loss_list, color='green', linestyle='--', label='val_loss') plt.ylim([0,0.04]) plt.legend() plt.xlabel('epoch') plt.ylabel('loss') plt.title('Training and validation loss') plt.grid() plt.savefig( 'test_4_1.png' ) plt.figure() plt.plot(range(TRAIN_NUM_EPOCHS), train_acc_list, color='blue', linestyle='-', label='train_acc') plt.plot(range(TRAIN_NUM_EPOCHS), val_acc_list, color='green', linestyle='--', label='val_acc') plt.ylim([0,1]) plt.legend() plt.xlabel('epoch') plt.ylabel('acc') plt.title('Training and validation accuracy') plt.grid() plt.savefig( 'test_4_2.png' ) if __name__ == '__main__': main()
MLP , AlexNet の実行結果を比較すると、 以下のように CNNである AlexNet の精度が高いことが分かります。
↓こうみたい
="費用:" & TEXT(N44,"#,###") & " × " & I43 & " ="&TEXT(O44,"#,###")