Skip to content

Commit 167da78

Browse files
authored
新增代码文件 脚本 场景生成 量化评估文件 (#95)
* Update hutbthesis_main.tex * Add files via upload * 添加scripts目录 包含一些运行脚本 * retrieve文件夹 retrieve 文件夹在项目中用于存储与场景描述检索相关的数据和代码,帮助从数据库中获取并生成动态场景。 * 添加 undergraduate/demo 文件夹 * Add files via upload * Add files via upload * 添加docs文件夹 * Add files via upload * 添加safebench.egg-info文件夹 * 添加 safebench 文件夹 * 添加 undergraduate/tools 文件夹 * 添加 undergraduate/Scenic 文件夹 * 为 Python 包 safebench 创建一个可安装的包 为 Python 包 safebench 创建一个可安装的包,并指定了依赖项(gym 和 pygame)以及包的基本信息。 * 这是原作者的一个许可证 MIT 许可证是一个非常宽松的开源许可协议,允许他人自由地使用和修改代码,只要他们保留版权声明并且了解代码的“原样”提供,不承担任何责任。 * 包含用于构建和运行 Docker 容器的相关配置文件 docker 文件夹包含用于构建和运行 Docker 容器的相关配置文件(如 Dockerfile 和 run_docker.sh),目的是创建一个可重复的环境来运行项目或应用,通常用于依赖管理和环境配置。 * 用于存储和管理与自然语言描述生成场景相关的数据和代码。 用于存储和管理与自然语言描述生成场景相关的数据和代码。 * Update README.md * 输出文件outputs * 更新存放量化评估的文件夹 * Update README.md * Update README.md * Update README.md * Delete scene/undergraduate/demo/.idea directory * Delete scene/undergraduate/retrieve/__pycache__ directory * Delete scene/undergraduate/safebench.egg-info directory * Delete scene/undergraduate/outputs/screenshots directory * Delete scene/undergraduate/setup.py * Delete scene/undergraduate/safebench/__pycache__ directory * Delete scene/undergraduate/scripts/__pycache__ directory * Delete scene/undergraduate/safebench/agent/__pycache__ directory * Delete scene/undergraduate/Scenic directory * Delete scene/undergraduate/demo directory * Delete scene/undergraduate/docker directory * Delete scene/undergraduate/evaluation directory * Delete scene/undergraduate/docs directory * Delete scene/undergraduate/retrieve directory * Delete scene/undergraduate/safebench directory * Delete scene/undergraduate/scripts directory * Delete scene/undergraduate/tools directory * Delete scene/undergraduate/LICENSE * 增加代码文件夹 一些脚本 一些场景生成文件 一些量化评估文件 * Delete scene/retrieve/__pycache__ directory * Delete scene/retrieve/database_v1.pkl * Delete scene/scripts/__pycache__ directory
1 parent 0730bac commit 167da78

17 files changed

Lines changed: 947 additions & 0 deletions
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import os
2+
import json
3+
import numpy as np
4+
import matplotlib.pyplot as plt
5+
from sklearn.metrics import pairwise_distances_argmin_min
6+
import cv2
7+
8+
# 文件路径
9+
DESCRIPTION_FILE = 'D:/sceneMain/chatScene/retrieve/scenario_descriptions.txt'
10+
HISTORY_FILE = 'D:/sceneMain/chatScene/retrieve/scenario_history.txt'
11+
SCENE_IMAGE_DIR = 'D:/sceneMain/chatScene/outputs/'
12+
13+
# 加载最新的场景描述(只读取文件的第一行)
14+
def load_latest_description(path):
15+
"""只读取描述文件中的第一行"""
16+
with open(path, 'r', encoding='utf-8') as f:
17+
first_line = f.readline().strip() # 读取第一行
18+
return first_line
19+
20+
# 将新的场景描述追加到历史记录文件
21+
def append_to_history(new_description, history_path):
22+
"""将新的场景描述追加到历史文件"""
23+
with open(history_path, 'a', encoding='utf-8') as f:
24+
f.write(new_description + '\n')
25+
26+
# 计算图像相似度(使用结构相似度)
27+
def calculate_image_similarity(image1, image2):
28+
"""计算两张图像之间的相似度"""
29+
gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
30+
gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
31+
score, _ = cv2.quality.QualitySSIM_compute(gray1, gray2)
32+
return score
33+
34+
# 计算场景的多样性(使用生成图像之间的距离)
35+
def calculate_scene_diversity(image_dir):
36+
"""计算所有图像之间的多样性"""
37+
images = []
38+
for filename in os.listdir(image_dir):
39+
if filename.endswith('.png'):
40+
img = cv2.imread(os.path.join(image_dir, filename))
41+
images.append(img)
42+
43+
# 转换为数组(每个图像的特征)
44+
image_features = [np.reshape(img, (-1, 3)) for img in images]
45+
image_features = np.concatenate(image_features, axis=0)
46+
47+
# 计算每对图像的最小距离
48+
distances = pairwise_distances_argmin_min(image_features, image_features)
49+
avg_distance = np.mean(distances[1]) # 平均最小距离
50+
return avg_distance
51+
52+
# 评估场景质量:语义一致性,图像质量,多样性
53+
def evaluate_scene_quality(image_dir):
54+
"""评估场景的质量"""
55+
56+
# 语义一致性(假设为手动指定或从其他方法中获得)
57+
semantic_consistency = 0.9 # 假设的值,通常需要根据具体情况进行计算
58+
59+
# 图像质量:假设使用已有的参考图像进行评估(此处为一个示例)
60+
reference_image = cv2.imread('D:/sceneMain/chatScene/reference_image.png') # 参考图像
61+
image_files = [f for f in os.listdir(image_dir) if f.endswith('.png')]
62+
avg_image_quality = 0
63+
for image_file in image_files:
64+
img = cv2.imread(os.path.join(image_dir, image_file))
65+
similarity = calculate_image_similarity(reference_image, img)
66+
avg_image_quality += similarity
67+
avg_image_quality /= len(image_files)
68+
69+
# 多样性
70+
diversity = calculate_scene_diversity(image_dir)
71+
72+
# 打印评估结果
73+
print(f"语义一致性: {semantic_consistency}")
74+
print(f"平均图像质量: {avg_image_quality}")
75+
print(f"场景多样性: {diversity}")
76+
77+
return semantic_consistency, avg_image_quality, diversity
78+
79+
# 主函数
80+
def main():
81+
# 读取最新的场景描述
82+
latest_description = load_latest_description(DESCRIPTION_FILE)
83+
84+
# 将描述追加到历史记录
85+
append_to_history(latest_description, HISTORY_FILE)
86+
87+
# 打印最新描述
88+
print(f"最新的场景描述: {latest_description}")
89+
90+
# 评估生成的场景质量
91+
semantic_consistency, avg_image_quality, diversity = evaluate_scene_quality(SCENE_IMAGE_DIR)
92+
93+
# 可以根据需要将评估结果保存为JSON或其他格式
94+
evaluation_results = {
95+
"semantic_consistency": semantic_consistency,
96+
"avg_image_quality": avg_image_quality,
97+
"diversity": diversity
98+
}
99+
100+
# 保存评估结果到文件
101+
with open('D:/sceneMain/chatScene/outputs/evaluation_results.json', 'w') as f:
102+
json.dump(evaluation_results, f, indent=4)
103+
104+
if __name__ == "__main__":
105+
main()

scene/retrieve/architecture.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import os
2+
import openai
3+
import torch
4+
import transformers
5+
os.environ["OPENAI_API_KEY"] = 'sk-proj-xxx'
6+
7+
class LLMChat():
8+
def __init__(self, model_name = 'meta-llama/Meta-Llama-3-8B-Instruct'):
9+
super(LLMChat, self).__init__()
10+
self.model_name = model_name
11+
if model_name.startswith('gpt'):
12+
self.client = openai.OpenAI()
13+
else:
14+
self.pipeline = transformers.pipeline(
15+
"text-generation",
16+
model=model_name,
17+
model_kwargs={"torch_dtype": torch.bfloat16},
18+
device="cuda",
19+
)
20+
21+
def generate(self, messages, max_new_tokens = 500):
22+
if self.model_name.startswith('gpt'):
23+
response = self.client.chat.completions.create(
24+
model=self.model_name,
25+
messages=messages,
26+
temperature=0,
27+
)
28+
return response.choices[0].message.content
29+
else:
30+
outputs = self.pipeline(
31+
messages,
32+
max_new_tokens=max_new_tokens,
33+
do_sample=False
34+
)
35+
return outputs[0]["generated_text"][-1]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Now, your task is to help write part of the Scenic code for defining the adversarial behavior of an agent given the corresponding description. Here are some related description-snippet pairs:
2+
{content}
3+
Now, provide the snippet for the following description. Note that if there is already one in the example that matches the description, directly return snippet. Otherwise, please construct the snippet following the same format as above. Note that the name of the behavior function should always be AdvBehavior, and any hyperparameter should be defined as param OPT_xxx, and use it inside the behavior function with globalParameters.OPT_xxx. Please strictly follow the syntax as those used in the examples.
4+
5+
Description: {current_description}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
Your task is to decompose full descriptions of safety-critical scenarios into sub-descriptions for the following distinct components:
2+
3+
Adversarial Object: Indicate the type of the adversarial agent, restricted to Car, Pedestrian, Bicycle, or Motorcycle.
4+
Behavior: Describe the behavior of the adversarial agent.
5+
Geometry: Specify the road condition where the scenario occurs (e.g., straight road, four-way intersection), including traffic light conditions.
6+
Spawn Position: Indicate the initial relative position of the adversarial object to the ego vehicle, including any potential obstructions like a vending machine.
7+
8+
Here are some examples:
9+
Scenario: The ego vehicle is driving on a straight road, and the car in front brakes suddenly as the ego approaches.
10+
Adversarial Object: Car
11+
Behavior: The adversarial car suddenly brakes as the ego approaches.
12+
Geometry: A straight road.
13+
Spawn Position: The adversarial agent is directly in front of the ego vehicle on the same straight road, heading in the same direction.
14+
15+
Scenario: The ego vehicle attempts a right turn at a four-way intersection, and an adversarial pedestrian crosses the road and suddenly stops.
16+
Adversarial Object: Pedestrian
17+
Behavior: The adversarial pedestrian deliberately steps onto the road in front of the ego vehicle.
18+
Geometry: The ego vehicle drives across a four-way intersection.
19+
Spawn Position: The adversarial agent is on the right front of the ego vehicle at the end of the ego's initial lane for crossing.
20+
21+
Scenario: The ego vehicle navigates around a parked car, and an oncoming car suddenly turns into its path.
22+
Adversarial Object: Car
23+
Behavior: The adversarial car suddenly turns into the ego's path.
24+
Geometry: The ego vehicle is positioned on a two-lane road with traffic flowing in opposite directions.
25+
Spawn Position: The adversarial agent comes from the near opposite oncoming lane, with a parked car blocking the ego vehicle's lane.
26+
27+
Scenario: The ego vehicle is traveling along a straight road when a pedestrian, initially hidden behind a bus stop on the sidewalk to the right, unexpectedly dashes onto the road directly in front of the ego vehicle and comes to an abrupt stop.
28+
Adversarial Object: Pedestrian
29+
Behavior: The adversarial pedestrian suddenly sprints from the right, stopping abruptly in front of the ego vehicle.
30+
Geometry: A straight road.
31+
Spawn Position: The adversarial agent spawns from behind a bus stop on the right front of the ego vehicle on the same straight road for crossing.
32+
33+
Scenario: The ego vehicle is changing to the right lane when an adversarial vehicle approaches rapidly from the right.
34+
Adversarial Object: Car
35+
Behavior: The adversarial car approaches rapidly.
36+
Geometry: The ego vehicle is placed in a straight lane that includes a right lane.
37+
Spawn Position: The adversarial car drives straight from the rear right of the ego.
38+
39+
Scenario: The ego vehicle is turning right at an intersection, and a crossing car from the left violates the red light and suddenly brakes.
40+
Adversarial Object: Car
41+
Behavior: The adversarial car suddenly brakes near the ego vehicle.
42+
Geometry: The ego vehicle drives straight across a four-way signalized intersection; the light is red for the adversarial agent.
43+
Spawn Position: The adversarial car is crossing the intersection from the left.
44+
45+
Now, extract the adversarial behavior, geometry and spawn position in the same format from the following scenario, notice Adversarial Object is restricted to Car, Pedestrian, Bicycle, or Motorcycle.
46+
Scenario: {scenario}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Now, your task is to help write part of the Scenic code for defining the geometry for the ego agent given the corresponding description. Here are some related description-snippet pairs:
2+
{content}
3+
Now, provide the snippet for the following description. Note that if there is already one in the example that matches the description, directly return snippet. Otherwise, please construct the snippet following the same format as above. Please do not use the syntax outside of those used in the examples.
4+
5+
Description: {current_description}

scene/retrieve/prompts/spawn.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Now, your task is to help write part of the Scenic code for defining the spawn point for the adversarial agent given the corresponding description. Here are some related description-snippet pairs:
2+
{content}
3+
Now, provide the snippet for the following description. Note that if there is already a snippet in the example that matches the description, directly return snippet. Otherwise, please construct a new snippet following the format provided above. Note that any hyperparameters should be defined as param OPT_xxx, and use them as globalParameters.OPT_xxx. If there is a blocker involved, you must also define it. The blocker can be chosen only from the following options: 'Car', 'ATM', 'Barrel', 'Barrier', 'Bench', 'BusStop', 'Chair', 'Debris', 'Garbage', 'Mailbox', 'VendingMachine'. Please do not use the syntax outside of those used in the examples.
4+
5+
Description: {current_description}

scene/retrieve/retrieve.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import setGPU
2+
import os
3+
import csv
4+
import pickle
5+
import re
6+
from sentence_transformers import SentenceTransformer
7+
from os import path as osp
8+
from tqdm import tqdm
9+
import argparse
10+
from architecture import LLMChat
11+
from utils import load_file, retrieve_topk, generate_code_snippet, save_scenic_code
12+
13+
# no need for faiss currently
14+
# import faiss
15+
16+
parser = argparse.ArgumentParser(description="Set up configurations for your script.")
17+
parser.add_argument('--port_ip', type=int, default=2000, help='Port IP address (default: 2000)')
18+
parser.add_argument('--topk', type=int, default=3, help='Top K value (default: 3) for retrieval')
19+
parser.add_argument('--model', type=str, default='gpt-4o', help="Model name (default: 'gpt-4o'), also support transformers model")
20+
parser.add_argument('--use_llm', action='store_true', help='if use llm for generating new snippets')
21+
args = parser.parse_args()
22+
23+
port_ip = args.port_ip
24+
topk = args.topk
25+
use_llm = args.use_llm
26+
27+
llm_model = LLMChat(args.model)
28+
local_path = osp.abspath(osp.dirname(osp.dirname(osp.realpath(__file__))))
29+
extraction_prompt = load_file(osp.join(local_path, 'retrieve', 'prompts', 'extraction.txt'))
30+
behavior_prompt = load_file(osp.join(local_path, 'retrieve', 'prompts', 'behavior.txt'))
31+
geometry_prompt = load_file(osp.join(local_path, 'retrieve', 'prompts', 'geometry.txt'))
32+
spawn_prompt = load_file(osp.join(local_path, 'retrieve', 'prompts', 'spawn.txt'))
33+
scenario_descriptions = load_file(osp.join(local_path, 'retrieve', 'scenario_descriptions.txt')).split('\n')
34+
encoder = SentenceTransformer('sentence-transformers/sentence-t5-large', device='cuda')
35+
36+
# Load the database
37+
with open(osp.join(local_path, 'retrieve/database_v1.pkl'), 'rb') as file:
38+
database = pickle.load(file)
39+
40+
behavior_descriptions = database['behavior']['description']
41+
geometry_descriptions = database['geometry']['description']
42+
spawn_descriptions = database['spawn']['description']
43+
behavior_snippets = database['behavior']['snippet']
44+
geometry_snippets = database['geometry']['snippet']
45+
spawn_snippets = database['spawn']['snippet']
46+
47+
behavior_embeddings = encoder.encode(behavior_descriptions, device='cuda', convert_to_tensor=True)
48+
geometry_embeddings = encoder.encode(geometry_descriptions, device='cuda', convert_to_tensor=True)
49+
spawn_embeddings = encoder.encode(spawn_descriptions, device='cuda', convert_to_tensor=True)
50+
51+
## This is the head for scenic file, you can modify the carla map or ego model here
52+
head = '''param map = localPath(f'../maps/{Town}.xodr')
53+
param carla_map = Town
54+
model scenic.simulators.carla.model
55+
EGO_MODEL = "vehicle.lincoln.mkz_2017"
56+
'''
57+
58+
log_file_path = osp.join(local_path, 'safebench', 'scenario', 'scenario_data', 'scenic_data', 'dynamic_scenario', 'dynamic_log.csv')
59+
60+
with open(log_file_path, mode='w', newline='') as file:
61+
log_writer = csv.writer(file)
62+
log_writer.writerow(['Scenario', 'AdvObject', 'Behavior Description', 'Behavior Snippet', 'Geometry Description', 'Geometry Snippet', 'Spawn Description', 'Spawn Snippet', 'Success'])
63+
64+
for q, current_scenario in tqdm(enumerate(scenario_descriptions)):
65+
messages = [
66+
{"role": "system", "content": "You are a helpful assistant."},
67+
{"role": "user", "content": extraction_prompt.format(scenario=current_scenario)},
68+
]
69+
70+
response = llm_model.generate(messages)
71+
72+
try:
73+
match = re.search(r"Adversarial Object:(.*?)Behavior:(.*?)Geometry:(.*?)Spawn Position:(.*)", response, re.DOTALL)
74+
if not match:
75+
raise ValueError("Failed to extract components from the response")
76+
77+
current_adv_object, current_behavior, current_geometry, current_spawn = [s.strip() for s in match.groups()]
78+
79+
# Retrieve the top K relevant snippets
80+
top_behavior_descriptions, top_behavior_snippets = retrieve_topk(encoder, topk, behavior_descriptions, behavior_snippets, behavior_embeddings, current_behavior)
81+
top_geometry_descriptions, top_geometry_snippets = retrieve_topk(encoder, topk, geometry_descriptions, geometry_snippets, geometry_embeddings, current_geometry)
82+
top_spawn_descriptions, top_spawn_snippets = retrieve_topk(encoder, topk, spawn_descriptions, spawn_snippets, spawn_embeddings, current_spawn)
83+
84+
# Generate code snippets using the LLM
85+
generated_behavior_code = generate_code_snippet(
86+
llm_model, behavior_prompt, top_behavior_descriptions, top_behavior_snippets, current_behavior, topk, use_llm
87+
)
88+
89+
generated_geometry_code = generate_code_snippet(
90+
llm_model, geometry_prompt, top_geometry_descriptions, top_geometry_snippets, current_geometry, topk, use_llm
91+
)
92+
93+
generated_spawn_code = generate_code_snippet(
94+
llm_model, spawn_prompt, top_spawn_descriptions, top_spawn_snippets, current_spawn, topk, use_llm
95+
)
96+
97+
# Log the results
98+
log_writer.writerow([current_scenario, current_adv_object, current_behavior, generated_behavior_code, current_geometry, generated_geometry_code, current_spawn, generated_spawn_code, 1])
99+
100+
Town, generated_geometry_code = generated_geometry_code.split('\n', 1)
101+
scenic_code = '\n'.join([f"'''{current_scenario}'''", Town, head, generated_behavior_code, generated_geometry_code, generated_spawn_code.format(AdvObject=current_adv_object)])
102+
save_scenic_code(local_path, port_ip, scenic_code, q)
103+
104+
except Exception as e:
105+
log_writer.writerow([current_scenario, '', '', '', '', '', '', '', 0])
106+
print(f"Failure for scenario: {current_scenario} - Error: {e}")

0 commit comments

Comments
 (0)