Photo by Deepmind on Unsplash
Phép nhân ma trận là một phép toán cơ bản được sử dụng trong nhiều hệ thống, từ mạng thần kinh cho đến quy trình tính toán khoa học. Việc tìm kiếm các thuật toán hiệu quả và chính xác có thể chứng minh được cho phép nhân ma trận có thể có tác động lớn đến việc tính toán nhanh hơn và hiệu quả hơn, nhưng lại là một nhiệm vụ rất khó khăn. Không gian của các thuật toán có thể là rất lớn và các phương pháp truyền thống để khám phá các thuật toán, chẳng hạn như phương pháp phỏng đoán do con người thiết kế hoặc tìm kiếm tổ hợp, thường không tối ưu.
DeepmindGiải pháp dựa trên AI được đề xuất gần đây cho tìm kiếm tự động vượt xa trực giác của con người. Giải pháp này bao gồm một tác nhân học tăng cường sâu có tên là AlphaTensor, được xây dựng dựa trên alphazero. Đặc vụ này được đào tạo để chơi trò chơi một người chơi, TensorGame, trong đó mục tiêu là khám phá các thuật toán tính toán hiệu quả để nhân ma trận.
AlphaTensor đặc biệt giỏi trong việc xử lý các ma trận lớn bằng cách phân tách các phép nhân ma trận lớn thành các phép nhân nhỏ hơn. Hơn nữa, AlphaTensor có thể được sử dụng để đạt được hiệu suất tiên tiến nhất cho phép nhân ma trận sau khi được tinh chỉnh trên một thiết bị phần cứng cụ thể.
AlphaTensor có tiềm năng lớn để tăng tốc điện toán học sâu. Trong học sâu, nhiều thao tác tốn thời gian có thể được ánh xạ tới phép nhân ma trận. Bằng cách sử dụng AlphaTensor để tối ưu hóa các hoạt động này, hiệu suất tổng thể của các mô hình học sâu có thể được cải thiện đáng kể.
Gần đây, OpenAlphaTensor, triển khai mã nguồn mở đầu tiên của AlphaTensor, đã được phát hành, có thể cách mạng hóa sức mạnh tính toán của các mô hình học sâu.
Phép nhân ma trận Tenor
Đối với những người không phải là chuyên gia về tối ưu hóa phép nhân ma trận, có thể không đơn giản để hiểu cách một phép toán chẳng hạn như phép nhân ma trận có thể được ánh xạ trong một tensor ba chiều. Tôi sẽ cố gắng giải thích nó bằng những từ đơn giản và có ví dụ.
Hãy xem xét tích C = A*B, trong đó để đơn giản, cả A và B đều là ma trận vuông kích thước N. Phép toán nhân có thể được ánh xạ trong một tenxơ 3D có hình dạng (N^2, N^2, N^2). Kích thước tensor đầu tiên đại diện cho ma trận phẳng A, kích thước thứ hai là ma trận phẳng B và kích thước thứ ba là ma trận phẳng C.
Tenxơ chỉ có các giá trị nhị phân (1 hoặc 0) cho mỗi mục nhập. Lưu ý rằng tenxơ đại diện cho phép toán nhân, vì vậy nó độc lập với các giá trị của ma trận A và B.
Mọi mục nhập của tenxơ tương ứng với hệ số của phép toán. Ví dụ, để tính C[1,1], cần nhân cả A[1,1] và B[1,1]. Do đó, mục tensor [0,0,0], tương ứng với A[1,1], B[1,1] và C[1,1], sẽ có giá trị 1. Ngược lại, để tính C[1,1 ,2,1], A[1] là không cần thiết. Do đó, hàng tenxơ T[N+0, :, XNUMX] sẽ chỉ chứa các số không.
Hình ảnh dưới đây cho thấy một ví dụ về tensor cho N=2.
Hình ảnh từ DeepMind's giấy xuất bản năm Thiên nhiên
Như thể hiện trong (b) và (c) trong hình trên, có thể triển khai thuật toán tính toán sản phẩm bằng cách phân tách tenxơ 3D. Cụ thể hơn, thuật toán dưới đây có thể được sử dụng để chuyển đổi phân tích tenxơ (ma trận U, V, W) thành thuật toán nhân ma trận.
Siêu thuật toán được tham số hóa để tính toán tích ma trận C=AB được giới thiệu trong DeepMind's giấy
TenorGame
Vấn đề tìm kiếm các thuật toán hiệu quả cho phép nhân ma trận là vô cùng khó khăn vì số lượng các thuật toán có thể xem xét lớn hơn nhiều so với số lượng nguyên tử trong vũ trụ, ngay cả đối với các trường hợp nhân ma trận nhỏ.
DeepMind đã biến vấn đề này thành trò chơi một người chơi và gọi nó là TensorGame. Trong trò chơi này, người chơi chọn cách kết hợp các mục khác nhau của ma trận để nhân chúng lên. Điểm số được chỉ định dựa trên số lượng thao tác cần thiết để đạt được kết quả phép nhân chính xác. Trò chơi kết thúc khi đạt đến thang đo bằng XNUMX hoặc khi đã thực hiện số lần di chuyển tối đa. Hệ số cuối cùng được đánh giá dựa trên ước tính về thứ hạng còn lại và các tiêu chí tối ưu hóa nhất định, chẳng hạn như độ phức tạp của thời gian tiệm cận hoặc thời gian chạy thực tế.
Vị trí ban đầu trong TensorGame tương ứng với Tensor nhân ma trận được biểu thị trên cơ sở ngẫu nhiên nào đó.
Trong mỗi bước t của trò chơi, người chơi viết ra ba vectơ
, chỉ định các tenxơ hạng 1 . Trạng thái của trò chơi được cập nhật bằng cách trừ các vectơ do người chơi chọn:
Ở đâu
là Phép nhân ma trận Tenor.Nếu trò chơi kết thúc trong p bước, điều này có nghĩa là Tensor nhân ma trận
có thể được phân tách thành các tenxơ hạng 1 , tức là nó có ít nhất hạng p.TensorGame sau đó có thể được hiểu là một thuật toán phân tách thứ hạng và AlphaTensor có thể được coi là một thuật toán để ước tính thứ hạng của tensor.
Kiến trúc AlphaTensor
Cho đến nay, chúng ta đã tìm hiểu về TensorGame và làm rõ cách giải pháp của nó có thể được xem như một thuật toán nhân ma trận. Bây giờ chúng ta hãy khám phá các khái niệm chính về AlphaTensor, thuật toán được sử dụng cho trò chơi.
Kiến trúc AlphaTensor về cơ bản là kiến trúc Máy biến áp mã hóa-giải mã trong đó:
- bộ mã hóa lấy đầu vào là trạng thái trò chơi , n hành động trước đó được thực hiện bởi mô hình (thường là n=7) và chỉ số thời gian t của hành động hiện tại. Thông tin được xếp chồng lên nhau trong một tensor có hình dạng (n+1, N^2, N^2, N^2). Tenor này sau đó được định hình lại và biến đổi (sử dụng ba lớp tuyến tính) thành một tenxơ có hình dạng (N^2, N^2, c) trong đó c là kích thước bên trong của mô hình.
- bộ giải mã tạo ra các hành động n_steps từ vectơ nhúng do bộ mã hóa cung cấp theo cách tự động hồi quy. Mỗi hành động tương ứng với một mã thông báo của bộ ba đại diện cho một trong các bộ ba phân tách tensor trò chơi (tức là giảm thứ hạng của nó)
Mô hình được đào tạo bằng cách luân phiên nhân giống ngược và diễn xuất mô hình. Diễn xuất mô hình được sử dụng để tạo dữ liệu sau đó được sử dụng để huấn luyện mô hình. Trong thực tế, mô hình được đào tạo với hỗn hợp dữ liệu được tạo tổng hợp và dữ liệu do mô hình tạo ra trong quá trình hoạt động. Bước diễn xuất được thực hiện bằng cách sử dụng một tenxơ 3D tương ứng với phép toán ma trận và chơi các trò chơi n_actors trên đó. Mỗi diễn viên chơi một trò chơi trên cơ sở tiêu chuẩn hoặc trên cơ sở thay thế (sự thay đổi cơ sở được áp dụng với một xác suất nhất định). Các kết quả sau đó được thu thập và có thể được sử dụng trong bước đào tạo với dữ liệu tổng hợp.
Bước diễn xuất dựa trên Monte Carlo Tree Search (MCTS) của AlphaZero, được sửa đổi để hỗ trợ các không gian hành động lớn. Nói tóm lại, trước khi chọn hành động, các đường dẫn n_sims được khám phá từ đầu ra của mô hình với khả năng khám phá tối đa trong tương lai là 5 bước. Xác suất do mô hình tạo ra sau đó được điều chỉnh có tính đến các đường dẫn được tạo. Sau đó, hành động có (các) con đường tương lai hứa hẹn nhất sẽ được chọn để tiếp tục trò chơi.
Trong khi đào tạo mô hình, phần thưởng thực sự là một phần thưởng tiêu cực (hình phạt). Giá trị tuyệt đối của nó tăng lên với mỗi bước bổ sung cần thiết để giải quyết trò chơi. Nếu mô hình thực hiện m bước để giải một TensorGame, thì phần thưởng liên quan đến trò chơi là r=-m. Nếu mô hình không thể giải được TensorGame trong các bước max_rank, thì phần thưởng được tính bằng cách ước tính thứ hạng của tenor còn lại. Xếp hạng được ước tính bằng tổng các hạng của ma trận tạo nên tensor. Ước tính là giới hạn trên của hạng thực của tenxơ.
Khi tinh chỉnh mô hình, phần thưởng phạt ở trạng thái cuối cũng phải tính đến độ trễ của thuật toán do mô hình tạo ra. Công thức phần thưởng trở thành rt'=rt+λbt, trong đó rt là sơ đồ phần thưởng được mô tả trước đó, bt là phần thưởng chuẩn (chỉ khác 0 ở trạng thái cuối) và λ là một hệ số do người dùng chỉ định.
Tăng tốc (%) các thuật toán do AlphaTensor phát hiện được thiết kế riêng cho GPU và TPU, được trích xuất từ bài báo của DeepMind. Tốc độ tăng được đo tương ứng với phép nhân ma trận tiêu chuẩn (ví dụ: cuBLAS cho GPU) trên cùng một phần cứng và được so sánh với Thuật toán Strassen-vuông. Nguồn: Deepmind.
Gần đây tôi đã phát hành OpenAlphaTensor, triển khai mã nguồn mở đầu tiên của AlphaTensor. Trong phần này tôi sẽ hướng dẫn thực hiện. Như chúng ta đã thảo luận trước đó, kiến trúc AlphaTensor khá đơn giản, dựa trên một biến áp tiêu chuẩn với kiến trúc bộ mã hóa-giải mã. Các thành phần thú vị nhất của AlphaTensor là lớp đầu tiên trong phần mã hóa và cách các hành động được lấy mẫu.
Hãy bắt đầu với lớp mã hóa đầu tiên.
# x.size = (N, T, S, S, S)
# scalars.size = (N, s)
batch_size = x.shape[0]
S = x.shape[-1]
T = x.shape[1]
x1 = x.permute(0, 2, 3, 4, 1).reshape(batch_size, S, S, S * T)
x2 = x.permute(0, 4, 2, 3, 1).reshape(batch_size, S, S, S * T)
x3 = x.permute(0, 3, 4, 2, 1).reshape(batch_size, S, S, S * T)
input_list = [x1, x2, x3]
for i in range(3): temp = self.linears_1[i](scalars).reshape(batch_size, S, S, 1) input_list[i] = torch.cat([input_list[i], temp], dim=-1) input_list[i] = self.linears_2[i](input_list[i])
x1, x2, x3 = input_list
Trong đoạn mã trên, chúng tôi chỉ ra cách tenxơ đầu vào được phân tách thành ba tenxơ, sau đó được sử dụng làm đầu vào truy vấn, khóa và giá trị của lớp biến áp.
- Trên ba chiều tensor đại diện cho các ma trận phẳng (A, B, C), tensor đầu vào được làm phẳng dọc theo mỗi chiều cùng với chiều đại diện cho các hành động trước đó. Theo cách này, trong mỗi bản sao phẳng của tenxơ đầu vào, thứ nguyên được chọn là tổng hợp của các giá trị T-1 cuối cùng và giá trị thực, cho tất cả các giá trị S của thứ nguyên đã chọn, trong đó S=N^2. Về mặt triết học, đối với mỗi chiều, chúng ta tập trung vào những gì đã xảy ra trong các hành động trước đó trong chiều đó.
- Các vô hướng được ánh xạ trong ba không gian khác nhau của kích thước S^2, và sau đó được định hình lại để được nối với các tensor thu được tại điểm trước đó. Về mặt khái niệm, các đại lượng vô hướng được ánh xạ tới một không gian nhúng có kích thước S^2, sau đó thông tin nhúng được chia thành các vectơ S và xếp chồng lên nhau, tương tự như những gì xảy ra với văn bản khi được mã hóa.
- Mã thông báo vô hướng được nối với tenxơ đầu vào được cấu trúc lại và sau đó được cung cấp làm đầu vào cho một lớp tuyến tính để ánh xạ thông tin tiêu điểm về vô hướng + lịch sử kênh trong chiều bên trong của mô hình.
Ba bước này có thể được hiểu là một cách cung cấp cho mô hình cả thông tin về vô hướng (như trong bước thời gian TensorGame) và tiêu điểm vào các hành động trước đó cho mỗi kênh.
Về cách các hành động được tạo ra, thật thú vị khi lưu ý rằng AlphaTensor tạo ra đầu ra bộ ba u, v, w, nhằm mục đích giảm thứ hạng tensor. Ba vectơ có kích thước S và vì chúng được ghép nối nên mô hình phải tạo ra một vectơ có kích thước 3*S. AlphaTensor được đào tạo bằng thuật toán RL, vì vậy tất cả các hành động có thể xảy ra phải được biểu thị dưới dạng xác suất trong một không gian liệt kê, tức là mô hình tạo ra xác suất đối với các hành động khác nhau. Điều này có nghĩa là mỗi vectơ trong không gian 3S phải được ánh xạ tới một hành động khác. Điều này dẫn đến một không gian hành động có kích thước |F|^(3S), trong đó |F| là số giá trị khác nhau mà phần tử u, v, w có thể nhận. Thông thường, các giá trị được giới hạn ở (-2, -1, 0, 1, 2), dẫn đến lực lượng gồm 5 phần tử.
Đây là một thách thức lớn: để tạo xác suất hành động cho tích ma trận gồm các ma trận có kích thước 5, chúng ta sẽ cần bộ nhớ 5^75 * 4 byte, nghĩa là ~10^44 GB bộ nhớ. Rõ ràng, chúng tôi không thể quản lý một không gian hành động lớn như vậy.
Làm thế nào để chúng tôi giải quyết vấn đề? Để giảm dung lượng bộ nhớ của các xác suất hành động, chúng ta có thể chia các bộ ba thành các phần nhỏ hơn, “mã hóa” chúng và coi các phần này là các mã thông báo được tạo trong kiến trúc máy biến áp, tức là các mã thông báo được cung cấp làm đầu vào cho bộ giải mã trong quá trình hồi quy tự động đường. Trong ví dụ trên, chúng ta có thể chia bộ ba thành 15 phần, giảm mức tiêu thụ bộ nhớ xuống 15 * 5^(75/15) * 4, tức là 187.5 KB.
def _eval_forward(self, e: torch.Tensor): bs = e.shape[0] future_g = ( torch.zeros((bs, self.n_samples, self.n_steps)).long().to(e.device) ) ps = torch.ones((bs, self.n_samples)).to(e.device) e = e.unsqueeze(1).repeat(1, self.n_samples, 1, 1) future_g = future_g.view(-1, self.n_steps) ps = ps.view(-1) e = e.view(-1, e.shape[-2], e.shape[-1]) for i in range(self.n_steps): o_s, z_s = self.core(future_g[:, : i + 1], e) future_g[:, i], p_i = sample_from_logits(o_s[:, i]) ps *= p_i future_g = future_g.view(bs, self.n_samples, self.n_steps) ps = ps.view(bs, self.n_samples) return ( future_g, ps, z_s[:, 0].view(bs, self.n_samples, *z_s.shape[2:]).mean(1), )
Ở trên, chúng tôi hiển thị đoạn mã để tạo hành động đầy đủ. Trong mã, self.core chứa lớp giải mã và tensor e biểu thị đầu ra của lớp mã hóa. Số không có thể được coi là mã thông báo trong các mô hình NLP và các hành động n_steps đại diện cho các khối n_steps được tạo theo cách lũy tiến.
Mô hình trả về ba đại lượng:
- Các hành động được tạo
- Xác suất liên quan đến toàn bộ hành động
- Nhật ký được tạo để tạo hành động đầu tiên (đoạn đầu tiên) sẽ được sử dụng để tính toán giá trị mô hình.
Thật đáng để dành một vài từ cho tham số n_samples. Tham số được sử dụng cho bước diễn xuất và nó cho phép mô hình tạo ra các phiên bản khác nhau của bộ ba, sau đó sẽ được sử dụng để khám phá không gian hành động trong thuật toán Tìm kiếm cây Monte Carlo được sử dụng trong quy trình Diễn xuất. Các hành động khác nhau của n_samples được lấy mẫu theo chính sách do mô hình tạo ra.
Bước diễn xuất
Phần phức tạp nhất của toàn bộ thuật toán có lẽ là bước Diễn xuất được sử dụng để giải TensorGame. Thuật toán không được giải thích sâu trong bài báo AlphaTensor, vì nó dựa trên một số bài báo trước đây của DeepMind chỉ được trích dẫn và đưa ra như đã biết. Ở đây, tôi sẽ xây dựng lại tất cả các phần còn thiếu và giải thích từng bước triển khai của chúng tôi.
Chúng ta có thể tổ chức các bước diễn xuất theo ba thành phần khác nhau:
- Tìm kiếm cây Monte-Carlo
- Mô phỏng trò chơi
- Tính toán chính sách được cải thiện
Hãy để chúng tôi phân tích từng cái một.
Tìm kiếm cây Monte-Carlo (MCTS)
Tìm kiếm cây Monte Carlo (MCTS) là một kỹ thuật trí tuệ nhân tạo được sử dụng rộng rãi để chơi trò chơi, đặc biệt là trong trò chơi cờ bàn và trò chơi điện tử. Thuật toán tạo ra một cây trò chơi mô phỏng các nước đi và kết quả tiềm năng, đồng thời sử dụng phương pháp lấy mẫu ngẫu nhiên để đánh giá phần thưởng dự kiến cho mỗi nước đi. Sau đó, thuật toán chọn lặp đi lặp lại nước đi có phần thưởng kỳ vọng cao nhất và mô phỏng các kết quả cho đến khi nó đạt đến trạng thái cuối cùng hoặc một điều kiện dừng cụ thể. Các mô phỏng được sử dụng để ước tính xác suất chiến thắng cho mỗi nước đi và hướng dẫn quá trình ra quyết định. MCTS đã được chứng minh là có hiệu quả trong các trò chơi phức tạp trong đó số lượng nước đi và kết quả có thể xảy ra lớn và nó đã được sử dụng trong các hệ thống AI chơi trò chơi thành công, chẳng hạn như AlphaGo.
Trong AlphaTensor, một phiên bản sửa đổi của MCTS gốc được sử dụng. Đặc biệt, thay vì chọn ngẫu nhiên hành động từ toàn bộ không gian hành động, hành động được chọn trong một tập hợp con do mô hình tạo trực tiếp (thông qua n_samples đã trình bày trước đó). Việc sửa lỗi nâng cấp chính sách sau đó được áp dụng trong bước tính toán Chính sách được cải thiện.
Khi triển khai, chúng tôi quyết định giữ tất cả thông tin về cây Monte-Carlo trong một từ điển có khóa là phiên bản băm của trạng thái TensorGame và làm giá trị thông tin được liên kết với chính trạng thái đó. Mỗi bước đi của Monte-Carlo bắt đầu từ một nút và mô phỏng các trò chơi nhỏ n_sim, khám phá tương lai với đường chân trời gồm 5 bước di chuyển. Nếu nút đã được khám phá trong các mô phỏng trước đó, thì n_sim được điều chỉnh dựa trên số lần khám phá trước đó. Đối với mỗi nút, số lượt truy cập được lưu trữ trong tenxơ N_s_a, vì tenxơ này chứa số lượt truy cập trên mỗi hành động con của nút (trong số những lượt truy cập được mô hình lấy mẫu).
def monte_carlo_tree_search( model: torch.nn.Module, state: torch.Tensor, n_sim: int, t_time: int, n_steps: int, game_tree: Dict, state_dict: Dict,
): """Runs the monte carlo tree search algorithm. Args: model (torch.nn.Module): The model to use for the simulation. state (torch.Tensor): The initial state. n_sim (int): The number of simulations to run. t_time (int): The current time step. n_steps (int): The maximum number of steps to simulate. game_tree (Dict): The game tree. state_dict (Dict): The dictionary containing the states. """ state_hash = to_hash(extract_present_state(state)) if state_hash in state_dict: with torch.no_grad(): N_s_a = state_dict[state_hash][3] n_sim -= int(N_s_a.sum()) n_sim = max(n_sim, 0) for _ in range(n_sim): simulate_game(model, state, t_time, n_steps, game_tree, state_dict) # return next state possible_states_dict, _, repetitions, N_s_a, q_values, _ = state_dict[ state_hash ] possible_states = _recompose_possible_states(possible_states_dict) next_state_idx = select_future_state( possible_states, q_values, N_s_a, repetitions, return_idx=True ) next_state = possible_states[next_state_idx] return next_state
Đoạn mã trên cho thấy việc triển khai thuật toán của chúng tôi. Để đơn giản hóa mã, việc sửa chính sách được thực hiện trong hàmsimulator_game.
Mô phỏng trò chơi
Hàmsimulator_game chịu trách nhiệm khám phá cây bao gồm các nút đại diện cho một trạng thái cụ thể của TensorGame. Nó cũng chạy mô hình bất cứ khi nào gặp một nút lá và nó lưu trữ tất cả thông tin về nút trong từ điển state_dict. Chúng ta hãy nhìn sâu vào việc thực hiện nó:
@torch.no_grad()
def simulate_game( model, state: torch.Tensor, t_time: int, max_steps: int, game_tree: Dict, states_dict: Dict, horizon: int = 5,
): """Simulates a game from a given state. Args: model: The model to use for the simulation. state (torch.Tensor): The initial state. t_time (int): The current time step. max_steps (int): The maximum number of steps to simulate. game_tree (Dict): The game tree. states_dict (Dict): The states dictionary. horizon (int): The horizon to use for the simulation. """ idx = t_time max_steps = min(max_steps, t_time + horizon) state_hash = to_hash(extract_present_state(state)) trajectory = [] # selection while state_hash in game_tree: ( possible_states_dict, old_idx_to_new_idx, repetition_map, N_s_a, q_values, actions, ) = states_dict[state_hash] possible_states = _recompose_possible_states(possible_states_dict) state_idx = select_future_state( possible_states, q_values, N_s_a, repetition_map, return_idx=True ) trajectory.append((state_hash, state_idx)) # state_hash, action_idx future_state = extract_present_state(possible_states[state_idx]) state = possible_states[state_idx] state_hash = to_hash(future_state) idx += 1 # expansion if idx = max_steps: trajectory.append((state_hash, None)) if not game_is_finished(extract_present_state(state)): state = state.to(model.device) scalars = get_scalars(state, idx).to(state.device) actions, probs, q_values = model(state, scalars) ( possible_states, cloned_idx_to_idx, repetitions, not_dupl_indexes, ) = extract_children_states_from_actions( state, actions, ) not_dupl_actions = actions[:, not_dupl_indexes].to("cpu") not_dupl_q_values = torch.zeros(not_dupl_actions.shape[:-1]).to( "cpu" ) N_s_a = torch.zeros_like(not_dupl_q_values).to("cpu") present_state = extract_present_state(state) states_dict[to_hash(present_state)] = ( _reduce_memory_consumption_before_storing(possible_states), cloned_idx_to_idx, repetitions, N_s_a, not_dupl_q_values, not_dupl_actions, ) game_tree[to_hash(present_state)] = [ to_hash(extract_present_state(fut_state)) for fut_state in possible_states ] leaf_q_value = q_values else: leaf_q_value = -int(torch.linalg.matrix_rank(state).sum()) # backup backward_pass(trajectory, states_dict, leaf_q_value=leaf_q_value)
Mỗi mô phỏng được chia thành ba phần:
- Lựa chọn
- Sự bành trướng
- sao lưu
Trong phần lựa chọn, mô phỏng được chạy trên các nút cây đã được tạo và nút sau được chọn bằng chức năng sau:
def select_future_state( possible_states: List[torch.Tensor], q_values: torch.Tensor, N_s_a: torch.Tensor, repetitions: Dict[int, list], c_1: float = 1.25, c_2: float = 19652, return_idx: bool = False,
) -> torch.Tensor: """Select the future state maximizing the upper confidence bound."""
# q_values (1, K, 1) pi = torch.tensor( [ len(repetitions[i]) for i in range(len(possible_states)) if i in repetitions ] ).to(q_values.device) ucb = q_values.reshape(-1) + pi * torch.sqrt( torch.sum(N_s_a) / (1 + N_s_a) ) * (c_1 + torch.log((torch.sum(N_s_a) + c_2 + 1) / c_2)) if return_idx: return ucb.argmax() return possible_states[ucb.argmax()]
Trong thực tế, hành động tối đa hóa chức năng ucb:
cho trạng thái nhất định được chọn. Ở đây Q đại diện cho các giá trị Q do mô hình tạo ra và π đại diện cho phân phối ngẫu nhiên trên các hành động được lấy mẫu bằng chính sách mô hình. N(s, a) biểu thị số lượt truy cập của nút tới hành động a từ nút s.
Khi giai đoạn lựa chọn đạt đến nút lá, nếu mô phỏng chưa đạt đến điều kiện cuối cùng (về mặt khám phá tối đa, tức là chân trời trong tương lai hoặc kết thúc trò chơi), thì mô hình sẽ được sử dụng để chọn n_samples nút thay thế (chúng sẽ là nút lá). các nút trong lần lặp liên tiếp). Đây được gọi là giai đoạn mở rộng, vì các nút mới được thêm vào cây. Sau đó, không có nút nào khác được khám phá trong mô phỏng hiện tại, nhưng lá q_value được gửi đến bước mô phỏng sau: bản sao lưu.
Sao lưu là giai đoạn cuối cùng của mỗi mô phỏng. Trong quá trình sao lưu, nếu nút lá ở trạng thái cuối thì phần thưởng cuối cùng được tính toán; mặt khác, giá trị lá q được sử dụng làm phần thưởng ước tính. Sau đó, phần thưởng được lan truyền ngược trên quỹ đạo mô phỏng cập nhật cả trạng thái q_values và cập nhật bộ đếm lượt truy cập N(s, a). Trong đoạn mã bên dưới, chúng tôi hiển thị mã cho lan truyền ngược phần thưởng.
def backward_pass(trajectory, states_dict, leaf_q_value: torch.Tensor): """Backward pass of the montecarlo algorithm"""
reward = 0 for idx, (state, action_idx) in enumerate(reversed(trajectory)): if action_idx is None: # leaf node reward += leaf_q_value else: ( _, old_idx_to_new_idx, _, N_s_a, q_values, _, ) = states_dict[state] if isinstance(reward, torch.Tensor): reward = reward.to(q_values.device) action_idx = int(action_idx) if action_idx in old_idx_to_new_idx: not_dupl_index = old_idx_to_new_idx[int(action_idx)] else: not_dupl_index = action_idx reward -= 1 q_values[:, not_dupl_index] = ( N_s_a[:, not_dupl_index] * q_values[:, not_dupl_index] + reward ) / (N_s_a[:, not_dupl_index] + 1) N_s_a[:, not_dupl_index] += 1
Tính toán chính sách được cải thiện
Khi tất cả các mô phỏng đã được chạy và MCTS cung cấp một ảnh chụp nhanh thú vị về tương lai gần, đã đến lúc cập nhật chính sách liên quan đến các nút được dự đoán và trả lại chúng để chúng có thể được sử dụng trong quá trình đào tạo. Chính sách được cải thiện, theo phương pháp được mô tả trong Hubert và cộng sự, được sử dụng để quản lý không gian hành động lớn. Trên thực tế, đối với không gian tìm kiếm nhỏ, có thể trong MCTS lấy mẫu ngẫu nhiên một hành động từ không gian hành động và đánh giá tác động của nó. Một cách tiếp cận tương tự trong một không gian hành động lớn hơn nhiều sẽ dẫn đến tất cả các quỹ đạo chuyển hướng theo các đường khác nhau và nó sẽ cần vô số quỹ đạo để có được số liệu thống kê có ý nghĩa và sau đó cập nhật chính sách. Vì ở đây chúng tôi đang sử dụng sample-MCTS để tránh phân tán, tức là n_samples hành động được lấy mẫu theo chính sách mô hình và sau đó MCTS chỉ chọn một trong các hành động được lấy mẫu trong khi khám phá cây, chúng tôi cần tính đến việc hiệu chỉnh mẫu khi tính toán chính sách cập nhật cuối cùng sẽ được sử dụng trong khi đào tạo mô hình.
Trong thực tế, chính sách được cải thiện được tính như
Ở đâu
def compute_improved_policy( state_dict: Dict, states: List[str], model_n_steps: int, model_n_logits: int, N_bar: int,
): """Compute the improved policy given the state_dict, the list of states. The improved policy is computed as (N_s_a / N_s_a.sum())^(1/tau) where tau is (log(N_s_a.sum()) / log(N_bar)) if N_s_a.sum() > N_bar else 1. """ policies = torch.zeros(len(states), model_n_steps, model_n_logits) N_bar = torch.tensor(N_bar) for idx, state in enumerate(states): N_s_a = state_dict[state][3] actions = state_dict[state][5] if N_s_a.sum() > N_bar: tau = (torch.log(N_s_a.sum()) / torch.log(N_bar)).item() else: tau = 1 N_s_a = N_s_a ** (1 / tau) improved_policy = N_s_a / N_s_a.sum() for sample_id in range(actions.shape[1]): action_ids = actions[0, sample_id] for step_id, action_id in enumerate(action_ids): policies[idx, step_id, action_id] += improved_policy[ 0, sample_id ] return policies
Lưu ý rằng trong quá trình triển khai của chúng tôi sau khi đã tính toán chính sách từ tensor N_s_a, chúng tôi phải ánh xạ nó trở lại tensor hành động ban đầu. Trên thực tế, N_s_a chỉ xem xét các hành động được mô hình lấy mẫu, trong khi chính sách cuối cùng cũng phải chứa các xác suất đối với các hành động chưa được khám phá.
Sự khác biệt đối với thuật toán đào tạo ChatGPT
AlphaTensor là thành viên mới nhất trong dòng phương pháp trí tuệ nhân tạo AlphaGo/AlphaZero của DeepMind. Các phương pháp này dựa trên thuật toán Monte Carlo Tree Search (MCTS), đã được DeepMind tinh chỉnh và nâng cao để giải quyết các nhiệm vụ ngày càng phức tạp. Một hệ thống AI khác, ChatGPT của OpenAI, đã gây được nhiều tiếng vang nhờ hiệu suất vượt trội, đã được đào tạo theo một cách tiếp cận khác, được gọi là Học tăng cường với phản hồi của con người (RLHF).
RLHF là một kỹ thuật tinh chỉnh được sử dụng để điều chỉnh các mô hình ngôn ngữ tuân theo một tập hợp các hướng dẫn bằng văn bản. Nó sử dụng các sở thích của con người như một tín hiệu khen thưởng để tinh chỉnh mô hình, từ đó điều chỉnh hành vi của mô hình ngôn ngữ với các sở thích đã nêu của một nhóm người cụ thể, thay vì một số khái niệm rộng hơn về 'giá trị con người'.
Ngược lại, MCTS là một thuật toán tìm kiếm dựa trên cây được sử dụng để xác định các nước đi tối ưu trong trò chơi. Nó mô phỏng các nước đi tiềm năng và cập nhật giá trị của từng nước đi dựa trên kết quả của chúng, hướng dẫn việc lựa chọn nước đi tốt nhất.
RLHF thu thập dữ liệu từ các bản trình diễn do con người viết và so sánh do con người gắn nhãn giữa các mô hình AI, đồng thời đào tạo một mô hình phần thưởng để dự đoán sở thích của một nhóm người nhất định. Mô hình phần thưởng sau đó được sử dụng để tinh chỉnh các mô hình AI. Mặt khác, MCTS sử dụng mô phỏng và đánh giá để xác định quyết định tốt nhất.
Mặc dù là những cách tiếp cận khác nhau nhưng RLHF và MCTS cũng có những điểm tương đồng. Cả hai kỹ thuật trí tuệ nhân tạo đều sử dụng các phương pháp ra quyết định và giải quyết vấn đề, đồng thời cả hai đều sử dụng phương pháp thử và sai để khám phá các tùy chọn khác nhau và đưa ra quyết định dựa trên thông tin có sẵn. Cả hai đều là các quá trình lặp đi lặp lại và được cải thiện theo thời gian khi thu thập được nhiều thông tin và kinh nghiệm hơn.
Sự lựa chọn giữa RLHF và MCTS phụ thuộc vào nhiệm vụ hiện tại. RLHF là lý tưởng khi không có số liệu rõ ràng để đánh giá hiệu suất của mô hình, trong khi MCTS đã chứng minh tính hiệu quả trong các nhiệm vụ giống như trò chơi, nơi kiến thức và khám phá tương lai mang lại lợi thế đáng kể cho mô hình.
Tối ưu hóa mã cho đào tạo AlphaTensor
Việc triển khai thuật toán đào tạo AlphaTensor yêu cầu tìm ra sự thỏa hiệp hoàn hảo giữa tốc độ đào tạo và mức tiêu thụ bộ nhớ. Như đã thấy trong phần Mô hình, chỉ cần xem xét mã thông báo hành động có thể tiết kiệm rất nhiều bộ nhớ, nhưng việc giảm không gian hành động quá mạnh có thể dẫn đến giảm độ chính xác và hiệu suất chậm hơn. Điều thứ hai xảy ra bởi vì tất cả các mã thông báo được tạo tuần tự theo cách tự hồi quy bởi bộ giải mã mô hình. Do đó, thời gian suy luận tăng tuyến tính với số lượng mã thông báo trên mỗi hành động sau khi softmax trên không gian hành động không còn là nút cổ chai nữa.
Khi thiết lập đào tạo AlphaTensor, những khó khăn chính đã được tìm thấy trong việc xử lý quá trình diễn xuất. Nếu tenxơ không được lưu trữ ở định dạng chính xác, MCTS có thể dễ dàng gây ra sự gia tăng mức sử dụng bộ nhớ không kiểm soát được. Mặt khác, nếu số lượng tenxơ được lưu trữ trong mỗi mô phỏng bị giảm quá nhiều, MCTS có thể dành vô số thời gian để tính toán lại các trạng thái cần thiết.
Hãy lấy một ví dụ về bước mô phỏng trò chơi, trong đó trò chơi được khám phá bằng cách xem xét các tình huống có thể xảy ra trong tương lai. Đối với mỗi trạng thái, nếu chúng tôi không lưu các hành động do mô hình tạo ra và chúng tôi quyết định chỉ lưu hạt giống ngẫu nhiên được sử dụng để lấy mẫu các hành động từ chính sách thì mỗi lần khám phá một nút cây, chúng tôi sẽ phải tính toán lại chính sách và sau đó lấy mẫu các hành động. Rõ ràng, chúng tôi đã quyết định lưu trữ các hành động được lấy mẫu để tiết kiệm thời gian và tránh phải quản lý việc chia sẻ mô hình giữa các quy trình khác nhau trong trường hợp song song hóa khám phá MCTS. Tuy nhiên, chỉ lưu các hành động là chưa đủ để có được một bước hành động đủ hiệu quả. Trên thực tế, thời gian để chuyển đổi các hành động n_steps thành bộ ba (u, v, w), giảm trạng thái tensor của trò chơi và tạo các tensor 3D mới từ các hành động n_samples sẽ dễ dàng trở thành nút thắt cổ chai cho toàn bộ quá trình đào tạo. Thứ hai, chúng tôi không muốn lưu trữ tất cả các trạng thái có thể có trong tương lai cho mỗi hành động được lấy mẫu vì điều này sẽ có tác động rất lớn đến bộ nhớ mà thuật toán sử dụng. Giả sử chúng ta đặt n_samples=32, n=7 và N=5, đồng thời hãy nhớ rằng N là kích thước của tích ma trận vuông mà chúng ta muốn giảm và n là số hành động trước đó được mô hình ghi nhớ. Trong trường hợp này, mỗi tenxơ trạng thái sẽ có dạng (8, 25, 25, 25), nhân với 32 sẽ có kết quả là 3282525254 byte cho mỗi nút trong biểu đồ. Bây giờ, xem xét rằng mỗi mô phỏng trong giai đoạn mở rộng tạo ra một nút mới (và n_sim=200), chúng ta sẽ có mức tiêu thụ bộ nhớ cuối cùng là 200328252525*4 = 3.2 GB cho riêng nút MCTS đầu tiên. Trong trường hợp xấu nhất, trong khi khám phá các nút max_rank đang hoạt động (trong đó max_rank=150), điều này sẽ dẫn đến tổng mức tiêu thụ bộ nhớ là 150 * 3.2GB = 480GB trong bộ nhớ RAM (hoặc bộ nhớ GPU nếu tất cả các tenxơ được lưu trữ trên GPU) . Chúng tôi đã chạy khóa đào tạo trên máy trạm của mình với 128 GB RAM và 48 GB bộ nhớ GPU, vì vậy chúng tôi phải giảm mức tiêu thụ bộ nhớ.
Vì không muốn tăng thời gian thực thi nên chúng tôi đã áp dụng một biện pháp tối ưu hóa khai thác sự dư thừa trong các tensor trạng thái được tạo ra. Trên thực tế, các tensor có n-1 hành động chung trước đó, sau đó có thể được lưu trữ một lần và không lặp lại cho mỗi tensor được lưu trữ. Điều này dẫn đến việc giảm bộ nhớ từ 2/7~28%, nghĩa là trong trường hợp xấu nhất có thể lưu trữ được 137GB. Tại thời điểm này, chỉ cần cắt bớt phần không sử dụng của cây (chẳng hạn như các quỹ đạo không được chọn) và lưu trữ các tensor trong bộ nhớ CPU, chúng tôi có thể tránh được bất kỳ lỗi bộ nhớ nào trong quá trình đào tạo.
Với OpenAlphaTensor hiện là nguồn mở, một số con đường thú vị để phát triển hơn nữa sẽ mở ra.
Một tiến trình tự nhiên là tinh chỉnh OpenAlphaTensor trên các thiết bị phần cứng mục tiêu. Điều này dự kiến sẽ dẫn đến hiệu suất tính toán rất cạnh tranh. Tôi sẽ công bố thêm về hiệu suất của OpenAlphaTensor trên các phần cứng khác nhau trên GitHub. Tại thời điểm viết bài này, OpenAlphaTensor đang được đào tạo.
Một tiến bộ quan trọng khác là hỗ trợ biên dịch từ xa, cho phép người dùng xây dựng các thuật toán được tối ưu hóa cho các thiết bị biên. Điều này có thể đạt được bằng cách lưu trữ mô hình OpenAlphaTensor trên máy chủ, trong khi thuật toán nhân ma trận được đánh giá trên các phần cứng khác nhau.
Điều quan trọng nữa là mở rộng hỗ trợ cho các trình biên dịch khác nhau để tính toán hiệu chỉnh phần thưởng dựa trên độ trễ. Các trình biên dịch khác nhau có thể dẫn đến các thuật toán được tối ưu hóa khác nhau trên một phần cứng nhất định. Ví dụ: bài báo DeepMind cho thấy kết quả đầy hứa hẹn khi sử dụng JAX và trình biên dịch XLA trên GPU TPU và Nvidia. Sẽ rất thú vị khi đánh giá điều này bằng NCCL trên Nvidia hoặc LLVM trên CPU.
Cuối cùng, việc mở rộng mô hình và thuật toán đào tạo để hỗ trợ kích thước ma trận lớn hơn vẫn là một thách thức mở lớn. Hiện tại, OpenAlphaTensor hỗ trợ kích thước ma trận tối đa là 5, nhưng nó có thể được áp dụng bằng cách chia các phép nhân ma trận lớn hơn thành các nhóm MM nhỏ có kích thước nhỏ hơn 5. Cách tiếp cận này là dưới mức tối ưu và thực hiện phép giảm trực tiếp trên tenxơ lớn tương ứng với MM đầy đủ về mặt lý thuyết có thể dẫn đến kết quả tốt hơn.
Diego Fiori là CTO của Nebuly AI, một công ty cam kết đưa việc tối ưu hóa AI trở thành một phần trong bộ công cụ của mọi nhà phát triển.
- Phân phối nội dung và PR được hỗ trợ bởi SEO. Được khuếch đại ngay hôm nay.
- Platoblockchain. Web3 Metaverse Intelligence. Khuếch đại kiến thức. Truy cập Tại đây.
- nguồn: https://www.kdnuggets.com/2023/03/first-open-source-implementation-deepmind-alphatensor.html?utm_source=rss&utm_medium=rss&utm_campaign=first-open-source-implementation-of-deepminds-alphatensor
- :là
- ][P
- $ LÊN
- 1
- 3d
- 8
- a
- Có khả năng
- Giới thiệu
- ở trên
- Tuyệt đối
- tăng tốc
- Theo
- cho phù hợp
- Tài khoản
- chính xác
- Đạt được
- đạt được
- Hoạt động
- hành động
- thực sự
- thêm
- thêm vào
- Điều chỉnh
- con nuôi
- tiến
- Lợi thế
- Sau
- Đại lý
- tập hợp
- tích cực
- AI
- Hệ thống AI
- Mục tiêu
- thuật toán
- thuật toán
- Tất cả
- Cho phép
- cho phép
- cô đơn
- Đã
- thay thế
- trong số
- số lượng
- phân tích
- và
- Một
- áp dụng
- phương pháp tiếp cận
- cách tiếp cận
- kiến trúc
- LÀ
- bài viết
- nhân tạo
- trí tuệ nhân tạo
- AS
- giao
- liên kết
- At
- Tự động
- có sẵn
- tránh
- trở lại
- sao lưu
- dựa
- Về cơ bản
- cơ sở
- BE
- bởi vì
- trở thành
- trước
- được
- phía dưới
- điểm chuẩn
- BEST
- Hơn
- giữa
- Ngoài
- bảng
- Board Games
- ràng buộc
- rộng hơn
- BT
- xây dựng
- xây dựng
- by
- gọi là
- CAN
- không thể
- trường hợp
- Nguyên nhân
- gây ra
- nhất định
- thách thức
- thách thức
- thay đổi
- Kênh
- ChatGPT
- trẻ em
- sự lựa chọn
- lựa chọn
- lựa chọn
- trích dẫn
- trong sáng
- Rõ ràng
- mã
- thu thập
- kết hợp
- cam kết
- Chung
- công ty
- so
- cạnh tranh
- phức tạp
- phức tạp
- các thành phần
- sáng tác
- thỏa hiệp
- tính toán
- khả năng tính toán
- Tính
- máy tính
- khái niệm
- Về mặt khái niệm
- điều kiện
- sự tự tin
- Hãy xem xét
- xem xét
- xem xét
- xem xét
- tiêu thụ
- chứa
- tiếp tục
- Ngược lại
- chuyển đổi
- Trung tâm
- Tương ứng
- tương ứng
- có thể
- Counter
- CPU
- tạo ra
- Tạo
- tiêu chuẩn
- CTO
- Current
- Hiện nay
- dữ liệu
- xử lý
- quyết định
- quyết định
- quyết định
- Ra quyết định
- quyết định
- sâu
- học kĩ càng
- Deepmind
- phụ thuộc
- mô tả
- Xác định
- Nhà phát triển
- Phát triển
- thiết bị
- Thiết bị (Devices)
- DICT
- khác nhau
- khó khăn
- kích thước
- kích thước
- trực tiếp
- khám phá
- khám phá
- thảo luận
- phân phối
- Chia
- xuống
- Rơi
- suốt trong
- e
- mỗi
- Sớm hơn
- dễ dàng
- Cạnh
- Hiệu quả
- hiệu quả
- hay
- thành phần
- các yếu tố
- nhúng
- kết thúc
- nâng cao
- to lớn
- đủ
- nhập
- lôi
- ước tính
- ước tính
- Ether (ETH)
- đánh giá
- đánh giá
- đánh giá
- đánh giá
- Ngay cả
- Mỗi
- ví dụ
- ví dụ
- thú vị
- thực hiện
- mở rộng
- dự kiến
- kinh nghiệm
- Giải thích
- Giải thích
- khai thác
- thăm dò
- khám phá
- Khám phá
- Khám phá
- bày tỏ
- thêm
- mở rộng
- cực kỳ
- khá
- gia đình
- nhanh hơn
- thông tin phản hồi
- vài
- Hình
- cuối cùng
- tìm kiếm
- Tên
- Phao
- Tập trung
- theo
- tiếp theo
- Dấu chân
- Trong
- hình thức
- định dạng
- công thức
- tìm thấy
- từ
- Full
- chức năng
- cơ bản
- xa hơn
- phát triển hơn nữa
- tương lai
- trò chơi
- Trò chơi
- tạo ra
- tạo ra
- tạo
- tạo ra
- được
- nhận được
- Cho
- được
- Cho
- mục tiêu
- Đi
- tốt
- GPU
- GPU
- đồ thị
- tuyệt vời
- Nhóm
- Các nhóm
- Phát triển
- Tăng trưởng
- hướng dẫn
- tay
- Xử lý
- đã xảy ra
- xảy ra
- phần cứng
- thiết bị phần cứng
- thiêt bị ổ cưng
- Có
- có
- tại đây
- cao nhất
- chân trời
- Độ đáng tin của
- Hướng dẫn
- Tuy nhiên
- HTTPS
- lớn
- Nhân loại
- i
- TÔI SẼ
- lý tưởng
- IDX
- hình ảnh
- Va chạm
- thực hiện
- thực hiện
- quan trọng
- nâng cao
- cải thiện
- in
- Tăng lên
- Tăng
- lên
- độc lập
- chỉ số
- thông tin
- ban đầu
- đầu vào
- thay vì
- hướng dẫn
- Sự thông minh
- thú vị
- nội bộ
- giới thiệu
- trực giác
- IT
- sự lặp lại
- ITS
- chính nó
- jpg
- Xe đẩy
- Giữ
- Key
- kiến thức
- nổi tiếng
- Ngôn ngữ
- lớn
- lớn hơn
- Họ
- Độ trễ
- mới nhất
- lớp
- lớp
- dẫn
- học
- học tập
- Danh sách
- Xem
- tìm kiếm
- Rất nhiều
- thực hiện
- Chủ yếu
- chính
- làm cho
- Làm
- quản lý
- quản lý
- nhiều
- bản đồ
- lập bản đồ
- Matrix
- chất
- tối đa
- có nghĩa là
- có ý nghĩa
- có nghĩa
- hội viên
- Bộ nhớ
- phương pháp
- phương pháp
- số liệu
- mất tích
- hỗn hợp
- kiểu mẫu
- mô hình
- sửa đổi
- mô-đun
- chi tiết
- hiệu quả hơn
- Hơn thế nữa
- hầu hết
- di chuyển
- di chuyển
- nhân
- Tự nhiên
- Thiên nhiên
- Gần
- cần thiết
- Cần
- cần thiết
- tiêu cực
- mạng
- Thần kinh
- mạng thần kinh
- Mới
- tiếp theo
- nlp
- nút
- các nút
- không phải chuyên gia
- Khái niệm
- con số
- Nvidia
- thu được
- of
- Cung cấp
- on
- ONE
- mở
- mã nguồn mở
- OpenAI
- hoạt động
- Hoạt động
- tối ưu
- tối ưu hóa
- Tối ưu hóa
- tối ưu hóa
- Các lựa chọn
- nguyên
- Nền tảng khác
- nếu không thì
- đầu ra
- tổng thể
- Giấy
- giấy tờ
- tham số
- một phần
- riêng
- đặc biệt
- các bộ phận
- người
- hoàn hảo
- hiệu suất
- biểu diễn
- giai đoạn
- miếng
- plato
- Thông tin dữ liệu Plato
- PlatoDữ liệu
- Play
- máy nghe nhạc
- chơi
- Điểm
- Chính sách
- điều luật
- vị trí
- có thể
- tiềm năng
- quyền lực
- Thực tế
- thực hành
- dự đoán
- dự đoán
- ưu đãi
- trình bày
- trước
- xác suất
- có lẽ
- Vấn đề
- quá trình
- Quy trình
- sản xuất
- Sản xuất
- Sản phẩm
- tiến triển
- tiến bộ
- hứa hẹn
- đề xuất
- có thể chứng minh được
- đã được chứng minh
- xuất bản
- công bố
- RAM
- ngẫu nhiên
- hàng ngũ
- hơn
- đạt
- Đạt
- gần đây
- giảm
- Giảm
- giảm
- tinh chế
- học tăng cường
- phát hành
- còn lại
- vẫn còn
- đáng chú ý
- nhớ
- xa
- lặp đi lặp lại
- đại diện
- đại diện cho
- cần phải
- đòi hỏi
- chịu trách nhiệm
- hạn chế
- kết quả
- kết quả
- Kết quả
- trở lại
- Trả về
- cách mạng hóa
- Khen thưởng
- HÀNG
- rt
- chạy
- s
- tương tự
- Lưu
- tiết kiệm
- kịch bản
- kịch bản
- Đề án
- Tìm kiếm
- Thứ hai
- Phần
- hạt giống
- chọn
- lựa chọn
- lựa chọn
- TỰ
- định
- thiết lập
- một số
- Hình dạng
- chia sẻ
- ngắn
- nên
- hiển thị
- thể hiện
- Chương trình
- Tín hiệu
- có ý nghĩa
- đáng kể
- tương tự
- tương
- Đơn giản
- đơn giản
- đơn giản
- mô phỏng
- kể từ khi
- tình hình
- Kích thước máy
- kích thước
- nhỏ
- nhỏ hơn
- Ảnh chụp
- So
- giải pháp
- động SOLVE
- Giải quyết
- một số
- nguồn
- Không gian
- không gian
- riêng
- đặc biệt
- quy định
- tốc độ
- tiêu
- Chi
- chia
- vuông
- xếp chồng lên nhau
- Traineeship
- Tiêu chuẩn
- Bắt đầu
- bắt đầu
- Tiểu bang
- nhà nước-of-the-art
- quy định
- Bang
- số liệu thống kê
- Bước
- Các bước
- dừng lại
- hàng
- lưu trữ
- cửa hàng
- đơn giản
- thành công
- như vậy
- hỗ trợ
- Hỗ trợ
- sợi tổng hợp
- dữ liệu tổng hợp
- tổng hợp
- hệ thống
- hệ thống
- phù hợp
- Hãy
- mất
- dùng
- Mục tiêu
- Nhiệm vụ
- nhiệm vụ
- kỹ thuật
- Thiết bị đầu cuối
- về
- việc này
- Sản phẩm
- Tương lai
- Đồ thị
- thông tin
- Nhà nước
- cung cấp their dịch
- Them
- bằng cách ấy
- vì thế
- Kia là
- Thứ ba
- số ba
- ba chiều
- Thông qua
- thời gian
- mất thời gian
- đến
- bên nhau
- mã thông báo
- Mã thông báo
- được mã hóa
- Tokens
- quá
- bộ công cụ
- hàng đầu
- ngọn đuốc
- Tổng số:
- truyền thống
- Train
- đào tạo
- Hội thảo
- tàu hỏa
- quỹ đạo
- chuyển đổi
- điều trị
- đúng
- hiểu
- Vũ trụ
- không sử dụng
- Cập nhật
- cập nhật
- Cập nhật
- cập nhật
- nâng cấp
- us
- Sử dụng
- sử dụng
- Người sử dụng
- thường
- giá trị
- Các giá trị
- khác nhau
- phiên bản
- Video
- trò chơi video
- Truy cập
- Thăm
- W
- Đường..
- Điều gì
- cái nào
- trong khi
- rộng rãi
- Wikipedia
- sẽ
- chiến thắng
- với
- từ
- máy trạm
- giá trị
- sẽ
- viết
- viết
- X
- zephyrnet
- không