iT邦幫忙

2024 iThome 鐵人賽

DAY 20
0
Software Development

LSTM結合Yolo v8對於多隻斑馬魚行為分析系列 第 20

Lstm結合yolo分析斑馬魚陰影是否造成實驗誤差

  • 分享至 

  • xImage
  •  

今天是第二十天我們做實驗發現斑馬魚陰影可能會影響到實驗的準確值,因此我們可以寫一個lstm結合yolo的程式去分析,以下是程式碼

  1. 多類YOLO檢測:不僅檢測斑馬魚和陰影,還可以檢測其他可能影響實驗的物體,如光源、其他魚類等。
  2. LSTM模型增強:我們會引入多層LSTM和雙向LSTM來捕捉更複雜的時間依賴性。
  3. 數據增強和預處理:對YOLO的輸出進行進一步處理,例如計算斑馬魚與陰影之間的距離、陰影面積、魚的速度等,這些都將作為LSTM模型的輸入特徵。
  4. 多目標優化:LSTM模型可以輸出多個指標,分析陰影對不同行為的影響,例如焦慮、逃避等。

1. 複雜的YOLO檢測

import torch
from yolov5 import YOLOv5
import cv2

# 初始化 YOLOv5 模型
model = YOLOv5("yolov5s.pt")  # 使用訓練好的模型

def detect_objects(image):
    results = model.predict(image)
    detected_objects = {'fish': [], 'shadow': [], 'light': [], 'other': []}

    for result in results:
        for det in result.boxes:
            cls_id = int(det.cls)
            x1, y1, x2, y2 = map(int, det.xyxy)
            if cls_id == 0:  # 假設斑馬魚類別ID為0
                detected_objects['fish'].append([x1, y1, x2, y2])
            elif cls_id == 1:  # 假設陰影類別ID為1
                detected_objects['shadow'].append([x1, y1, x2, y2])
            elif cls_id == 2:  # 假設光源類別ID為2
                detected_objects['light'].append([x1, y1, x2, y2])
            else:  # 其他物體
                detected_objects['other'].append([x1, y1, x2, y2])

    return detected_objects

2. 高階數據處理

這裡我們不僅輸出位置資訊,還會計算距離、速度、面積等作為LSTM的輸入特徵。

import numpy as np

def calculate_distance(box1, box2):
    x1_center = (box1[0] + box1[2]) / 2
    y1_center = (box1[1] + box1[3]) / 2
    x2_center = (box2[0] + box2[2]) / 2
    y2_center = (box2[1] + box2[3]) / 2
    return np.sqrt((x1_center - x2_center)**2 + (y1_center - y2_center)**2)

def calculate_area(box):
    return (box[2] - box[0]) * (box[3] - box[1])

def calculate_velocity(previous_box, current_box, time_interval):
    previous_center = [(previous_box[0] + previous_box[2]) / 2, (previous_box[1] + previous_box[3]) / 2]
    current_center = [(current_box[0] + current_box[2]) / 2, (current_box[1] + current_box[3]) / 2]
    distance = np.sqrt((current_center[0] - previous_center[0])**2 + (current_center[1] - previous_center[1])**2)
    return distance / time_interval

def prepare_complex_sequence_data(detected_objects_list, sequence_length=10, time_interval=1.0):
    sequence_data = []
    
    for i in range(len(detected_objects_list) - sequence_length):
        fish_seq = []
        shadow_seq = []
        for j in range(sequence_length):
            fish_boxes = detected_objects_list[i+j]['fish']
            shadow_boxes = detected_objects_list[i+j]['shadow']
            
            # 距離、面積和速度特徵
            if fish_boxes and shadow_boxes:
                fish_box = fish_boxes[0]
                shadow_box = shadow_boxes[0]
                
                distance = calculate_distance(fish_box, shadow_box)
                fish_area = calculate_area(fish_box)
                shadow_area = calculate_area(shadow_box)
                
                if i > 0:  # 速度計算需要前一個時間點的數據
                    prev_fish_box = detected_objects_list[i+j-1]['fish'][0]
                    fish_velocity = calculate_velocity(prev_fish_box, fish_box, time_interval)
                else:
                    fish_velocity = 0
                
                # 特徵序列
                fish_seq.append([distance, fish_area, fish_velocity])
                shadow_seq.append([shadow_area])
            else:
                fish_seq.append([0, 0, 0])
                shadow_seq.append([0])
        
        seq = np.array(fish_seq + shadow_seq).flatten()
        sequence_data.append(seq)

    return np.array(sequence_data)

3. 高階LSTM模型

這裡我們使用雙向LSTM並增強模型的複雜度,讓其更好地捕捉時間序列的模式。

import torch
import torch.nn as nn

class AdvancedFishBehaviorLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers=2, bidirectional=True):
        super(AdvancedFishBehaviorLSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=bidirectional)
        self.fc1 = nn.Linear(hidden_size * 2 if bidirectional else hidden_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h_0 = torch.zeros(2 if self.lstm.bidirectional else 1, x.size(0), self.lstm.hidden_size)
        c_0 = torch.zeros(2 if self.lstm.bidirectional else 1, x.size(0), self.lstm.hidden_size)

        out, _ = self.lstm(x, (h_0, c_0))
        out = torch.relu(self.fc1(out[:, -1, :]))
        out = self.fc2(out)
        return out

# 假設我們的輸入是更加複雜的特徵組合
input_size = 3 * 10 + 1 * 10  # 魚的3個特徵(距離、面積、速度) * 10個時間步長 + 陰影的1個特徵(面積) * 10個時間步長
hidden_size = 256
output_size = 3  # 假設我們有三個行為影響指標(例如焦慮、逃避、活動水平)

model = AdvancedFishBehaviorLSTM(input_size, hidden_size, output_size)

# 假設 sequence_data 是你使用複雜特徵集準備的數據
sequence_data = prepare_complex_sequence_data(detected_objects_list)
sequence_data_tensor = torch.tensor(sequence_data, dtype=torch.float32)

# 進行預測
predictions = model(sequence_data_tensor)

4. 多目標優化與評估

這裡我們會對多個行為指標進行預測並輸出每個指標的評估結果。

# 假設我們對每個行為指標都設定了不同的閾值
anxiety_threshold = 0.6
avoidance_threshold = 0.5
activity_level_threshold = 0.7

impact_anxiety = (predictions[:, 0] > anxiety_threshold).numpy()
impact_avoidance = (predictions[:, 1] > avoidance_threshold).numpy()
impact_activity = (predictions[:, 2] > activity_level_threshold).numpy()

# 輸出結果
print("斑馬魚焦慮是否受到陰影影響:", impact_anxiety)
print("斑馬魚逃避行為是否受到陰影影響:", impact_avoidance)
print("斑馬魚活動水平是否受到陰影影響:", impact_activity)

1. 複雜的YOLO檢測

import torch
from yolov5 import YOLOv5
import cv2

# 初始化 YOLOv5 模型
model = YOLOv5("yolov5s.pt")  # 使用訓練好的模型

def detect_objects(image):
    results = model.predict(image)
    detected_objects = {'fish': [], 'shadow': [], 'light': [], 'other': []}

    for result in results:
        for det in result.boxes:
            cls_id = int(det.cls)
            x1, y1, x2, y2 = map(int, det.xyxy)
            if cls_id == 0:  # 假設斑馬魚類別ID為0
                detected_objects['fish'].append([x1, y1, x2, y2])
            elif cls_id == 1:  # 假設陰影類別ID為1
                detected_objects['shadow'].append([x1, y1, x2, y2])
            elif cls_id == 2:  # 假設光源類別ID為2
                detected_objects['light'].append([x1, y1, x2, y2])
            else:  # 其他物體
                detected_objects['other'].append([x1, y1, x2, y2])

    return detected_objects
  1. YOLOv5 模型初始化

    • 我們導入了 YOLOv5 模型,並使用 yolov5s.pt 作為預訓練模型。這個模型可以用來檢測圖片中的不同物體。
  2. detect_objects 函數

    • 此函數接收一張圖像作為輸入,然後使用 YOLOv5 模型進行物體檢測。
    • 檢測結果包含了每個物體的邊界框和類別ID,我們根據這些類別ID將物體分類為fish)、陰影shadow)、光源light)和其他other)。
    • 函數返回一個字典,包含了不同類別的物體邊界框座標。

2. 高階數據處理

import numpy as np

def calculate_distance(box1, box2):
    x1_center = (box1[0] + box1[2]) / 2
    y1_center = (box1[1] + box1[3]) / 2
    x2_center = (box2[0] + box2[2]) / 2
    y2_center = (box2[1] + box2[3]) / 2
    return np.sqrt((x1_center - x2_center)**2 + (y1_center - y2_center)**2)

def calculate_area(box):
    return (box[2] - box[0]) * (box[3] - box[1])

def calculate_velocity(previous_box, current_box, time_interval):
    previous_center = [(previous_box[0] + previous_box[2]) / 2, (previous_box[1] + previous_box[3]) / 2]
    current_center = [(current_box[0] + current_box[2]) / 2, (current_box[1] + current_box[3]) / 2]
    distance = np.sqrt((current_center[0] - previous_center[0])**2 + (current_center[1] - previous_center[1])**2)
    return distance / time_interval

def prepare_complex_sequence_data(detected_objects_list, sequence_length=10, time_interval=1.0):
    sequence_data = []
    
    for i in range(len(detected_objects_list) - sequence_length):
        fish_seq = []
        shadow_seq = []
        for j in range(sequence_length):
            fish_boxes = detected_objects_list[i+j]['fish']
            shadow_boxes = detected_objects_list[i+j]['shadow']
            
            # 距離、面積和速度特徵
            if fish_boxes and shadow_boxes:
                fish_box = fish_boxes[0]
                shadow_box = shadow_boxes[0]
                
                distance = calculate_distance(fish_box, shadow_box)
                fish_area = calculate_area(fish_box)
                shadow_area = calculate_area(shadow_box)
                
                if i > 0:  # 速度計算需要前一個時間點的數據
                    prev_fish_box = detected_objects_list[i+j-1]['fish'][0]
                    fish_velocity = calculate_velocity(prev_fish_box, fish_box, time_interval)
                else:
                    fish_velocity = 0
                
                # 特徵序列
                fish_seq.append([distance, fish_area, fish_velocity])
                shadow_seq.append([shadow_area])
            else:
                fish_seq.append([0, 0, 0])
                shadow_seq.append([0])
        
        seq = np.array(fish_seq + shadow_seq).flatten()
        sequence_data.append(seq)

    return np.array(sequence_data)
  1. calculate_distance 函數

    • 計算兩個邊界框(box1box2)的中心點之間的歐幾里得距離。
  2. calculate_area 函數

    • 計算邊界框的面積,即長寬的乘積。
  3. calculate_velocity 函數

    • 計算某個物體在時間間隔 time_interval 內的移動速度。這是通過計算前後兩個邊界框中心點之間的距離來實現的。
  4. prepare_complex_sequence_data 函數

    • 該函數從 YOLO 檢測結果中提取出對應的特徵(如距離、面積、速度)並構建成一個時間序列數據集。
    • 將時間序列的每一步包含的魚和陰影的特徵組合成一個輸入向量,然後組合這些輸入向量以形成最終的數據集。

3. 高階LSTM模型

import torch
import torch.nn as nn

class AdvancedFishBehaviorLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers=2, bidirectional=True):
        super(AdvancedFishBehaviorLSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=bidirectional)
        self.fc1 = nn.Linear(hidden_size * 2 if bidirectional else hidden_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h_0 = torch.zeros(2 if self.lstm.bidirectional else 1, x.size(0), self.lstm.hidden_size)
        c_0 = torch.zeros(2 if self.lstm.bidirectional else 1, x.size(0), self.lstm.hidden_size)

        out, _ = self.lstm(x, (h_0, c_0))
        out = torch.relu(self.fc1(out[:, -1, :]))
        out = self.fc2(out)
        return out

# 假設我們的輸入是更加複雜的特徵組合
input_size = 3 * 10 + 1 * 10  # 魚的3個特徵(距離、面積、速度) * 10個時間步長 + 陰影的1個特徵(面積) * 10個時間步長
hidden_size = 256
output_size = 3  # 假設我們有三個行為影響指標(例如焦慮、逃避、活動水平)

model = AdvancedFishBehaviorLSTM(input_size, hidden_size, output_size)

# 假設 sequence_data 是你使用複雜特徵集準備的數據
sequence_data = prepare_complex_sequence_data(detected_objects_list)
sequence_data_tensor = torch.tensor(sequence_data, dtype=torch.float32)

# 進行預測
predictions = model(sequence_data_tensor)
  1. LSTM 模型設計

    • AdvancedFishBehaviorLSTM 是一個包含雙向 LSTM 的深度學習模型,用於分析時間序列數據。
    • input_size 是每個時間步的輸入特徵數量,這裡是魚和陰影的特徵組合。
    • hidden_size 是 LSTM 層中隱藏單元的數量。
    • output_size 是最終輸出的數量,代表不同行為的影響指標。
  2. 模型的前向傳播

    • forward 函數中,LSTM 層將輸入數據處理成隱藏狀態。
    • 緊接著,我們使用全連接層來進一步處理隱藏狀態,並通過 ReLU 激

活函數來引入非線性。

  • 最終的輸出是不同行為影響指標的預測值。
  1. 模型預測
    • 使用前面準備好的時間序列數據,我們將其轉換為張量並通過模型進行預測,得出最終的預測結果。

整體流程概述

這段程式碼的整體流程如下:

  1. 使用 YOLOv5 模型檢測圖像中的魚、陰影和光源。
  2. 提取出魚和陰影的相關特徵(如距離、面積、速度),並構建時間序列數據集。
  3. 使用一個高階的 LSTM 模型來分析這些時間序列數據,最終預測出魚行為的不同指標。

上一篇
day 19 Yolo分析公路車胎壓結合lstm換輪胎時間
下一篇
day 21lstm預測晶圓良率結合yolo淘汰不良的晶圓
系列文
LSTM結合Yolo v8對於多隻斑馬魚行為分析30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言