From 0f9f080e77aee2c4cae8d3a4b1a8e7d5865865a0 Mon Sep 17 00:00:00 2001 From: huangfu <3045324663@qq.com> Date: Fri, 6 Feb 2026 14:13:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=AD=E7=BB=83=E6=96=B0=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expert_replay_env.cpython-313.pyc | Bin 20984 -> 16092 bytes .../expert_replay_env.cpython-39.pyc | Bin 7990 -> 7617 bytes .../inverse_dynamics.cpython-39.pyc | Bin 2008 -> 2008 bytes Env/__pycache__/scenario_env.cpython-313.pyc | Bin 12636 -> 13605 bytes Env/__pycache__/scenario_env.cpython-39.pyc | Bin 7469 -> 7804 bytes Env/bc_env.py | 24 +--- Env/expert_replay_env.py | 104 ++++------------ Env/scenario_env.py | 5 + Env/utils.py | 84 +++++++++++++ dataset/loader.py | 29 +++++ ...nts.out.tfevents.1770305241.Hfkk.1085091.0 | Bin 0 -> 3660 bytes ...nts.out.tfevents.1770305658.Hfkk.1087435.0 | Bin 0 -> 1726 bytes ...nts.out.tfevents.1770305767.Hfkk.1088080.0 | Bin 0 -> 3805 bytes ...nts.out.tfevents.1770306009.Hfkk.1089433.0 | Bin 0 -> 88 bytes ...nts.out.tfevents.1770306026.Hfkk.1089559.0 | Bin 0 -> 152686 bytes scripts/visualize.py | 32 ++--- train_bc.py | 114 +++++++++++------- 17 files changed, 233 insertions(+), 159 deletions(-) create mode 100644 logs/bc/20260205-232721/events.out.tfevents.1770305241.Hfkk.1085091.0 create mode 100644 logs/bc/20260205-233418/events.out.tfevents.1770305658.Hfkk.1087435.0 create mode 100644 logs/bc/20260205-233607/events.out.tfevents.1770305767.Hfkk.1088080.0 create mode 100644 logs/bc/20260205-234009/events.out.tfevents.1770306009.Hfkk.1089433.0 create mode 100644 logs/bc/20260205-234026/events.out.tfevents.1770306026.Hfkk.1089559.0 diff --git a/Env/__pycache__/expert_replay_env.cpython-313.pyc b/Env/__pycache__/expert_replay_env.cpython-313.pyc index a3f53e1b4bf6d9fc09c00f72b4120c65b335315f..c1d8408a2f42f4cc047c840390369cf4d56792c1 100644 GIT binary patch delta 6524 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 diff --git a/Env/__pycache__/expert_replay_env.cpython-39.pyc b/Env/__pycache__/expert_replay_env.cpython-39.pyc index fcb7475c31ef6d2fd36ffd8652c0ae08218072ab..8d83baca58fcec765d484ef529353acc4b6597c7 100644 GIT binary patch delta 903 zcmZ8f%WD%s7@wJa%~#-__QyG=GtHtFm(eVABK zFH(AtxoL$4yog@3r6(`m6vU%K4ube66uel)Z<-X*VeY1O`??!@JAmBx? zPVGH3A6$GL{NnL-t9Dsiwp6W9VBbQmZdG$s(=wem-uHO@6~tCi9&O_~x{T6WGo*%V zM8{R4lNfr6o{^eR6(EA-g}hinba2sYqME1+RRY>gU2NVEFT@a_7(=?WMQY+9M{;Cf zLyRsTdR^dkZ%Q?(Ds8)TkG}57k~+qyDjk2KDqMgx+iu-k$5l!70M!RnN%byzb^kO< z1lDG!c|QvDqu7q-m>FeG%PeGRY01)+ijgxj1;bWKR>n{?N1=voI7*LIQtVu5S#`{! zq0E~F$DkvMHCzIJu~g9t%G{~~m#HU`vKL&366g zPc}S%6HX<3G|4@K?7-hE(=f;>b~Z48)9gl|YoZ5qL|SkVHo+ne6B*0DWl;u=Z_s|q zF7EZ?wc+uVvO%3|M!BG^j$4)FzwdYM`28}NXFXb6=4T9!EduBWW`(C{1mpy!t#Gjq zq5i-o4UL1laZPeqt7EG|qvye$*+KQXKAZ=;koP$|p9$8i)P-sx|-B8m-?9Ax*}6gdGU?IZTQZ9cxhsl1pbM7dN1=!Fn!v7X2VUSPWs z#mkKYP2<-{Olk=51neL(fekhu9m5&+C_3s(c`{3ssB) zdOnM{JNIJ|f^+Oids?1srv24^3Fp~pM*%OfmmO!0$)7vYLn}Z@xh=!Y=H^PY;VPQ8 fZCY7+mnZ$N`m10YVtQvCYLerVLewp?>G=0QQcdI} delta 1269 zcmZux-D@0G6u;-rM|LOK>9(Z1$tG_5U?iKip`b0;##Lx5RWOJVT5GqP&ECmowwwJp zGbXmovX%%6MI_uu6?Vmk_MwOd#kb;v_yIl(`{0XzfS}-uAf7YJk_VmP{N{Ylz4vzx z_uGqK7u`xKA_9e zg|3XGf?4*<+Y%kcwlOO{5}(Mf5gFt+>So>A5m@XvzUZ3Dj3ik~S)(uIn^Z5AH7k_; zvFw_0jU7%ROT2Pbfz@H8}tfku_c-GFJFElay|ilce#stg_Q_ zlvopmsnuaJ*lO*TLx0=D6Lc1Qf?#Mjyk;%j8d|%)3b!6ge1k(bIAm>jHNS~Zk^ay` zol7mcg-KlI_*sTUeJ!;FL;YUr4BXORrB1xKL~b#83|z~VE=XxYTH0X$V_P=J_$BLa zJL$Tv;lSOcD{r?w3}5rwjmn)X&7I{#%Jt7~s%O*RERstk!2^Ow^u<7csEIC+NIE;z zW!>nTaZ6UIB?b{_^eqJgz#5s8v92uL*~#~Y4|}{ZEd%U z-;w<%iMac`{?t9yTV83js+C4iBxRgaNa0JAfu|WRFkEDaTlq9=MTSL!p+Q4|>uf&5 z@EpTAf`X0H^cg0@RvEqR){b{0-P)*o)i5ZNtJ?4?h_4HARKyz|CaZ5DmV?l1Yu`P+ z@Hy26^8~_37$%r91CDgSh8b{RN+w{MCgz~;o`J%3O2Rw?lW;hc_$He-8F((Sr2jf{ zKfOWfFj1*_&9Lk%yruWkC*k{pFVnA>r%-VoZR&scQ+{>CUzu8jo4Rm(Gmrnx#DIM3 zqm)O-?*r;*Gbb0>$*sjrQVRK)IpkXexvhAVp+=zZWv)U)|CG4|b?s)07W(YHmVMIR z<{Y|WvfU$hSmm}NPx~JSshO;VmR`t}>~}^hzn^;nI{L?418VyG+`_oHGFO5~Kc36d h4MEjBJBKrZuaa5Qzt0V5?fvr diff --git a/Env/__pycache__/scenario_env.cpython-313.pyc b/Env/__pycache__/scenario_env.cpython-313.pyc index 7d8143bf8a823d9dd258dc90f393f21ea0af1565..d6fe5b59f629ec2003f3b5149c20a4d532eec11a 100644 GIT binary patch delta 3369 zcmai0eNa@_6@PEpw;wFaF1sur3kwexkwt;Uf?82S)B*-X!xJ@u^ttRl;NkLiy}M}W z*g}#v(ZsaWs}o3Vy3?@*-%&o#8ya4$m2WO3z~6 zSpRIdp3`<4>NFhVqz1J0pideyau!bCozCe%#t=@Orjx3pIRnu$3}^>vWa5lY3T1HV zgqk@Mp_yDpx24vlXEIV~tivc6A<`l3;U))K!W;3$g<2$h}E&|p6A4@prJ z3I>G$aexr0Nr3_c& zc3U~#R%ymh*t6HcDSV}Mtp5swOgkDM!P`K5b2OBy65?5tI)2#qEQ9zwN&-F?;!WB4 zBW_jQ3!yAiXI-reqc(M<27>46s&TCuSW+hUuj|dR*;TS!wU_`SE;YAA{1 zDM^FJw7J-Aw&TAu*|@PV`-m+)vzczGqo^UG7p~jo#bHl2E;SR>7_el?$@CHa7Pw1V zj%FzQp_#>_7IPZiVF82`r>O@{&QZ%L`I<|EtWA)_bY#JiUbPr=iYcngPPj_z%6>4w zd$SxxrBo-Q8d3YLG^dqxiwt;)hh30ol=g4|$5fG9^cd6CV4BmBpLT`flWJb=VXd;2 zzEhL>o)Iml2k$up&`#aLHyKlNEmNc$kfJIG_<%3! zt7fjT)kAwhyB@0B%Kwuoz@tc%eA+1WH}{e_!DSH}Hx%Ii9Qy7F^A)x} z!PfuTQlGR|T(Q<9tTm@hm#u4)d9LxkiOkskL|)AplU&(wRy-}9-E(@+aqfieo&2BY zPu9pr z8s=-8=c`&iE^LWEH^Pq@lUDZ?Yh}V(nRFJ%(i6^QldTEo>SW2XWRW}8JRwa!n-Ww2o)1o(ra!JrQo^jRMCWz3J znL1#|^eBYCbmcmSVMy`_g&aVjb}4C_BxP^WcHKcTm#g7GajYnhJ~(x*$gHD};y;#E z(XIINve(z_T3GQW=o-m`h*$0~dI2Ouz|_K>m(AgjNKg`zc$kv?XO{5vd0be&y6jz0 zJqhH;pl^OqPRNt3uRn_BKyU^>U%p0n2*jm|KYuFEpkq^?l<#FmjuI}^C#5x^cGAmw zp7#ZVJnu0ng$;pssV`d%BLy1=Kr!9dOOQ!?7QzTV7b$yW2w^c23J57aNBACNsz7}V zI*P+2c~B@$QCXCn<|EZjkA(d`6o{ag@YUr-^a1?u<;C=eQw3FidL%jx>F%YejJpO8;~rlU)5iQUW5QW^pCmK) z9U!0WpzX|)^kf!JdEDLmugPX132m(pj+@?y)ODw{DrqYt6xJ` Nj<u+006`!$luisAMXX4t49XoBDws|xTZPK)4*)0hP$##9~?6!8-y|r%~r;hE6 zotCW-A)+95m)-3$LbM-{l2SxiKF|_G0|JpE0WCtRFBH|>MWW&_Xeg`l1&KM=aaw_x zD8D&#<~L`~W6t&W=Kp%$`qW}EA~uF!UCI8ThP|2ZC^clF=FH)zr@I4qb2 zE};_|68eaSW8{b?h9X$tJ!oD(-!PAfLC|>+F$#KyCc%&}CoBnF!kTELD|;Q^G&Z`8 zjM_k&1rxEw&@oKxAr!VKPWnNglO8qxo1bP@l@MFHHcpuiU>v0@=6Ci@D-9({N~bj7 z;m$CzS$UJtyYVj6L^R;9@;U4qI>D%)^@En8m4zSJN;Xe z$r0lO9gqY)V4jch(fweZPJ0ZEE_Rq*P#e)6TJ$*W{2;EaU&VqUuX~Xn-p}~`b$)D@ zDHsp3`uw-0ATJ>HXE>yVo9kAAsan>@P}HLaq&mCI2`1G~Ghj@&>$j!07I3Ys|D!kV zmb)IQwRS?qx~^tL|9`CL1!H&JjL_J_)t&XT3QYAPWI}!v)7sJaA(p}hx@vRd7t1xU zlWiA{r~w^@1Uu|##!%AqqLPLkv?5fv9z8;jH2XMX-Vig=GtEKz6`Q>&W_*4dOG(Yb zF^YS9S`JpuQ5={bAra=6aug9qDPU&UYFmENdJ^(YwcU|shDFHzUMz+;)Mjrh5`bjlP% zXIGdn7eY+zL180~;;U+ra_!Pb1_0hMzdq!AsP?%FR*|cIP%@r;s z%h?4<;m%8$Y@WcTqLuRL@Bjgy6+TzUWF$hMS4ot9yp`0~&P zE>8C{Fvqm?W7jvDp71ENx1#q~gPmV*c&PVN#W%eC*xqu@_2IFbQ;$MJa%kw!_Mxid zz$3?i>=?K;`Oq<1^#)e=U7ub*EPDs8o~RBE-#LBz^qu(a_)XjQTW_?k4?Ya^Z=Jt7 zQJp;bVCeqPgQNG4-qfz1_^xsNwKeNcYyNZss_8(-D}5hh2>u77+7dTM zWdHcR&dSNx@Ap(rr{sxrMal;%#l?!WC{K_|duiLm54xTq-s#?UqF@|94IyuYe%l?w zk&R!tBbfg^a-K9c&{3mnBi>%cEg49*DOJdqNgWR6Y-`fXXZ8McxVo787S z7U}x|w+9MD+5wyZK>&CvWQP7KaEiamM5RZqUvEbXUfCG$u<$rVXSxpJ33{dLJwG&5 z?Zidk8ZuHjSt^TViM$OvU!witR=h|j!%6%j`or*%&>E<30Gwl>SlHW|oz13_xol>x zOnwR*KcKqqVg5td?ojVO+ik|zH|Dz+x#bkoLZIsSESX}nqDv;lTrQamn`)tfCpDjr zfV2p31&Bs*mN~}!lZpgFBkCPyshBMl(o#(i-wSElB0LLYlzuIdK56Uui_%2T%*C#SQq! diff --git a/Env/__pycache__/scenario_env.cpython-39.pyc b/Env/__pycache__/scenario_env.cpython-39.pyc index 918470ddc3723cbcd124f61b61ea199f37c24524..0a2a0bc9b6fe22bac68a37a4f15d812f8c7facea 100644 GIT binary patch delta 1541 zcmZ`(T}&KR6rQ`Vv$O0^cUhM5mv;Fnu&G!cz>?bf1JkTnA#0L{=H4<&mNLv~n^u?$8>ez=SvXsULOnmjha~7;Wv6IX<-#z!c zch33lnOQpY$KkLZ3ROvXU0<0szi+=5u9w+oqEnt>`@|RW7<*sDeH~L==03x_$PC%= z%~sAZRWah+Zz$ZC_S8#;f04~eX=YRzf!UB+Wdx1TtfU5vu(1oDK_g;B@fqS_zKi>L zgh$7#X4!I2zxRx(&dnyHv!xVxvA!|=w!*Xt{vmlkhq zT>f%>WvTS;2OIBvx_Rr$=B=xnYu7iXZ*DAnwY7R7rGqwVf-|O>Rywa`P1{M_Usx;M zn7XpH`u5i9#r4$>ON&?6SLRFaT};?x`3cQ2b3AeX^7(r=mlAeCpRj(JKIg{%XQQOY zt;llA^<}uDI}Sh_<^^>RpdOjqU=?#(DsMTE&t|!SX=rweTY3b{e7Qyss-%k3-Qto` z`!F$Tm%sHt>IrD5{hbz^K0taQ2b*GjICSM~K9k`9)CTQL&x-|(Wh8Ic@21H%7rG<)slL)HU0X_9Pq=;9gO|Tt} z4p0@ZMjO1xF?wqGOthJ`W=IhD#~A<_4`T!ggk*&))~eeFOyc3POF*UqCF%ytJ+NaB zgeXo{Km$RPppk$qMbkQCUCb3Du@3KR7?@u^7pwFzF6QE0>=E%zeE!hE2jX#Lt{;0x zv$1_Rs5CQ7!OE;|aWz!Po0g;HEscgSB+k}q?2Ncm+t=ohv`8?DpoY+hblOZ|duPTR zn5Kyd(YL$TOa1c6GVFenVG_U9Jr{d5~n{*I#(t>>QlO{;N(5V|yY+i(Z@SsF zW;cW&@tM$^xbV0UA-Dq)@&QgDls}+|;~o&4IHMlRp);FOq)J_BfBTzxzxQU|%D$@;rVGkrSp+MP3Z857WM6@6bNu!@RINXchL9LB%S*rZh`& zS$7ta?GGBLFCQSd^cd zYs0bD5s@850B1=tA@3C@%5kY}L+hpsQMcv#PSEn)Fp@@ozVT#o%saNXDMHI^djfUA z&2`a^!Z@9na7MnB|5JUILM+J(L(5aIAYH*XJcpn#m1UXE8ca{=$dIS{Uk^>DSS)`n z)Y!88qcCl(q7W_T46WXiZh=5fI@}D35*eY5y9{OSe#<@Hd4!I2Yv*B z=Lz0|Wm0g0NrdKrCGVAvuL$CKNTO1ifwH%9Vb9+39~1{n@>3z8N>Cs;NW2gV~$Y6@ykO!mlY)<|&`q|`D55*3$ID=hlh1fU&)NQyTzdAC;R^?Ae zT5MZZD$g{4+#$i+2$qSJa2&Udt?YCo_<$BRWmGwnwvc|=|Gx4*!+SC&kX}E4*iShYU)s;9sk%tXK2~&}y?1r~S>1-Zreu*>M-A;*0Sm_ME&k Reg%J#iDOkZE0>O4xDVS$6gmI^ diff --git a/Env/bc_env.py b/Env/bc_env.py index 59c080c..9f6730f 100644 --- a/Env/bc_env.py +++ b/Env/bc_env.py @@ -51,10 +51,8 @@ class BCScenarioEnv(MultiAgentScenarioEnv): return car_birth_info_list, background_vehicles, obj_to_clean def _spawn_background_vehicles(self): - """Spawn static background vehicles so they appear in active_agents and thus in obs (same as ExpertReplayEnv).""" + """Spawn all static background vehicles once at reset (no show_time filter; same as ExpertReplayEnv).""" for sid, car in self.background_vehicles.items(): - if car["show_time"] != self.round: - continue bg_id = f"bg_{car['id']}" if bg_id in self.engine.agent_manager.active_agents: continue @@ -70,24 +68,12 @@ class BCScenarioEnv(MultiAgentScenarioEnv): ) v.set_velocity([0, 0]) self.engine.agent_manager.active_agents[bg_id] = v - v.valid_mask = car["valid"] - v.start_t = car["show_time"] + v.valid_mask = car.get("valid") + v.start_t = car.get("show_time") def _update_background_vehicles(self): - self._spawn_background_vehicles() - to_remove = [] - objects_to_clear = [] - for aid, v in self.engine.agent_manager.active_agents.items(): - if not aid.startswith("bg_"): - continue - if hasattr(v, "valid_mask"): - if self.round >= len(v.valid_mask) or not v.valid_mask[self.round]: - to_remove.append(aid) - objects_to_clear.append(v) - for aid in to_remove: - self.engine.agent_manager.active_agents.pop(aid, None) - if objects_to_clear: - self.engine.clear_objects([v.id for v in objects_to_clear]) + # Static vehicles are spawned once at init and never removed. + pass def step(self, action_dict): self.round += 1 diff --git a/Env/expert_replay_env.py b/Env/expert_replay_env.py index d850244..a0cded0 100644 --- a/Env/expert_replay_env.py +++ b/Env/expert_replay_env.py @@ -97,7 +97,7 @@ class ExpertReplayEnv(MultiAgentScenarioEnv): # We covered most of it. self._spawn_controlled_agents() - self._spawn_background_vehicles() # Initial spawn for background + self._spawn_all_background_vehicles_at_init() # Ensure SDC/ego is moved to the correct initial expert state. if self.replay_sdc: @@ -114,87 +114,33 @@ class ExpertReplayEnv(MultiAgentScenarioEnv): return self._get_all_obs() - def _spawn_background_vehicles(self): - # Spawn static/background vehicles - # Since they are static, we might just spawn them once if their show_time is 0 - # But Waymo tracks have valid bits, they might appear/disappear. - # For optimization, if they are truly static (never move), we just spawn them when show_time matches. - - # We need to track spawned background vehicles to remove them if they become invalid? - # Since we defined them as "static", they probably stay put. - # But validity might change (e.g. late spawn). - - # For simplicity in this step, let's just iterate and spawn if time matches + def _spawn_all_background_vehicles_at_init(self): + """Spawn all static background vehicles once at reset (no show_time filter; no removal by valid).""" for sid, car in self.background_vehicles.items(): - if car['show_time'] == self.round: - # Spawn as a Traffic Vehicle (not PolicyVehicle), or just a static object? - # Using DefaultVehicle is fine, but don't add to controlled_agents - - # Check duplication - bg_id = f"bg_{car['id']}" - # if bg_id in self.engine.obj_to_id: # obj_to_id might not be available in all versions - if bg_id in self.engine.agent_manager.active_agents: - continue - - vehicle_config = {} - if 'length' in car and 'width' in car: - vehicle_config = { - "length": car['length'], - "width": car['width'] - } - - v = self.engine.spawn_object( - DefaultVehicle, - name=bg_id, - vehicle_config=vehicle_config, - position=car['begin'], - heading=car['heading'] - ) - - # Set color to grey/dark to indicate background - v.set_velocity([0, 0]) - # Maybe set color? MetaDrive vehicles random color. - # v.set_color(...) if supported - - # Register as an active object but NOT controlled agent - # The engine manages it. - # CRITICAL: We need it in self.engine.agent_manager.active_agents for Observation? - # If we want it to be seen by Lidar/Observation, it needs to be an "agent" or "traffic". - # DefaultVehicle spawned this way is just an object. - # We should add it to traffic manager? Or just leave it as object? - # MultiAgentScenarioEnv._get_all_obs iterates self.engine.agent_manager.active_agents - - # If we want it in observation, we must add it to active_agents OR iterate over all objects. - # Adding to active_agents is easier for compatibility. - self.engine.agent_manager.active_agents[bg_id] = v - - # Store valid mask to remove it later if needed? - v.valid_mask = car['valid'] - v.start_t = car['show_time'] + bg_id = f"bg_{car['id']}" + if bg_id in self.engine.agent_manager.active_agents: + continue + vehicle_config = {} + if 'length' in car and 'width' in car: + vehicle_config = { + "length": car['length'], + "width": car['width'] + } + v = self.engine.spawn_object( + DefaultVehicle, + name=bg_id, + vehicle_config=vehicle_config, + position=car['begin'], + heading=car['heading'] + ) + v.set_velocity([0, 0]) + self.engine.agent_manager.active_agents[bg_id] = v + v.valid_mask = car.get('valid') + v.start_t = car['show_time'] def _update_background_vehicles(self): - # Remove background vehicles if they become invalid - # Or spawn new ones - self._spawn_background_vehicles() - - # Check validity for existing - to_remove = [] - objects_to_clear = [] - - for aid, v in self.engine.agent_manager.active_agents.items(): - if aid.startswith("bg_"): - # Check validity - if hasattr(v, 'valid_mask'): - curr_step = self.round - if curr_step >= len(v.valid_mask) or not v.valid_mask[curr_step]: - to_remove.append(aid) - objects_to_clear.append(v) - - for aid in to_remove: - self.engine.agent_manager.active_agents.pop(aid, None) - - if objects_to_clear: - self.engine.clear_objects([v.id for v in objects_to_clear]) + # Static vehicles are spawned once at init and never removed (no spawn/remove by show_time or valid). + pass def _spawn_controlled_agents(self): for car in self.car_birth_info_list: diff --git a/Env/scenario_env.py b/Env/scenario_env.py index 2ee4a49..c40a3fe 100644 --- a/Env/scenario_env.py +++ b/Env/scenario_env.py @@ -81,6 +81,11 @@ class MultiAgentScenarioEnv(ScenarioEnv): if self.engine is None: raise ValueError("Broken MetaDrive instance.") + # 注意:_build_birth_lists_from_traffic() 在 engine.reset() 之前执行,读的是当前 engine 的 + # current_traffic_data 与 map_manager.current_map。若复用同一 env 连续 reset(0)、reset(1), + # MetaDrive 可能已按 seed 更新了 traffic 为 scenario 1,但 map 仍为 scenario 0(在 engine.reset() 才切图), + # 导致 is_on_lane( scenario_1 车位, scenario_0 地图 ) 全为 False → 全部 off_lane → 0 受控车。 + # 因此多场景时应“每个 scenario 单独建 env”(start_scenario_index=i, num_scenarios=1)再 reset(seed=i)。 self.background_vehicles = getattr(self, "background_vehicles", {}) self.car_birth_info_list, self.background_vehicles, _obj_to_clean = self._build_birth_lists_from_traffic() for scenario_id in _obj_to_clean: diff --git a/Env/utils.py b/Env/utils.py index 8dfced6..567982a 100644 --- a/Env/utils.py +++ b/Env/utils.py @@ -5,6 +5,86 @@ import random from metadrive.type import MetaDriveType +def _static_obbs_overlap(car_a, car_b): + """ + Check if two static vehicle OBBs overlap (2D SAT). + car_a, car_b: dicts with "begin" (x, y), "heading" (rad), "length", "width". + begin is center; half-extents are length/2, width/2. + """ + def _get_corners(car): + cx, cy = car["begin"][0], car["begin"][1] + h = float(car["heading"]) + L2 = float(car["length"]) / 2.0 + W2 = float(car["width"]) / 2.0 + ux, uy = np.cos(h), np.sin(h) + vx, vy = -np.sin(h), np.cos(h) + return np.array([ + [cx + L2 * ux + W2 * vx, cy + L2 * uy + W2 * vy], + [cx + L2 * ux - W2 * vx, cy + L2 * uy - W2 * vy], + [cx - L2 * ux - W2 * vx, cy - L2 * uy - W2 * vy], + [cx - L2 * ux + W2 * vx, cy - L2 * uy + W2 * vy], + ]) + + def _get_axes(car): + h = float(car["heading"]) + return [ + np.array([np.cos(h), np.sin(h)]), + np.array([-np.sin(h), np.cos(h)]), + ] + + corners_a = _get_corners(car_a) + corners_b = _get_corners(car_b) + axes = _get_axes(car_a) + _get_axes(car_b) + + for axis in axes: + proj_a = corners_a @ axis + proj_b = corners_b @ axis + min_a, max_a = proj_a.min(), proj_a.max() + min_b, max_b = proj_b.min(), proj_b.max() + if max_a < min_b or max_b < min_a: + return False + return True + + +def _deduplicate_background_by_collision(background_vehicles): + """ + Merge static tracks that collide (same physical vehicle). Build collision graph, + find connected components, keep one representative per component (min show_time, then scenario_id). + """ + if not background_vehicles: + return background_vehicles + items = list(background_vehicles.items()) + n = len(items) + # Build adjacency by index + parent = list(range(n)) + + def find(i): + if parent[i] != i: + parent[i] = find(parent[i]) + return parent[i] + + def union(i, j): + pi, pj = find(i), find(j) + if pi != pj: + parent[pi] = pj + + for i in range(n): + for j in range(i + 1, n): + if _static_obbs_overlap(items[i][1], items[j][1]): + union(i, j) + + # Representative per component: index with min (show_time, scenario_id) + comp_rep = {} + for i in range(n): + r = find(i) + sid, car = items[i][0], items[i][1] + key = (car.get("show_time", 0), sid) + if r not in comp_rep or key < comp_rep[r][0]: + comp_rep[r] = (key, sid, car) + + return {sid: car for (_, sid, car) in comp_rep.values()} + + def is_on_lane(pos, map_manager, threshold=2.0): """Check if a position is on a valid lane (within lateral tolerance).""" if map_manager is None or map_manager.current_map is None: @@ -31,6 +111,7 @@ def filter_traffic_tracks_to_birth_lists( static_displacement_threshold=5.0, static_speed_threshold=1.0, return_stats=False, + deduplicate_static_by_collision=True, ): """ Filter traffic tracks into controlled (car_birth_info_list) and background lists. @@ -127,6 +208,9 @@ def filter_traffic_tracks_to_birth_lists( "width": track["state"]["width"][first_show], }) + if deduplicate_static_by_collision and background_vehicles: + background_vehicles = _deduplicate_background_by_collision(background_vehicles) + if return_stats: stats = { "n_total": n_total, diff --git a/dataset/loader.py b/dataset/loader.py index c1693cd..bbe75d4 100644 --- a/dataset/loader.py +++ b/dataset/loader.py @@ -49,6 +49,35 @@ def load_expert_pkl(expert_data_path): return obs_data, act_data +def get_expert_scenario_ids(expert_data_path, max_ids=10): + """ + 从专家 pkl 中收集出现过的 scenario_id(这些场景在采集时曾有受控车)。 + 用于 eval 时只在这些场景上评估,保证 eval 有受控车。 + 返回排序后的 list,最多 max_ids 个。 + """ + if os.path.isdir(expert_data_path): + pkl_files = glob.glob(os.path.join(expert_data_path, "*.pkl")) + elif os.path.exists(expert_data_path): + pkl_files = [expert_data_path] + else: + return [] + + seen = set() + for pkl_file in pkl_files: + try: + with open(pkl_file, "rb") as f: + data = pickle.load(f) + if isinstance(data, list): + for traj in data: + if "scenario_id" in traj: + seen.add(traj["scenario_id"]) + # dict 格式通常没有 per-trajectory scenario_id,跳过 + except Exception: + continue + out = sorted(seen)[:max_ids] + return out + + class MAGAILExpertDataset(Dataset): def __init__(self, data_dir, transform=None): """ diff --git a/logs/bc/20260205-232721/events.out.tfevents.1770305241.Hfkk.1085091.0 b/logs/bc/20260205-232721/events.out.tfevents.1770305241.Hfkk.1085091.0 new file mode 100644 index 0000000000000000000000000000000000000000..a83310aa602569bef2eea077ca06fdfa6a870cea GIT binary patch literal 3660 zcmZwHdo+}J9LI5#m=OjemtC83oKhL*w7UFQQI@pP?y8M#m8R3UbQ#->Yn;S3QYxWN z#$=;XvE|YUS*CMb7i@fd*ER_He;gIj_(`h6nt){arscHwild{ggiGA!jf{ zcKOVcTYKy#PA@$XnQ*DN6J>>PCGa?l0ueK?HGEjvd9D=?@mh<1)9tNDQsNvmK|r80np0lq=%qM>J@nRw?TmbltkAo zpx&&b$bNxW002dtaIL36x(pD{ZWT_hIXDJDE_tMfpq_EVK;d53Xq{Q+IDz>Th17Vw)7pyEsU z*#IQp8E~Hh88ASe+UfX1Vs{1r-H0bW1pTU&hEJOKo&_L&0;yR*nOo9Om9>usfcAI4 zZ>B&~8K6@?9mAuOvr+(PZ4c=o$oO_14tjSn41i>G%>pXY-H$3Hb4CHE$+x(L0vR$u z2Slf^ougYk0M+=B9)iTn^RP~7l`R1E(=`id&FNIs-W2W+Ko9mrwNfA>21wj}9w)ZE zFaw}!8R;SDM_VPHo;U>mmVI>10!s1Ti-vj&p94_);?k!S$e00oV^xWN-!P>OfUY3Y zLy+24f%{rF8i6-7MAs~!#eFg~wWKr>fV6)}S5qJ!0~FX+fvsB==K<&*-9u2F<3qe! zqr3q?T0!J=7SP6{dys7{{}lk0pS!D}Kqd^3waGPHcDH&R09_~~Jp`rtJi==JcL@O0 zN!Ki(;ibQ!_1+o`Kzb)N9Tdov0Wzwt$6@XJ76DKr-9ymwus<*-ROJak!*tC88W>1I z9T7_|08mP=#|sK%#sJM(e;0q>oMR6_K7FKzpjuu(R^D%M2B2MZ%>r6cup1p}E2{!m zd)L>wpFylwdz4-03$Wn%pz1Gb0iUrzR(}s4_j$PkENFO3dbq$VH3_?GDd0`2Gel~Z z1+OZ1p|qm0!vM5tpSp_znKMB0G&RmyqIwNLGxn1ng8t6@fIa5ET?k&OA6>J69?VTZ z3uJ>|0FctLwTA*tV}PdKe1+e8=amA`Edl8vDEsGsamhap*8%9U6RBB1o@e6Fk(rZ& y0Ej24>7zgv43PTjBb>vPX=pKR^od@wQS7j&w@ucK*7LdcN7^HkZrR;w$&3d)~ literal 0 HcmV?d00001 diff --git a/logs/bc/20260205-233418/events.out.tfevents.1770305658.Hfkk.1087435.0 b/logs/bc/20260205-233418/events.out.tfevents.1770305658.Hfkk.1087435.0 new file mode 100644 index 0000000000000000000000000000000000000000..a3728718122c6552469d7cca64387513d1f883ec GIT binary patch literal 1726 zcmZwHX-E`d7{GDYdq>2hRm5Y>EZsbIX|r@RTk=3N!Lkn$g6pbduDFM@t7aawMq+At zq_7$s_Le8Kgp~7RMG6YJIpgS&Rkg3AIi`W@r>-mRMJyQYpw{aS^H16Qr0hR`P6R z9wFa;qZ8CW6q@FKn0A)(vtxul#<>AIFeeO4)aY~)z3~GsP7aN-An)c-PgDKuakCd+ z7Hg`VFbB+*stXl)E^h8TS?=wjSszo&D_L6QYyY>dm;kd+Bow4tsXi?y6?($u*1ZmV ze7x-EPSb(C-)XACCb21=B-LnXGR3;&<(5U(@tE-9^#- zHKyhOVWM{2|5ukY0C}vvRu69%FXs+O(k>fO0nIngf*G z)r!xL^-KX!)qxp53S_|o$-_O7s3x};fDRv|dkBhI3`7HE6)FHyGBpQi(6t2@g{92` zkoMz-hyq!%K>3D4=#}TCRsf3qME4N%yzdkm%CGGMpnRt004-i=#^0`_t^$yM=5hc9 zvSNWc#3xbt>yQEfT48z!5_YDbrs#<;0OXZLPv-z_3Yu{5<#&wBql0Oj7LdkA`& zB1biQ+(!VYg{e6}j{SA`1?x5lYM9sVr$BrbD7~@@9qZ;b0MLmAx`&{F$PT17mly!3 zl&LvD5wgqpWa`oraFd=-SPe0O1eh~smrN9G-SrZ}c=eiXJyP?eCh$woOa_Ef2QbzK po>uiJw)|Z**dStx?%@V~WDSZElq7%+@|c=q1HqeGyyE)(sDF%B0Js1E literal 0 HcmV?d00001 diff --git a/logs/bc/20260205-233607/events.out.tfevents.1770305767.Hfkk.1088080.0 b/logs/bc/20260205-233607/events.out.tfevents.1770305767.Hfkk.1088080.0 new file mode 100644 index 0000000000000000000000000000000000000000..8e966bfdd6875a84ab23d9658da12a6e8bdebc5a GIT binary patch literal 3805 zcmZwIdrVVT9Kdn#Nv~F*w$%_Jq67s@u{xcHr+|ezQ9Fjt=b%6_h_qU&=w?tJiU=YU z3o0_fp(yb+6m^0ufyG>5zcAuX< zy}X=PeZLh+lz)b}@Z+?~B(+4gL8aFDO^cFHQ*ccHI|D<25(h1q{sf9!)t@RHP;~)mJz01)__>qTs*d z{jQ9&)t4I$uDnK*t#+myDF?dVpj;yo2Yn1W^I@!)yREhVp}Uv&?*CRy2`PT0N~u*R zsaM5ll{%HE=3E()yfDlkZ#&@Cb4 z%dPDO0NTRT9H7MVy~xA8OaVa0R7*o?&|ntmeTyef9R7h1Ks|}1hoF}YVOaBhiUNRK zSCN_nbXHu7UZISs02Ep=eGUy8!UFNE;kY|s+)DrwRgxZp4g@a4#*UE302I#D9H8gL z1~mR^ZUX@EqN#8iG?WFBt@{q^Onx!|y2kVnRMe7=UkM&m0g&AyGMxj|FWiG7)Urze zl(D-bf(8v^futE~Tt2Fy4S*Ddq=%rcJDGS*{a{xB+QQTvpeOtEh+keD20-&fN9NL? z;Vh6{0Xi_D2-U=2Ne3YR%FKB*$bkj&mgQo! zJ{beh_(Pwt$;de)QD>8%RhAs1Z@Bv`=@vuWI1xwfpq! zpS0tPT3z%kjM&ix1df=GUZ$8|2jN!WSHK1Hc9vrsmi{*q)DWnZ<7b z=ytBhH#BGj3)E9vh2M0Vk^#s!kMs~!A~=t0mUtusP&HF?fb^^L(4cpDzXH&Eceh0} zXe0}?R$GnNEw6tLK+O|K4?%8|>x{^^E)#&>Ff|9LX6R0oGBe;`0P-lA{w)pSvp^f9 zwK!8fLz;QH~o(D{d2kiNL)&$bAY0&cA$q=GrTAKtg%aJ&?pvYN#!NHDt5t6 z0Q$)E5M=tL6Z^-=CjrpZ*JL^eXnS}Lns_|oCU`@9W8HEZG>0f9n|oK*C3)hoB78KlrDL**^nN z7*lhAdPB01@yNp00Mu1+FpdTZSfJdFzwqMIC&K_}UnS`wXvvOlJg1~{7yz|0H3!II z$v}>KZ%_cVyhy5|L8Doqgp)V0w3W&OARj&HA!t_I3G5JTDFC1qOw9qBdw45SPHD#A zYL`eJCE7roSNoS<_GiEba(ihKeL%?Cpk#d~E{>@11RFRHB0b!oD4`d(R0(3i1~R7R z*uZ=~9d-DQi2|U-rI(Uvkcb6}oNdNOqprCDkoR8FL(qb|{W$%2=^X%C%G4a7TRxl7 zfuXzMZ~XdWq?!haS)eaMda-?cz65~I_K_ZfLJJzOOKyP`fF3h72Po{wCgiYfk_NmX zli~VW8Z?Fl52tiLx*{L*W rEDKbV_5fGhs)B!hjZLJ7AidleR91V?1Ar_{%>hb1sY7|LAKLx{>Th~` literal 0 HcmV?d00001 diff --git a/logs/bc/20260205-234009/events.out.tfevents.1770306009.Hfkk.1089433.0 b/logs/bc/20260205-234009/events.out.tfevents.1770306009.Hfkk.1089433.0 new file mode 100644 index 0000000000000000000000000000000000000000..19a8af9b78bfffc1d9b5f230fa981f1b6bc0fed3 GIT binary patch literal 88 zcmeZZfPjCKJmzw`e)BEUOT6VM#hX-=n3<>NT9%quVr3Mh$E8z}npd1(l$4)Xl%iK$ hnwy(gRH;{9lv$Emq?Za(6`z)wlNt{Z+26izF#reyAdmn6 literal 0 HcmV?d00001 diff --git a/logs/bc/20260205-234026/events.out.tfevents.1770306026.Hfkk.1089559.0 b/logs/bc/20260205-234026/events.out.tfevents.1770306026.Hfkk.1089559.0 new file mode 100644 index 0000000000000000000000000000000000000000..c13bda841e3867ec8291b3172016bf3d7b19080a GIT binary patch literal 152686 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»R1ed^hE&>}GP7RnW-uqRJ7iGe?GJ%7((4xO0E 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 HzFq$hkYGQJ literal 0 HcmV?d00001 diff --git a/scripts/visualize.py b/scripts/visualize.py index d7a9e47..1006efa 100644 --- a/scripts/visualize.py +++ b/scripts/visualize.py @@ -30,29 +30,31 @@ def _run_replay(args): max_available = len(summary_lookup) - args.start_index num_to_run = min(args.num_scenarios, max_available) - env_config = { - "data_directory": data_path, - "is_multi_agent": True, - "num_controlled_agents": 100, - "horizon": args.horizon, - "use_render": True, - "sequential_seed": True, - "reactive_traffic": False, - "start_scenario_index": args.start_index, - "num_scenarios": -1, - "log_level": 40, - } - print(f"Initializing ExpertReplayEnv with data from {data_path}...") - env = ExpertReplayEnv(config=env_config) try: for i in range(args.start_index, args.start_index + num_to_run): print(f"\n--- Playing Scenario {i} ---") + # Each scenario uses a fresh env (start_scenario_index=i, num_scenarios=1) so the second + # scenario and beyond are fully cleaned and loaded like a single-scenario run. + env_config = { + "data_directory": data_path, + "is_multi_agent": True, + "num_controlled_agents": 100, + "horizon": args.horizon, + "use_render": True, + "sequential_seed": True, + "reactive_traffic": False, + "start_scenario_index": i, + "num_scenarios": 1, + "log_level": 40, + } + env = ExpertReplayEnv(config=env_config) try: obs = env.reset(seed=i) except Exception as e: print(f"Error resetting scenario {i}: {e}") + env.close() continue print(f"Scenario loaded. Controlled agents (current): {len(env.controlled_agents)}, total in scenario: {env.num_controlled_in_scenario}") @@ -67,6 +69,7 @@ def _run_replay(args): if dones["__all__"]: print(f"Scenario {i} finished at step {step}") break + env.close() except KeyboardInterrupt: print("Interrupted by user") except Exception as e: @@ -74,7 +77,6 @@ def _run_replay(args): traceback.print_exc() print(f"Global error: {e}") finally: - env.close() print("Environment closed.") diff --git a/train_bc.py b/train_bc.py index d134f53..13a98cd 100644 --- a/train_bc.py +++ b/train_bc.py @@ -15,11 +15,12 @@ from torch.utils.tensorboard import SummaryWriter from Algorithm.policy import StateIndependentPolicy from Algorithm.bc import train_bc_epoch, eval_bc_epoch from Env.bc_env import BCScenarioEnv -from dataset.loader import load_expert_pkl +from dataset.loader import load_expert_pkl, get_expert_scenario_ids def evaluate_policy(policy, args, device): - """在 BCScenarioEnv 中评估策略,跑若干 episode,返回平均 reward。""" + """在 BCScenarioEnv 中评估策略:仅使用专家数据中出现过的 scenario_id,保证 eval 有受控车。 + 输出与 replay 对齐:agents (current)=reset 时受控车数,total in scenario=该场景受控轨迹总数(car_birth_info_list 长度)。""" waymo_data_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data") data_dir = os.path.join(waymo_data_dir, "exp_filtered") if not os.path.exists(data_dir): @@ -28,53 +29,74 @@ def evaluate_policy(policy, args, device): print(f"[ERROR] Could not find scenario data in {waymo_data_dir}. Evaluation skipped.") return 0.0 - env_config = { - "data_directory": data_dir, - "is_multi_agent": True, - "num_controlled_agents": 3, - "use_render": False, - "sequential_seed": True, - "horizon": 200, - } - env = BCScenarioEnv(env_config, agent2policy=None) - total_rewards = [] + scenario_ids = get_expert_scenario_ids(args.expert_data_path, max_ids=5) + if not scenario_ids: + print("[WARN] No scenario_id in expert pkl, falling back to scenarios [0,1,2]. Eval may have 0 controlled agents.") + scenario_ids = [0, 1, 2] - try: - for i in range(3): - obs_dict = env.reset(seed=i) - episode_reward = 0 - dones = {"__all__": False} - step_count = 0 - horizon = 200 - while not dones["__all__"]: - step_count += 1 - if step_count >= horizon: - break - if not obs_dict: - obs_dict, _, dones, _ = env.step({}) - continue - agent_ids = list(obs_dict.keys()) - obs_list = [obs_dict[aid] for aid in agent_ids] - obs_tensor = torch.FloatTensor(np.array(obs_list)).to(device) - with torch.no_grad(): - actions, _ = policy.sample(obs_tensor) - actions = actions.cpu().numpy() - action_dict = {aid: act for aid, act in zip(agent_ids, actions)} - obs_dict, rewards, dones, _ = env.step(action_dict) - episode_reward += sum(rewards.values()) - total_rewards.append(episode_reward) - print(f" Eval Episode {i}: Total Reward {episode_reward:.2f}") - avg_reward = float(np.mean(total_rewards)) - print(f" Average Evaluation Reward: {avg_reward:.2f}") - return avg_reward - except Exception as e: - print(f"Evaluation failed: {e}") - import traceback - traceback.print_exc() - return 0.0 - finally: + total_rewards = [] + horizon = 200 + + for idx, scenario_id in enumerate(scenario_ids): + env_config = { + "data_directory": data_dir, + "is_multi_agent": True, + "num_controlled_agents": 100, + "use_render": False, + "sequential_seed": True, + "horizon": horizon, + "start_scenario_index": scenario_id, + "num_scenarios": 1, + } + env = BCScenarioEnv(env_config, agent2policy=None) + try: + obs_dict = env.reset(seed=scenario_id) + except Exception as e: + print(f" Eval Episode {idx} (scenario {scenario_id}): reset failed: {e}") + env.close() + continue + + n_controlled = len(env.controlled_agents) + n_total_in_scenario = getattr(env, "num_controlled_in_scenario", n_controlled) + if n_controlled == 0: + print( + f" Eval Episode {idx} (scenario {scenario_id}): 0 controlled agents (total in scenario: {n_total_in_scenario}), skip." + ) + env.close() + continue + + episode_reward = 0.0 + step_count = 0 + dones = {"__all__": False} + while not dones["__all__"] and step_count < horizon: + step_count += 1 + if not obs_dict: + obs_dict, _, dones, _ = env.step({}) + continue + agent_ids = list(obs_dict.keys()) + obs_list = [obs_dict[aid] for aid in agent_ids] + obs_tensor = torch.FloatTensor(np.array(obs_list)).to(device) + with torch.no_grad(): + actions, _ = policy.sample(obs_tensor) + actions = actions.cpu().numpy() + action_dict = {aid: act for aid, act in zip(agent_ids, actions)} + obs_dict, rewards, dones, _ = env.step(action_dict) + episode_reward += sum(rewards.values()) + + total_rewards.append(episode_reward) + print( + f" Eval Episode {idx} (scenario {scenario_id}): Total Reward {episode_reward:.2f}, steps {step_count}, " + f"agents (current): {n_controlled}, total in scenario: {n_total_in_scenario}" + ) env.close() + if not total_rewards: + print(" No valid eval episodes (all skipped or failed).") + return 0.0 + avg_reward = float(np.mean(total_rewards)) + print(f" Average Evaluation Reward: {avg_reward:.2f}") + return avg_reward + def main(args): device = torch.device("cuda" if torch.cuda.is_available() else "cpu")