Pythonでニューラルネットワーク
3D座標データの集まりを1つの軌跡としてテキストファイルに保存しています。そのデータをニューラルネットワークで学習させ学習モデルを作り、新しい軌跡データが入力された時にどの軌跡に分類されるか判断するプログラムを作成しようとしています。しかし、作成したプログラムを実行すると全然正解してくれません。解決方法を教えてください。
例)
Ruby on RailsでQiitaのようなWebアプリをつくっています。
記事を投稿する機能の実装中にエラーが発生しました。
解決方法を教えて下さい。
発生している問題・エラー
エラーは発生しないのですが、どんなデータを入れても予測クラスの数値がラベル順に大きくなります。
例)
ラベル1の予測クラス: 79
ラベル2の予測クラス: 119
ラベル3の予測クラス: 159
ラベル4の予測クラス: 199
該当するソースコード
ソースコード
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import os
# ニューラルネットワークのモデルを定義
class FixedNet(nn.Module):
def __init__(self, input_size, output_size):
super(FixedNet, self).__init__()
self.fc1 = nn.Linear(input_size, 64)
self.fc2 = nn.Linear(64, 32)
self.fc3 = nn.Linear(32, output_size)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
# ファイル名からラベル情報を抽出する関数
def extract_label_from_filename(filename):
parts = filename.split("_")
if len(parts) >= 2:
label_part = parts[1].replace("label", "")
return int(label_part)
else:
return None
# ラベルを整数からファイル名の形式に変換する関数
def label_to_filename(label):
return f"label{label}_model.pth"
# データファイルのメインディレクトリ
main_data_directory = "/home/osumi/catkin_ws/src/ros_openpose-master/openposedata"
# 学習済みモデルの保存ディレクトリ
model_directory = "/home/osumi/catkin_ws/src/ros_openpose-master/ニューラルネットワーク2"
# ニューラルネットワークモデルの初期化
input_size = 3 # 3D座標データの次元
# 損失関数と最適化アルゴリズムを定義
criterion = nn.CrossEntropyLoss()
# 学習のループ
num_epochs = 10
# ラベルごとにデータセットとモデルを管理するための辞書を作成
label_datasets = {}
label_models = {}
# 各ディレクトリ内のファイルを順番に処理
for label_directory in os.listdir(main_data_directory):
label = label_directory # ラベルはディレクトリ名と同じと仮定
# ラベルごとのデータディレクトリ
data_directory = os.path.join(main_data_directory, label_directory)
# 学習データを格納するリスト
data = []
labels = []
# データディレクトリ内のファイルを処理
for filename in os.listdir(data_directory):
# ファイル名からラベルを抽出
label = extract_label_from_filename(filename)
if label:
# データファイルのパス
file_path = os.path.join(data_directory, filename)
# データの読み込みと前処理
with open(file_path, 'r') as file:
for line in file:
parts = line.strip().split()
data_point = [float(parts[0]), float(parts[1]), float(parts[2])]
data.append(data_point)
labels.append(int(label)) # ラベルを整数に変換
# データをPyTorchのテンソルに変換
data = torch.tensor(data, dtype=torch.float32)
labels = torch.tensor(labels, dtype=torch.long)
# DataLoaderを作成
batch_size = 32
dataset = TensorDataset(data, labels)
data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
# ニューラルネットワークモデルの初期化
output_size = max(labels).item() + 1
model = FixedNet(input_size, output_size)
# 各ラベルごとにデータセットとモデルを保存
label_datasets[label] = data_loader
label_models[label] = model
# ラベルごとにモデルを訓練
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(num_epochs):
for data_batch, labels_batch in data_loader:
optimizer.zero_grad() # 勾配を初期化
outputs = model(data_batch) # モデルの予測
loss = criterion(outputs, labels_batch) # 損失を計算
loss.backward() # 逆伝播
optimizer.step() # パラメータの更新
# 学習済みモデルを保存
os.makedirs(model_directory, exist_ok=True)
model_filename = label_to_filename(label) # モデルのファイル名を生成
model_save_path = os.path.join(model_directory, model_filename)
# ラベルの整数値を保存
with open(os.path.join(model_directory, f"label{label}.txt"), 'w') as label_file:
label_file.write(str(label))
torch.save(model.state_dict(), model_save_path)
# 新しいデータを予測
new_data_file = "/home/osumi/catkin_ws/src/ros_openpose-master/openposedata/label1/coordinates_label1_20231016194432.txt"
new_data = []
with open(new_data_file, 'r') as file:
for line in file:
parts = line.strip().split()
data_point = [float(parts[0]), float(parts[1]), float(parts[2])]
new_data.append(data_point)
# 新しいデータをPyTorchのテンソルに変換
new_data = torch.tensor(new_data, dtype=torch.float32)
# 各学習済みモデルを使って新しいデータを予測
predictions = []
for label in os.listdir(model_directory):
if label.endswith(".pth"):
# ラベルの整数値を取得
label_int = int(label.split("_")[0].replace("label", ""))
model_filename = label_to_filename(label_int)
model_path = os.path.join(model_directory, label)
# 学習済みモデルのロード前にデバッグ情報を表示
print(f"ロード対象のモデルファイルパス: {model_path}")
# 学習済みモデルをロード
if os.path.exists(model_path):
# 予測モデルの形状に合わせて新しいモデルを初期化
model = label_models.get(label_int)
if model is not None:
model.load_state_dict(torch.load(model_path))
model.eval()
with torch.no_grad():
output = model(new_data)
predictions.append((label_int, output))
else:
print(f"ラベル {label_int} のモデルが見つかりません")
else:
print(f"モデルが見つかりません: {model_path}")
# 予測結果の確認
sorted_predictions = sorted(predictions, key=lambda x: x[0]) # ラベルの数値順にソート
for label_int, output in sorted_predictions:
predicted_class = torch.argmax(output).item()
print(f"ラベル{label_int}の予測クラス: {predicted_class}")
###このプログラムの詳細
このプログラムは、ニューラルネットワークモデルをトレーニングし、新しいデータのラベルを予測するためのものです。下記にその手順を示します。
ニューラルネットワークのモデルを定義します。FixedNet クラスは、3次元の入力を受け取り、線形レイヤーを組み合わせてニューラルネットワークを構築します。
ファイル名からラベル情報を抽出するための関数 extract_label_from_filename を定義します。これは、ファイル名からラベルを抽出するユーティリティ関数です。
ラベルを整数からファイル名の形式に変換する関数 label_to_filename を定義します。これは、ラベルをモデルのファイル名に変換するためのユーティリティ関数です。
メインデータディレクトリと学習済みモデルの保存ディレクトリを指定します。ここで、学習データと学習済みモデルを格納するディレクトリのパスを指定します。
ニューラルネットワークモデルの初期化に必要な入力次元数(input_size)を定義します。
損失関数(criterion)をクロスエントロピー損失関数で、最適化アルゴリズムを Adam で初期化します。
ラベルごとにデータセットとモデルを管理するための辞書を作成します。
メインデータディレクトリ内の各ラベルディレクトリをループで処理し、学習データを収集し、対応するモデルを訓練します。学習データはファイルから読み込まれ、PyTorchのテンソルに変換され、DataLoader を使用してミニバッチとしてロードされます。
各ラベルごとにモデルを訓練し、学習済みモデルを保存します。モデルは指定されたディレクトリに保存され、ファイル名はラベルに関連づけられます。
新しいデータを読み込み、各学習済みモデルを使用して新しいデータのラベルを予測します。各学習済みモデルは保存されたファイルからロードされ、新しいデータに適用されます。
最後に、予測されたラベルとそのクラスを表示します。ラベルは label{label}_model.pth のファイル名形式と一致するように整数から変換され、予測クラスが表示されます。
このプログラムで、なにか間違いがあれば教えてください。