Xavierの初期値 Heの初期値の考察
ゼロから作るDeep Learning 第6章を参考に、ニューラルネットワークの隠れ層のアクティベーション(活性化関数の出力)の分布を確認してみます。
次のプログラムは1000件のサンプル(1つのサンプルは100次元のベクトル)を、5層の隠れ層(ノードはすべて100)に流すものです。
import numpy as np import matplotlib.pyplot as plt def sigmoid(x): return 1 / (1 + np.exp(-x)) def tanh(x): return np.tanh(x) def relu(x): return np.maximum(0, x) def show_activation(activation, weights, ylim=(0, 50000)): x = np.random.randn(1000, 100) node = 100 hidden = 5 activations = {} for i in range(hidden): if i != 0: x = activations[i - 1] w = weights(node) z = np.dot(x, w) a = activation(z) activations[i] = a plt.figure(figsize=(18, 4)) for i, a in activations.items(): plt.subplot(1, len(activations), i + 1) plt.title(str(i + 1) + "-layer") plt.hist(a.flatten(), 30, range=(0,1)) plt.ylim(ylim) plt.show() show_activation(sigmoid, lambda n: np.random.randn(n, n) * 1) # show_activation(sigmoid, lambda n: np.random.randn(n, n) * 0.01) # show_activation(sigmoid, lambda n: np.random.randn(n, n) * np.sqrt(1.0 / n), (0, 10000)) # Xavier # show_activation(relu, lambda n: np.random.randn(n, n) * 0.01, (0, 7000)) # show_activation(relu, lambda n: np.random.randn(n, n) * np.sqrt(1.0 / n), (0, 7000)) # Xavier # show_activation(relu, lambda n: np.random.randn(n, n) * np.sqrt(2.0 / n), (0, 7000)) # He
このプログラムでは重みのスケールを標準偏差1のガウス分布としています。
show_activation(sigmoid, lambda n: np.random.randn(n, n) * 1)
以降、重みを変更するとアクティベーションにどのような変化を及ぼすか確認していきます。
標準偏差1の場合
標準偏差1の実行結果は次のようになります。
アクティベーションが0と1に偏っているのがわかります。sigmoid関数の出力が0に近くにつれて(あるいは1に近くづにつれて)、その微分の値は0に近づきます。そのため、0と1に偏った分布では逆伝搬での勾配の値が小さくなってしまいます。このような現象は「勾配消失問題(gradient vanishing)」と呼ばれます。
標準偏差0.01の場合
次は重みのスケールを標準偏差0.01のガウス分布としています。
show_activation(sigmoid, lambda n: np.random.randn(n, n) * 0.01)
結果は次のようになります。
0.5付近に集中するようになりました。勾配消失問題は解消できましたが、アクティベーションに偏りがあるということは表現力が乏しいということです。複数のニューロンが同じような出力をするのであれば、ニューロンが複数存在する意味が失われてしまいます。「表現力の制限」が問題になってしまいます。
Xavierの初期値の場合
次にXavier Glorotの初期値を試してみます。これは前層のノード数が n の場合 1/sqrt(n) を標準偏差とした分布を使うというものです。
Kerasの場合はglorot_uniform、florot_normalのような初期値が定義されています。
show_activation(sigmoid, lambda n: np.random.randn(n, n) * np.sqrt(1.0 / n), (0, 10000)) # Xavier
結果は次のようになります。
これまでの結果に比べてばらつきのある結果を得ることができました。「勾配消失問題」や「表現力の制限」といった問題を上手く回避できているのがわかります。
ReLU関数の場合
ここまでsigmoid関数のアクティベーションを見てきました。ReLU関数の場合はどうでしょうか。
標準偏差0.01の場合
show_activation(relu, lambda n: np.random.randn(n, n) * 0.01, (0, 7000))
Xavierの初期値の場合
show_activation(relu, lambda n: np.random.randn(n, n) * np.sqrt(1.0 / n), (0, 7000)) # Xavier
ReLU関数の場合、Xavierの初期値を使ったとしても、層が深くなるにつれて偏りが大きくなります。そこでReLU関数の場合はHeの初期値を使うことでこのようなケースに対処できます。Heの初期値は sqrt(2.0 / n)を標準偏差とするものです。ReLU関数の場合、負の領域がすべて0になるため、ばらつきにより広がりを持たせるために、2倍にすると考えます。
Heの初期値の場合
show_activation(relu, lambda n: np.random.randn(n, n) * np.sqrt(2.0 / n), (0, 7000)) # He
実行結果を見ていましょう。
Heの初期値を使えば偏りのないアクティベーションを確認することができました。
Kerasで画像認識 - MNIST編 - ReLU関数
KerasのMNISTのサンプルプログラムについて、活性化関数をsigmoid関数からReLU関数に変更してみましょう。
from keras.models import Sequential from keras.layers import Dense, Activation from keras.utils import to_categorical from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() # 28x28 => 784 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) # one-hot ex: 3 => [0,0,0,1,0,0,0,0,0,0] y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) model = Sequential() model.add(Dense(50, input_dim=784)) model.add(Activation('relu')) model.add(Dense(20)) model.add(Activation('relu')) model.add(Dense(10)) model.add(Activation('softmax')) model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=32, validation_data=(x_test, y_test))
プログラムを実行してみると、、学習が上手くいかないようです。
Train on 60000 samples, validate on 10000 samples Epoch 1/10 60000/60000 [==============================] - 10s - loss: 14.5407 - acc: 0.0977 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 2/10 60000/60000 [==============================] - 7s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 3/10 60000/60000 [==============================] - 7s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 4/10 60000/60000 [==============================] - 6s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 5/10 60000/60000 [==============================] - 6s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 6/10 60000/60000 [==============================] - 6s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 7/10 60000/60000 [==============================] - 7s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 8/10 60000/60000 [==============================] - 6s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 9/10 60000/60000 [==============================] - 7s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982 Epoch 10/10 60000/60000 [==============================] - 7s - loss: 14.5487 - acc: 0.0974 - val_loss: 14.5353 - val_acc: 0.0982
入力データの正規化
MNISTの画像ベクトルは0-255の値が格納されています。学習が上手く進むようにこの値を0-1の値に変換しておきます。
# 0-255 => 0-1 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255
このような作業を正規化といいます。
プログラムを次のように実装して再度実行してみましょう。
from keras.models import Sequential from keras.layers import Dense, Activation from keras.utils import to_categorical from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() # 28x28 => 784 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) # 0-255 => 0-1 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 # one-hot ex: 3 => [0,0,0,1,0,0,0,0,0,0] y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) model = Sequential() model.add(Dense(50, input_dim=784)) model.add(Activation('relu')) model.add(Dense(20)) model.add(Activation('relu')) model.add(Dense(10)) model.add(Activation('softmax')) model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=32, validation_data=(x_test, y_test))
プログラムの実行結果は次のようになります。
Train on 60000 samples, validate on 10000 samples Epoch 1/10 60000/60000 [==============================] - 6s - loss: 0.6895 - acc: 0.8073 - val_loss: 0.3421 - val_acc: 0.9029 Epoch 2/10 60000/60000 [==============================] - 6s - loss: 0.3159 - acc: 0.9085 - val_loss: 0.2759 - val_acc: 0.9218 Epoch 3/10 60000/60000 [==============================] - 8s - loss: 0.2626 - acc: 0.9243 - val_loss: 0.2375 - val_acc: 0.9306 Epoch 4/10 60000/60000 [==============================] - 14s - loss: 0.2282 - acc: 0.9338 - val_loss: 0.2081 - val_acc: 0.9388 Epoch 5/10 60000/60000 [==============================] - 8s - loss: 0.2027 - acc: 0.9413 - val_loss: 0.1904 - val_acc: 0.9437 Epoch 6/10 60000/60000 [==============================] - 7s - loss: 0.1833 - acc: 0.9469 - val_loss: 0.1774 - val_acc: 0.9468 Epoch 7/10 60000/60000 [==============================] - 6s - loss: 0.1682 - acc: 0.9520 - val_loss: 0.1669 - val_acc: 0.9516 Epoch 8/10 60000/60000 [==============================] - 7s - loss: 0.1560 - acc: 0.9541 - val_loss: 0.1575 - val_acc: 0.9531 Epoch 9/10 60000/60000 [==============================] - 6s - loss: 0.1452 - acc: 0.9578 - val_loss: 0.1476 - val_acc: 0.9548 Epoch 10/10 60000/60000 [==============================] - 6s - loss: 0.1360 - acc: 0.9606 - val_loss: 0.1412 - val_acc: 0.9563
今度は上手く学習できているようです。前回sigmoid関数で実行した場合は90%程度でしたので5%近く結果は向上したようです。
Heの初期値
KerasはDenseレイヤーの重みの初期化にglorot_uniform(Glorot(Xavier)の一様分布)を返します。sigmoid関数の場合はGlorotが良いようですが、ReLU関数を使う場合、He の正規分布を使うのが良いとされています。こちらも試してみましょう。
重みの初期化は次のように実装します。
from keras.initializers import he_normal model.add(Dense(20, kernel_initializer=he_normal()))
利用可能な初期値はKerasのマニュアルページが参考になります。
https://keras.io/ja/initializers/
先ほどのプログラムを修正してみましょう。
from keras.models import Sequential from keras.layers import Dense, Activation from keras.utils import to_categorical from keras.datasets import mnist from keras.initializers import he_normal (x_train, y_train), (x_test, y_test) = mnist.load_data() # 28x28 => 784 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) # 0-255 => 0-1 x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 # one-hot ex: 3 => [0,0,0,1,0,0,0,0,0,0] y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) model = Sequential() model.add(Dense(50, input_dim=784, kernel_initializer=he_normal())) model.add(Activation('relu')) model.add(Dense(20, kernel_initializer=he_normal())) model.add(Activation('relu')) model.add(Dense(10, kernel_initializer=he_normal())) model.add(Activation('softmax')) model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) history2 = model.fit(x_train, y_train, batch_size=32, validation_data=(x_test, y_test))
プログラムの実行結果は次のようになります。
Train on 60000 samples, validate on 10000 samples Epoch 1/10 60000/60000 [==============================] - 12s - loss: 0.7723 - acc: 0.7700 - val_loss: 0.3472 - val_acc: 0.8991 Epoch 2/10 60000/60000 [==============================] - 15s - loss: 0.3223 - acc: 0.9079 - val_loss: 0.2798 - val_acc: 0.9179 Epoch 3/10 60000/60000 [==============================] - 9s - loss: 0.2673 - acc: 0.9229 - val_loss: 0.2414 - val_acc: 0.9291 Epoch 4/10 60000/60000 [==============================] - 6s - loss: 0.2325 - acc: 0.9336 - val_loss: 0.2169 - val_acc: 0.9371 Epoch 5/10 60000/60000 [==============================] - 8s - loss: 0.2070 - acc: 0.9406 - val_loss: 0.1937 - val_acc: 0.9427 Epoch 6/10 60000/60000 [==============================] - 14s - loss: 0.1872 - acc: 0.9458 - val_loss: 0.1786 - val_acc: 0.9484 Epoch 7/10 60000/60000 [==============================] - 9s - loss: 0.1706 - acc: 0.9509 - val_loss: 0.1644 - val_acc: 0.9520 Epoch 8/10 60000/60000 [==============================] - 9s - loss: 0.1561 - acc: 0.9547 - val_loss: 0.1552 - val_acc: 0.9542 Epoch 9/10 60000/60000 [==============================] - 9s - loss: 0.1443 - acc: 0.9582 - val_loss: 0.1445 - val_acc: 0.9576 Epoch 10/10 60000/60000 [==============================] - 10s - loss: 0.1344 - acc: 0.9611 - val_loss: 0.1369 - val_acc: 0.9589
若干の改善はありませんが、大きな変化はみられませんでした。今回のMNISTデータだと効果がわかりにくいのかもしれません。重みの初期化についてはまた時間のあるときに考察してみようと思います。
Kerasで画像認識 - MNIST編
Kerasを使った画像認識のプログラムです。有名なMNISTデータ(手書き数字)を使ったものです。
MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges
from keras.models import Sequential from keras.layers import Dense, Activation from keras.utils import to_categorical from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() # 28x28 => 784 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) # one-hot ex: 3 => [0,0,0,1,0,0,0,0,0,0] y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) model = Sequential() model.add(Dense(50, input_dim=784)) model.add(Activation('sigmoid')) model.add(Dense(20)) model.add(Activation('sigmoid')) model.add(Dense(10)) model.add(Activation('softmax')) model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=32, validation_data=(x_test, y_test))
コードを書いて実行してみましょう。機械学習の開発環境にはJupyter Notebookがオススメです。
実行結果は次のようになります。テストデータで91%の正答率(val_acc)です。
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz 10862592/11490434 [===========================>..] - ETA: 0sTrain on 60000 samples, validate on 10000 samples Train on 60000 samples, validate on 10000 samples Epoch 1/10 60000/60000 [==============================] - 6s - loss: 1.8023 - acc: 0.5735 - val_loss: 1.3870 - val_acc: 0.7524 Epoch 2/10 60000/60000 [==============================] - 5s - loss: 1.0939 - acc: 0.8008 - val_loss: 0.8456 - val_acc: 0.8457 Epoch 3/10 60000/60000 [==============================] - 5s - loss: 0.7209 - acc: 0.8618 - val_loss: 0.6233 - val_acc: 0.8767 Epoch 4/10 60000/60000 [==============================] - 5s - loss: 0.5610 - acc: 0.8814 - val_loss: 0.5006 - val_acc: 0.8945 Epoch 5/10 60000/60000 [==============================] - 5s - loss: 0.4770 - acc: 0.8892 - val_loss: 0.4278 - val_acc: 0.8998 Epoch 6/10 60000/60000 [==============================] - 6s - loss: 0.4267 - acc: 0.8960 - val_loss: 0.3993 - val_acc: 0.9026 Epoch 7/10 60000/60000 [==============================] - 8s - loss: 0.4097 - acc: 0.8970 - val_loss: 0.3959 - val_acc: 0.8984 Epoch 8/10 60000/60000 [==============================] - 6s - loss: 0.3875 - acc: 0.9016 - val_loss: 0.3856 - val_acc: 0.9044 Epoch 9/10 60000/60000 [==============================] - 5s - loss: 0.3673 - acc: 0.9035 - val_loss: 0.3514 - val_acc: 0.9076 Epoch 10/10 60000/60000 [==============================] - 5s - loss: 0.3458 - acc: 0.9070 - val_loss: 0.3296 - val_acc: 0.9112
初回実行時はMNISTデータのダウンロードが発生します。そのあと10回の学習が進んでいるのがわかります。
プログラムの解説
プログラムの詳細を見てみましょう。Kerasを使えばMNISTデータもKerasのAPIでダウンロードできます。
(x_train, y_train), (x_test, y_test) = mnist.load_data() # 28x28 => 784 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) # one-hot ex: 3 => [0,0,0,1,0,0,0,0,0,0] y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10)
ここではダウンロード後のデータを全結合型のニューラルネットワークで処理できるようにデータを整形しています。
今回のプログラムは全結合型のニューラルネットワークです。KerasのDenseクラスで全結合レイヤーを作っています。
model.add(Dense(50, input_dim=784))
入力層のノード数はinput_dimで指定します。MNISTの画像データが28x28だから784になります。あと今回は0-9の10クラス分類なので出力層のノード数も10になります。
あとは活性化関数を指定して、レイヤーを並べています。中間層の活性化関数にはsigmoid関数、出力層の活性化関数にはsoftmax関数を指定しています。今回は多クラス分類なので出力層の活性化関数にはsoftmax関数を使っています。
モデルが完成したらコンパイルします。コンパイル時には損失関数とオプティマイザを指定します。損失関数には"categorical_crossentropy"、オプティマイザにはSGDを指定しています。metricsに指定した内容はエポック時に表示したい内容です。ここでは正答率(acc)を表示しています。
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])
ちなみに多クラス分類ではなく2値分類(yes/noみたいな)の場合は損失関数(loss)にbinary_crossentropyを指定します。その場合出力層の活性化関数をsigmoidにもできます。
あとは学習開始です。
history = model.fit(x_train, y_train, batch_size=32, validation_data=(x_test, y_test)))
MNISTの訓練データは60000件(テストデータは10000件)あるので、32件ずつランダムに取り出して勾配を求めます。求めた勾配よって重みが各ノードの重み・バイアスが更新されます(SGD)。引数にvalidation_dataを指定することでエポックごとにテストデータで検証(ホールドアウト検証)してくれます。デフォルトで10エポック(同じことを10回)学習します。
学習のグラフ化
matplotlibを使って学習の様子をグラフにしてみましょう。
import matplotlib.pyplot as plt plt.ylim(0.0, 1) plt.plot(history.history['acc'], label="acc") plt.plot(history.history['val_acc'], label="val_acc") plt.legend() plt.show()
参考
オプティマイザについては以下のページが参考になります。
ImageNetから画像データをダウンロードする方法
機械学習、画像認識を始めると「大量の画像データないかなー」とググることになります。そうするとすぐにImageNetなる存在に気づきます。
ImageNetとはスタンフォード大学がインターネット上から画像を集め分類したデータセット。一般画像認識用に用いられる。ImageNetを利用して画像検出・識別精度を競うThe ImageNet Large Scale Visual Recognition Challenge(ILSVRC)などコンテストも開かれる。(:AI白書より引用)
ILSVRC、2012年のコンテストでディープラーニングを使ったチームが圧勝した話も有名です。
それでImageNetのサイトを訪問すると、画像を検索して、そんで画像選んで、ダウンロードしようとするとURLの一覧が表示されてー。え。これからどうしようとなります。一括ダウンロードするサンプルプログラムもネット上にいくつかありますが、Python2系のものだったり、すぐに動かなかったので自分の勉強用に作ってみました。Anacondaとか入れておいて必要なライブラリが揃っていれば動くと思います。
ダウンロードできる画像は、著作権フリーというのではないので、自己学習用のものです。
import sys import os from urllib import request from PIL import Image def download(url, decode=False): response = request.urlopen(url) if response.geturl() == "https://s.yimg.com/pw/images/en-us/photo_unavailable.png": # Flickr :This photo is no longer available iamge. raise Exception("This photo is no longer available iamge.") body = response.read() if decode == True: body = body.decode() return body def write(path, img): file = open(path, 'wb') file.write(img) file.close() # see http://image-net.org/archive/words.txt classes = {"apple":"n07739125", "banana":"n07753592", "orange":"n07747607"} offset = 0 max = 10 for dir, id in classes.items(): print(dir) os.makedirs(dir, exist_ok=True) urls = download("http://www.image-net.org/api/text/imagenet.synset.geturls?wnid="+id, decode=True).split() print(len(urls)) i = 0 for url in urls: if i < offset: continue if i > max: break try: file = os.path.split(url)[1] path = dir + "/" + file write(path, download(url)) print("done:" + str(i) + ":" + file) except: print("Unexpected error:", sys.exc_info()[0]) print("error:" + str(i) + ":" + file) i = i + 1 print("end")
imagenet.pyとかで保存して、
python imagenet.py
みたいにプログラムを実行すると apple, banana, orange 3種類の画像をダウンロードしてきます。カレントフォルダ上にapple, banana, orangeフォルダができます。
apple, banana, orange以外の画像を集めたい場合は以下の部分を編集してみてください。
# see http://image-net.org/archive/words.txt classes = {"apple":"n07739125", "banana":"n07753592", "orange":"n07747607"}
ImageNet上にwords.txtというファイルがあり、そこに画像分類ごとのIDみたいなのが振られています。
それからダウンロードする枚数は以下の部分で調整できます。
offset = 0 max = 10
なんとなく見た感じだと、apple, banana, orangeだと1000枚程度はあるので、maxを2000くらいにしておけばそれなりにデータが揃います。offsetは続きからダウンロードしたいとき用です。
あとImageNetからの画像のリンク先がFlickrであることが多く、公開停止になっているリンクも多いです。その場合、エラー画像をダウンロードしてしまうので、その部分を回避するコードです。
response = request.urlopen(url) if response.geturl() == "https://s.yimg.com/pw/images/en-us/photo_unavailable.png": # Flickr :This photo is no longer available iamge. raise Exception("This photo is no longer available iamge.")
AIにおける知的財産の考え方について
「AI白書2017 3.2 知的財産」の自分用まとめです。AIの活用シーンにおける以下の3点についてまとめます。
- AI生成物
- 学習済みモデル
- 学習用データ
注意:以下に示す内容は現在も議論されている段階です。
AI生成物の著作権保護
音楽や文学作品などのコンテンツを学習することで、新たな創作が可能になりつつあります。たとえばAIを活用して生成された音楽コンテンツには次のようなものがあります。
- 自動作曲プログラム lamus(ラムス) - マラガ大学
- ビートルズ風ポップミュージック Daddy's Car - ソニーコンピュータサイエンス研究所
このようなAI生成物の著作権の取り扱いについて「次世代知財システム検討委員会報告書」には以下の記載があります。
AI生成物を生み出す過程において、学習済みモデルの利用者に創作意図があり、同時に、具体的な出力であるAI生成物を得るための創作的寄与があれば、利用者が思想感情を創作的に表現するための「道具」としてAIを使用して当該AI生成物を生み出したものと考えられることから、当該AI生成物には著作物性が認められその著作者は利用者となる
上記は著作権が認められるケースです。「創作意図」があるかどうかがポイントになるようです。
一方で、利用者の寄与が、創作的寄与が認められないような簡単な指示に留まる場合(AIのプログラムや学習済みモデルの作成者が著作者となる例外的な場合を除く)、当該AI生成物は、AIが自律的に生成した「AI創作物」であると整理され、現行の著作権法上は著作物と認められないこととなる
AIが自律的に生成した成果物は、著作物に該当せず著作権も発生しないと考えられます。
たとえば先のDaddy' Carは、作曲家(Benoit Carre氏)が「ビートルズ風」というスタイルと曲の長さを指定して生成し、作詞・編曲を行っているため、創作的寄与があると考えられます。つまり著作権が発生すると考えられます。
一方で、lamusによる楽曲はAIのみで自律的に制作されているそうです。そのため「AI創作物」として著作権は認められない、と考えられます。
学習済みモデルの保護
学習済みのモデルはプログラムとパラメータで構成されており、著作権法上の「プログラムの著作物」に該当するか議論されています。仮に該当しないとしても、特許法上では「プログラム等」に該当するならば、特許法の要件を満たすなら保護される可能性があります。
また上記に該当しない場合でも不正競争防止法条の秘密管理性、有用性、非公知性といった要件を満たす場合は「営業秘密」として保護されるようです。
(正直、この辺は専門外なのでちょっと難しい。。)
蒸留モデル
学習済みモデルに対して、データの入出力を繰り返し、その結果を別の学習モデルに学習させることもできます。このように作られたものは「蒸留モデル」と呼ばれます。
蒸留モデルは、元のモデルからの依拠性を証明することが難しく、著作権による保護が困難になります。一方で、特許権による保護は、依拠性の立証がなくても認められるため、特許権の範囲での対応も議論されています。
また学習済みモデルの利用規約により、蒸留モデルを禁止する等の契約で保護することもできます。この場合契約当事者以外の第三者から守ることはできないものの、柔軟な対応が可能となります。
学習データについて
AI白書には以下の一文があります。
インターネット上のデータ等の著作物を元に学習用データを作成・解析することは営利目的の場合も含めて、著作権法47条の7に基づいて著作権侵害には当たらないとされており、機械学習活用の促進にとって我が国特有の有用な制度となっている。(AI白書より)
学習データについては著作権法47条の7がポイントのようです。以前、こちらの記事も話題になっていました。
日本はインターネット上のデータを機械学習に活用しやすい一方で、AIの研究開発推進に向けての国産の共有データセット(ImageNetのようなもの)の整備が遅れているとの指摘もあります。
それから著作権法47条の7の規定は、もともと機械学習の促進を想定したものではないため、解釈の仕方や議論の余地が残っています。
共有データセットについての問題
海外にはImageNetやMNIST、MS COCOといった共有データセットが存在します。また、これらのデータを活用して、事前に学習済みのモデルも公開されています。
これらの学習済みモデルは、欧米で作られた共有データセットで作られている点を理解しておく必要があります。そのため日本固有の「ラーメン」のような画像認識ができない、といった問題があります。
参考書籍
Jupyter Notebookで始める機械学習プログラミング
Python
PythonはWebアプリの開発からちょっとしたツールの開発まで、多目的に利用できるプログラミング言語です。また機械学習ライブラリが充実しているため近年注目を集めています。
次のAnacondaディストリビューションでPythonをインストールすることもできます。
Anaconda
Pythonで機械学習を始めるにはCONTINUUM社の配布しているはAnacondaディストリビューションを活用すると良いでしょう。以下のURLからダウンロートすることができます。
AnacondaにはPython本体だけでなく機械学習に必要なライブラリも梱包されているため、Anacondaをインストールすればすぐに機械学習プログラミングを始めることができます。
Jupyter Notebook
AnacondaにはJupyter Notebookというブラウザ上で動作するPython開発環境も付属しています。ターミナル(コマンドプロンプト)上で jupyter-notebook コマンドを実行するとローカルでサーバプログラムが起動し、ブラウザが起動します。
Jupyter Notebookの起動方法について補足しておきます。Anacondaインストール後、Windowsでは画面左下のWindowsメニューから「jupyter-notebook」とタイプするとアプリが見つかります。Macでは、ターミナル上でjupyter-notebookコマンドをタイプします。Jupyter Notebookはデフォルトで8888番ポートを使って起動します。ブラウザで http://localhost:8888/ にアクセスすると開発画面が表示されるでしょう。
Jupyter Notebookでは、ノートブックという形式でファイルを作成できます。ノートブックにはPythonコードや実行結果だけでなく、Markdown形式で文章を挿入することもできるので、データ分析の評価レポートを作成しやすいようになっています。またノートブックファイルは拡張子.ipynbという形式保存されます。.ipynbファイルはGitHubやGistなどでも表示できます。
クラウド上でJupyter Notebookを起動する
Jupyter Notebookの実体はブラウザで利用するWebアプリケーションです。そのためサーバ上でJupyter Notebookを起動すれば、手元のパソコンのブラウザからサーバ上でPythonプログラムを実行することも可能です。
ここではあらかじめJupyter環境をインストール済みのDockerコンテナを起動する方法を紹介します。またDeepLearning開発を支援するPaaS型サービスであるFloydHubを紹介します。
DockerでJupyter環境を構築するには
ここではクラウド環境としてAWSのEC2インスタンス(Ubuntu / Small)があるものとします。
sshでEC2インスンタンスにログインします。まずUbuntuのパッケージ情報を更新しておきます。
sudo apt update
次にDockerをインストールします。
sudo apt install docker.io -y
Dockerコンテナ(murayama333/ai-prog)を起動します。
sudo docker run -p 8888:8888 --name ai-prog -it murayama333/ai-prog
Dockerの出力ログにURLが表示されます。URLはlocalhostとなっているので、EC2のグローバルIPに置き換えてアクセスすると完了です。
ここで利用したDockerイメージはこちらの記事を参考に作っています。勉強になりました。
FloydHubで開発する
Dockerを使えばあっという間に開発環境を構築できますが、FloydHubを使えばもっと手軽にJupyter環境を整えることもできます。
FloydHub - Deep Learning Platform - Cloud GPU
FloydHubを一言で説明するなら
FloydHub is Heroku for DL
FloydHubはDeepLearningのためのHerokuです。つまり、DeepLearningのためのPaaS(Platform as a Service)です。FloydHubの素晴らしいところは、クラウド上ですぐに開発&実行ができるだけでなく、GPUインスタンスを利用することができる点です。無料アカウントの場合、GPUインスタンスは 2時間 / 月 まで利用できます。
FloydHub - Deep Learning Platform - Cloud GPU
FloydHub上でアカウントを作成後、開発キット(floyd-cli)をインストールします。
pip install -U floyd-cli
pipはPythonライブラリの追加コマンドです。pipコマンドを利用するにはローカルにPythonがインストールされている必要があります。
floydコマンドが有効になるので、FloydHubにログインします。
$ floyd login
以下、オフィシャルのクイックスタートを参考に動かしてみましょう。
https://docs.floydhub.com/getstarted/quick_start/
GitHubからサンプルのリポジトリをダウンロードしておきます。
git clone https://github.com/floydhub/quick-start.git cd quick-start
リポジトリの中のファイルの一覧を確認しましょう。
ls eval.py LICENSE mnist_cnn.ipynb README.md train_and_eval.py train.py
以降は、上記の train_and_eval.py プログラムをFloydHub上で実行してみます。
FloydHubプロジェクトを初期化します。
floyd init mnist-cnn
FloydHubでPythonプログラムを実行してみましょう。
floyd run --gpu --env tensorflow-1.3 "python train_and_eval.py"
ここでは --gpu オプションを指定してるので、GPUインスタンス上で実行されます。
FloydHubでJupyter Notebookを起動する
FloydHubのプロジェクトフォルダ上で(先のquick-startフォルダなど)、次のようにコマンドを実行します。
floyd run --mode jupyter Creating project run. Total upload size: 198.0B Syncing code ... [================================] 946/946 - 00:00:00 JOB NAME ----------------------------------- murayama333/projects/mnist-cnn/1 Setting up your instance and waiting for Jupyter notebook to become available ............. Path to jupyter notebook: https://floydlabs.com/notebooks/xxx
数秒(数十秒)でJupyterが起動します。
floyd run --gpu --mode jupyter
Jupyterを起動している間、GPUインスタンスの利用時間がカウントされるので、利用を終えたらインスタンスを停止しておきましょう。停止するときは JOB NAME(floyd run時のログを参照)を指定します。
floyd stop murayama333/projects/mnist-cnn/1
Reactだけ学ぶハンズオン
Reactだけ学ぶハンズオン
- Hello React・・・はじめてのReact
- Greeting・・・プロパティを学ぶ
- GreetingList・・・コレクションの考え方を学ぶ
- Echo・・・ステートを学ぶ
- Welcome・・・コンポジットなコンポーネントの作り方を学ぶ
昔の勉強会の資料です。内容古かったらすみません。
こっちのが見やすいかもです。