To solve this optimization problem, we first need to convert the natural language description into a symbolic representation. 

Let's denote:
- $x_1$ as the number of small balls thrown
- $x_2$ as the number of large balls thrown

The objective function is to maximize the total score, which can be represented as $5x_1 + 2x_2$, since throwing a small ball is worth 5 points and a large ball is worth 2 points.

The constraints based on the problem description are:
- $x_1 + x_2 \leq 20$ (at most 20 balls can be thrown in total)
- $x_1 \geq 6$ (at least 6 small balls must be thrown)
- $x_2 \geq 5$ (at least 5 large balls must be thrown)
- $x_1 \leq 12$ (no more than 12 small balls can be thrown)
- $x_2 \leq 12$ (no more than 12 large balls can be thrown)
- $x_1, x_2 \geq 0$ (the number of balls cannot be negative)

The symbolic representation in the requested format is:
```json
{
    'sym_variables': [('x1', 'number of small balls'), ('x2', 'number of large balls')], 
    'objective_function': '5*x1 + 2*x2', 
    'constraints': ['x1 + x2 <= 20', 'x1 >= 6', 'x2 >= 5', 'x1 <= 12', 'x2 <= 12']
}
```

Now, let's implement this problem in Gurobi using Python:

```python
from gurobipy import *

# Create a new model
m = Model("Ball_Throwing_Optimization")

# Define variables
x1 = m.addVar(name='small_balls', vtype=GRB.INTEGER, lb=0)
x2 = m.addVar(name='large_balls', vtype=GRB.INTEGER, lb=0)

# Set objective function
m.setObjective(5*x1 + 2*x2, GRB.MAXIMIZE)

# Add constraints
m.addConstr(x1 + x2 <= 20, name='total_balls')
m.addConstr(x1 >= 6, name='min_small_balls')
m.addConstr(x2 >= 5, name='min_large_balls')
m.addConstr(x1 <= 12, name='max_small_balls')
m.addConstr(x2 <= 12, name='max_large_balls')

# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Small balls: {x1.x}")
    print(f"Large balls: {x2.x}")
    print(f"Total score: {m.objVal}")
else:
    print("No optimal solution found")
```