zip関数
Pythonのzip関数は、複数のリストの要素からタプルを作ることが出来る便利な関数です。
片方のリストの要素数が、もう一方のリストの要素数より少ない場合に、zip関数を使うと、少ない要素数に合わせてタプルが作成されます。
コード:
country = ['USA', 'Japan','France'] language = ['English', 'Japanese', 'French'] for cou, lan in zip(country, language): print(cou, lan, sep='-')
実行結果:
USA-English Japan-Japanese France-French
ドット積
ここからは、オライリーの書籍「Python計算機科学新教本」の学習の備忘録です。
Pythonのzip( )とsum( )を使って、ドット関数を実装します。
from typing import List from math import exp #2つのベクトルのドット積 def dot_product(xs: List[float], ys: List[float]) -> float: return sum(x * y for x, y in zip(xs, ys))
活性化関数
ニューロンの信号が次の層に渡る前に、ニューロンの出力を変換します。
シグモイド関数は活性化関数によく使われる関数です。
シグモイド関数の値は、常に0と1の間です。
値が常に0と1の間であるのは、ネットワークにとって扱いやすく便利です。
#古典的なシグモイド活性化関数
def sigmoid(x: float) -> float: return 1.0 / (1.0 + exp(-x)) def derivative_sigmoid(x: float) -> float: sig: float = sigmoid(x) return sig * (1 - sig)
ネットワークの構築
ニューロン、層(レイヤー)、ネットワークそのものというネットワークの3つの構成要素全てをモデル化するクラスを作ります。
1番小さいニューロンから、真ん中の要素層、そして最大のネットワーク全体と順に行います。
最小から最大へと進行するにつれて、前の段階をカプセル化します。
ニューロンは自分自身についてしか知らず、層は自分が含むニューロンと他の層しか知りません。
ネットワークは全ての層を知っています。
ニューロンの実装
1つのニューロンには、次の要素が格納されます。
- 重み
- デルタ
- 学習率
- 直前の出力のキャッシュ
- 活性化関数
- 活性化関数の導関数
from typing import List, Callable from util1 import dot_product class Neuron: #パラメーターを__init__()メソッド内で初期化 def __init__(self, weights: List[float], learning_rate: float,activation_function: Callable[[float], float],derivative_activation_function: Callable[[float], float]) -> None: self.weights: List[float] = weights self.activation_function: Callable[[float], float] = activation_function self.derivative_activation_function: Callable[[float], float] = derivative_activation_function self.learning_rate: float = learning_rate self.output_cache: float = 0.0 self.delta: float = 0.0 # Neuron作成時には、deltaとoutput_cacheがわからないので、0に初期化している。 #ニューロンへの入力信号を受け取り、入力信号はドット積と重みと組み合わされます。 def output(self, inputs: List[float]) -> float: self.output_cache = dot_product(inputs, self.weights) return self.activation_function(self.output_cache)
層の実装
層は状態の3要素である、ニューロン、前の層、出力キャッシュを管理する必要があります。
出力キャッシュは、ニューロンの場合と同様だが、1つレベルが上になります。
層内の各ニューロンに活性化関数が適用される前の出力をキャッシュします。
Layerクラスの__init__( )メソッドは、初期化するニューロンの個数、その活性化関数、およびその学習率を知る必要があります。
この簡単なネットワークでは層内の全ニューロンが同じ活性化関数と学習率を持ちます。
ネットワークの実装
ネットワークそのものには、管理している層という1種類の状態しかありません。
_ _ init _ _ ( ) メソッドは、ネットワークの構造を記述するintリストを引数に取ります。
例えば、リスト[2, 4, 3]は、入力層に2ニューロン、隠れ層に4ニューロン、出力層に3ニューロンのネットワークです。
この簡単なネットワークでは、ネットワークの全層がニューロンに同じ活性化関数と学習率を使うものと仮定します。
ラムダ式
defを使わずに簡潔に関数と同じ機能を書ける。
func = lambda a, b: a * b print(func(3,2))
ドキュメーション文字列
ドキュメーション文字列は、関数. _ _doc_ _ で表示させれるコメント
“”” “””の中に記述し、大文字で始まり、ピリオドで終わる 文章のこと。
def plus(a, b): """Add a and b. 'add(a, b)' is same as 'a + b'. """ return a + b print(plus.__doc__)
関数のアノテーション
関数定義で、仮引数や返り値の型を書けます。
これをアノテーションと言います。
実行には影響しません。
アノテーションの情報は、関数名. _ _annotations _ _ で取得できる。
def func(args1: str, args2: int = 0) -> list: print(func.__annotations__) return [args1, args2]
この場合、printはスルーされる。