Pada artikel ini saya akan berbicara tentang proyek kursus saya, yang saya kerjakan bersama dengan Laboratorium Algoritma Robot Seluler JetBrains Research : About the Issue Checker yang saya tulis untuk emulator Gym-Duckietown . Kami akan berbicara tentang sistem pengujian dan integrasi sistem ini dengan platform online pendidikan yang menggunakan teknologi Pemeringkat Eksternal - misalnya, dengan platform Stepik.org .
tentang Penulis
Nama saya Daniil Plushenko, dan saya adalah mahasiswa tahun pertama (kedua) dari program Master " Pemrograman dan Analisis Data " di St. Petersburg HSE. Pada 2019, saya menyelesaikan gelar Sarjana Matematika Terapan dan Ilmu Komputer di universitas yang sama.
Platform Duckietown
Duckietown adalah proyek penelitian kendaraan otonom . Penyelenggara proyek telah menciptakan platform yang membantu menerapkan pendekatan baru untuk pembelajaran di bidang kecerdasan buatan dan robotika. Semuanya dimulai sebagai kursus di MIT pada tahun 2016, tetapi secara bertahap menyebar ke seluruh dunia dan di berbagai tingkat pendidikan, dari sekolah menengah hingga program magister.
Platform Duckietown memiliki dua bagian. Pertama, ini adalah model lingkungan transportasi perkotaan yang diperkecil dengan jalan, bangunan, rambu jalan, dan rintangan. Kedua, transportasi. Robot seluler kecil (Duckiebots) yang menjalankan Raspberry Pi menerima informasi tentang dunia di sekitar mereka melalui kamera dan mengangkut penduduk kota - bebek karet kuning - di sepanjang jalan.
Saya telah bekerja dengan emulator Duckietown. Itu disebutGym-Duckietown , dan ini adalah proyek sumber terbuka yang ditulis dengan Python. Emulator menempatkan bot Anda di dalam kota, mengubah posisinya tergantung pada algoritme yang Anda gunakan (atau pada tombol yang Anda tekan), menggambar ulang gambar dan menulis posisi bot saat ini ke log.
Jika Anda tertarik untuk mencoba, saya sarankan untuk mengkloning repositori Anda sendiri dan menjalankan manual_control.py : dengan cara ini bot dapat dikontrol menggunakan panah pada keyboard.
Tangkapan layar dari emulator
Emulator dapat digunakan sebagai lingkungan untuk menjalankan tugas. Mari kita atur masalah berikut: pada peta tertentu, yang terdiri dari satu jalur, Anda perlu mengemudi satu meter dalam garis lurus.
Untuk mengatasi masalah tersebut, Anda dapat menggunakan algoritma berikut:
for _ in range(25):
env.step([1, 0])
env.render()
Variabel ini
env
menyimpan keadaan lingkungan.
Metode langkah mengambil masukan
action
: daftar dua elemen yang menjelaskan tindakan bot. Elemen pertama mengatur kecepatan, yang kedua - sudut rotasi. Metode render
menggambar ulang gambar, dengan mempertimbangkan posisi baru bot. Jumlah langkah dan kecepatan dipilih secara empiris: ini adalah nilai yang diperlukan bot untuk berjalan tepat satu meter dalam garis lurus.
Jika Anda ingin menggunakan potongan ini di manual_control.py, tempelkan di sini . Kode hingga saat ini memuat lingkungan. Untuk kesederhanaan, Anda dapat menggunakannya kembali, dan kemudian menambahkan solusi di atas ke masalah tersebut.
Sistem pengujian
Saya ingin dapat memeriksa tugas-tugas tersebut secara otomatis: melakukan implementasi algoritma kontrol bot, mensimulasikan perjalanan dan melaporkan apakah algoritma yang diusulkan melakukan tugas dengan benar. Sistem pengujian semacam itu akan memungkinkan untuk menggunakan lingkungan selama persiapan kompetisi dalam kendali transportasi otonom, serta untuk tujuan pendidikan: untuk mengeluarkan serangkaian masalah kepada siswa dan memeriksa solusi mereka secara otomatis. Saya terlibat dalam pengembangannya saat mengerjakan proyek kursus dan di bawah ini saya akan memberi tahu Anda tentang apa yang saya dapatkan.
Urutan langkah saat memeriksa solusi terlihat seperti ini:
Anda dapat menambahkan sendiri tugas ke sistem pengujian atau merujuk ke tugas yang saya lakukan. Setiap tugas memiliki generator kondisi - kelas yang menghasilkan status lingkungan. Ini berisi nama peta dan posisi awal bot di dalam sel awal. Koordinat target juga ditetapkan: dalam hal ini, titik satu meter dari posisi awal.
class Ride1MTaskGenerator(TaskGenerator):
def __init__(self, args):
super().__init__(args)
def generate_task(self):
env_loader = CVTaskEnv if self.args.is_cv_task else TrackingDuckietownEnv
env = env_loader(
map_name="straight_road",
position_on_initial_road_tile=PositionOnInitialRoadTile(
x_coefficient=0.5,
z_coefficient=0.5,
angle=0,
),
)
self.generated_task['target_coordinates'] = [[env.road_tile_size * 0.5 + 1, 0, env.road_tile_size * 0.5]]
self.generated_task['env'] = env
env.render()
return self.generated_task
Berikut
TrackingDuckietownEnv
dan CVTaskEnv
adalah kelas pembungkus yang digunakan untuk menyimpan informasi tentang perjalanan untuk analisa lebih lanjut.
class TrackingDuckietownEnv:
def __init__(self, **kwargs):
self.__wrapped = DuckietownEnv(**kwargs)
…
…
def step(self, action):
obs, reward, done, misc = self.__wrapped.step(action)
message = misc['Simulator']['msg']
if 'invalid pose' in message.lower():
raise InvalidPoseException(message)
for t in self.trackers:
t.track(self)
return obs, reward, done, misc
Pelacak mengumpulkan informasi tentang keadaan saat ini, seperti posisi bot.
CVTaskEnv
ini digunakan jika solusi diperlukan hanya dengan menggunakan informasi dari kamera ("computer vision"), dan bukan fungsi emulator: misalnya, jika Anda perlu mengetahui seberapa jauh bot dari pusat strip atau di mana objek terdekat yang terlihat. CVTaskEnv
Memanggil fungsi emulator dapat menyederhanakan tugas, dan class membatasi pemanggilan metode emulator. Ini digunakan saat bendera ditampilkan is_cv_task
.
class CVTaskEnv:
def __init__(self, **kwargs):
self.__wrapped = TrackingDuckietownEnv(**kwargs)
def __getattr__(self, item):
if item in self.__wrapped.overriden_methods:
return self.__wrapped.__getattribute__(item)
ALLOWED_FOR_CV_TASKS = [
'render', '_CVTaskEnv__wrapped', '_TrackingDuckietownEnv__wrapped',
'road_tile_size', 'trip_statistics'
]
if item in ALLOWED_FOR_CV_TASKS:
return self.__wrapped.__getattr__(item)
else:
raise AttributeError(item + " call is not allowed in CV tasks")
Setelah eksekusi keputusan selesai - asalkan tidak diganggu oleh batas waktu - informasi perjalanan diteruskan melalui urutan checker. Jika semua checker berhasil, masalah dianggap terselesaikan dengan benar. Jika tidak, putusan penjelasan akan ditampilkan - misalnya, bot macet, keluar dari jalan raya, dll.
Berikut adalah salah satu checker standar. Dia memeriksa bahwa bot telah kembali ke titik awal di akhir perjalanan. Ini dapat berguna jika, misalnya, dalam suatu tugas Anda perlu mengemudi ke titik tertentu dan kemudian kembali lagi.
class SameInitialAndFinalCoordinatesChecker(Checker):
def __init__(self, maximum_deviation=0.1, **kwargs):
super().__init__(**kwargs)
self.maximum_deviation = maximum_deviation
def check(self, generated_task, trackers, **kwargs):
trip_statistics = next(x for x in trackers if isinstance(x, TripStatistics))
trip_data = trip_statistics.trip_data
if len(trip_data) == 0:
return True
initial_coordinates = trip_data[0].position.coordinates
final_coordinates = trip_data[-1].position.coordinates
return np.linalg.norm(initial_coordinates - final_coordinates) < self.maximum_deviation
Sistem pengujian semacam itu dapat digunakan dalam mode manual, yaitu memulai pengujian secara manual, dan kemudian mempelajari putusan secara visual. Jika kami ingin, misalnya, meluncurkan kursus online tentang transportasi otonom di Stepik.org , kami memerlukan integrasi dengan platform tersebut. Ini akan dibahas di bagian artikel selanjutnya.
Integrasi dengan platform online
Untuk tugas pengujian, sering digunakan teknologi External Grader, yang dikembangkan oleh platform edX .
Saat menggunakan External Grader, platform pendidikan tidak memeriksa tugasnya sendiri, tetapi menghasilkan antrian paket yang dikirim ke perangkat lain. Fungsionalitas koneksi antrian diimplementasikan dalam proyek xqueue-watcher . Xqueue-watcher mengambil parsel dan kemudian diuji oleh validator (yang biasanya melakukan lebih banyak tindakan non-sepele daripada perbandingan teks / angka). Setelah itu, putusan verifikasi dikirim kembali ke sisi platform pendidikan.
Mari pertimbangkan secara lebih detail saat menghubungkan ke antrian. Setelah platform pendidikan menyediakan data koneksi, mereka perlu ditambahkan kefile konfigurasi , dan dalam metode kelas , terapkan peluncuran verifikasi secara langsung. Instruksi lebih rinci dapat ditemukan di sini dan di sini .
Xqueue-watcher memanggil get_submission titik akhir , yang akan mengambil paket dari antrian jika memungkinkan. Setelah itu, dia pergi untuk pengujian. Pengamat xqueue kemudian memanggil put_result untuk mengembalikan putusan.
Anda dapat memulai xqueue-watcher seperti ini:
make requirements && python -m xqueue_watcher -d conf.d/
Katakanlah kita ingin menggunakan teknologi Pengukur Eksternal, tetapi tidak ingin menjalankan kursus di platform online. Xqueue-watcher diimplementasikan dengan asumsi bahwa ada beberapa penyimpanan file di mana file dengan solusi diunggah (platform memiliki penyimpanan seperti itu). Kita bisa memodifikasi Xqueue sehingga penyimpanan file tidak lagi dibutuhkan, dan sistem seperti itu bisa dijalankan, secara umum, bahkan di laptop kita.
Pertama, Anda perlu mempelajari cara mengelola antrean parsel itu sendiri. Fungsionalitas antrian disediakan oleh proyek xqueue .
Gambar diambil dari dokumentasi .
Anda dapat menjalankannya seperti ini:
apt-get install libaio1 libaio-dev
apt-get install libmysqlclient-dev
pip3 install -r requirements.txt
python3 manage.py migrate
python3 manage.py runserver $xqueue_address
Anda mungkin perlu membuat file ~ / edx / edx.log
Secara default, xqueue memberi xqueue-watcher bukan konten dari paket, yaitu file dengan solusi untuk masalah, tetapi link ke file ini di penyimpanan file. Agar tidak bergantung pada penyimpanan file, Anda dapat membuat file itu sendiri dikirim dan menyimpannya di mesin yang sama yang menjalankan xqueue-watcher.
Berikut cara kode sumber perlu dimodifikasi untuk mencapai ini:
Penerapan metode _upload di lms_interface.py diganti dengan yang ini:
def _upload(file_to_upload, path, name):
'''
Upload file using the provided keyname.
Returns:
URL to access uploaded file
'''
full_path = os.path.join(path, name)
return default_storage.save(full_path, file_to_upload)
Jika tidak ada penyimpanan file yang terhubung, maka metode ini akan menyimpan file dengan solusi ke jalur $ queue_name / $ file_to_upload_hash.
Dalam implementasi get_sumbission di file ext_interface.py, alih-alih baris ini, tulis:
xqueue_files = json.loads(submission.urls)
for xqueue_file in xqueue_files.keys():
with open(xqueue_files[xqueue_file], 'r') as f:
xqueue_files[xqueue_file] = f.readlines()
Mari kita transfer bukan tautan (jalur) ke file, tetapi isinya.
Setiap solusi dijalankan dalam kontainer buruh pelabuhan "satu kali" dengan sumber daya terbatas, yaitu, wadah terpisah dibuat untuk eksekusi setiap solusi, yang dihapus setelah pengujian selesai. Untuk membuat kontainer seperti itu dan menjalankan perintah di dalamnya, portainer-api digunakan (pada kenyataannya, sebagai pembungkus di atas Docker API).
Hasil
Dalam artikel ini, saya berbicara tentang bagaimana sistem pengujian dan tugas untuk transportasi otonom dibuat, serta integrasi sistem ini dengan platform pendidikan online yang menggunakan teknologi Pengukur Eksternal. Saya berharap kursus yang menggunakan sistem ini segera diluncurkan, dan bagian tentang integrasi dengan platform online akan bermanfaat bagi mereka yang ingin membuat kursus offline atau online mereka sendiri.