Geminiに質問した解答集です。
NumPyの「ブロードキャスト」と「ブールインデックス参照」
import numpy as np
def step_function(x):
return np.array(x>0, dtype=np.int64)
#入力はNumPy配列
x = np.array([-0.5, 0.4, 1.2])
y = step_function(x)
# Python 3.6:fを付けると、{name} が変数の値に置き換わる
print(f"Input Type: {type(x)}") #<class 'numpy.ndarray'>
print(f"Output: {y}")
step_functionの記述について
- x > 0 (比較演算とブロードキャスト)
もし x が np.array([-1.0, 1.0, 2.0]) だとした場合、x > 0 は各要素に対して個別に実行されます。
-1.0 > 0 → False
1.0 > 0 → True
2.0 > 0 → True
結果として、[False, True, True] という Boolean(真偽値)の配列が生成されます。 - dtype=np.int64 (型変換)
ステップ関数は「0か1」を返したいので、False/True を 0/1 という数値に変換する必要があります。 dtype=np.int64(または int)を指定することで、NumPyは以下のように変換します。
False → 0
True → 1 - np.array(...) (新しい配列の生成)
これらをまとめて、新しいNumPy配列として出力します。
3層ニューラルネットワークのコード
import numpy as np
#シグモイド関数
def sigmoid(x):
return 1/ (1+np.exp(-x))
#辞書型(dict)**というデータ構造を初期化
#network['W1'] のように、名前(キー)を指定して値を取り出せます。
def init_network():
network={}# 空の辞書を作る
network['W1']=np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
network['B1']=np.array([0.1,0.2,0.3])
network['W2']=np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
network['B2']=np.array([0.1,0.2])
network['W3']=np.array([[0.1,0.3],[0.2,0.4]])
network['B3']=np.array([0.1,0.2])
return network
def identity_function(x):
return x
#第一引数 network 第2引数 入力データ
def forward(_network, x):
W1,W2,W3 = _network['W1'],_network['W2'],_network['W3']
B1,B2,B3 = _network['B1'],_network['B2'],_network['B3']
#第一層
A1 = np.dot(x,W1)+B1
Z1 = sigmoid(A1)
#第ニ層
A2 = np.dot(Z1,W2)+B2
Z2 = sigmoid(A2)
#第3層
A3 = np.dot(Z2,W3)+B3
Y = identity_function(A3)
return Y
#1.重みの準備
network = init_network()
#2.入力データの準備
inputData = np.array([1.0,0.5])
#3.計算の実行
Y = forward(network,inputData)
print(Y)
1. NumPyの使用方法:行列計算の基礎
ディープラーニングの実装に欠かせないNumPyの挙動を整理しました。
np.ndarray クラス
np.array([1, 2, 3]) で生成される多次元配列オブジェクト。
Python標準の「リスト」とは異なり、高速な演算と数学的な一括処理が可能。
要素別演算(ブロードキャスト)
x > 0 や np.exp(-x) のように、配列に対して演算を行うと、全要素に対して一斉に計算が適用される。
これにより、for 文を使わずに簡潔かつ高速なコードが書ける。
行列の内積 (np.dot)
np.dot(X, W) + B の形で、ニューラルネットワークの「線形変換」を表現する。
(1, 2) の行列と (2, 3) の行列をかけると、結果は (1, 3) になるという「形状(Shape)の連鎖」が重要。
2. Pythonの文法:設計と管理
「動くコード」を「管理しやすいコード」にするためのテクニックです。
辞書型 ({}) によるパラメータ管理
network = {} で初期化。
network['W1'] = ... のようにキー(名前)で重みやバイアスを保存することで、複数の層のデータを一括管理できる。
関数のスコープ(ローカル変数)
forward 関数内で宣言された W1, A1, Y などはすべてローカル変数。
計算が終わるとメモリから解放され、関数の外側には影響を与えない。
アンパック代入
W1, W2, W3 = network['W1'], network['W2'], network['W3']
辞書からまとめて変数に取り出すことで、数式を記述する際の可読性を高める。
f文字列 (f-strings)
print(f"Output: {Y}") のように、文字列の前に f をつけ、{} で変数を埋め込む。
計算結果や行列の形状(.shape)をデバッグ表示する際に最適。
pass 文
関数の「中身」を空にできないPythonの仕様に対応するためのキーワード。設計時に「後で書く」場所を示すのに使う。
動的型付け
実行時にインタプリタが型を判断する。型宣言を省略できるため、数式に近い直感的な記述が可能。
NumPyの**「ファンシーインデックス参照(Fancy Indexing)」
「各データの正解ラベルに対応する確率($y$の値)だけを、一気に抜き出す」
import numpy as np
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
# 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
if t.size == y.size:
t = t.argmax(axis=1)
batch_size = y.shape[0]
delta = 1e-7
# 各データの正解ラベルに対応する出力yの値を抽出し、平均をとる
return -np.sum(np.log(y[np.arange(batch_size), t] + delta)) / batch_size
# 例:y (予測値)
y = np.array([
[0.1, 0.2, 0.6, 0.05, 0.05], # データ0:正解はインデックス2 (0.6)
[0.7, 0.1, 0.1, 0.05, 0.05], # データ1:正解はインデックス0 (0.7)
[0.2, 0.1, 0.1, 0.1, 0.5 ] # データ2:正解はインデックス4 (0.5)
])
# 例:t (正解ラベル)
t = np.array([2, 0, 4])
np.arange(batch_size) の役割
batch_size が 3 の場合、np.arange(3) は [0, 1, 2] という配列を作ります。これは 「行番号」 を指定するために使います。
インデックス指定の合体
y[np.arange(batch_size), t] は、NumPyに対して次のような指示を出しています。
(0行目, t[0]列目) の要素を取れ → y[0, 2]
(1行目, t[1]列目) の要素を取れ → y[1, 0]
(2行目, t[2]列目) の要素を取れ → y[2, 4]
結果として、[0.6, 0.7, 0.5] という、各データの正解に対する確率だけが並んだ配列が返ってきます。
見た目は全く同じなのに動かない
というのは、Pythonプログラマーが必ず一度は直面する「Pythonあるある」の代表格です。
-
全角スペースの混入(一番怪しい)
日本語環境でコードを書いていると、意図せず全角スペースが混じることがあります。 Pythonにとって「半角スペース4つ」と「全角スペース」は別物です。もし it.iternext() の前に全角スペースが混じっていた場合、Pythonは「ループの外」と判断したり、構文エラー(になればまだマシですが、変な解釈をすること)があります。 -
インデントの「混在」(タブとスペース)
見た目では同じ4文字分の空白でも、**「タブ文字(Tab)」で下げている行と、「半角スペース4つ」**で下げている行が混在すると、Pythonはパニックを起こします。
print(idx) はスペースで下げた
it.iternext() はタブで下げた この場合、人間には同じ位置に見えても、Pythonは別のブロック(ループの外)として認識することがあります。
VS Codeでこれを防ぐ「エディタ設定」
二度と同じトラブルに遭わないために、VS Codeの設定を以下のように変更することをおすすめします。
① 空白を可視化する
「目に見えない空白」を見えるようにします。
VS Codeのメニューから 設定(Ctrl + ,) を開く。
検索窓に render whitespace と入力。
Editor: Render Whitespace を all に変更。
これで、半角スペースは「・」、タブは「→」と表示され、全角スペースも異常な空白として目立つようになります。
② 保存時に自動で整形(超おすすめ)
検索窓に format on save と入力。
Editor: Format On Save にチェックを入れる。
これで、保存するたびにインデントのズレや余計な空白をVS Codeが自動的に「正しいPythonのルール」に修正してくれます。